mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-25 03:29:51 +01:00
feat: better layout
This commit is contained in:
1 parent
299ccef579
commit
ab510361b5
6 files changed
+96
-68
No files matched your search
@@ -32,7 +32,7 @@ export function Info({
|
|||||||
style={{ width: '100%', paddingLeft: indent ? 24 : 0 }}
|
style={{ width: '100%', paddingLeft: indent ? 24 : 0 }}
|
||||||
gap="4"
|
gap="4"
|
||||||
>
|
>
|
||||||
<Text color={highlight ? 'amber' : undefined}>
|
<Text color={highlight ? 'amber' : 'gray'}>
|
||||||
{name}
|
{name}
|
||||||
{unit != undefined && (
|
{unit != undefined && (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -25,12 +25,14 @@ import {
|
|||||||
} from '../../../../../../core/blitzkit/tankDefinitions/constants';
|
} from '../../../../../../core/blitzkit/tankDefinitions/constants';
|
||||||
import { useEquipment } from '../../../../../../hooks/useEquipment';
|
import { useEquipment } from '../../../../../../hooks/useEquipment';
|
||||||
import { useFullScreen } from '../../../../../../hooks/useFullScreen';
|
import { useFullScreen } from '../../../../../../hooks/useFullScreen';
|
||||||
|
import { useWideFormat } from '../../../../../../hooks/useWideFormat';
|
||||||
import { mutateDuel, useDuel } from '../../../../../../stores/duel';
|
import { mutateDuel, useDuel } from '../../../../../../stores/duel';
|
||||||
import { useTankopediaTemporary } from '../../../../../../stores/tankopedia';
|
import { useTankopediaTemporary } from '../../../../../../stores/tankopedia';
|
||||||
import { Info } from './components/Info';
|
import { Info } from './components/Info';
|
||||||
import { InfoWithDelta } from './components/InfoWithDelta';
|
import { InfoWithDelta } from './components/InfoWithDelta';
|
||||||
|
|
||||||
export function Characteristics() {
|
export function Characteristics() {
|
||||||
|
const wideFormat = useWideFormat(960);
|
||||||
const awaitedEquipmentDefinitions = use(equipmentDefinitions);
|
const awaitedEquipmentDefinitions = use(equipmentDefinitions);
|
||||||
const awaitedModelDefinitions = use(modelDefinitions);
|
const awaitedModelDefinitions = use(modelDefinitions);
|
||||||
const awaitedProvisionDefinitions = use(provisionDefinitions);
|
const awaitedProvisionDefinitions = use(provisionDefinitions);
|
||||||
@@ -128,7 +130,8 @@ export function Characteristics() {
|
|||||||
if (isFullScreen) return null;
|
if (isFullScreen) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex direction="column" gap="8">
|
<Flex direction={wideFormat ? 'row' : 'column'} gap="8" wrap="wrap">
|
||||||
|
<Flex direction="column" gap="8" style={{ flex: 1 }}>
|
||||||
<Flex direction="column" gap="2">
|
<Flex direction="column" gap="2">
|
||||||
<Flex align="center" gap="4">
|
<Flex align="center" gap="4">
|
||||||
<Heading size="5">Fire</Heading>
|
<Heading size="5">Fire</Heading>
|
||||||
@@ -248,7 +251,8 @@ export function Characteristics() {
|
|||||||
{lerp(
|
{lerp(
|
||||||
shell.penetration[0],
|
shell.penetration[0],
|
||||||
shell.penetration[1],
|
shell.penetration[1],
|
||||||
(penetrationDistance * penetrationLossOverDistanceCoefficient) /
|
(penetrationDistance *
|
||||||
|
penetrationLossOverDistanceCoefficient) /
|
||||||
500,
|
500,
|
||||||
) * penetrationCoefficient}
|
) * penetrationCoefficient}
|
||||||
</InfoWithDelta>
|
</InfoWithDelta>
|
||||||
@@ -419,7 +423,68 @@ export function Characteristics() {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
<Flex direction="column" gap="2">
|
||||||
|
<Flex gap="2" align="center">
|
||||||
|
<Heading size="5">Crew training</Heading>
|
||||||
|
|
||||||
|
<Popover.Root>
|
||||||
|
<Popover.Trigger>
|
||||||
|
<IconButton variant="ghost">
|
||||||
|
<InfoCircledIcon />
|
||||||
|
</IconButton>
|
||||||
|
</Popover.Trigger>
|
||||||
|
|
||||||
|
<Popover.Content>
|
||||||
|
<Flex gap="1" align="center">
|
||||||
|
<AccessibilityIcon />
|
||||||
|
<Text>
|
||||||
|
represents the other roles a crew member can take.
|
||||||
|
</Text>
|
||||||
|
</Flex>
|
||||||
|
</Popover.Content>
|
||||||
|
</Popover.Root>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
{tank.crew.map((member) => {
|
||||||
|
const count = member.count ?? 1;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment key={member.type}>
|
||||||
|
<InfoWithDelta
|
||||||
|
key={`${member.type}-root`}
|
||||||
|
name={`${CREW_MEMBER_NAMES[member.type]}${count > 1 ? ` x ${count}` : ''}`}
|
||||||
|
unit="%"
|
||||||
|
decimals={0}
|
||||||
|
>
|
||||||
|
{(member.type === 'commander'
|
||||||
|
? commanderMastery
|
||||||
|
: crewMemberMastery) * 100}
|
||||||
|
</InfoWithDelta>
|
||||||
|
{member.substitute && (
|
||||||
|
<Info
|
||||||
|
key={`${member.type}-substitute`}
|
||||||
|
indent
|
||||||
|
name={
|
||||||
|
<>
|
||||||
|
<Flex align="center" gap="1">
|
||||||
|
<AccessibilityIcon />
|
||||||
|
{member.substitute
|
||||||
|
.map((sub, index) =>
|
||||||
|
index === 0 ? CREW_MEMBER_NAMES[sub] : sub,
|
||||||
|
)
|
||||||
|
.join(', ')}
|
||||||
|
</Flex>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
|
<Flex direction="column" gap="8" style={{ flex: 1 }}>
|
||||||
<Flex direction="column" gap="2">
|
<Flex direction="column" gap="2">
|
||||||
<Heading size="5">Maneuverability</Heading>
|
<Heading size="5">Maneuverability</Heading>
|
||||||
<Info name="Speed" unit="km/hr" />
|
<Info name="Speed" unit="km/hr" />
|
||||||
@@ -464,7 +529,6 @@ export function Characteristics() {
|
|||||||
{stats.hullTraverseSoftTerrain}
|
{stats.hullTraverseSoftTerrain}
|
||||||
</InfoWithDelta>
|
</InfoWithDelta>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Flex direction="column" gap="2">
|
<Flex direction="column" gap="2">
|
||||||
<Heading size="5">Survivability</Heading>
|
<Heading size="5">Survivability</Heading>
|
||||||
<InfoWithDelta name="Health" unit="hp" decimals={0}>
|
<InfoWithDelta name="Health" unit="hp" decimals={0}>
|
||||||
@@ -510,63 +574,6 @@ export function Characteristics() {
|
|||||||
{stats.volume}
|
{stats.volume}
|
||||||
</Info>
|
</Info>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Flex direction="column" gap="2">
|
|
||||||
<Flex gap="2" align="center">
|
|
||||||
<Heading size="5">Crew training</Heading>
|
|
||||||
|
|
||||||
<Popover.Root>
|
|
||||||
<Popover.Trigger>
|
|
||||||
<IconButton variant="ghost">
|
|
||||||
<InfoCircledIcon />
|
|
||||||
</IconButton>
|
|
||||||
</Popover.Trigger>
|
|
||||||
|
|
||||||
<Popover.Content>
|
|
||||||
<Flex gap="1" align="center">
|
|
||||||
<AccessibilityIcon />
|
|
||||||
<Text>represents the other roles a crew member can take.</Text>
|
|
||||||
</Flex>
|
|
||||||
</Popover.Content>
|
|
||||||
</Popover.Root>
|
|
||||||
</Flex>
|
|
||||||
|
|
||||||
{tank.crew.map((member) => {
|
|
||||||
const count = member.count ?? 1;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Fragment key={member.type}>
|
|
||||||
<InfoWithDelta
|
|
||||||
key={`${member.type}-root`}
|
|
||||||
name={`${CREW_MEMBER_NAMES[member.type]}${count > 1 ? ` x ${count}` : ''}`}
|
|
||||||
unit="%"
|
|
||||||
decimals={0}
|
|
||||||
>
|
|
||||||
{(member.type === 'commander'
|
|
||||||
? commanderMastery
|
|
||||||
: crewMemberMastery) * 100}
|
|
||||||
</InfoWithDelta>
|
|
||||||
{member.substitute && (
|
|
||||||
<Info
|
|
||||||
key={`${member.type}-substitute`}
|
|
||||||
indent
|
|
||||||
name={
|
|
||||||
<>
|
|
||||||
<Flex align="center" gap="1">
|
|
||||||
<AccessibilityIcon />
|
|
||||||
{member.substitute
|
|
||||||
.map((sub, index) =>
|
|
||||||
index === 0 ? CREW_MEMBER_NAMES[sub] : sub,
|
|
||||||
)
|
|
||||||
.join(', ')}
|
|
||||||
</Flex>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { Flex, Heading } from '@radix-ui/themes';
|
import { Flex, Heading } from '@radix-ui/themes';
|
||||||
import PageWrapper from '../../../../../../components/PageWrapper';
|
|
||||||
import { useWideFormat } from '../../../../../../hooks/useWideFormat';
|
import { useWideFormat } from '../../../../../../hooks/useWideFormat';
|
||||||
import { Characteristics } from '../Characteristics';
|
import { Characteristics } from '../Characteristics';
|
||||||
import { Consumables } from '../Characteristics/components/Consumables';
|
import { Consumables } from '../Characteristics/components/Consumables';
|
||||||
@@ -10,16 +9,25 @@ import { Provisions } from '../Characteristics/components/Provisions';
|
|||||||
import { Skills } from '../Characteristics/components/Skills';
|
import { Skills } from '../Characteristics/components/Skills';
|
||||||
|
|
||||||
export function CharacteristicsSection() {
|
export function CharacteristicsSection() {
|
||||||
const wideFormat = useWideFormat(720);
|
const wideFormat = useWideFormat(700);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageWrapper >
|
<Flex
|
||||||
|
align="center"
|
||||||
|
px="4"
|
||||||
|
style={{
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
}}
|
||||||
|
direction={wideFormat ? 'row' : 'column'}
|
||||||
|
mt="4"
|
||||||
|
>
|
||||||
<Flex
|
<Flex
|
||||||
gap="6"
|
gap="6"
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
direction={wideFormat ? 'row' : 'column'}
|
direction={wideFormat ? 'row' : 'column'}
|
||||||
|
justify="center"
|
||||||
>
|
>
|
||||||
<Flex style={{ flex: 1, maxWidth: 480 }} direction="column" gap="4">
|
<Flex style={{ flex: 1, maxWidth: 380 }} direction="column" gap="4">
|
||||||
<Heading>Configure</Heading>
|
<Heading>Configure</Heading>
|
||||||
<Modules />
|
<Modules />
|
||||||
<Equipment />
|
<Equipment />
|
||||||
@@ -30,7 +38,11 @@ export function CharacteristicsSection() {
|
|||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Flex
|
<Flex
|
||||||
style={{ flex: 1, width: wideFormat ? undefined : '100%' }}
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
maxWidth: wideFormat ? 640 : undefined,
|
||||||
|
minWidth: 320,
|
||||||
|
}}
|
||||||
direction="column"
|
direction="column"
|
||||||
gap="4"
|
gap="4"
|
||||||
>
|
>
|
||||||
@@ -38,6 +50,6 @@ export function CharacteristicsSection() {
|
|||||||
<Characteristics />
|
<Characteristics />
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
</PageWrapper>
|
</Flex>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -25,7 +25,7 @@ export function HeroSection() {
|
|||||||
style={{
|
style={{
|
||||||
background: `linear-gradient(${wideFormat ? -90 : 180}deg, ${theme.colors.appBackground1}, ${theme.colors.appBackground2})`,
|
background: `linear-gradient(${wideFormat ? -90 : 180}deg, ${theme.colors.appBackground1}, ${theme.colors.appBackground2})`,
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
height: wideFormat ? undefined : 'calc(87.5vh - 64px)',
|
height: wideFormat ? undefined : 'calc(75vh - 64px)',
|
||||||
}}
|
}}
|
||||||
gap="4"
|
gap="4"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -124,7 +124,12 @@ export function TechTreeSection() {
|
|||||||
<PageWrapper
|
<PageWrapper
|
||||||
style={{
|
style={{
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
|
}}
|
||||||
|
containerProps={{
|
||||||
|
style: {
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
|
marginTop: 16,
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
size={tank.ancestors && tank.successors ? 880 : 480}
|
size={tank.ancestors && tank.successors ? 880 : 480}
|
||||||
gap="0"
|
gap="0"
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ type PageWrapperProps = FlexProps & {
|
|||||||
noPadding?: boolean;
|
noPadding?: boolean;
|
||||||
noMaxWidth?: boolean;
|
noMaxWidth?: boolean;
|
||||||
highlight?: boolean;
|
highlight?: boolean;
|
||||||
|
containerProps?: ComponentProps<typeof Theme>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function PageWrapper({
|
export default function PageWrapper({
|
||||||
@@ -18,6 +19,7 @@ export default function PageWrapper({
|
|||||||
noPadding = false,
|
noPadding = false,
|
||||||
noMaxWidth = false,
|
noMaxWidth = false,
|
||||||
highlight = false,
|
highlight = false,
|
||||||
|
containerProps,
|
||||||
...props
|
...props
|
||||||
}: PageWrapperProps) {
|
}: PageWrapperProps) {
|
||||||
return (
|
return (
|
||||||
@@ -30,7 +32,9 @@ export default function PageWrapper({
|
|||||||
background: highlight
|
background: highlight
|
||||||
? `linear-gradient(-90deg, ${theme.colors.appBackground1}, ${theme.colors.appBackground2})`
|
? `linear-gradient(-90deg, ${theme.colors.appBackground1}, ${theme.colors.appBackground2})`
|
||||||
: undefined,
|
: undefined,
|
||||||
|
...containerProps?.style,
|
||||||
}}
|
}}
|
||||||
|
{...containerProps}
|
||||||
>
|
>
|
||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
|
|||||||
Reference in new issue
Block a user