feat: more customizations

This commit is contained in:
TrèsAbhi committed 2024-08-06 13:33:39 -05:00
1 parent 6a18abf17f
commit 38f3ccfbd8
4 files changed
+627 -333

No files matched your search

+27 -27
View File
@@ -1,13 +1,11 @@
'use client'; 'use client';
import { Box } from '@radix-ui/themes';
import { Dispatch, SetStateAction, use, useState } from 'react'; import { Dispatch, SetStateAction, use, useState } from 'react';
import { EmbedConfigInputs } from '../../../../../components/EmbedConfigInputs'; import { EmbedConfigInputs } from '../../../../../components/EmbedConfigInputs';
import { import {
TanksEmbedCard, TanksEmbedCard,
TanksEmbedWrapper, TanksEmbedWrapper,
} from '../../../../../components/TanksEmbed'; } from '../../../../../components/TanksEmbed';
import { imgur } from '../../../../../core/blitzkit/imgur';
import { tanksDefinitionsArray } from '../../../../../core/blitzkit/tankDefinitions'; import { tanksDefinitionsArray } from '../../../../../core/blitzkit/tankDefinitions';
import { import {
EmbedConfig, EmbedConfig,
@@ -17,9 +15,11 @@ import {
import { extractEmbedConfigDefaults } from '../../utilities'; import { extractEmbedConfigDefaults } from '../../utilities';
const tankEmbedConfig = { const tankEmbedConfig = {
showTotal: { type: EmbedConfigType.Boolean, default: true },
listWidth: { type: EmbedConfigType.Number, default: 320, unit: 'px' }, listWidth: { type: EmbedConfigType.Number, default: 320, unit: 'px' },
listGap: { type: EmbedConfigType.Size, default: '2' }, listGap: { type: EmbedConfigType.Size, default: '2' },
listMaxTanks: { type: EmbedConfigType.Number, default: 8, pad: true }, listMaxTanks: { type: EmbedConfigType.Number, default: 4, pad: true },
cardRadius: { type: EmbedConfigType.Radius, default: '2' }, cardRadius: { type: EmbedConfigType.Radius, default: '2' },
cardHeaderBackgroundColor: { cardHeaderBackgroundColor: {
@@ -27,6 +27,12 @@ const tankEmbedConfig = {
default: { base: 'gray', variant: '3' }, default: { base: 'gray', variant: '3' },
}, },
cardHeaderPadding: { type: EmbedConfigType.Size, default: '1' }, cardHeaderPadding: { type: EmbedConfigType.Size, default: '1' },
cardTitle: {
type: EmbedConfigType.FullTextControl,
default: { color: undefined, weight: 'bold', size: '3' },
},
cardTitleAutoColor: { type: EmbedConfigType.Boolean, default: true },
cardTitleAutoIcon: { type: EmbedConfigType.Boolean, default: true },
cardBodyBackgroundColor: { cardBodyBackgroundColor: {
type: EmbedConfigType.Color, type: EmbedConfigType.Color,
default: { base: 'gray', variant: '2' }, default: { base: 'gray', variant: '2' },
@@ -34,12 +40,13 @@ const tankEmbedConfig = {
cardBodyPadding: { type: EmbedConfigType.Size, default: '2', pad: true }, cardBodyPadding: { type: EmbedConfigType.Size, default: '2', pad: true },
columnGap: { type: EmbedConfigType.Size, default: '0' }, columnGap: { type: EmbedConfigType.Size, default: '0' },
columnValueSize: { type: EmbedConfigType.SizeNo0, default: '3' }, columnValue: {
columnValueColor: { type: EmbedConfigType.TextColor, default: undefined }, type: EmbedConfigType.FullTextControl,
columnLabelSize: { type: EmbedConfigType.SizeNo0, default: '2' }, default: { color: undefined, size: '3', weight: 'regular' },
columnLabelColor: { },
type: EmbedConfigType.TextColor, columnLabel: {
default: 'gray', type: EmbedConfigType.FullTextControl,
default: { color: 'gray', size: '2', weight: 'regular' },
pad: true, pad: true,
}, },
@@ -62,29 +69,22 @@ export default function Page() {
); );
return ( return (
<Box <EmbedConfigInputs
width="100vw" config={tankEmbedConfig}
height="100vh" state={state}
style={{ setState={
background: `url(${imgur('pAidayf')})`, setState as Dispatch<
backgroundSize: 'cover', SetStateAction<ExtractEmbedConfigType<EmbedConfig>>
}} >
}
> >
<TanksEmbedWrapper state={state}> <TanksEmbedWrapper state={state}>
{state.showTotal && <TanksEmbedCard state={state} tank={null} />}
{tanks.slice(0, state.listMaxTanks).map((tank) => ( {tanks.slice(0, state.listMaxTanks).map((tank) => (
<TanksEmbedCard key={tank.id} tank={tank} state={state} /> <TanksEmbedCard key={tank.id} tank={tank} state={state} />
))} ))}
</TanksEmbedWrapper> </TanksEmbedWrapper>
</EmbedConfigInputs>
<EmbedConfigInputs
config={tankEmbedConfig}
state={state}
setState={
setState as Dispatch<
SetStateAction<ExtractEmbedConfigType<EmbedConfig>>
>
}
/>
</Box>
); );
} }
+20
View File
@@ -8,6 +8,8 @@ export enum EmbedConfigType {
SizeNo0, SizeNo0,
TextColor, TextColor,
String, String,
FullTextControl,
Boolean,
} }
export const radixGrays = [ export const radixGrays = [
@@ -19,9 +21,15 @@ export const radixGrays = [
'sand', 'sand',
] as const; ] as const;
export const radixTextWeights = ['light', 'regular', 'medium', 'bold'] as const;
export type EmbedConfig = Record<string, EmbedConfigItem>; export type EmbedConfig = Record<string, EmbedConfigItem>;
export type EmbedConfigItem = ( export type EmbedConfigItem = (
| {
type: EmbedConfigType.Boolean;
default: boolean;
}
| { | {
type: EmbedConfigType.Number; type: EmbedConfigType.Number;
default: number; default: number;
@@ -51,12 +59,24 @@ export type EmbedConfigItem = (
type: EmbedConfigType.TextColor; type: EmbedConfigType.TextColor;
default: RadixTextColor; default: RadixTextColor;
} }
| {
type: EmbedConfigType.FullTextControl;
default: {
color: RadixTextColor;
size: RadixSizeNo0;
weight: RadixTextWeight;
};
}
) & { ) & {
pad?: boolean; pad?: boolean;
}; };
export type EmbedConfigItemType<Type extends EmbedConfigType> =
(EmbedConfigItem & { type: Type })['default'];
export type RadixRadius = `${1 | 2 | 3 | 4}` | 'full'; export type RadixRadius = `${1 | 2 | 3 | 4}` | 'full';
export type RadixSize = `${0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9}`; export type RadixSize = `${0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9}`;
export type RadixTextWeight = (typeof radixTextWeights)[number];
export type RadixSizeNo0 = Exclude<RadixSize, '0'>; export type RadixSizeNo0 = Exclude<RadixSize, '0'>;
export type RadixColor = { base: RadixColorBase; variant: RadixColorVariant }; export type RadixColor = { base: RadixColorBase; variant: RadixColorVariant };
export type RadixColorBase = Exclude< export type RadixColorBase = Exclude<
+538 -302
View File
@@ -1,25 +1,37 @@
import * as radixColors from '@radix-ui/colors'; import * as radixColors from '@radix-ui/colors';
import { DragHandleDots2Icon } from '@radix-ui/react-icons'; import {
DragHandleDots2Icon,
EnterFullScreenIcon,
ExitFullScreenIcon,
ImageIcon,
} from '@radix-ui/react-icons';
import { import {
Box, Box,
Button,
Card, Card,
Flex, Flex,
IconButton,
Inset,
ScrollArea, ScrollArea,
Select, Select,
Switch,
Text, Text,
TextField, TextField,
} from '@radix-ui/themes'; } from '@radix-ui/themes';
import { produce } from 'immer'; import { produce } from 'immer';
import { capitalize, startCase, times } from 'lodash'; import { capitalize, clamp, startCase, times } from 'lodash';
import { import {
Dispatch, Dispatch,
ReactNode, ReactNode,
SetStateAction, SetStateAction,
useCallback, useCallback,
useEffect,
useRef, useRef,
useState,
} from 'react'; } from 'react';
import { import {
EmbedConfig, EmbedConfig,
EmbedConfigItemType,
EmbedConfigType, EmbedConfigType,
ExtractEmbedConfigType, ExtractEmbedConfigType,
RadixColor, RadixColor,
@@ -29,7 +41,10 @@ import {
radixGrays, radixGrays,
RadixRadius, RadixRadius,
RadixSize, RadixSize,
RadixSizeNo0,
RadixTextColor, RadixTextColor,
RadixTextWeight,
radixTextWeights,
} from '../app/tools/embed/types'; } from '../app/tools/embed/types';
import { toColorVar, toRadiusVar } from '../app/tools/embed/utilities'; import { toColorVar, toRadiusVar } from '../app/tools/embed/utilities';
@@ -37,13 +52,19 @@ interface EmbedConfigInputsProps {
config: EmbedConfig; config: EmbedConfig;
state: ExtractEmbedConfigType<EmbedConfig>; state: ExtractEmbedConfigType<EmbedConfig>;
setState: Dispatch<SetStateAction<ExtractEmbedConfigType<EmbedConfig>>>; setState: Dispatch<SetStateAction<ExtractEmbedConfigType<EmbedConfig>>>;
children: ReactNode;
} }
export function EmbedConfigInputs({ export function EmbedConfigInputs({
config, config,
state, state,
setState, setState,
children,
}: EmbedConfigInputsProps) { }: EmbedConfigInputsProps) {
const [expanded, setExpanded] = useState(true);
const [backgroundImage, setBackgroundImage] = useState(
'https://upload.wikimedia.org/wikipedia/commons/f/f6/Swiss_National_Park_131.JPG',
);
const mutateState = useCallback( const mutateState = useCallback(
(recipe: (draft: ExtractEmbedConfigType<EmbedConfig>) => void) => { (recipe: (draft: ExtractEmbedConfigType<EmbedConfig>) => void) => {
setState(produce(recipe)); setState(produce(recipe));
@@ -56,164 +77,133 @@ export function EmbedConfigInputs({
if (!wrapper.current) return; if (!wrapper.current) return;
wrapper.current.style.top = `${parseFloat(wrapper.current.style.top) + event.movementY}px`; wrapper.current.style.top = `${clamp(parseFloat(wrapper.current.style.top) + event.movementY, 32, window.innerHeight - 32 - 32)}px`;
wrapper.current.style.right = `${parseFloat(wrapper.current.style.right) - event.movementX}px`; wrapper.current.style.right = `${clamp(parseFloat(wrapper.current.style.right) - event.movementX, 32, window.innerWidth - 32 - 320)}px`;
}, []); }, []);
const handlePointerUp = useCallback(() => {
const handlePointerUp = useCallback((event: PointerEvent) => {
window.removeEventListener('pointermove', handlePointerMove); window.removeEventListener('pointermove', handlePointerMove);
window.removeEventListener('pointerup', handlePointerUp); window.removeEventListener('pointerup', handlePointerUp);
}, []); }, []);
const fileInput = useRef<HTMLInputElement>();
useEffect(() => {
fileInput.current = document.createElement('input');
fileInput.current.type = 'file';
fileInput.current.style.display = 'none';
fileInput.current.accept = 'image/*';
fileInput.current.onchange = (event) => {
const file = (event.target as HTMLInputElement).files?.[0];
if (!file) return;
setBackgroundImage(URL.createObjectURL(file));
};
}, []);
return ( return (
<Card <Flex
style={{ position: 'fixed', top: 0, right: 0, minWidth: 320 }} width="100vw"
ref={wrapper} height="100vh"
align="center"
justify="center"
overflow="hidden"
style={{
background: `url(${backgroundImage}) center / cover no-repeat`,
}}
> >
<Flex <Card
align="center" style={{ position: 'fixed', top: 32, right: 32, minWidth: 320 }}
justify="center" ref={wrapper}
p="2"
mb="2"
style={{
backgroundColor: 'var(--color-panel-translucent)',
borderRadius: 'var(--radius-2)',
cursor: 'grab',
}}
onPointerDown={(event) => {
window.addEventListener('pointermove', handlePointerMove);
window.addEventListener('pointerup', handlePointerUp);
}}
> >
<DragHandleDots2Icon style={{ transform: 'rotate(90deg)' }} /> <Inset mb="4">
</Flex> <Flex
align="center"
justify="center"
p="2"
mb={expanded ? '2' : '0'}
position="relative"
style={{
backgroundColor: 'var(--color-panel-translucent)',
cursor: 'grab',
}}
onPointerDown={(event) => {
event.preventDefault();
window.addEventListener('pointermove', handlePointerMove);
window.addEventListener('pointerup', handlePointerUp);
}}
>
<Text color="gray" trim="end">
<DragHandleDots2Icon style={{ transform: 'rotate(90deg)' }} />
</Text>
<ScrollArea <Box
scrollbars="vertical" position="absolute"
style={{ height: '100%', maxHeight: 640 }} right="0"
> top="50%"
<Flex direction="column" gap="2"> pr="2"
{Object.entries(config).map(([key, setting]) => { style={{ transform: 'translateY(-25%)' }}
let control: ReactNode; >
<IconButton
variant="ghost"
color="gray"
onClick={() => setExpanded((expanded) => !expanded)}
>
{expanded ? <ExitFullScreenIcon /> : <EnterFullScreenIcon />}
</IconButton>
</Box>
</Flex>
</Inset>
switch (setting.type) { {expanded && (
case EmbedConfigType.Number: { <ScrollArea
control = ( scrollbars="vertical"
<TextField.Root style={{ height: '100%', maxHeight: 640 }}
size="1" >
style={{ width: 64 }} <Flex direction="column" gap="2">
type="number" <Button
value={state[key] as number} variant="outline"
onChange={(event) => { color="gray"
mutateState((draft) => { mb="6"
draft[key] = ( onClick={() => fileInput.current?.click()}
event.target as HTMLInputElement >
).valueAsNumber; <ImageIcon /> Upload test background
}); </Button>
}}
>
{setting.unit && (
<TextField.Slot side="right">px</TextField.Slot>
)}
</TextField.Root>
);
break;
}
case EmbedConfigType.String: { {Object.entries(config).map(([key, setting]) => {
control = ( let control: ReactNode;
<TextField.Root
placeholder="Empty"
size="1"
style={{ width: 64 }}
value={state[key] as string}
onChange={(event) => {
mutateState((draft) => {
draft[key] = (event.target as HTMLInputElement).value;
});
}}
/>
);
break;
}
case EmbedConfigType.SizeNo0: switch (setting.type) {
case EmbedConfigType.Size: { case EmbedConfigType.Boolean: {
control = ( control = (
<Select.Root <Switch
size="1" checked={state[key] as boolean}
value={state[key] as RadixSize} onCheckedChange={(checked) =>
onValueChange={(value) => { mutateState((draft) => {
mutateState((draft) => { draft[key] = checked;
draft[key] = value as RadixSize; })
}); }
}} />
> );
<Select.Trigger /> break;
<Select.Content> }
{times(10, (index) =>
setting.type === EmbedConfigType.SizeNo0 &&
index === 0 ? null : (
<Select.Item key={index} value={`${index}`}>
{index}
</Select.Item>
),
)}
</Select.Content>
</Select.Root>
);
break;
}
case EmbedConfigType.Radius: { case EmbedConfigType.FullTextControl: {
control = ( control = (
<Select.Root <>
size="1" <Select.Root
value={state[key] as RadixRadius} size="1"
onValueChange={(value) => { value={`${(state[key] as EmbedConfigItemType<EmbedConfigType.FullTextControl>).color}`}
mutateState((draft) => { onValueChange={(value) => {
draft[key] = value as RadixRadius; mutateState((draft) => {
}); (
}} draft[
> key
<Select.Trigger /> ] as EmbedConfigItemType<EmbedConfigType.FullTextControl>
<Select.Content> ).color = value as RadixTextColor;
{times(5, (index) => ( });
<Select.Item key={index} value={`${index}`}> }}
{index} >
</Select.Item> <Select.Trigger />
))} <Select.Content>
<Select.Item value="full">Full</Select.Item> <Select.Item value="undefined">
</Select.Content>
</Select.Root>
);
break;
}
case EmbedConfigType.Color: {
control = (
<>
<Select.Root
size="1"
value={(state[key] as RadixColor).base}
onValueChange={(value) => {
mutateState((draft) => {
(draft[key] as RadixColor).base =
value as RadixColorBase;
});
}}
>
<Select.Trigger />
<Select.Content>
{Object.entries(radixColors)
.filter(
([key]) =>
!key.endsWith('A') &&
!key.endsWith('P3') &&
!key.endsWith('Dark'),
)
.map(([key]) => (
<Select.Item key={key} value={key}>
<Box <Box
style={{ style={{
display: 'inline-block', display: 'inline-block',
@@ -221,139 +211,338 @@ export function EmbedConfigInputs({
height: '1em', height: '1em',
verticalAlign: 'text-top', verticalAlign: 'text-top',
borderRadius: toRadiusVar('full'), borderRadius: toRadiusVar('full'),
backgroundColor: toColorVar({ backgroundColor: 'white',
base: key as RadixColorBase,
variant: '9',
}),
}} }}
/>{' '} />{' '}
{capitalize(key)} White
</Select.Item> </Select.Item>
))} <Select.Item value="gray">
</Select.Content> <Box
</Select.Root> style={{
display: 'inline-block',
<Select.Root width: '1em',
size="1" height: '1em',
value={(state[key] as RadixColor).variant} verticalAlign: 'text-top',
onValueChange={(value) => { borderRadius: toRadiusVar('full'),
mutateState((draft) => { backgroundColor: 'gray',
(draft[key] as RadixColor).variant = }}
value as RadixColorVariant; />{' '}
}); Gray
}} </Select.Item>
> {Object.entries(radixColors)
<Select.Trigger /> .filter(
<Select.Content> ([key]) =>
{times(12, (index) => { !key.endsWith('A') &&
const variant = !key.endsWith('P3') &&
`${index + 1}` as RadixColorVariantRaw; !key.endsWith('Dark') &&
!radixGrays.includes(key),
return ( )
<> .map(([key]) => (
<Select.Item key={key} value={variant}> <Select.Item key={key} value={key}>
<Box
style={{
display: 'inline-block',
width: '1em',
height: '1em',
verticalAlign: 'text-top',
borderRadius: toRadiusVar('full'),
backgroundColor: toColorVar({
base: (state[key] as RadixColor).base,
variant,
}),
}}
/>{' '}
{variant}
</Select.Item>
<Select.Item key={key} value={`a${variant}`}>
<Box
style={{
display: 'inline-block',
overflow: 'hidden',
width: '1em',
height: '1em',
verticalAlign: 'text-top',
borderRadius: toRadiusVar('full'),
backgroundColor: toColorVar({
base: (state[key] as RadixColor).base,
variant: `a${variant}`,
}),
}}
>
<Box <Box
style={{ style={{
width: '50%', display: 'inline-block',
height: '100%', width: '1em',
height: '1em',
verticalAlign: 'text-top',
borderRadius: toRadiusVar('full'),
backgroundColor: toColorVar({ backgroundColor: toColorVar({
base: (state[key] as RadixColor).base, base: key as RadixColorBase,
variant, variant: '9',
}), }),
}} }}
/> />{' '}
</Box>{' '} {capitalize(key)}
{variant} translucent </Select.Item>
))}
</Select.Content>
</Select.Root>
<Select.Root
size="1"
value={
(
state[
key
] as EmbedConfigItemType<EmbedConfigType.FullTextControl>
).size
}
onValueChange={(value) => {
mutateState((draft) => {
(
draft[
key
] as EmbedConfigItemType<EmbedConfigType.FullTextControl>
).size = value as RadixSizeNo0;
});
}}
>
<Select.Trigger />
<Select.Content>
{times(9, (index) => (
<Select.Item key={index} value={`${index + 1}`}>
Size {index + 1}
</Select.Item> </Select.Item>
</> ))}
); </Select.Content>
})} </Select.Root>
</Select.Content> <Select.Root
</Select.Root> size="1"
</> value={
); (
break; state[
} key
] as EmbedConfigItemType<EmbedConfigType.FullTextControl>
).weight
}
onValueChange={(value) => {
mutateState((draft) => {
(
draft[
key
] as EmbedConfigItemType<EmbedConfigType.FullTextControl>
).weight = value as RadixTextWeight;
});
}}
>
<Select.Trigger />
<Select.Content>
{radixTextWeights.map((weight) => (
<Select.Item key={weight} value={weight}>
{startCase(weight)}
</Select.Item>
))}
</Select.Content>
</Select.Root>
</>
);
break;
}
case EmbedConfigType.TextColor: { case EmbedConfigType.Number: {
control = ( control = (
<Select.Root <TextField.Root
size="1" size="1"
value={`${state[key]}`} style={{ width: 64 }}
onValueChange={(value) => { type="number"
mutateState((draft) => { value={state[key] as number}
draft[key] = value as RadixTextColor; onChange={(event) => {
}); mutateState((draft) => {
}} draft[key] = (
> event.target as HTMLInputElement
<Select.Trigger /> ).valueAsNumber;
<Select.Content> });
<Select.Item value="undefined"> }}
<Box >
style={{ {setting.unit && (
display: 'inline-block', <TextField.Slot side="right">px</TextField.Slot>
width: '1em', )}
height: '1em', </TextField.Root>
verticalAlign: 'text-top', );
borderRadius: toRadiusVar('full'), break;
backgroundColor: 'white', }
case EmbedConfigType.String: {
control = (
<TextField.Root
placeholder="Empty"
size="1"
style={{ width: 64 }}
value={state[key] as string}
onChange={(event) => {
mutateState((draft) => {
draft[key] = (
event.target as HTMLInputElement
).value;
});
}}
/>
);
break;
}
case EmbedConfigType.SizeNo0:
case EmbedConfigType.Size: {
control = (
<Select.Root
size="1"
value={state[key] as RadixSize}
onValueChange={(value) => {
mutateState((draft) => {
draft[key] = value as RadixSize;
});
}}
>
<Select.Trigger />
<Select.Content>
{times(10, (index) =>
setting.type === EmbedConfigType.SizeNo0 &&
index === 0 ? null : (
<Select.Item key={index} value={`${index}`}>
{index}
</Select.Item>
),
)}
</Select.Content>
</Select.Root>
);
break;
}
case EmbedConfigType.Radius: {
control = (
<Select.Root
size="1"
value={state[key] as RadixRadius}
onValueChange={(value) => {
mutateState((draft) => {
draft[key] = value as RadixRadius;
});
}}
>
<Select.Trigger />
<Select.Content>
{times(5, (index) => (
<Select.Item key={index} value={`${index}`}>
{index}
</Select.Item>
))}
<Select.Item value="full">Full</Select.Item>
</Select.Content>
</Select.Root>
);
break;
}
case EmbedConfigType.Color: {
control = (
<>
<Select.Root
size="1"
value={(state[key] as RadixColor).base}
onValueChange={(value) => {
mutateState((draft) => {
(draft[key] as RadixColor).base =
value as RadixColorBase;
});
}} }}
/>{' '} >
White <Select.Trigger />
</Select.Item> <Select.Content>
<Select.Item value="gray"> {Object.entries(radixColors)
<Box .filter(
style={{ ([key]) =>
display: 'inline-block', !key.endsWith('A') &&
width: '1em', !key.endsWith('P3') &&
height: '1em', !key.endsWith('Dark'),
verticalAlign: 'text-top', )
borderRadius: toRadiusVar('full'), .map(([key]) => (
backgroundColor: 'gray', <Select.Item key={key} value={key}>
<Box
style={{
display: 'inline-block',
width: '1em',
height: '1em',
verticalAlign: 'text-top',
borderRadius: toRadiusVar('full'),
backgroundColor: toColorVar({
base: key as RadixColorBase,
variant: '9',
}),
}}
/>{' '}
{capitalize(key)}
</Select.Item>
))}
</Select.Content>
</Select.Root>
<Select.Root
size="1"
value={(state[key] as RadixColor).variant}
onValueChange={(value) => {
mutateState((draft) => {
(draft[key] as RadixColor).variant =
value as RadixColorVariant;
});
}} }}
/>{' '} >
Gray <Select.Trigger />
</Select.Item> <Select.Content>
{Object.entries(radixColors) {times(12, (index) => {
.filter( const variant =
([key]) => `${index + 1}` as RadixColorVariantRaw;
!key.endsWith('A') &&
!key.endsWith('P3') && return (
!key.endsWith('Dark') && <>
!radixGrays.includes(key), <Select.Item key={key} value={variant}>
) <Box
.map(([key]) => ( style={{
<Select.Item key={key} value={key}> display: 'inline-block',
width: '1em',
height: '1em',
verticalAlign: 'text-top',
borderRadius: toRadiusVar('full'),
backgroundColor: toColorVar({
base: (state[key] as RadixColor).base,
variant,
}),
}}
/>{' '}
{variant}
</Select.Item>
<Select.Item key={key} value={`a${variant}`}>
<Box
style={{
display: 'inline-block',
overflow: 'hidden',
width: '1em',
height: '1em',
verticalAlign: 'text-top',
borderRadius: toRadiusVar('full'),
backgroundColor: toColorVar({
base: (state[key] as RadixColor).base,
variant: `a${variant}`,
}),
}}
>
<Box
style={{
width: '50%',
height: '100%',
backgroundColor: toColorVar({
base: (state[key] as RadixColor)
.base,
variant,
}),
}}
/>
</Box>{' '}
{variant} translucent
</Select.Item>
</>
);
})}
</Select.Content>
</Select.Root>
</>
);
break;
}
case EmbedConfigType.TextColor: {
control = (
<Select.Root
size="1"
value={`${state[key]}`}
onValueChange={(value) => {
mutateState((draft) => {
draft[key] = value as RadixTextColor;
});
}}
>
<Select.Trigger />
<Select.Content>
<Select.Item value="undefined">
<Box <Box
style={{ style={{
display: 'inline-block', display: 'inline-block',
@@ -361,43 +550,90 @@ export function EmbedConfigInputs({
height: '1em', height: '1em',
verticalAlign: 'text-top', verticalAlign: 'text-top',
borderRadius: toRadiusVar('full'), borderRadius: toRadiusVar('full'),
backgroundColor: toColorVar({ backgroundColor: 'white',
base: key as RadixColorBase,
variant: '9',
}),
}} }}
/>{' '} />{' '}
{capitalize(key)} White
</Select.Item> </Select.Item>
))} <Select.Item value="gray">
</Select.Content> <Box
</Select.Root> style={{
); display: 'inline-block',
break; width: '1em',
} height: '1em',
} verticalAlign: 'text-top',
borderRadius: toRadiusVar('full'),
backgroundColor: 'gray',
}}
/>{' '}
Gray
</Select.Item>
{Object.entries(radixColors)
.filter(
([key]) =>
!key.endsWith('A') &&
!key.endsWith('P3') &&
!key.endsWith('Dark') &&
!radixGrays.includes(key),
)
.map(([key]) => (
<Select.Item key={key} value={key}>
<Box
style={{
display: 'inline-block',
width: '1em',
height: '1em',
verticalAlign: 'text-top',
borderRadius: toRadiusVar('full'),
backgroundColor: toColorVar({
base: key as RadixColorBase,
variant: '9',
}),
}}
/>{' '}
{capitalize(key)}
</Select.Item>
))}
</Select.Content>
</Select.Root>
);
break;
}
}
return ( return (
<Flex <Flex
direction="column" direction="column"
gap="1" gap="1"
mb="1" mb="1"
pb={setting.pad ? '6' : undefined} pb={setting.pad ? '6' : undefined}
> >
<Text color="gray" size="2"> <Text color="gray" size="2">
{capitalize(startCase(key))} {capitalize(startCase(key))}
</Text> </Text>
{control && <Flex gap="1">{control}</Flex>} {control && <Flex gap="1">{control}</Flex>}
{!control && ( {!control && (
<Text color="red" size="1"> <Text color="red" size="1">
Immutable Immutable
</Text> </Text>
)} )}
</Flex> </Flex>
); );
})} })}
</Flex> </Flex>
</ScrollArea> </ScrollArea>
</Card> )}
{!expanded && (
<Flex justify="center">
<Text size="2" color="gray">
Expand to configure
</Text>
</Flex>
)}
</Card>
{children}
</Flex>
); );
} }
+42 -4
View File
@@ -8,6 +8,10 @@ import {
toWidthVar, toWidthVar,
} from '../app/tools/embed/utilities'; } from '../app/tools/embed/utilities';
import { TankDefinition } from '../core/blitzkit/tankDefinitions'; import { TankDefinition } from '../core/blitzkit/tankDefinitions';
import { ClassHeavy } from './ClassIcon/components/ClassHeavy';
import { ClassLight } from './ClassIcon/components/ClassLight';
import { ClassMedium } from './ClassIcon/components/ClassMedium';
import { ClassTankDestroyer } from './ClassIcon/components/ClassTankDestroyer';
interface TanksEmbedWrapperProps { interface TanksEmbedWrapperProps {
children: ReactNode; children: ReactNode;
@@ -27,11 +31,12 @@ export function TanksEmbedWrapper({ children, state }: TanksEmbedWrapperProps) {
} }
interface TanksEmbedCardProps { interface TanksEmbedCardProps {
tank: TankDefinition; tank: TankDefinition | null;
state: TanksEmbedState; state: TanksEmbedState;
} }
export function TanksEmbedCard({ tank, state }: TanksEmbedCardProps) { export function TanksEmbedCard({ tank, state }: TanksEmbedCardProps) {
const { color: cardTitleColor, ...restCardTitleProps } = state.cardTitle;
return ( return (
<Flex <Flex
direction="column" direction="column"
@@ -48,7 +53,40 @@ export function TanksEmbedCard({ tank, state }: TanksEmbedCardProps) {
}} }}
p={state.cardHeaderPadding} p={state.cardHeaderPadding}
> >
{tank.name} <Text
color={
state.cardTitleAutoColor
? tank === null
? cardTitleColor
: tank.treeType === 'collector'
? 'blue'
: tank.treeType === 'premium'
? 'amber'
: cardTitleColor
: cardTitleColor
}
{...restCardTitleProps}
>
<Flex align="center" gap="1">
{tank !== null && state.cardTitleAutoIcon && (
<>
{tank.class === 'lightTank' && (
<ClassLight width="1em" height="1em" />
)}
{tank.class === 'mediumTank' && (
<ClassMedium width="1em" height="1em" />
)}
{tank.class === 'heavyTank' && (
<ClassHeavy width="1em" height="1em" />
)}
{tank.class === 'AT-SPG' && (
<ClassTankDestroyer width="1em" height="1em" />
)}
</>
)}{' '}
{tank === null ? 'Total' : tank.name}
</Flex>
</Text>
</Flex> </Flex>
<Flex p={state.cardBodyPadding}> <Flex p={state.cardBodyPadding}>
@@ -62,10 +100,10 @@ export function TanksEmbedCard({ tank, state }: TanksEmbedCardProps) {
gap={state.columnGap} gap={state.columnGap}
flexGrow="1" flexGrow="1"
> >
<Text size={state.columnValueSize} color={state.columnValueColor}> <Text {...state.columnValue}>
70{state[`column${column}Unit`]} 70{state[`column${column}Unit`]}
</Text> </Text>
<Text size={state.columnLabelSize} color={state.columnLabelColor}> <Text {...state.columnLabel}>
{state[`column${column}Label`]} {state[`column${column}Label`]}
</Text> </Text>
</Flex> </Flex>