feat: new layout

This commit is contained in:
TrèsAbhi committed 2024-02-01 11:52:48 -06:00
1 parent 281549add3
commit 9f2ced6bfd
5 files changed
+223 -225

No files matched your search

@@ -5,7 +5,7 @@ import { theme } from '../../../../../../../stitches.config';
interface InfoProps {
name: string;
children: ReactNode;
unit: string;
unit?: string;
indent?: boolean;
highlight?: boolean;
}
@@ -24,10 +24,15 @@ export function Info({
gap="4"
>
<Text color={highlight ? 'amber' : undefined}>
{name}{' '}
<Text color="gray" size="1">
{unit}
</Text>
{name}
{unit != undefined && (
<>
{' '}
<Text color="gray" size="1">
{unit}
</Text>
</>
)}
</Text>
<div
@@ -1,18 +1,15 @@
import { Flex, Heading, Tabs } from '@radix-ui/themes';
import { Flex, Heading } from '@radix-ui/themes';
import { use } from 'react';
import { resolveNearPenetration } from '../../../../../../core/blitz/resolveNearPenetration';
import { modelDefinitions } from '../../../../../../core/blitzkrieg/modelDefinitions';
import { normalizeBoundingBox } from '../../../../../../core/blitzkrieg/normalizeBoundingBox';
import { SHELL_NAMES } from '../../../../../../core/blitzkrieg/tankDefinitions';
import {
GUN_TYPE_NAMES,
SHELL_NAMES,
} from '../../../../../../core/blitzkrieg/tankDefinitions';
import { unionBoundingBox } from '../../../../../../core/blitzkrieg/unionBoundingBox';
import { useDuel } from '../../../../../../stores/duel';
import { Camouflage } from './components/Camouflage';
import { Consumables } from './components/Consumables';
import { Crew } from './components/Crew';
import { Equipments } from './components/Equipments';
import { Info } from './components/Info';
import { Modules } from './components/Modules';
import { Provisions } from './components/Provisions';
export function Characteristics() {
const awaitedModelDefinitions = use(modelDefinitions);
@@ -47,216 +44,192 @@ export function Characteristics() {
}
return (
<Tabs.Root defaultValue="configure" style={{ width: '100%' }}>
<Flex gap="4" direction="column">
<Tabs.List>
<Tabs.Trigger value="configure">Configure</Tabs.Trigger>
<Tabs.Trigger value="statistics">Statistics</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="statistics">
<Flex direction="column" gap="4">
<Flex direction="column" gap="2">
<Heading size="5">Survivability</Heading>
<Info name="Health" unit="hp">
{tank.health + turret.health}
</Info>
<Info name="Fire chance" unit="%">
{Math.round(engine.fire_chance * 100)}
</Info>
<Info name="View range" unit="m">
{turret.view_range}
</Info>
<Info name="Camouflage when still" unit="%">
{(tank.camouflage.still * 100).toFixed(2)}
</Info>
<Info indent name="Moving" unit="%">
{(tank.camouflage.moving * 100).toFixed(2)}
</Info>
<Info indent name="Shooting still" unit="%">
{(tank.camouflage.still * gun.camouflageLoss * 100).toFixed(2)}
</Info>
<Info indent name="Shooting on move" unit="%">
{(tank.camouflage.moving * gun.camouflageLoss * 100).toFixed(2)}
</Info>
<Info indent name="On fire penalty" unit="%">
{(tank.camouflage.onFire * 100).toFixed(2)}
</Info>
<Info indent name="Size" unit="m">
{size.map((component) => component.toFixed(2)).join(' x ')}
</Info>
</Flex>
<Flex direction="column" gap="2">
<Heading size="5">Fire</Heading>
<Info name="Damage per minute" unit="hp / min">
{dpm.toFixed(0)}
</Info>
{gun.type === 'auto_reloader' && (
<>
<Info indent name="Maximum" unit="hp / min">
TODO
</Info>
<Info indent name="Effective" unit="hp / min">
TODO
</Info>
</>
)}
{gun.type === 'auto_reloader' ? (
gun.reload.map((reload, index) => (
<Info
indent={index > 0}
name={
index > 0 ? `Shell ${index + 1}` : 'Reload on shell 1'
}
unit="s"
>
{reload.toFixed(2)}
</Info>
))
) : (
<Info name="Reload" unit="s">
{gun.reload.toFixed(2)}
</Info>
)}
<Info name="Caliber" unit="mm">
{shell.caliber}
</Info>
{gun.shells.map((shell, index) => (
<Info
indent={index > 0}
name={`${SHELL_NAMES[shell.type]}${index === 0 ? ' penetration' : ''}`}
unit="mm"
>
{resolveNearPenetration(shell.penetration)}
</Info>
))}
{gun.shells.map((shell, index) => (
<Info
indent={index > 0}
name={`${SHELL_NAMES[shell.type]}${index === 0 ? ' damage' : ''}`}
unit="hp"
>
{shell.damage.armor}
</Info>
))}
{gun.shells.map((shell, index) => (
<Info
indent={index > 0}
name={`${SHELL_NAMES[shell.type]}${index === 0 ? ' module damage' : ''}`}
unit="hp"
>
{shell.damage.module}
</Info>
))}
{gun.shells.map((shell, index) => (
<Info
indent={index > 0}
name={`${SHELL_NAMES[shell.type]}${index === 0 ? ' velocity' : ''}`}
unit="m/s"
>
{shell.speed}
</Info>
))}
<Info name="Aim time" unit="s">
TODO
</Info>
<Info name="Dispersion at 100m" unit="m">
TODO
</Info>
<Info indent name="On move" unit="m">
TODO
</Info>
<Info indent name="On hull traverse" unit="m">
TODO
</Info>
<Info indent name="On turret traverse" unit="m">
TODO
</Info>
<Info indent name="On shoot" unit="m">
TODO
</Info>
<Info name="Gun depression" unit="°">
{gunModelDefinition.pitch.max}
</Info>
<Info indent name="Elevation" unit="°">
{-gunModelDefinition.pitch.min}
</Info>
{gunModelDefinition.pitch.front && (
<>
<Info indent name="Frontal depression" unit="°">
{gunModelDefinition.pitch.front.max}
</Info>
<Info indent name="Frontal elevation" unit="°">
{-gunModelDefinition.pitch.front.min}
</Info>
</>
)}
{gunModelDefinition.pitch.back && (
<>
<Info indent name="Rear depression" unit="°">
{gunModelDefinition.pitch.back.max}
</Info>
<Info indent name="Rear elevation" unit="°">
{-gunModelDefinition.pitch.back.min}
</Info>
</>
)}
{turretModelDefinition.yaw && (
<Info indent name="Azimuth" unit="°">
{-turretModelDefinition.yaw.min},{' '}
{turretModelDefinition.yaw.max}
</Info>
)}
</Flex>
<Flex direction="column" gap="2">
<Heading size="5">Maneuverability</Heading>
<Info name="Speed forwards" unit="km/s">
TODO
</Info>
<Info indent name="Average" unit="km/s">
TODO
</Info>
<Info indent name="Backwards" unit="km/s">
TODO
</Info>
<Info name="Effective power on hard terrain" unit="hp/kg">
TODO
</Info>
<Info indent name="On medium terrain" unit="hp/kg">
TODO
</Info>
<Info indent name="On soft terrain" unit="hp/kg">
TODO
</Info>
<Info name="Weight" unit="mt">
TODO
</Info>
<Info name="Traverse speed on hard terrain" unit="°/s">
TODO
</Info>
<Info indent name="On medium terrain" unit="°/s">
TODO
</Info>
<Info indent name="On soft terrain" unit="°/s">
TODO
</Info>
</Flex>
</Flex>
</Tabs.Content>
<Tabs.Content value="configure">
<Flex direction="column" gap="4">
<Modules />
<Equipments />
<Crew />
<Consumables />
<Provisions />
<Camouflage />
</Flex>
</Tabs.Content>
<Flex direction="column" gap="4">
<Flex direction="column" gap="2">
<Heading size="5">Survivability</Heading>
<Info name="Health" unit="hp">
{tank.health + turret.health}
</Info>
<Info name="Fire chance" unit="%">
{Math.round(engine.fire_chance * 100)}
</Info>
<Info name="View range" unit="m">
{turret.view_range}
</Info>
<Info name="Camouflage when still" unit="%">
{(tank.camouflage.still * 100).toFixed(2)}
</Info>
<Info indent name="Moving" unit="%">
{(tank.camouflage.moving * 100).toFixed(2)}
</Info>
<Info indent name="Shooting still" unit="%">
{(tank.camouflage.still * gun.camouflageLoss * 100).toFixed(2)}
</Info>
<Info indent name="Shooting on move" unit="%">
{(tank.camouflage.moving * gun.camouflageLoss * 100).toFixed(2)}
</Info>
<Info indent name="On fire penalty" unit="%">
{(tank.camouflage.onFire * 100).toFixed(2)}
</Info>
<Info indent name="Size" unit="m">
{size.map((component) => component.toFixed(2)).join(' x ')}
</Info>
</Flex>
</Tabs.Root>
<Flex direction="column" gap="2">
<Heading size="5">Fire</Heading>
<Info name="Gun type">{GUN_TYPE_NAMES[gun.type]}</Info>
<Info name="Damage per minute" unit="hp / min">
{dpm.toFixed(0)}
</Info>
{gun.type === 'auto_reloader' && (
<>
<Info indent name="Maximum" unit="hp / min">
TODO
</Info>
<Info indent name="Effective" unit="hp / min">
TODO
</Info>
</>
)}
{gun.type === 'auto_reloader' ? (
gun.reload.map((reload, index) => (
<Info
indent={index > 0}
name={index > 0 ? `Shell ${index + 1}` : 'Reload on shell 1'}
unit="s"
>
{reload.toFixed(2)}
</Info>
))
) : (
<Info name="Reload" unit="s">
{gun.reload.toFixed(2)}
</Info>
)}
<Info name="Caliber" unit="mm">
{shell.caliber}
</Info>
{gun.shells.map((shell, index) => (
<Info
indent={index > 0}
name={`${SHELL_NAMES[shell.type]}${index === 0 ? ' penetration' : ''}`}
unit="mm"
>
{resolveNearPenetration(shell.penetration)}
</Info>
))}
{gun.shells.map((shell, index) => (
<Info
indent={index > 0}
name={`${SHELL_NAMES[shell.type]}${index === 0 ? ' damage' : ''}`}
unit="hp"
>
{shell.damage.armor}
</Info>
))}
{gun.shells.map((shell, index) => (
<Info
indent={index > 0}
name={`${SHELL_NAMES[shell.type]}${index === 0 ? ' module damage' : ''}`}
unit="hp"
>
{shell.damage.module}
</Info>
))}
{gun.shells.map((shell, index) => (
<Info
indent={index > 0}
name={`${SHELL_NAMES[shell.type]}${index === 0 ? ' velocity' : ''}`}
unit="m/s"
>
{shell.speed}
</Info>
))}
<Info name="Aim time" unit="s">
TODO
</Info>
<Info name="Dispersion at 100m" unit="m">
TODO
</Info>
<Info indent name="On move" unit="m">
TODO
</Info>
<Info indent name="On hull traverse" unit="m">
TODO
</Info>
<Info indent name="On turret traverse" unit="m">
TODO
</Info>
<Info indent name="On shoot" unit="m">
TODO
</Info>
<Info name="Gun depression" unit="°">
{gunModelDefinition.pitch.max}
</Info>
<Info indent name="Elevation" unit="°">
{-gunModelDefinition.pitch.min}
</Info>
{gunModelDefinition.pitch.front && (
<>
<Info indent name="Frontal depression" unit="°">
{gunModelDefinition.pitch.front.max}
</Info>
<Info indent name="Frontal elevation" unit="°">
{-gunModelDefinition.pitch.front.min}
</Info>
</>
)}
{gunModelDefinition.pitch.back && (
<>
<Info indent name="Rear depression" unit="°">
{gunModelDefinition.pitch.back.max}
</Info>
<Info indent name="Rear elevation" unit="°">
{-gunModelDefinition.pitch.back.min}
</Info>
</>
)}
{turretModelDefinition.yaw && (
<Info indent name="Azimuth" unit="°">
{-turretModelDefinition.yaw.min}, {turretModelDefinition.yaw.max}
</Info>
)}
</Flex>
<Flex direction="column" gap="2">
<Heading size="5">Maneuverability</Heading>
<Info name="Speed forwards" unit="km/s">
TODO
</Info>
<Info indent name="Average" unit="km/s">
TODO
</Info>
<Info indent name="Backwards" unit="km/s">
TODO
</Info>
<Info name="Effective power on hard terrain" unit="hp/kg">
TODO
</Info>
<Info indent name="On medium terrain" unit="hp/kg">
TODO
</Info>
<Info indent name="On soft terrain" unit="hp/kg">
TODO
</Info>
<Info name="Weight" unit="mt">
TODO
</Info>
<Info name="Traverse speed on hard terrain" unit="°/s">
TODO
</Info>
<Info indent name="On medium terrain" unit="°/s">
TODO
</Info>
<Info indent name="On soft terrain" unit="°/s">
TODO
</Info>
</Flex>
</Flex>
);
}
+15 -1
View File
@@ -8,6 +8,12 @@ import { mutateDuel, useDuel } from '../../../../stores/duel';
import { mutateTankopediaTemporary } from '../../../../stores/tankopedia';
import { AntagonistBar } from './components/AntagonistBar';
import { Characteristics } from './components/Characteristics';
import { Camouflage } from './components/Characteristics/components/Camouflage';
import { Consumables } from './components/Characteristics/components/Consumables';
import { Crew } from './components/Characteristics/components/Crew';
import { Equipments } from './components/Characteristics/components/Equipments';
import { Modules } from './components/Characteristics/components/Modules';
import { Provisions } from './components/Characteristics/components/Provisions';
import { TankSandbox } from './components/Model/TankSandbox';
import { Title } from './components/Title';
@@ -92,13 +98,21 @@ export default function Page({ params }: { params: { id: string } }) {
direction="column"
style={{
flex: 1,
position: wideFormat ? 'sticky' : undefined,
width: '100%',
top: 64,
}}
>
<TankSandbox />
<AntagonistBar />
<Flex direction="column" gap="4">
<Modules />
<Equipments />
<Crew />
<Consumables />
<Provisions />
<Camouflage />
</Flex>
</Flex>
<Flex style={{ width: wideFormat ? 320 : '100%' }}>
+1 -1
View File
@@ -5,7 +5,7 @@ export class EventManager<Type> {
this.callbacks.add(callback);
}
off(callback: (data: Type) => void) {
this.callbacks.delete(callback);
return this.callbacks.delete(callback);
}
emit(data: Type) {
+6
View File
@@ -91,6 +91,12 @@ export type ShellDefinition = {
explosionRadius?: number;
};
export const GUN_TYPE_NAMES: Record<GunDefinition['type'], string> = {
regular: 'Regular',
auto_loader: 'Auto loader',
auto_reloader: 'Auto reloader',
};
export const tankDefinitions = fetch(asset('definitions/tanks.json'), {
cache: 'no-cache',
}).then(async (response) => response.json() as Promise<TankDefinitions>);