[FEAT] local theme integration

This commit is contained in:
Edouard DUPIN 2025-01-23 18:09:57 +01:00
parent 12223347d3
commit 979ec4b576
40 changed files with 355 additions and 225 deletions

View File

@ -1,106 +1,112 @@
import { App as SpaApp } from '@/scene/App'; import { App as SpaApp } from '@/scene/App';
import { FullPage } from './ui'; import { Div, FullPage } from './ui';
import { useDisclosure } from './utils/disclosure';
import { useState } from 'react';
import { environment } from './environment';
import { hashLocalData } from './utils/sso';
import { USERS } from './service/session';
// const AppEnvHint = () => { const AppEnvHint = () => {
// const dialog = useDisclosure(); const dialog = useDisclosure();
// const [selectUserTest, setSelectUserTest] = useState<string>('NO_USER'); const [selectUserTest, setSelectUserTest] = useState<string>('NO_USER');
// //const setUser = useRightsStore((store) => store.setUser); //const setUser = useRightsStore((store) => store.setUser);
// const buildEnv = const buildEnv =
// process.env.NODE_ENV === 'development' process.env.NODE_ENV === 'development'
// ? 'Development' ? 'Development'
// : import.meta.env.VITE_DEV_ENV_NAME; : import.meta.env.VITE_DEV_ENV_NAME;
// const envName: Array<string> = []; const envName: Array<string> = [];
// !!buildEnv && envName.push(buildEnv); !!buildEnv && envName.push(buildEnv);
// if (!envName.length) { if (!envName.length) {
// return null; return null;
// } }
// const handleChange = (selectedOption) => { const handleChange = (selectedOption) => {
// console.log(`SELECT: [${selectedOption.target.value}]`); console.log(`SELECT: [${selectedOption.target.value}]`);
// setSelectUserTest(selectedOption.target.value); setSelectUserTest(selectedOption.target.value);
// }; };
// const onClose = () => { const onClose = () => {
// dialog.onClose(); dialog.onClose();
// if (selectUserTest == 'NO_USER') { if (selectUserTest == 'NO_USER') {
// window.location.href = `/${environment.applName}/sso/${hashLocalData()}/false/__LOGOUT__`; window.location.href = `/${environment.applName}/sso/${hashLocalData()}/false/__LOGOUT__`;
// } else { } else {
// window.location.href = `/${environment.applName}/sso/${hashLocalData()}/true/${USERS[selectUserTest]}`; window.location.href = `/${environment.applName}/sso/${hashLocalData()}/true/${USERS[selectUserTest]}`;
// } }
// }; };
// return ( return (
// <> <>
// <div style={{ <Div style={{
// zIndex: "100000", zIndex: "100000",
// position: "fixed", position: "fixed",
// top: "0", top: "0",
// height: "2px", height: "2px",
// background: "warning.400", width: "100%",
// cursor: "pointer" background: "warning.400",
// }} cursor: "pointer"
// data-test-id="devtools" }}
// onClick={dialog.onOpen} data-test-id="devtools"
// > onClick={dialog.onOpen}
// <div style={{ >
// position: "fixed", <Div style={{
// top: "0", position: "fixed",
// background: "warning.400", top: "0",
// color: "warning.900", background: "warning.400",
// fontSize: "0.6rem", color: "warning.900",
// fontWeight: "bold", fontSize: "0.6rem",
// paddingLeft: "10px", fontWeight: "bold",
// paddingRight: "10px", paddingLeft: "10px",
// marginLeft: "25%", paddingRight: "10px",
// borderRadius: "10px 0 10px 0", marginLeft: "25%",
// textTransform: "uppercase", borderRadius: "0 0 10px 10px",
// }} textTransform: "uppercase",
// > }}
// {envName.join(' : ')} >
// </div> {envName.join(' : ')}
// </div> </Div>
// <Dialog.Root open={dialog.open} onOpenChange={dialog.onClose}> </Div>
// <Dialog.Trigger asChild> {/* <Dialog.Root open={dialog.open} onOpenChange={dialog.onClose}>
// <Button> <Dialog.Trigger asChild>
// {dialog.open ? "Close" : "Open"} Dialog <Button>
// </Button> {dialog.open ? "Close" : "Open"} Dialog
// </Dialog.Trigger> </Button>
// <Portal> </Dialog.Trigger>
// <Dialog.Backdrop /> <Portal>
// <Dialog.Positioner> <Dialog.Backdrop />
// <Dialog.Content> <Dialog.Positioner>
// <Dialog.Title>Outils développeurs</Dialog.Title> <Dialog.Content>
// <Dialog.Description> <Dialog.Title>Outils développeurs</Dialog.Title>
// <HStack> <Dialog.Description>
// <Text>User</Text> <HStack>
// <Select.Root onChange={handleChange} collection={USERS_COLLECTION}> <Text>User</Text>
// <Select.Trigger> <Select.Root onChange={handleChange} collection={USERS_COLLECTION}>
// <SelectValueText placeholder="Select test user" /> <Select.Trigger>
// </Select.Trigger> <SelectValueText placeholder="Select test user" />
// <Select.Content> </Select.Trigger>
// {USERS_COLLECTION.items.map((value) => ( <Select.Content>
// <Select.Item item={value} key={value.value}> {USERS_COLLECTION.items.map((value) => (
// {value.label} <Select.Item item={value} key={value.value}>
// </Select.Item> {value.label}
// ))} </Select.Item>
// </Select.Content> ))}
// </Select.Root> </Select.Content>
// </HStack> </Select.Root>
// </Dialog.Description> </HStack>
// <Dialog.CloseTrigger> </Dialog.Description>
// <Button onClick={onClose}>Apply</Button> <Dialog.CloseTrigger>
// </Dialog.CloseTrigger> <Button onClick={onClose}>Apply</Button>
// </Dialog.Content> </Dialog.CloseTrigger>
// </Dialog.Positioner> </Dialog.Content>
// </Portal> </Dialog.Positioner>
// </Dialog.Root> </Portal>
// </> </Dialog.Root> */}
// ); </>
// }; );
};
const App = () => { const App = () => {
return ( return (
<FullPage data-test-id="Full-root-page"> <FullPage data-test-id="Full-root-page">
{/* <AppEnvHint /> */} <AppEnvHint />
<SpaApp data-test-id="app" /> <SpaApp data-test-id="app" />
{/* <Toaster /> */} {/* <Toaster /> */}
</FullPage> </FullPage>

View File

@ -80,7 +80,7 @@ export const AudioPlayer = ({ }: AudioPlayerProps) => {
const backColor = useColorThemeValue('back.100', 'back.800'); const backColor = useColorThemeValue('back.100', 'back.800');
const configButton = { const configButton = {
borderRadius: 'full', borderRadius: 'full',
backgroundColor: '#00000000', background: '#00000000',
_hover: { _hover: {
boxShadow: 'outline-over', boxShadow: 'outline-over',
bgColor: 'brand.500', bgColor: 'brand.500',
@ -216,7 +216,7 @@ export const AudioPlayer = ({ }: AudioPlayerProps) => {
zIndex: 1000, zIndex: 1000,
borderWidth: "1px", borderWidth: "1px",
borderColor: "brand.900", borderColor: "brand.900",
backgroundColor: backColor, background: backColor,
borderRadius: "10px 10px 0 0", borderRadius: "10px 10px 0 0",
}} }}
direction="column" direction="column"
@ -248,7 +248,7 @@ export const AudioPlayer = ({ }: AudioPlayerProps) => {
{dataAlbum && dataAlbum?.name} {dataAlbum && dataAlbum?.name}
{dataGender && ` / ${dataGender.name}`} {dataGender && ` / ${dataGender.name}`}
</Text> </Text>
<Flex style={{ width: "full", padding: "0 15px 0 15px" }}> <Flex style={{ width: "100%", padding: "0 15px 0 15px" }}>
<>TODO ... </> <>TODO ... </>
{/* <Slider.Root {/* <Slider.Root
defaultValue={[0]} defaultValue={[0]}

View File

@ -4,7 +4,7 @@ export const EmptyEnd = () => {
return ( return (
<Flex <Flex
style={{ style={{
width: "full", width: "100%",
height: "25%", height: "25%",
minHeight: "250px", minHeight: "250px",
}} }}

View File

@ -4,7 +4,7 @@ import { useLocation } from 'react-router-dom';
import background from '@/assets/images/ikon.svg'; import background from '@/assets/images/ikon.svg';
import { TOP_BAR_HEIGHT } from '@/components/TopBar/TopBar'; import { TOP_BAR_HEIGHT } from '@/components/TopBar/TopBar';
import { Flex } from '@/ui'; import { Flex, Image } from '@/ui';
export type LayoutProps = React.PropsWithChildren<unknown> & { export type LayoutProps = React.PropsWithChildren<unknown> & {
topBar?: ReactNode; topBar?: ReactNode;
@ -30,9 +30,10 @@ export const PageLayout = ({ children }: LayoutProps) => {
right: 0, right: 0,
minWidth: "300px", minWidth: "300px",
zIndex: -1, zIndex: -1,
background: "back.800",
}} }}
> >
{/* <Image src={background} boxSize="90%" margin="auto" opacity="30%" /> */} <Image src={background} boxSize="90%" style={{ margin: "auto", opacity: "30%" }} />
</Flex> </Flex>
<Flex <Flex
direction="column" direction="column"

View File

@ -3,7 +3,7 @@ import { CSSProperties, useEffect } from 'react';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import { PageLayout } from '@/components/Layout/PageLayout'; import { PageLayout } from '@/components/Layout/PageLayout';
import { colors } from '@/theme/colors'; import { basicColor } from '@/theme/colors';
import { useColorThemeValue } from '@/theme/ThemeContext'; import { useColorThemeValue } from '@/theme/ThemeContext';
import { Flex, FlexProps } from '@/ui'; import { Flex, FlexProps } from '@/ui';
@ -34,8 +34,8 @@ export const PageLayoutInfoCenter = ({
borderWidth: "1px", borderWidth: "1px",
borderRadius: "8px", borderRadius: "8px",
padding: "10px", padding: "10px",
boxShadow: '0px 0px 16px ' + colors.back[900], boxShadow: '0px 0px 16px ' + basicColor.back[900],
backgroundColor: useColorThemeValue('#FFFFFF', '#000000'), background: useColorThemeValue('#FFFFFF', '#000000'),
...style ...style
}} }}
{...rest} {...rest}

View File

@ -14,7 +14,7 @@ import { useNavigate } from 'react-router-dom';
import { useServiceContext } from '@/service/ServiceContext'; import { useServiceContext } from '@/service/ServiceContext';
import { SessionState } from '@/service/SessionState'; import { SessionState } from '@/service/SessionState';
import { colors } from '@/theme/colors'; import { basicColor } from '@/theme/colors';
import { requestSignIn, requestSignOut, requestSignUp } from '@/utils/sso'; import { requestSignIn, requestSignOut, requestSignUp } from '@/utils/sso';
import { useSessionService } from '@/service/session'; import { useSessionService } from '@/service/session';
import { MdHelp, MdHome, MdMore, MdOutlinePlaylistPlay, MdOutlineUploadFile, MdSupervisedUserCircle } from 'react-icons/md'; import { MdHelp, MdHome, MdMore, MdOutlinePlaylistPlay, MdOutlineUploadFile, MdSupervisedUserCircle } from 'react-icons/md';
@ -83,9 +83,9 @@ export const TopBar = ({ title, children }: TopBarProps) => {
left: 0, left: 0,
right: 0, right: 0,
height: TOP_BAR_HEIGHT, height: TOP_BAR_HEIGHT,
backgroundColor: backColor, background: backColor,
padding: "0 2 0 2", padding: "0 2 0 2",
boxShadow: `0px 2px 4px ${colors.back[900]}`, boxShadow: `0px 2px 4px ${basicColor.back[900]}`,
zIndex: 200, zIndex: 200,
}} }}
> >
@ -176,7 +176,7 @@ export const TopBar = ({ title, children }: TopBarProps) => {
as="button" as="button"
onClick={drawerDisclose.onClose} onClick={drawerDisclose.onClose}
boxShadow={'0px 2px 4px ' + colors.back[900]} boxShadow={'0px 2px 4px ' + colors.back[900]}
backgroundColor={backColor} background={backColor}
color={useColorModeValue('brand.900', 'brand.50')} color={useColorModeValue('brand.900', 'brand.50')}
textTransform="uppercase" textTransform="uppercase"
> >
@ -192,7 +192,7 @@ export const TopBar = ({ title, children }: TopBarProps) => {
background="#00000000" background="#00000000"
borderRadius="0px" borderRadius="0px"
onClick={onSelectHome} onClick={onSelectHome}
width="full" width="100%"
> >
<MdHome /> <MdHome />
<Text paddingLeft="3px" fontWeight="bold" marginRight="auto"> <Text paddingLeft="3px" fontWeight="bold" marginRight="auto">
@ -204,7 +204,7 @@ export const TopBar = ({ title, children }: TopBarProps) => {
background="#00000000" background="#00000000"
borderRadius="0px" borderRadius="0px"
onClick={onSelectOnAir} onClick={onSelectOnAir}
width="full" width="100%"
> >
<MdOutlinePlaylistPlay /> <MdOutlinePlaylistPlay />
<Text paddingLeft="3px" fontWeight="bold" marginRight="auto"> <Text paddingLeft="3px" fontWeight="bold" marginRight="auto">
@ -216,7 +216,7 @@ export const TopBar = ({ title, children }: TopBarProps) => {
background="#00000000" background="#00000000"
borderRadius="0px" borderRadius="0px"
onClick={onSelectAdd} onClick={onSelectAdd}
width="full" width="100%"
> >
<MdOutlineUploadFile /> <MdOutlineUploadFile />
<Text paddingLeft="3px" fontWeight="bold" marginRight="auto"> <Text paddingLeft="3px" fontWeight="bold" marginRight="auto">

View File

@ -15,13 +15,13 @@ export const DisplayAlbum = ({ dataAlbum }: DisplayAlbumProps) => {
const { countTracksOfAnAlbum } = useCountTracksWithAlbumId(dataAlbum?.id); const { countTracksOfAnAlbum } = useCountTracksWithAlbumId(dataAlbum?.id);
if (!dataAlbum) { if (!dataAlbum) {
return ( return (
<Flex direction="row" width="full" height="full"> <Flex direction="row" width="100%" height="full">
Fail to retrieve Album Data. Fail to retrieve Album Data.
</Flex> </Flex>
); );
} }
return ( return (
<Flex direction="row" width="full" height="full" <Flex direction="row" width="100%" height="full"
data-testid="display-album_flex"> data-testid="display-album_flex">
<Covers <Covers
data={dataAlbum?.covers} data={dataAlbum?.covers}

View File

@ -142,7 +142,7 @@ export const FormCovers = ({
onRestore={() => form.restoreValue({ [variableName]: true })} onRestore={() => form.restoreValue({ [variableName]: true })}
{...rest} {...rest}
> <></> > <></>
{/* <HStack wrap="wrap" width="full"> {/* <HStack wrap="wrap" width="100%">
{urls.map((data, index) => ( {urls.map((data, index) => (
<Flex align="flex-start" key={data}> <Flex align="flex-start" key={data}>
<Box width="125px" height="125px" position="relative"> <Box width="125px" height="125px" position="relative">

View File

@ -32,7 +32,7 @@ export const FormGroup = ({
padding="0 4px" padding="0 4px"
direction="column" direction="column"
> >
<Flex direction="row" width="full" gap="52px"> <Flex direction="row" width="100%" gap="52px">
{!!label && ( {!!label && (
<Text style={{ marginRight: "auto" }} fontWeight="bold"> <Text style={{ marginRight: "auto" }} fontWeight="bold">
{label}{' '} {label}{' '}

View File

@ -13,13 +13,13 @@ export const DisplayGender = ({ dataGender }: DisplayGenderProps) => {
const { countTracksOnAGender } = useCountTracksOfAGender(dataGender?.id); const { countTracksOnAGender } = useCountTracksOfAGender(dataGender?.id);
if (!dataGender) { if (!dataGender) {
return ( return (
<Flex direction="row" width="full" height="full"> <Flex direction="row" width="100%" height="full">
Fail to retrieve Gender Data. Fail to retrieve Gender Data.
</Flex> </Flex>
); );
} }
return ( return (
<Flex direction="row" width="full" height="full"> <Flex direction="row" width="100%" height="full">
<Covers <Covers
data={dataGender?.covers} data={dataGender?.covers}
size="100" size="100"

View File

@ -69,11 +69,11 @@ export const SelectList = ({
<Flex <Flex
direction="column" direction="column"
style={{ style={{
width: "full", width: "100%",
position: "absolute", position: "absolute",
border: "1px", border: "1px",
borderColor: "black", borderColor: "black",
backgroundColor: "gray.700", background: "gray.700",
overflowY: "auto", overflowY: "auto",
overflowX: "hidden", overflowX: "hidden",
maxHeight: "300px", maxHeight: "300px",
@ -93,8 +93,8 @@ export const SelectList = ({
margin: "1px 0", margin: "1px 0",
borderRadius: "0px", borderRadius: "0px",
//autoFocus: false, //autoFocus: false,
backgroundColor: data.isSelected ? 'green.800' : '0x00000000', background: data.isSelected ? 'green.800' : '0x00000000',
//_hover={ backgroundColor: 'gray.400' }, //_hover={ background: 'gray.400' },
}} }}
onClick={() => onSelectValue(data)} onClick={() => onSelectValue(data)}
//ref={data.isSelected ? scrollToRef : undefined} //ref={data.isSelected ? scrollToRef : undefined}
@ -110,7 +110,7 @@ export const SelectList = ({
margin: "1px 0", margin: "1px 0",
borderRadius: "0px", borderRadius: "0px",
//autoFocus:false, //autoFocus:false,
//_hover={ backgroundColor: 'gray.400' } //_hover={ background: 'gray.400' }
}} }}
onClick={() => onCreate(search)} onClick={() => onCreate(search)}
> >

View File

@ -99,9 +99,9 @@ export const SelectMultiple = ({
}; };
return ( return (
<Flex direction="column" width="full" gap="0px"> <Flex direction="column" width="100%" gap="0px">
{selectedOptions && ( {selectedOptions && (
<HStack style={{ flexWrap: "wrap", /*spacing="5px"*/ justifyContent: "left", width: "full", marginBottom: "2px" }}> <HStack style={{ flexWrap: "wrap", /*spacing="5px"*/ justifyContent: "left", width: "100%", marginBottom: "2px" }}>
{selectedOptions.map((data) => ( {selectedOptions.map((data) => (
<Flex align="flex-start" key={data[keyKey]}> <Flex align="flex-start" key={data[keyKey]}>
{/* <Tag.Root {/* <Tag.Root
@ -109,7 +109,7 @@ export const SelectMultiple = ({
key="md" key="md"
borderRadius="5px" borderRadius="5px"
variant="solid" variant="solid"
backgroundColor="green.500" background="green.500"
> >
<Tag.Label>{data[keyValue] ?? `id=${data[keyKey]}`}</Tag.Label> <Tag.Label>{data[keyValue] ?? `id=${data[keyKey]}`}</Tag.Label>
<Tag.CloseTrigger onClick={() => selectValue(data)} /> <Tag.CloseTrigger onClick={() => selectValue(data)} />
@ -123,7 +123,7 @@ export const SelectMultiple = ({
<Input <Input
ref={refFocus} ref={refFocus}
style={{ style={{
width: "full", width: "100%",
borderRadius: "5px 0 0 5px", borderRadius: "5px 0 0 5px",
}} }}
onChange={(e) => onChangeInput(e.target.value)} onChange={(e) => onChangeInput(e.target.value)}

View File

@ -101,13 +101,13 @@ export const SelectSingle = ({
}; };
return ( return (
<Flex direction="column" width="full" gap="0px"> <Flex direction="column" width="100%" gap="0px">
<Flex> <Flex>
<Input <Input
ref={refFocus} ref={refFocus}
style={{ style={{
width: "full", width: "100%",
backgroundColor: showList || !selectedOptions ? undefined : 'green.500', background: showList || !selectedOptions ? undefined : 'green.500',
borderRadius: "5px 0 0 5px", borderRadius: "5px 0 0 5px",
}} }}
onChange={(e) => onChangeInput(e.target.value)} onChange={(e) => onChangeInput(e.target.value)}

View File

@ -18,7 +18,7 @@ export const DisplayTrack = ({
}: DisplayTrackProps) => { }: DisplayTrackProps) => {
const { trackActive } = useActivePlaylistService(); const { trackActive } = useActivePlaylistService();
return ( return (
<Flex direction="row" width="full" height="full"> <Flex direction="row" width="100%" height="full">
<Covers <Covers
data={track?.covers} data={track?.covers}
size="50" size="50"
@ -30,7 +30,7 @@ export const DisplayTrack = ({
/> />
<Flex <Flex
direction="column" direction="column"
width="full" width="100%"
height="full" height="full"
paddingLeft="5px" paddingLeft="5px"
style={{ style={{

View File

@ -24,7 +24,7 @@ export const DisplayTrackFull = ({
const { dataGender } = useSpecificGender(track?.genderId); const { dataGender } = useSpecificGender(track?.genderId);
const { dataArtists } = useSpecificArtists(track?.artists); const { dataArtists } = useSpecificArtists(track?.artists);
return ( return (
<Flex direction="row" width="full" height="full" <Flex direction="row" width="100%" height="full"
data-testid="display-track-full"> data-testid="display-track-full">
<Covers <Covers
data={track?.covers} data={track?.covers}
@ -37,7 +37,7 @@ export const DisplayTrackFull = ({
/> />
<Flex <Flex
direction="column" direction="column"
width="full" width="100%"
height="full" height="full"
paddingLeft="5px" paddingLeft="5px"
onClick={onClick} onClick={onClick}

View File

@ -3,7 +3,7 @@ import { Flex } from "@/ui";
export const DisplayTrackSkeleton = () => { export const DisplayTrackSkeleton = () => {
return ( return (
<Flex direction="row" width="full" height="full"> <Flex direction="row" width="100%" height="full">
{/* <Skeleton {/* <Skeleton
borderRadius="0px" borderRadius="0px"
height="50" height="50"
@ -13,7 +13,7 @@ export const DisplayTrackSkeleton = () => {
/> */} /> */}
<Flex <Flex
direction="column" direction="column"
width="full" width="100%"
height="full" height="full"
paddingLeft="5px" paddingLeft="5px"
style={{ style={{

View File

@ -12,7 +12,7 @@ import { LuChevronUp, LuChevronDown } from 'react-icons/lu';
const ErrorFallback = ({ error }: FallbackProps) => { const ErrorFallback = ({ error }: FallbackProps) => {
const { open, onToggle } = useDisclosure(); const { open, onToggle } = useDisclosure();
return ( return (
<Flex direction="column" style={{ padding: 4, margin: "auto", backgroundColor: "red.500" }}> <Flex direction="column" style={{ padding: 4, margin: "auto", background: "red.500" }}>
<Text color='red'>An unexpected error has occurred.</Text> <Text color='red'>An unexpected error has occurred.</Text>
<Text>Message: {error.message}</Text> <Text>Message: {error.message}</Text>
{/* {/*

View File

@ -1,15 +1,16 @@
import ReactDOM from 'react-dom/client'; import ReactDOM from 'react-dom/client';
import App from '@/App'; import App from '@/App';
import { ThemeProvider } from './theme/ThemeContext'; import { ThemeProvider } from './theme/ThemeContext';
import { StrictMode } from 'react';
// Render the app // Render the app
const rootElement = document.getElementById('root'); const rootElement = document.getElementById('root');
if (rootElement && !rootElement.innerHTML) { if (rootElement && !rootElement.innerHTML) {
const root = ReactDOM.createRoot(rootElement); const root = ReactDOM.createRoot(rootElement);
root.render( root.render(
// <StrictMode> <StrictMode>
<ThemeProvider> <ThemeProvider>
<App /> <App />
</ThemeProvider> </ThemeProvider>
// </StrictMode> </StrictMode>
); );
} }

View File

@ -110,7 +110,7 @@ export const AlbumDetailPage = () => {
//height="60px" //height="60px"
border: "1px", border: "1px",
borderColor: "brand.900", borderColor: "brand.900",
backgroundColor: useColorThemeValue('#FFFFFF88', '#00000088'), background: useColorThemeValue('#FFFFFF88', '#00000088'),
padding: "5px", padding: "5px",
// _hover: { // _hover: {
// boxShadow: 'outline-over', // boxShadow: 'outline-over',

View File

@ -45,7 +45,7 @@ export const AlbumsPage = () => {
height: BASE_WRAP_HEIGHT, height: BASE_WRAP_HEIGHT,
border: "1px", border: "1px",
borderColor: "brand.900", borderColor: "brand.900",
backgroundColor: useColorThemeValue('#FFFFFF88', '#00000088'), background: useColorThemeValue('#FFFFFF88', '#00000088'),
padding: "5px", padding: "5px",
// _hover={ // _hover={
// boxShadow: 'outline-over', // boxShadow: 'outline-over',

View File

@ -137,7 +137,7 @@ export const ArtistAlbumDetailPage = () => {
height: "60px", height: "60px",
border: "1px", border: "1px",
borderColor: "brand.900", borderColor: "brand.900",
backgroundColor: useColorThemeValue('#FFFFFF88', '#00000088'), background: useColorThemeValue('#FFFFFF88', '#00000088'),
padding: "5px", padding: "5px",
// _hover: { // _hover: {
// boxShadow: 'outline-over', // boxShadow: 'outline-over',

View File

@ -98,7 +98,7 @@ export const ArtistDetailPage = () => {
height: BASE_WRAP_HEIGHT, height: BASE_WRAP_HEIGHT,
border: "1px", border: "1px",
borderColor: "brand.900", borderColor: "brand.900",
backgroundColor: useColorThemeValue('#FFFFFF88', '#00000088'), background: useColorThemeValue('#FFFFFF88', '#00000088'),
padding: "5px", padding: "5px",
// _hover={ // _hover={
// boxShadow: 'outline-over', // boxShadow: 'outline-over',

View File

@ -71,7 +71,7 @@ export const ArtistsPage = () => {
alignContent: "flex-start", alignContent: "flex-start",
border: "1px", border: "1px",
borderColor: "brand.900", borderColor: "brand.900",
backgroundColor: useColorThemeValue('#FFFFFF88', '#00000088'), background: useColorThemeValue('#FFFFFF88', '#00000088'),
padding: "5px", padding: "5px",
// _hover:{ // _hover:{
// boxShadow: 'outline-over', // boxShadow: 'outline-over',
@ -80,11 +80,11 @@ export const ArtistsPage = () => {
}} }}
onClick={() => onSelectItem(data)} onClick={() => onSelectItem(data)}
> >
<Flex direction="row" width="full" height="full"> <Flex direction="row" width="100%" height="full">
<Covers <Covers
data={data.covers} data={data.covers}
size={BASE_WRAP_ICON_SIZE} size={BASE_WRAP_ICON_SIZE}
style={{ height: "full" }} style={{ height: "100%" }}
// iconEmpty={LuUser} // iconEmpty={LuUser}
/> />
<Flex <Flex

View File

@ -106,7 +106,7 @@ export const GenderDetailPage = () => {
//height="60px", //height="60px",
border: "1px", border: "1px",
borderColor: "brand.900", borderColor: "brand.900",
backgroundColor: useColorThemeValue('#FFFFFF88', '#00000088'), background: useColorThemeValue('#FFFFFF88', '#00000088'),
padding: "5px", padding: "5px",
// _hover: { // _hover: {
// boxShadow: 'outline-over', // boxShadow: 'outline-over',

View File

@ -47,7 +47,7 @@ export const GendersPage = () => {
height: "120px", height: "120px",
border: "1px", border: "1px",
borderColor: "brand.900", borderColor: "brand.900",
//backgroundColor:{useColorModeValue('#FFFFFF88', '#00000088')}, //background:{useColorModeValue('#FFFFFF88', '#00000088')},
padding: "5px", padding: "5px",
// _hover: { // _hover: {
// boxShadow: 'outline-over', // boxShadow: 'outline-over',

View File

@ -421,7 +421,7 @@ export const AddPage = () => {
padding: "10px", padding: "10px",
}} }}
> >
<Flex direction="column" style={{ width: "full" }}> <Flex direction="column" style={{ width: "100%" }}>
<Flex> <Flex>
<Text>format:</Text> <Text>format:</Text>
<Text> <Text>
@ -479,7 +479,7 @@ export const AddPage = () => {
<Table.Header> <Table.Header>
<Table.Row> <Table.Row>
<Table.ColumnHeader>track ID</Table.ColumnHeader> <Table.ColumnHeader>track ID</Table.ColumnHeader>
<Table.ColumnHeader style={{ width: "full" }}>Title</Table.ColumnHeader> <Table.ColumnHeader style={{ width: "100%" }}>Title</Table.ColumnHeader>
<Table.ColumnHeader>actions</Table.ColumnHeader> <Table.ColumnHeader>actions</Table.ColumnHeader>
</Table.Row> </Table.Row>
</Table.Header> </Table.Header>
@ -493,7 +493,7 @@ export const AddPage = () => {
placeholder="e?" placeholder="e?"
value={data.trackId} value={data.trackId}
onChange={(e) => onTrackId(data, e.target.value)} onChange={(e) => onTrackId(data, e.target.value)}
backgroundColor={ background={
data.trackIdDetected === true data.trackIdDetected === true
? 'darkred' ? 'darkred'
: undefined : undefined
@ -506,14 +506,14 @@ export const AddPage = () => {
placeholder="Name of the Media" placeholder="Name of the Media"
value={data.title} value={data.title}
onChange={(e) => onTitle(data, e.target.value)} onChange={(e) => onTitle(data, e.target.value)}
backgroundColor={ background={
data.title === '' ? 'darkred' : undefined data.title === '' ? 'darkred' : undefined
} }
/> */} /> */}
{data.nameDetected === true && ( {data.nameDetected === true && (
<> <>
<br /> <br />
<Text style={{ backgroundColor: "red" }}> <Text style={{ background: "red" }}>
^^^This title already exist !!! ^^^This title already exist !!!
</Text> </Text>
</> </>
@ -558,7 +558,7 @@ export const AddPage = () => {
<Table.Header> <Table.Header>
<Table.Row> <Table.Row>
<Table.ColumnHeader>track ID</Table.ColumnHeader> <Table.ColumnHeader>track ID</Table.ColumnHeader>
<Table.ColumnHeader style={{ width: "full" }}>Title</Table.ColumnHeader> <Table.ColumnHeader style={{ width: "100%" }}>Title</Table.ColumnHeader>
<Table.ColumnHeader>actions</Table.ColumnHeader> <Table.ColumnHeader>actions</Table.ColumnHeader>
</Table.Row> </Table.Row>
</Table.Header> </Table.Header>

View File

@ -58,30 +58,43 @@ export const HomePage = () => {
<> <>
<TopBar title="Home" /> <TopBar title="Home" />
<PageLayout> <PageLayout>
<HStack style={{ flexWrap: "wrap", /*spacing="20px"*/ margin: "0 auto", padding: "20px", justify: "center" }}> <HStack style={{
flexWrap: "wrap",
/*spacing:"20px",*/
margin: "0 auto",
padding: "20px",
alignContent: "center"
}}>
{homeList.map((data) => ( {homeList.map((data) => (
<Flex align="flex-start" <Flex align="flex-start"
margin="auto"
key={data.id} key={data.id}
style={{ style={{
width: "200px", width: "200px",
height: "190px", height: "190px",
border: "1px", border: "1px",
borderColor: "brand.900", borderColor: "brand.900",
backgroundColor: useColorThemeValue('#FFFFFF88', '#00000088'), background: useColorThemeValue('#FFFFFF88', '#00000088'),
padding: "5px", padding: "5px",
// _hover:{ }}
// boxShadow: 'outline-over', _hover={{
// bgColor: useColorThemeValue('#FFFFFFF7', '#000000F7'), boxShadow: 'outline-over',
// } background: useColorThemeValue('#FFFFFFF7', '#000000F7'),
}} }}
onClick={() => onSelectItem(data)} onClick={() => onSelectItem(data)}
> >
<Flex direction="column" style={{ width: "full", height: "full" }}> <Flex
<Div style={{ alignContent: "center", height: "full" }}>{data.icon}</Div> direction="column"
<Div style={{ alignContent: "center", height: "full" }}> style={{
width: "100%",
margin: "auto"
}}>
<Div style={{ margin: "auto", height: "100%", color: "black.50" }}>{data.icon}</Div>
<Div style={{ margin: "auto", height: "100%" }}>
<Text <Text
fontSize="25px" fontSize="25px"
fontWeight="bold" fontWeight="bold"
color="black.50"
style={{ style={{
textTransform: "uppercase", textTransform: "uppercase",
userSelect: "none", userSelect: "none",

View File

@ -88,7 +88,7 @@ export const OnAirPage = () => {
//height:"60px", //height:"60px",
border: "1px", border: "1px",
borderColor: "brand.900", borderColor: "brand.900",
backgroundColor: useColorThemeValue('#FFFFFF88', '#00000088'), background: useColorThemeValue('#FFFFFF88', '#00000088'),
padding: "5px", padding: "5px",
// _hover: { // _hover: {
// boxShadow: 'outline-over', // boxShadow: 'outline-over',

View File

@ -50,8 +50,8 @@ export const SSOPage = () => {
<PageLayoutInfoCenter width="35%" gap="15px"> <PageLayoutInfoCenter width="35%" gap="15px">
<Text>LOGIN (after SSO)</Text> <Text>LOGIN (after SSO)</Text>
<Flex width="full"> <Flex width="100%">
<Image href={avatar_generic} boxSize="150px" style={{ borderRadius: "full" }} /> <Image src={avatar_generic} boxSize="150px" style={{ borderRadius: "full" }} />
</Flex> </Flex>
{token === '__CANCEL__' && ( {token === '__CANCEL__' && (
<Text> <Text>

View File

@ -50,7 +50,7 @@ export const TrackSelectionPage = () => {
height="75px" height="75px"
border="1px" border="1px"
borderColor="brand.900" borderColor="brand.900"
backgroundColor={useColorThemeValue('#FFFFFF88', '#00000088')} background={useColorThemeValue('#FFFFFF88', '#00000088')}
key={data} key={data}
padding="5px" padding="5px"
as="button" as="button"
@ -60,7 +60,7 @@ export const TrackSelectionPage = () => {
}} }}
onClick={() => onSelectItem(data)} onClick={() => onSelectItem(data)}
> >
<Flex direction="column" width="full" height="full"> <Flex direction="column" width="100%" height="full">
<Text <Text
margin="auto" margin="auto"
fontSize="25px" fontSize="25px"

View File

@ -63,7 +63,7 @@ export const TracksStartLetterDetailPage = () => {
//height:"60px", //height:"60px",
border: "1px", border: "1px",
borderColor: "brand.900", borderColor: "brand.900",
backgroundColor: useColorThemeValue('#FFFFFF88', '#00000088'), background: useColorThemeValue('#FFFFFF88', '#00000088'),
padding: "5px", padding: "5px",
// _hover: { // _hover: {
// boxShadow: 'outline-over', // boxShadow: 'outline-over',
@ -83,7 +83,7 @@ export const TracksStartLetterDetailPage = () => {
//height:"60px", //height:"60px",
border: "1px", border: "1px",
borderColor: "brand.900", borderColor: "brand.900",
backgroundColor: useColorThemeValue('#FFFFFF88', '#00000088'), background: useColorThemeValue('#FFFFFF88', '#00000088'),
padding: "5px", padding: "5px",
// _hover: { // _hover: {

View File

@ -2,21 +2,41 @@
import { createContext, useContext, useState, useEffect, CSSProperties, ReactNode, useCallback } from "react"; import { createContext, useContext, useState, useEffect, CSSProperties, ReactNode, useCallback } from "react";
import { basicColor } from "./colors"; import { basicColor } from "./colors";
type themeContextProps = { export type ApplyThemeProperty = {
componentType?: String;
// define the format of the shape
shape?: String;
// Define the color model used
palette?: String;
}
export type ThemeContextProps = {
theme: string; theme: string;
themeList: string[]; themeList: string[];
setTheme: (string) => void; setTheme: (string) => void;
toggleTheme: () => void; toggleTheme: () => void;
convertStyle: (style: CSSProperties) => CSSProperties, convertStyle: (style: CSSProperties) => CSSProperties,
applyTheme: (style: CSSProperties, theme: ApplyThemeProperty) => CSSProperties,
} }
const ThemeContext = createContext<themeContextProps>({ const ThemeContext = createContext<ThemeContextProps>({
theme: "error", theme: "error",
themeList: ["error"], themeList: ["error"],
setTheme: (_: string) => { }, setTheme: (_: string) => {
toggleTheme: () => { }, console.error("Request setTheme without context");
convertStyle: (style: CSSProperties): CSSProperties => { return style; }, },
toggleTheme: () => {
console.error("Request toggleTheme without context");
},
convertStyle: (style: CSSProperties): CSSProperties => {
console.error("Request convertStyle without context");
return style;
},
applyTheme: (style: CSSProperties, _theme: ApplyThemeProperty) => {
console.error("Request applyTheme without context");
return style;
},
}); });
const themes = { const themes = {
@ -36,11 +56,40 @@ const themes = {
background: "#181818", background: "#181818",
text: "#ffffff", text: "#ffffff",
}, },
},
base: {
Button: {
border: '1px solid red',
},
Flex: {
},
},
shape: {
outline: {
border: '1px solid transparent',
},
},
palette: {
primary: {
borderColor: "green"
},
secondary: {
},
danger: {
},
success: {
}
} }
}; };
export function ThemeProvider({ children, themeList = ["light", "dark"] }: { children: ReactNode, themeList?: string[] }) { export function ThemeProvider({ children, themeList = ["light", "dark"] }: { children: ReactNode, themeList?: string[] }) {
const [theme, setTheme] = useState<string>(themeList[0]); const [theme, setTheme] = useState<string>(themeList[1]);
const [basicsColor, setBasicsColor] = useState<{ [key: string]: string }>({}); const [basicsColor, setBasicsColor] = useState<{ [key: string]: string }>({});
// update the global CSS wen theme is updated: // update the global CSS wen theme is updated:
@ -66,7 +115,6 @@ export function ThemeProvider({ children, themeList = ["light", "dark"] }: { chi
}, [theme, setBasicsColor]); }, [theme, setBasicsColor]);
const toggleTheme = useCallback(() => { const toggleTheme = useCallback(() => {
console.log(`plop: ${theme}`);
setTheme((previous) => { setTheme((previous) => {
if (themeList.length <= 1) { if (themeList.length <= 1) {
return previous; return previous;
@ -85,24 +133,62 @@ export function ThemeProvider({ children, themeList = ["light", "dark"] }: { chi
if (typeof value !== "string") { if (typeof value !== "string") {
return; return;
} }
// console.log(`request convert value: ${value}`);
if (basicsColor[value]) { if (basicsColor[value]) {
// console.log(`convert value: ${value} in ${basicsColor[value]}`);
style[key] = basicsColor[value]; style[key] = basicsColor[value];
} }
}, [basicsColor]); }, [basicsColor]);
const convertStyle = useCallback((style: CSSProperties): CSSProperties => { const convertStyle = useCallback((style: CSSProperties): CSSProperties => {
console.log(`plop: ${theme}`); //console.log(`plop: ${theme}`);
if (!style) { if (!style) {
return style; return style;
} }
const out = { ...style } const out = { ...style }
convertElementStyle(out, "background"); convertElementStyle(out, "background");
convertElementStyle(out, "backgroundColor");
convertElementStyle(out, "borderColor"); convertElementStyle(out, "borderColor");
convertElementStyle(out, "color"); convertElementStyle(out, "color");
return out; return out;
}, [convertElementStyle]); }, [convertElementStyle]);
const applyTheme = useCallback((style: CSSProperties, selectedTheme?: ApplyThemeProperty): CSSProperties => {
let out = style;
console.log(`apply style ... ${JSON.stringify(selectedTheme, null, 2)}`);
// Apply the basic theme of the component:
if (selectedTheme?.componentType) {
console.log(`detect component type theme ... ${selectedTheme?.componentType}`);
const base = themes?.base[selectedTheme.componentType];
console.log(` base = ${JSON.stringify(base, null, 2)}`);
if (base) {
out = { ...base, ...out };
}
}
// Apply the variant selected:
if (selectedTheme?.shape) {
const shape = themes?.shape[selectedTheme.shape];
if (shape) {
out = { ...shape, ...out };
}
}
// Apply the palette selected:
if (selectedTheme?.palette) {
const palette = themes?.shape[selectedTheme.palette];
if (palette) {
const palette2 = palette[theme];
if (palette2) {
out = { ...palette2, ...out };
}
}
}
return convertStyle(out);
}, [convertStyle]);
return ( return (
<ThemeContext.Provider value={{ theme, themeList, setTheme, toggleTheme, convertStyle }}> <ThemeContext.Provider value={{ theme, themeList, setTheme, toggleTheme, convertStyle, applyTheme }}>
{children} {children}
</ThemeContext.Provider> </ThemeContext.Provider>
); );
@ -111,5 +197,6 @@ export const useTheme = () => useContext(ThemeContext);
export function useColorThemeValue<T>(firstTheme: T, secondTheme: T) { export function useColorThemeValue<T>(firstTheme: T, secondTheme: T) {
const { theme, themeList } = useTheme() const { theme, themeList } = useTheme()
//console.log(`use theme =${theme} ==> ${theme === themeList[0] ? firstTheme : secondTheme}`);
return theme === themeList[0] ? firstTheme : secondTheme return theme === themeList[0] ? firstTheme : secondTheme
} }

View File

@ -12,7 +12,7 @@ const brand = {
900: '#00071e', 900: '#00071e',
}; };
const back = { const black = {
50: '#f2f2f2', 50: '#f2f2f2',
100: '#d9d9d9', 100: '#d9d9d9',
200: '#bfbfbf', 200: '#bfbfbf',
@ -112,14 +112,15 @@ const cyan = {
} }
export const basicColor = { export const basicColor = {
green, red, orange, back, blue, yellow, purple, cyan brand,
} green,
red,
export const colors = { orange,
black,
brand: brand, blue,
back: back, yellow,
success: green, purple,
error: red, cyan,
back: black,
warning: orange, warning: orange,
} as const; }

View File

@ -1,24 +1,27 @@
import { useTheme } from "@/theme/ThemeContext"; import { ApplyThemeProperty, useTheme } from "@/theme/ThemeContext";
import { ReactNode, CSSProperties } from "react"; import { ReactNode, CSSProperties } from "react";
export type ButtonProps = { export type ButtonProps = {
children: ReactNode; children: ReactNode;
onClick?: () => void; onClick?: () => void;
style?: CSSProperties; style?: CSSProperties;
componentType?: ApplyThemeProperty['componentType'];
shape?: ApplyThemeProperty['shape'];
palette?: ApplyThemeProperty['palette'];
}; };
export const Button = ({ children, onClick, style }: ButtonProps) => { export const Button = ({ children, onClick, style, componentType = "Button", shape, palette }: ButtonProps) => {
const { convertStyle } = useTheme(); const { applyTheme } = useTheme();
const themedStyle = style ? convertStyle({ const themedStyle = style ? applyTheme({
padding: '10px 20px', padding: '10px 20px',
backgroundColor: '#3182CE', background: '#3182CE',
color: '#FFF', color: '#FFF',
border: 'none', //border: 'none',
borderRadius: '4px', //borderRadius: '4px',
cursor: 'pointer', cursor: 'pointer',
fontSize: '16px', fontSize: '16px',
...style, ...style,
}) : undefined; }, { componentType, shape, palette }) : undefined;
return ( return (
<button <button
onClick={onClick} onClick={onClick}

View File

@ -1,17 +1,29 @@
import { useTheme } from '@/theme/ThemeContext'; import { ApplyThemeProperty, useTheme } from '@/theme/ThemeContext';
import { CSSProperties, ReactNode } from 'react'; import { CSSProperties, ReactNode, useState } from 'react';
export type DivProps = { export type DivProps = {
children?: ReactNode; children?: ReactNode;
onClick?: () => void; onClick?: () => void;
style?: CSSProperties style?: CSSProperties;
_hover?: CSSProperties;
componentType?: ApplyThemeProperty['componentType'];
shape?: ApplyThemeProperty['shape'];
palette?: ApplyThemeProperty['palette'];
}; };
export const Div = ({ children, onClick, style }: DivProps) => { export const Div = ({ children, onClick, style, _hover, ...themeToApply }: DivProps) => {
const { convertStyle } = useTheme(); const { applyTheme } = useTheme();
const themedStyle = style ? convertStyle(style) : undefined; const [hover, setHover] = useState(false);
const hoverTheme = hover ? _hover : {};
const themedStyle = style ? applyTheme({ ...style, ...hoverTheme }, themeToApply) : undefined;
return ( return (
<div <div
onMouseEnter={() => {
setHover(true);
}}
onMouseLeave={() => {
setHover(false);
}}
onClick={onClick} onClick={onClick}
style={themedStyle} style={themedStyle}
> >

View File

@ -1,8 +1,12 @@
import React, { CSSProperties, ReactNode } from 'react'; import React, { CSSProperties, ReactNode } from 'react';
import { Div } from './Div'; import { Div } from './Div';
import { ApplyThemeProperty } from '@/theme/ThemeContext';
export type FlexProps = { export type FlexProps = {
children?: ReactNode; children?: ReactNode;
componentType?: ApplyThemeProperty['componentType'];
shape?: ApplyThemeProperty['shape'];
palette?: ApplyThemeProperty['palette'];
onClick?: () => void; onClick?: () => void;
direction?: 'row' | 'column'; direction?: 'row' | 'column';
gap?: string | number; gap?: string | number;
@ -25,6 +29,7 @@ export type FlexProps = {
marginTop?: CSSProperties['marginTop']; marginTop?: CSSProperties['marginTop'];
marginBottom?: CSSProperties['marginBottom']; marginBottom?: CSSProperties['marginBottom'];
style?: Omit<CSSProperties, "flexDirection" | "display" | "justifyContent" | "alignItems" | "alignItems" | "direction"> style?: Omit<CSSProperties, "flexDirection" | "display" | "justifyContent" | "alignItems" | "alignItems" | "direction">
_hover?: CSSProperties;
}; };
export const Flex = ({ export const Flex = ({
@ -38,11 +43,11 @@ export const Flex = ({
height, height,
padding, padding,
margin, margin,
maxWidth, maxWidth, minWidth, maxHeight, minHeight,
minWidth, paddingLeft, paddingRight, paddingTop, paddingBottom,
maxHeight, marginLeft, marginRight, marginTop, marginBottom,
minHeight, paddingLeft, paddingRight, paddingTop, paddingBottom, marginLeft, marginRight, marginTop, marginBottom, componentType = "Flex", shape, palette,
style }: FlexProps) => { style, _hover }: FlexProps) => {
return ( return (
<Div <Div
@ -57,14 +62,15 @@ export const Flex = ({
height, height,
padding, padding,
margin, margin,
maxWidth, maxWidth, minWidth, maxHeight, minHeight,
minWidth, paddingLeft, paddingRight, paddingTop, paddingBottom,
maxHeight, marginLeft, marginRight, marginTop, marginBottom,
minHeight, paddingLeft, paddingRight, paddingTop, paddingBottom, marginLeft, marginRight, marginTop, marginBottom,
...style, ...style,
}} }}
_hover={_hover}
componentType={componentType} shape={shape} palette={palette}
> >
{children} {children}
</Div> </Div >
); );
}; };

View File

@ -13,7 +13,7 @@ export const HStack = ({ children, spacing = '8px', align = 'flex-start', style
<Div <Div
style={{ style={{
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'row',
alignItems: align, alignItems: align,
gap: spacing, gap: spacing,
...style, ...style,

View File

@ -3,7 +3,7 @@ import { useTheme } from "@/theme/ThemeContext";
export type ImageProps = { export type ImageProps = {
ref?: RefObject<any>; ref?: RefObject<any>;
href?: string; src?: string;
boxSize?: string; boxSize?: string;
onChange?: (e) => void; onChange?: (e) => void;
style?: Omit<CSSProperties, "fontSize" | "fontWeight" | "color">; style?: Omit<CSSProperties, "fontSize" | "fontWeight" | "color">;
@ -11,7 +11,7 @@ export type ImageProps = {
export const Image = ({ export const Image = ({
ref, ref,
href, src,
boxSize, boxSize,
onChange, onChange,
style, style,
@ -19,12 +19,12 @@ export const Image = ({
const { convertStyle } = useTheme(); const { convertStyle } = useTheme();
const themedStyle = style ? convertStyle({ width: boxSize, height: boxSize, ...style }) : undefined; const themedStyle = style ? convertStyle({ width: boxSize, height: boxSize, ...style }) : undefined;
return ( return (
<image <img
ref={ref} ref={ref}
href={href} src={src}
onChange={onChange} onChange={onChange}
style={themedStyle} style={themedStyle}
> >
</image> </img>
); );
}; };

View File

@ -3,14 +3,14 @@ import { CSSProperties, ReactNode } from 'react'
export type RootProps = { export type RootProps = {
children?: ReactNode; children?: ReactNode;
background?: CSSProperties['backgroundColor']; background?: CSSProperties['background'];
style?: CSSProperties; style?: CSSProperties;
} }
export const Root = ({ background, children, style }: RootProps) => { export const Root = ({ background, children, style }: RootProps) => {
const { convertStyle } = useTheme(); const { convertStyle } = useTheme();
const themedStyle = style ? convertStyle({ const themedStyle = style ? convertStyle({
backgroundColor: background, background: background,
...style ...style
}) : undefined; }) : undefined;
return (<table return (<table

View File

@ -13,7 +13,7 @@ export const VStack = ({ children, spacing = '8px', align = 'flex-start', style
<Div <Div
style={{ style={{
display: 'flex', display: 'flex',
flexDirection: 'row', flexDirection: 'column',
alignItems: align, alignItems: align,
gap: spacing, gap: spacing,
...style, ...style,