mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-23 19:49:50 +02:00
feat: better layout
This commit is contained in:
1 parent
ca39b8e215
commit
4b2367699a
3 files changed
+464
-475
No files matched your search
+4
-3
@@ -28,9 +28,10 @@ const robotoFlex = Roboto_Flex({
|
|||||||
|
|
||||||
export default function RootLayout({ children }: RootLayoutProps) {
|
export default function RootLayout({ children }: RootLayoutProps) {
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
const hideNav =
|
// const hideNav =
|
||||||
pathname.startsWith('/tools/embed/host') ||
|
// pathname.startsWith('/tools/embed/host') ||
|
||||||
pathname.startsWith('/tools/embed/customize');
|
// pathname.startsWith('/tools/embed/customize');
|
||||||
|
const hideNav = false;
|
||||||
const isRoot = pathname === '/';
|
const isRoot = pathname === '/';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import * as radixColors from '@radix-ui/colors';
|
import * as radixColors from '@radix-ui/colors';
|
||||||
import {
|
import {
|
||||||
DragHandleDots2Icon,
|
BorderSolidIcon,
|
||||||
EnterFullScreenIcon,
|
Cross1Icon,
|
||||||
ExitFullScreenIcon,
|
|
||||||
ImageIcon,
|
ImageIcon,
|
||||||
|
SquareIcon,
|
||||||
} from '@radix-ui/react-icons';
|
} from '@radix-ui/react-icons';
|
||||||
import {
|
import {
|
||||||
Box,
|
Box,
|
||||||
@@ -47,6 +47,9 @@ import {
|
|||||||
radixTextWeights,
|
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';
|
||||||
|
import { imgur } from '../core/blitzkit/imgur';
|
||||||
|
import { NAVBAR_HEIGHT } from './Navbar';
|
||||||
|
import PageWrapper from './PageWrapper';
|
||||||
|
|
||||||
interface EmbedConfigInputsProps {
|
interface EmbedConfigInputsProps {
|
||||||
config: EmbedConfig;
|
config: EmbedConfig;
|
||||||
@@ -61,10 +64,7 @@ export function EmbedConfigInputs({
|
|||||||
setState,
|
setState,
|
||||||
children,
|
children,
|
||||||
}: EmbedConfigInputsProps) {
|
}: EmbedConfigInputsProps) {
|
||||||
const [expanded, setExpanded] = useState(true);
|
const [backgroundImage, setBackgroundImage] = useState(imgur('SO13zur'));
|
||||||
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));
|
||||||
@@ -99,444 +99,53 @@ export function EmbedConfigInputs({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex
|
<PageWrapper padding="0" size={1028 + 640}>
|
||||||
width="100vw"
|
<Flex>
|
||||||
height="100vh"
|
<ScrollArea
|
||||||
align="center"
|
scrollbars="vertical"
|
||||||
justify="center"
|
style={{ height: '100%', maxWidth: 320 }}
|
||||||
overflow="hidden"
|
>
|
||||||
style={{
|
<Flex direction="column" gap="2" p="4">
|
||||||
background: `url(${backgroundImage}) center / cover no-repeat`,
|
<Button
|
||||||
}}
|
variant="outline"
|
||||||
>
|
color="gray"
|
||||||
<Card
|
mb="6"
|
||||||
style={{ position: 'fixed', top: 32, right: 32, minWidth: 320 }}
|
onClick={() => fileInput.current?.click()}
|
||||||
ref={wrapper}
|
|
||||||
>
|
|
||||||
<Inset mb="4">
|
|
||||||
<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>
|
|
||||||
|
|
||||||
<Box
|
|
||||||
position="absolute"
|
|
||||||
right="0"
|
|
||||||
top="50%"
|
|
||||||
pr="2"
|
|
||||||
style={{ transform: 'translateY(-25%)' }}
|
|
||||||
>
|
>
|
||||||
<IconButton
|
<ImageIcon /> Upload test background
|
||||||
variant="ghost"
|
</Button>
|
||||||
color="gray"
|
|
||||||
onClick={() => setExpanded((expanded) => !expanded)}
|
|
||||||
>
|
|
||||||
{expanded ? <ExitFullScreenIcon /> : <EnterFullScreenIcon />}
|
|
||||||
</IconButton>
|
|
||||||
</Box>
|
|
||||||
</Flex>
|
|
||||||
</Inset>
|
|
||||||
|
|
||||||
{expanded && (
|
{Object.entries(config).map(([key, setting]) => {
|
||||||
<ScrollArea
|
let control: ReactNode;
|
||||||
scrollbars="vertical"
|
|
||||||
style={{ height: '100%', maxHeight: 640 }}
|
|
||||||
>
|
|
||||||
<Flex direction="column" gap="2">
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
color="gray"
|
|
||||||
mb="6"
|
|
||||||
onClick={() => fileInput.current?.click()}
|
|
||||||
>
|
|
||||||
<ImageIcon /> Upload test background
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
{Object.entries(config).map(([key, setting]) => {
|
switch (setting.type) {
|
||||||
let control: ReactNode;
|
case EmbedConfigType.Boolean: {
|
||||||
|
control = (
|
||||||
|
<Switch
|
||||||
|
checked={state[key] as boolean}
|
||||||
|
onCheckedChange={(checked) =>
|
||||||
|
mutateState((draft) => {
|
||||||
|
draft[key] = checked;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
switch (setting.type) {
|
case EmbedConfigType.FullTextControl: {
|
||||||
case EmbedConfigType.Boolean: {
|
control = (
|
||||||
control = (
|
<>
|
||||||
<Switch
|
<Select.Root
|
||||||
checked={state[key] as boolean}
|
size="1"
|
||||||
onCheckedChange={(checked) =>
|
value={`${(state[key] as EmbedConfigItemType<EmbedConfigType.FullTextControl>).color}`}
|
||||||
|
onValueChange={(value) => {
|
||||||
mutateState((draft) => {
|
mutateState((draft) => {
|
||||||
draft[key] = checked;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case EmbedConfigType.FullTextControl: {
|
|
||||||
control = (
|
|
||||||
<>
|
|
||||||
<Select.Root
|
|
||||||
size="1"
|
|
||||||
value={`${(state[key] as EmbedConfigItemType<EmbedConfigType.FullTextControl>).color}`}
|
|
||||||
onValueChange={(value) => {
|
|
||||||
mutateState((draft) => {
|
|
||||||
(
|
|
||||||
draft[
|
|
||||||
key
|
|
||||||
] as EmbedConfigItemType<EmbedConfigType.FullTextControl>
|
|
||||||
).color = value as RadixTextColor;
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Select.Trigger />
|
|
||||||
<Select.Content>
|
|
||||||
<Select.Item value="undefined">
|
|
||||||
<Box
|
|
||||||
style={{
|
|
||||||
display: 'inline-block',
|
|
||||||
width: '1em',
|
|
||||||
height: '1em',
|
|
||||||
verticalAlign: 'text-top',
|
|
||||||
borderRadius: toRadiusVar('full'),
|
|
||||||
backgroundColor: 'white',
|
|
||||||
}}
|
|
||||||
/>{' '}
|
|
||||||
White
|
|
||||||
</Select.Item>
|
|
||||||
<Select.Item value="gray">
|
|
||||||
<Box
|
|
||||||
style={{
|
|
||||||
display: 'inline-block',
|
|
||||||
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>
|
|
||||||
<Select.Root
|
|
||||||
size="1"
|
|
||||||
value={
|
|
||||||
(
|
(
|
||||||
state[
|
draft[
|
||||||
key
|
key
|
||||||
] as EmbedConfigItemType<EmbedConfigType.FullTextControl>
|
] as EmbedConfigItemType<EmbedConfigType.FullTextControl>
|
||||||
).size
|
).color = value as RadixTextColor;
|
||||||
}
|
|
||||||
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.Content>
|
|
||||||
</Select.Root>
|
|
||||||
<Select.Root
|
|
||||||
size="1"
|
|
||||||
value={
|
|
||||||
(
|
|
||||||
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.Number: {
|
|
||||||
control = (
|
|
||||||
<TextField.Root
|
|
||||||
size="1"
|
|
||||||
style={{ width: 64 }}
|
|
||||||
type="number"
|
|
||||||
value={state[key] as number}
|
|
||||||
onChange={(event) => {
|
|
||||||
mutateState((draft) => {
|
|
||||||
draft[key] = (
|
|
||||||
event.target as HTMLInputElement
|
|
||||||
).valueAsNumber;
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{setting.unit && (
|
|
||||||
<TextField.Slot side="right">px</TextField.Slot>
|
|
||||||
)}
|
|
||||||
</TextField.Root>
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<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
|
|
||||||
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;
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Select.Trigger />
|
|
||||||
<Select.Content>
|
|
||||||
{times(12, (index) => {
|
|
||||||
const variant =
|
|
||||||
`${index + 1}` as RadixColorVariantRaw;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Select.Item key={key} value={variant}>
|
|
||||||
<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
|
|
||||||
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;
|
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -596,44 +205,420 @@ export function EmbedConfigInputs({
|
|||||||
))}
|
))}
|
||||||
</Select.Content>
|
</Select.Content>
|
||||||
</Select.Root>
|
</Select.Root>
|
||||||
);
|
<Select.Root
|
||||||
break;
|
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.Content>
|
||||||
|
</Select.Root>
|
||||||
|
<Select.Root
|
||||||
|
size="1"
|
||||||
|
value={
|
||||||
|
(
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
case EmbedConfigType.Number: {
|
||||||
<Flex
|
control = (
|
||||||
direction="column"
|
<TextField.Root
|
||||||
gap="1"
|
size="1"
|
||||||
mb="1"
|
style={{ width: 64 }}
|
||||||
pb={setting.pad ? '6' : undefined}
|
type="number"
|
||||||
>
|
value={state[key] as number}
|
||||||
<Text color="gray" size="2">
|
onChange={(event) => {
|
||||||
{capitalize(startCase(key))}
|
mutateState((draft) => {
|
||||||
|
draft[key] = (
|
||||||
|
event.target as HTMLInputElement
|
||||||
|
).valueAsNumber;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{setting.unit && (
|
||||||
|
<TextField.Slot side="right">px</TextField.Slot>
|
||||||
|
)}
|
||||||
|
</TextField.Root>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<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
|
||||||
|
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;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Select.Trigger />
|
||||||
|
<Select.Content>
|
||||||
|
{times(12, (index) => {
|
||||||
|
const variant =
|
||||||
|
`${index + 1}` as RadixColorVariantRaw;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Select.Item key={key} value={variant}>
|
||||||
|
<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
|
||||||
|
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
|
||||||
|
style={{
|
||||||
|
display: 'inline-block',
|
||||||
|
width: '1em',
|
||||||
|
height: '1em',
|
||||||
|
verticalAlign: 'text-top',
|
||||||
|
borderRadius: toRadiusVar('full'),
|
||||||
|
backgroundColor: 'white',
|
||||||
|
}}
|
||||||
|
/>{' '}
|
||||||
|
White
|
||||||
|
</Select.Item>
|
||||||
|
<Select.Item value="gray">
|
||||||
|
<Box
|
||||||
|
style={{
|
||||||
|
display: 'inline-block',
|
||||||
|
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 (
|
||||||
|
<Flex
|
||||||
|
direction="column"
|
||||||
|
gap="1"
|
||||||
|
mb="1"
|
||||||
|
pb={setting.pad ? '6' : undefined}
|
||||||
|
>
|
||||||
|
<Text color="gray" size="2">
|
||||||
|
{capitalize(startCase(key))}
|
||||||
|
</Text>
|
||||||
|
{control && <Flex gap="1">{control}</Flex>}
|
||||||
|
{!control && (
|
||||||
|
<Text color="red" size="1">
|
||||||
|
Immutable
|
||||||
</Text>
|
</Text>
|
||||||
{control && <Flex gap="1">{control}</Flex>}
|
)}
|
||||||
{!control && (
|
</Flex>
|
||||||
<Text color="red" size="1">
|
);
|
||||||
Immutable
|
})}
|
||||||
</Text>
|
|
||||||
)}
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Flex>
|
|
||||||
</ScrollArea>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!expanded && (
|
|
||||||
<Flex justify="center">
|
|
||||||
<Text size="2" color="gray">
|
|
||||||
Expand to configure
|
|
||||||
</Text>
|
|
||||||
</Flex>
|
</Flex>
|
||||||
)}
|
</ScrollArea>
|
||||||
</Card>
|
|
||||||
|
|
||||||
{children}
|
<Box
|
||||||
</Flex>
|
p="4"
|
||||||
|
flexGrow="1"
|
||||||
|
position="sticky"
|
||||||
|
top={`${NAVBAR_HEIGHT}px`}
|
||||||
|
height={`calc(100vh - ${NAVBAR_HEIGHT}px)`}
|
||||||
|
>
|
||||||
|
<Card style={{ height: '100%' }}>
|
||||||
|
<Flex direction="column" gap="2" height="100%">
|
||||||
|
<Inset style={{ borderRadius: 0 }}>
|
||||||
|
<Flex
|
||||||
|
justify="between"
|
||||||
|
p="2"
|
||||||
|
px="3"
|
||||||
|
style={{
|
||||||
|
backgroundColor: 'var(--color-panel-translucent)',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text color="gray">Streaming software</Text>
|
||||||
|
|
||||||
|
<Flex align="center" gap="3">
|
||||||
|
<IconButton color="gray" disabled size="1" variant="ghost">
|
||||||
|
<BorderSolidIcon />
|
||||||
|
</IconButton>
|
||||||
|
<IconButton color="gray" disabled size="1" variant="ghost">
|
||||||
|
<SquareIcon />
|
||||||
|
</IconButton>
|
||||||
|
<IconButton color="gray" disabled size="1" variant="ghost">
|
||||||
|
<Cross1Icon />
|
||||||
|
</IconButton>
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</Inset>
|
||||||
|
|
||||||
|
<Flex
|
||||||
|
mt="4"
|
||||||
|
flexGrow="1"
|
||||||
|
style={{
|
||||||
|
borderRadius: toRadiusVar('3'),
|
||||||
|
overflow: 'hidden',
|
||||||
|
background: `url(${backgroundImage}) center / cover no-repeat`,
|
||||||
|
}}
|
||||||
|
align="center"
|
||||||
|
justify="center"
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Flex>
|
||||||
|
</Flex>
|
||||||
|
</Card>
|
||||||
|
</Box>
|
||||||
|
</Flex>
|
||||||
|
</PageWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Flex, FlexProps, Theme } from '@radix-ui/themes';
|
import { Flex, FlexProps, Theme } from '@radix-ui/themes';
|
||||||
import { ComponentProps } from 'react';
|
import { ComponentProps } from 'react';
|
||||||
|
import { RadixSize } from '../app/tools/embed/types';
|
||||||
|
|
||||||
type PageWrapperProps = FlexProps & {
|
type PageWrapperProps = FlexProps & {
|
||||||
color?: ComponentProps<typeof Theme>['accentColor'];
|
color?: ComponentProps<typeof Theme>['accentColor'];
|
||||||
@@ -7,6 +8,7 @@ type PageWrapperProps = FlexProps & {
|
|||||||
noMaxWidth?: boolean;
|
noMaxWidth?: boolean;
|
||||||
containerProps?: ComponentProps<typeof Theme>;
|
containerProps?: ComponentProps<typeof Theme>;
|
||||||
noFlex1?: boolean;
|
noFlex1?: boolean;
|
||||||
|
padding?: RadixSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function PageWrapper({
|
export default function PageWrapper({
|
||||||
@@ -17,6 +19,7 @@ export default function PageWrapper({
|
|||||||
noMaxWidth = false,
|
noMaxWidth = false,
|
||||||
noFlex1 = false,
|
noFlex1 = false,
|
||||||
containerProps,
|
containerProps,
|
||||||
|
padding = '4',
|
||||||
...props
|
...props
|
||||||
}: PageWrapperProps) {
|
}: PageWrapperProps) {
|
||||||
return (
|
return (
|
||||||
@@ -33,7 +36,7 @@ export default function PageWrapper({
|
|||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
gap="4"
|
gap="4"
|
||||||
p="4"
|
p={padding}
|
||||||
style={{
|
style={{
|
||||||
width: '100%',
|
width: '100%',
|
||||||
maxWidth: noMaxWidth ? undefined : size,
|
maxWidth: noMaxWidth ? undefined : size,
|
||||||
|
|||||||
Reference in new issue
Block a user