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

View File

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

View File

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

View File

@ -4,7 +4,7 @@ import { useLocation } from 'react-router-dom';
import background from '@/assets/images/ikon.svg';
import { TOP_BAR_HEIGHT } from '@/components/TopBar/TopBar';
import { Flex } from '@/ui';
import { Flex, Image } from '@/ui';
export type LayoutProps = React.PropsWithChildren<unknown> & {
topBar?: ReactNode;
@ -30,9 +30,10 @@ export const PageLayout = ({ children }: LayoutProps) => {
right: 0,
minWidth: "300px",
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
direction="column"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -12,7 +12,7 @@ import { LuChevronUp, LuChevronDown } from 'react-icons/lu';
const ErrorFallback = ({ error }: FallbackProps) => {
const { open, onToggle } = useDisclosure();
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>Message: {error.message}</Text>
{/*

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,21 +2,41 @@
import { createContext, useContext, useState, useEffect, CSSProperties, ReactNode, useCallback } from "react";
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;
themeList: string[];
setTheme: (string) => void;
toggleTheme: () => void;
convertStyle: (style: CSSProperties) => CSSProperties,
applyTheme: (style: CSSProperties, theme: ApplyThemeProperty) => CSSProperties,
}
const ThemeContext = createContext<themeContextProps>({
const ThemeContext = createContext<ThemeContextProps>({
theme: "error",
themeList: ["error"],
setTheme: (_: string) => { },
toggleTheme: () => { },
convertStyle: (style: CSSProperties): CSSProperties => { return style; },
setTheme: (_: string) => {
console.error("Request setTheme without context");
},
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 = {
@ -36,11 +56,40 @@ const themes = {
background: "#181818",
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[] }) {
const [theme, setTheme] = useState<string>(themeList[0]);
const [theme, setTheme] = useState<string>(themeList[1]);
const [basicsColor, setBasicsColor] = useState<{ [key: string]: string }>({});
// update the global CSS wen theme is updated:
@ -66,7 +115,6 @@ export function ThemeProvider({ children, themeList = ["light", "dark"] }: { chi
}, [theme, setBasicsColor]);
const toggleTheme = useCallback(() => {
console.log(`plop: ${theme}`);
setTheme((previous) => {
if (themeList.length <= 1) {
return previous;
@ -85,24 +133,62 @@ export function ThemeProvider({ children, themeList = ["light", "dark"] }: { chi
if (typeof value !== "string") {
return;
}
// console.log(`request convert value: ${value}`);
if (basicsColor[value]) {
// console.log(`convert value: ${value} in ${basicsColor[value]}`);
style[key] = basicsColor[value];
}
}, [basicsColor]);
const convertStyle = useCallback((style: CSSProperties): CSSProperties => {
console.log(`plop: ${theme}`);
//console.log(`plop: ${theme}`);
if (!style) {
return style;
}
const out = { ...style }
convertElementStyle(out, "background");
convertElementStyle(out, "backgroundColor");
convertElementStyle(out, "borderColor");
convertElementStyle(out, "color");
return out;
}, [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 (
<ThemeContext.Provider value={{ theme, themeList, setTheme, toggleTheme, convertStyle }}>
<ThemeContext.Provider value={{ theme, themeList, setTheme, toggleTheme, convertStyle, applyTheme }}>
{children}
</ThemeContext.Provider>
);
@ -111,5 +197,6 @@ export const useTheme = () => useContext(ThemeContext);
export function useColorThemeValue<T>(firstTheme: T, secondTheme: T) {
const { theme, themeList } = useTheme()
//console.log(`use theme =${theme} ==> ${theme === themeList[0] ? firstTheme : secondTheme}`);
return theme === themeList[0] ? firstTheme : secondTheme
}

View File

@ -12,7 +12,7 @@ const brand = {
900: '#00071e',
};
const back = {
const black = {
50: '#f2f2f2',
100: '#d9d9d9',
200: '#bfbfbf',
@ -112,14 +112,15 @@ const cyan = {
}
export const basicColor = {
green, red, orange, back, blue, yellow, purple, cyan
}
export const colors = {
brand: brand,
back: back,
success: green,
error: red,
brand,
green,
red,
orange,
black,
blue,
yellow,
purple,
cyan,
back: black,
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";
export type ButtonProps = {
children: ReactNode;
onClick?: () => void;
style?: CSSProperties;
componentType?: ApplyThemeProperty['componentType'];
shape?: ApplyThemeProperty['shape'];
palette?: ApplyThemeProperty['palette'];
};
export const Button = ({ children, onClick, style }: ButtonProps) => {
const { convertStyle } = useTheme();
const themedStyle = style ? convertStyle({
export const Button = ({ children, onClick, style, componentType = "Button", shape, palette }: ButtonProps) => {
const { applyTheme } = useTheme();
const themedStyle = style ? applyTheme({
padding: '10px 20px',
backgroundColor: '#3182CE',
background: '#3182CE',
color: '#FFF',
border: 'none',
borderRadius: '4px',
//border: 'none',
//borderRadius: '4px',
cursor: 'pointer',
fontSize: '16px',
...style,
}) : undefined;
}, { componentType, shape, palette }) : undefined;
return (
<button
onClick={onClick}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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