diff --git a/src/app/tools/embed/customize/tanks/page.tsx b/src/app/tools/embed/customize/tanks/page.tsx index 4c51c23ce..39355d665 100644 --- a/src/app/tools/embed/customize/tanks/page.tsx +++ b/src/app/tools/embed/customize/tanks/page.tsx @@ -1,7 +1,7 @@ 'use client'; -import { Dispatch, SetStateAction, use, useState } from 'react'; -import { EmbedConfigInputs } from '../../../../../components/EmbedConfigInputs'; +import { use } from 'react'; +import { EmbedCustomize } from '../../../../../components/EmbedCustomize'; import { TanksEmbedCard, TanksEmbedWrapper, @@ -12,12 +12,11 @@ import { EmbedConfigType, ExtractEmbedConfigType, } from '../../types'; -import { extractEmbedConfigDefaults } from '../../utilities'; const tankEmbedConfig = { showTotal: { type: EmbedConfigType.Boolean, default: true }, - listWidth: { type: EmbedConfigType.Number, default: 320, unit: 'px' }, + listWidth: { type: EmbedConfigType.Slider, default: 320, min: 128, max: 640 }, listGap: { type: EmbedConfigType.Size, default: '2' }, listMaxTanks: { type: EmbedConfigType.Number, default: 4, pad: true }, @@ -64,27 +63,19 @@ export type TanksEmbedState = ExtractEmbedConfigType; export default function Page() { const tanks = use(tanksDefinitionsArray); - const [state, setState] = useState( - extractEmbedConfigDefaults(tankEmbedConfig), - ); return ( - > - > - } - > - - {state.showTotal && } + preview={(state) => ( + + {state.showTotal && } - {tanks.slice(0, state.listMaxTanks).map((tank) => ( - - ))} - - + {tanks.slice(0, state.listMaxTanks).map((tank) => ( + + ))} + + )} + /> ); } diff --git a/src/app/tools/embed/types.ts b/src/app/tools/embed/types.ts index f8a351dce..40acdc719 100644 --- a/src/app/tools/embed/types.ts +++ b/src/app/tools/embed/types.ts @@ -10,6 +10,7 @@ export enum EmbedConfigType { String, FullTextControl, Boolean, + Slider, } export const radixGrays = [ @@ -26,6 +27,12 @@ export const radixTextWeights = ['light', 'regular', 'medium', 'bold'] as const; export type EmbedConfig = Record; export type EmbedConfigItem = ( + | { + type: EmbedConfigType.Slider; + default: number; + min: number; + max: number; + } | { type: EmbedConfigType.Boolean; default: boolean; @@ -71,9 +78,6 @@ export type EmbedConfigItem = ( pad?: boolean; }; -export type EmbedConfigItemType = - (EmbedConfigItem & { type: Type })['default']; - export type RadixRadius = `${1 | 2 | 3 | 4}` | 'full'; export type RadixSize = `${0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9}`; export type RadixTextWeight = (typeof radixTextWeights)[number]; @@ -97,3 +101,6 @@ export type ExtractEmbedConfigType = { type: Config[Key]['type']; } & EmbedConfigItem)['default']; }; + +export type EmbedConfigItemType = + (EmbedConfigItem & { type: Type }) diff --git a/src/components/EmbedConfigInputs.tsx b/src/components/EmbedCustomize.tsx similarity index 84% rename from src/components/EmbedConfigInputs.tsx rename to src/components/EmbedCustomize.tsx index 59386ec3d..deb1dafde 100644 --- a/src/components/EmbedConfigInputs.tsx +++ b/src/components/EmbedCustomize.tsx @@ -15,22 +15,14 @@ import { Inset, ScrollArea, Select, - Separator, + Slider, Switch, Text, TextField, } from '@radix-ui/themes'; -import { produce } from 'immer'; +import { Immutable, produce } from 'immer'; import { capitalize, startCase, times } from 'lodash'; -import { - Dispatch, - ReactNode, - SetStateAction, - useCallback, - useEffect, - useRef, - useState, -} from 'react'; +import { ReactNode, useCallback, useEffect, useRef, useState } from 'react'; import { EmbedConfig, EmbedConfigItemType, @@ -48,27 +40,28 @@ import { RadixTextWeight, radixTextWeights, } from '../app/tools/embed/types'; -import { toColorVar, toRadiusVar } from '../app/tools/embed/utilities'; +import { + extractEmbedConfigDefaults, + toColorVar, + toRadiusVar, +} from '../app/tools/embed/utilities'; import { imgur } from '../core/blitzkit/imgur'; import { NAVBAR_HEIGHT } from './Navbar'; import PageWrapper from './PageWrapper'; -interface EmbedConfigInputsProps { - config: EmbedConfig; - state: ExtractEmbedConfigType; - setState: Dispatch>>; - children: ReactNode; +interface EmbedConfigInputsProps { + config: Config; + preview: (state: ExtractEmbedConfigType) => ReactNode; } -export function EmbedConfigInputs({ +export function EmbedCustomize({ config, - state, - setState, - children, -}: EmbedConfigInputsProps) { + preview, +}: EmbedConfigInputsProps) { + const [state, setState] = useState(extractEmbedConfigDefaults(config)); const [backgroundImage, setBackgroundImage] = useState(imgur('SO13zur')); const mutateState = useCallback( - (recipe: (draft: ExtractEmbedConfigType) => void) => { + (recipe: (draft: Immutable>) => void) => { setState(produce(recipe)); }, [], @@ -107,17 +100,49 @@ export function EmbedConfigInputs({ Upload test background - {Object.entries(config).map(([key, setting]) => { + {Object.entries(config).map(([keyUntyped, setting]) => { + const key = keyUntyped as keyof ( + | Immutable> + | ExtractEmbedConfigType + ); let control: ReactNode; switch (setting.type) { + case EmbedConfigType.Slider: { + control = ( + + ).min + } + max={ + ( + config[ + key + ] as EmbedConfigItemType + ).max + } + onValueChange={([value]) => + mutateState((draft) => { + (draft[key] as number) = value; + }) + } + /> + ); + break; + } + case EmbedConfigType.Boolean: { control = ( mutateState((draft) => { - draft[key] = checked; + (draft[key] as boolean) = checked; }) } /> @@ -129,13 +154,13 @@ export function EmbedConfigInputs({ control = ( <> ).color}`} + value={`${(state[key] as EmbedConfigItemType['default']).color}`} onValueChange={(value) => { mutateState((draft) => { ( draft[ key - ] as EmbedConfigItemType + ] as EmbedConfigItemType['default'] ).color = value as RadixTextColor; }); }} @@ -201,7 +226,7 @@ export function EmbedConfigInputs({ ( state[ key - ] as EmbedConfigItemType + ] as EmbedConfigItemType['default'] ).size } onValueChange={(value) => { @@ -209,7 +234,7 @@ export function EmbedConfigInputs({ ( draft[ key - ] as EmbedConfigItemType + ] as EmbedConfigItemType['default'] ).size = value as RadixSizeNo0; }); }} @@ -228,7 +253,7 @@ export function EmbedConfigInputs({ ( state[ key - ] as EmbedConfigItemType + ] as EmbedConfigItemType['default'] ).weight } onValueChange={(value) => { @@ -236,7 +261,7 @@ export function EmbedConfigInputs({ ( draft[ key - ] as EmbedConfigItemType + ] as EmbedConfigItemType['default'] ).weight = value as RadixTextWeight; }); }} @@ -263,7 +288,7 @@ export function EmbedConfigInputs({ value={state[key] as number} onChange={(event) => { mutateState((draft) => { - draft[key] = ( + (draft[key] as number) = ( event.target as HTMLInputElement ).valueAsNumber; }); @@ -285,7 +310,9 @@ export function EmbedConfigInputs({ value={state[key] as string} onChange={(event) => { mutateState((draft) => { - draft[key] = (event.target as HTMLInputElement).value; + (draft[key] as string) = ( + event.target as HTMLInputElement + ).value; }); }} /> @@ -296,50 +323,38 @@ export function EmbedConfigInputs({ case EmbedConfigType.SizeNo0: case EmbedConfigType.Size: { control = ( - { + mutateState((draft) => { - draft[key] = value as RadixSize; - }); - }} - > - - - {times(10, (index) => - setting.type === EmbedConfigType.SizeNo0 && - index === 0 ? null : ( - - {index} - - ), - )} - - + (draft[key] as RadixSize) = `${value}` as RadixSize; + }) + } + /> ); break; } case EmbedConfigType.Radius: { control = ( - { + mutateState((draft) => { - draft[key] = value as RadixRadius; - }); - }} - > - - - {times(5, (index) => ( - - {index} - - ))} - Full - - + (draft[key] as RadixRadius) = ( + value === 5 ? 'full' : `${value}` + ) as RadixRadius; + }) + } + /> ); break; } @@ -403,7 +418,7 @@ export function EmbedConfigInputs({ return ( <> - + {' '} {variant} - + { mutateState((draft) => { - draft[key] = value as RadixTextColor; + (draft[key] as RadixTextColor) = + value as RadixTextColor; }); }} > @@ -535,11 +551,7 @@ export function EmbedConfigInputs({ mb="1" pb={setting.pad ? '6' : undefined} > - - {capitalize(startCase(key))} - - - + {capitalize(startCase(key as string))} {control && {control}} {!control && Immutable} @@ -567,7 +579,7 @@ export function EmbedConfigInputs({ backgroundColor: 'var(--color-panel-translucent)', }} > - Streaming software + Example preview @@ -594,7 +606,7 @@ export function EmbedConfigInputs({ align="center" justify="center" > - {children} + {preview(state)}