[DEV] restart from scratch with no toolbox ==> maybe slower but funny

This commit is contained in:
Edouard DUPIN 2025-01-21 00:54:27 +01:00
parent d52052de90
commit f9019ec508
96 changed files with 999 additions and 3437 deletions

View File

@ -29,16 +29,6 @@
"*.{ts,tsx,js,jsx,json}": "prettier --write" "*.{ts,tsx,js,jsx,json}": "prettier --write"
}, },
"dependencies": { "dependencies": {
"@chakra-ui/anatomy": "2.3.4",
"@chakra-ui/cli": "3.3.1",
"@chakra-ui/react": "3.3.1",
"@emotion/react": "11.14.0",
"@emotion/styled": "11.14.0",
"allotment": "1.20.2",
"css-mediaquery": "0.1.2",
"dayjs": "1.11.13",
"history": "5.3.0",
"next-themes": "^0.4.4",
"react": "18.3.1", "react": "18.3.1",
"react-dom": "18.3.1", "react-dom": "18.3.1",
"react-error-boundary": "5.0.0", "react-error-boundary": "5.0.0",
@ -50,7 +40,6 @@
"zustand": "5.0.3" "zustand": "5.0.3"
}, },
"devDependencies": { "devDependencies": {
"@chakra-ui/styled-system": "^2.12.0",
"@playwright/test": "1.49.1", "@playwright/test": "1.49.1",
"@storybook/addon-actions": "8.4.7", "@storybook/addon-actions": "8.4.7",
"@storybook/addon-essentials": "8.4.7", "@storybook/addon-essentials": "8.4.7",
@ -82,7 +71,6 @@
"lint-staged": "15.3.0", "lint-staged": "15.3.0",
"npm-check-updates": "^17.1.13", "npm-check-updates": "^17.1.13",
"prettier": "3.4.2", "prettier": "3.4.2",
"puppeteer": "24.0.0",
"react-is": "19.0.0", "react-is": "19.0.0",
"storybook": "8.4.7", "storybook": "8.4.7",
"ts-node": "10.9.2", "ts-node": "10.9.2",

2114
front/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1,132 +1,109 @@
import { useState } from 'react';
import {
Box,
Button,
ChakraProvider,
DialogBody,
DialogContent,
DialogFooter,
DialogHeader,
DialogRoot,
DialogTrigger,
SelectContent,
SelectItem,
SelectRoot,
SelectTrigger,
SelectValueText,
Stack,
Text,
useDisclosure,
} from '@chakra-ui/react';
import { environment } from '@/environment';
import { App as SpaApp } from '@/scene/App'; import { App as SpaApp } from '@/scene/App';
import { USERS, USERS_COLLECTION } from '@/service/session'; import { FullPage } from './ui';
import { hashLocalData } from '@/utils/sso';
import { Toaster } from './components/ui/toaster';
import { systemTheme } from './theme/theme';
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 (
<> // <>
<Box // <div style={{
zIndex="100000" // zIndex: "100000",
position="fixed" // position: "fixed",
top="0" // top: "0",
insetStart="0" // height: "2px",
insetEnd="0" // background: "warning.400",
h="2px" // cursor: "pointer"
bg="warning.400" // }}
as="button" // data-test-id="devtools"
cursor="pointer" // onClick={dialog.onOpen}
data-test-id="devtools" // >
onClick={dialog.onOpen} // <div style={{
> // position: "fixed",
<Text // top: "0",
position="fixed" // background: "warning.400",
top="0" // color: "warning.900",
insetStart="4" // fontSize: "0.6rem",
bg="warning.400" // fontWeight: "bold",
color="warning.900" // paddingLeft: "10px",
fontSize="0.6rem" // paddingRight: "10px",
fontWeight="bold" // marginLeft: "25%",
px="10px" // borderRadius: "10px 0 10px 0",
marginLeft="25%" // textTransform: "uppercase",
borderBottomStartRadius="sm" // }}
borderBottomEndRadius="sm" // >
textTransform="uppercase" // {envName.join(' : ')}
> // </div>
{envName.join(' : ')} // </div>
</Text> // <Dialog.Root open={dialog.open} onOpenChange={dialog.onClose}>
</Box> // <Dialog.Trigger asChild>
<DialogRoot open={dialog.open} onOpenChange={dialog.onClose}> // <Button>
<DialogContent> // {dialog.open ? "Close" : "Open"} Dialog
<DialogHeader>Outils développeurs</DialogHeader> // </Button>
<DialogTrigger asChild> // </Dialog.Trigger>
<Button variant="outline" size="sm"> // <Portal>
{dialog.open ? "Close" : "Open"} Dialog // <Dialog.Backdrop />
</Button> // <Dialog.Positioner>
</DialogTrigger> // <Dialog.Content>
<DialogBody> // <Dialog.Title>Outils développeurs</Dialog.Title>
<Stack> // <Dialog.Description>
<Text>User</Text> // <HStack>
<SelectRoot onChange={handleChange} collection={USERS_COLLECTION}> // <Text>User</Text>
<SelectTrigger> // <Select.Root onChange={handleChange} collection={USERS_COLLECTION}>
<SelectValueText placeholder="Select test user" /> // <Select.Trigger>
</SelectTrigger> // <SelectValueText placeholder="Select test user" />
<SelectContent> // </Select.Trigger>
{USERS_COLLECTION.items.map((value) => ( // <Select.Content>
<SelectItem item={value} key={value.value}> // {USERS_COLLECTION.items.map((value) => (
{value.label} // <Select.Item item={value} key={value.value}>
</SelectItem> // {value.label}
))} // </Select.Item>
</SelectContent> // ))}
</SelectRoot> // </Select.Content>
</Stack> // </Select.Root>
</DialogBody> // </HStack>
<DialogFooter> // </Dialog.Description>
<Button onClick={onClose}>Apply</Button> // <Dialog.CloseTrigger>
</DialogFooter> // <Button onClick={onClose}>Apply</Button>
</DialogContent> // </Dialog.CloseTrigger>
</DialogRoot> // </Dialog.Content>
</> // </Dialog.Positioner>
); // </Portal>
}; // </Dialog.Root>
// </>
// );
// };
const App = () => { const App = () => {
return ( return (
<ChakraProvider value={systemTheme}> <FullPage data-test-id="Full-root-page">
<AppEnvHint /> {/* <AppEnvHint /> */}
<SpaApp /> <SpaApp data-test-id="app" />
<Toaster /> {/* <Toaster /> */}
</ChakraProvider> </FullPage>
); );
}; };

View File

@ -1,16 +1,6 @@
import { SyntheticEvent, useEffect, useRef, useState } from 'react'; import { SyntheticEvent, useEffect, useRef, useState } from 'react';
import {
Box,
Button,
Flex,
IconButton,
Slider,
SliderRoot,
SliderThumb,
SliderTrack,
Text,
} from '@chakra-ui/react';
import { import {
MdFastForward, MdFastForward,
MdFastRewind, MdFastRewind,
@ -35,6 +25,7 @@ import { DataUrlAccess } from '@/utils/data-url-access';
import { useColorModeValue } from '@/components/ui/color-mode'; import { useColorModeValue } from '@/components/ui/color-mode';
import { isNullOrUndefined } from '@/utils/validator'; import { isNullOrUndefined } from '@/utils/validator';
import { Icon } from './Icon'; import { Icon } from './Icon';
import { Flex, Text } from '@/ui';
export enum PlayMode { export enum PlayMode {
PLAY_ONE, PLAY_ONE,
@ -213,47 +204,53 @@ export const AudioPlayer = ({ }: AudioPlayerProps) => {
<> <>
{!isNullOrUndefined(trackOffset) && ( {!isNullOrUndefined(trackOffset) && (
<Flex <Flex
position="absolute" style={{
height="150px" position: "absolute",
minHeight="150px" height: "150px",
paddingY="5px" minHeight: "150px",
paddingX="10px" padding: "5px 10px 5px 10px",
marginX="15px" margin: "0 15px 0 15px",
bottom={0} bottom: 0,
left={0} left: 0,
right={0} right: 0,
zIndex={1000} zIndex: 1000,
borderWidth="1px" borderWidth: "1px",
borderColor="brand.900" borderColor: "brand.900",
bgColor={backColor} backgroundColor: backColor,
borderTopRadius="10px" borderRadius: "10px 10px 0 0",
}}
direction="column" direction="column"
> >
<Text <Text
alignContent="left"
fontSize="20px" fontSize="20px"
fontWeight="bold" fontWeight="bold"
userSelect="none" style={{
marginRight="auto" alignContent: "left",
overflow="hidden" userSelect: "none",
marginRight: "auto",
overflow: "hidden",
}}
// noOfLines={1} // noOfLines={1}
> >
{dataTrack?.name ?? '???'} {dataTrack?.name ?? '???'}
</Text> </Text>
<Text <Text
alignContent="left"
fontSize="16px" fontSize="16px"
userSelect="none" style={{
marginRight="auto" alignContent: "left",
overflow="hidden" userSelect: "none",
// noOfLines={1} marginRight: "auto",
overflow: "hidden",
//noOfLines:1
}}
> >
{dataArtists.map((data) => data.name).join(', ')} /{' '} {dataArtists.map((data) => data.name).join(', ')} /{' '}
{dataAlbum && dataAlbum?.name} {dataAlbum && dataAlbum?.name}
{dataGender && ` / ${dataGender.name}`} {dataGender && ` / ${dataGender.name}`}
</Text> </Text>
<Box width="full" paddingX="15px"> <Flex style={{ width: "full", padding: "0 15px 0 15px" }}>
<Slider.Root <>TODO ... </>
{/* <Slider.Root
defaultValue={[0]} defaultValue={[0]}
value={[timeProgress]} value={[timeProgress]}
min={0} min={0}
@ -264,26 +261,28 @@ export const AudioPlayer = ({ }: AudioPlayerProps) => {
// focusThumbOnChange={false} // focusThumbOnChange={false}
> >
<SliderTrack bg="gray.200" height="10px" borderRadius="full"> <SliderTrack bg="gray.200" height="10px" borderRadius="full">
{/* <SliderFilledTrack bg="brand.600" /> */} {/ * <SliderFilledTrack bg="brand.600" /> * /}
</SliderTrack> </SliderTrack>
</Slider.Root> </Slider.Root> */}
</Box> </Flex>
<Flex> <Flex>
<Text <Text
alignContent="left"
fontSize="16px" fontSize="16px"
userSelect="none" style={{
marginRight="auto" alignContent: "left",
overflow="hidden" userSelect: "none",
// noOfLines={1} marginRight: "auto",
overflow: "hidden",
// noOfLines={1},
}}
> >
{formatTime(timeProgress)} {formatTime(timeProgress)}
</Text> </Text>
<Text alignContent="left" fontSize="16px" userSelect="none"> <Text fontSize="16px" style={{ alignContent: "left", userSelect: "none" }}>
{formatTime(duration)} {formatTime(duration)}
</Text> </Text>
</Flex> </Flex>
<Flex gap="5px"> {/* <Flex gap="5px">
<IconButton <IconButton
{...configButton} {...configButton}
aria-label={'Play'} aria-label={'Play'}
@ -327,7 +326,7 @@ export const AudioPlayer = ({ }: AudioPlayerProps) => {
aria-label={'continue to the end'} aria-label={'continue to the end'}
onClick={onTypePlay} onClick={onTypePlay}
>{playModeIcon[playingMode]}</IconButton> >{playModeIcon[playingMode]}</IconButton>
</Flex> </Flex> */}
</Flex> </Flex>
)} )}

View File

@ -1,11 +1,9 @@
import { ReactElement, useEffect, useState } from 'react'; import { ReactElement, useEffect, useState } from 'react';
import { Box, BoxProps, Flex, FlexProps } from '@chakra-ui/react';
import { Image } from '@chakra-ui/react';
import { DataUrlAccess } from '@/utils/data-url-access'; import { DataUrlAccess } from '@/utils/data-url-access';
import { Icon } from './Icon'; import { Icon } from './Icon';
import { ObjectId } from '@/back-api'; import { ObjectId } from '@/back-api';
import { Flex } from '@/ui';
export type CoversProps = Omit<BoxProps, "iconEmpty"> & { export type CoversProps = Omit<BoxProps, "iconEmpty"> & {
data?: ObjectId[]; data?: ObjectId[];
@ -45,26 +43,28 @@ export const Covers = ({
return <Icon icon={iconEmpty} sizeIcon={size} />; return <Icon icon={iconEmpty} sizeIcon={size} />;
} else { } else {
return ( return (
<Box <Flex
width={size} style={{
height={size} width: size,
minHeight={size} height: size,
minWidth={size} minHeight: size,
borderColor="blue" minWidth: size,
borderWidth="1px" borderColor: "blue",
margin="auto" borderWidth: "1px",
margin: "auto",
}}
{...rest} {...rest}
></Box> ></Flex>
); );
} }
} }
if (slideshow === false || data.length === 1) { if (slideshow === false || data.length === 1) {
const url = DataUrlAccess.getThumbnailUrl(data[0]); const url = DataUrlAccess.getThumbnailUrl(data[0]);
return <Image loading="lazy" src={url} maxWidth={size} boxSize={size} /*{...rest}*/ />; return <></>;//<image loading="lazy" src={url} maxWidth={size} boxSize={size} /*{...rest}*/ />;
} }
const urlCurrent = DataUrlAccess.getThumbnailUrl(data[currentImageIndex]); const urlCurrent = DataUrlAccess.getThumbnailUrl(data[currentImageIndex]);
const urlPrevious = DataUrlAccess.getThumbnailUrl(data[previousImageIndex]); const urlPrevious = DataUrlAccess.getThumbnailUrl(data[previousImageIndex]);
return <Flex return <></>/*<Flex
position="relative" position="relative"
// {...rest} // {...rest}
maxWidth={size} maxWidth={size}
@ -95,5 +95,5 @@ export const Covers = ({
opacity={topOpacity} opacity={topOpacity}
zIndex={2} zIndex={2}
/> />
</Flex> </Flex>*/
}; };

View File

@ -1,13 +1,15 @@
import { Box } from '@chakra-ui/react'; import { Flex } from "@/ui";
export const EmptyEnd = () => { export const EmptyEnd = () => {
return ( return (
<Box <Flex
width="full" style={{
height="25%" width: "full",
minHeight="250px" height: "25%",
minHeight: "250px",
}}
// borderWidth="1px" // borderWidth="1px"
// borderColor="red" // borderColor="red"
></Box> ></Flex>
); );
}; };

View File

@ -1,8 +1,5 @@
import {
Box, import { Flex, FlexProps } from '@/ui';
Flex,
FlexProps,
} from '@chakra-ui/react';
import { forwardRef, ReactNode } from 'react'; import { forwardRef, ReactNode } from 'react';
export type IconProps = FlexProps & { export type IconProps = FlexProps & {
@ -12,26 +9,31 @@ export type IconProps = FlexProps & {
}; };
export const Icon = forwardRef<HTMLDivElement, IconProps>( export const Icon = forwardRef<HTMLDivElement, IconProps>(
({ icon: IconEl, color, sizeIcon = '1em', ...rest }, ref) => { ({ icon: IconEl, color, sizeIcon = '1em', style, ...rest }, ref) => {
return ( return (
<Flex flex="none" <Flex
minWidth={sizeIcon}
minHeight={sizeIcon}
maxWidth={sizeIcon}
maxHeight={sizeIcon}
align="center" align="center"
padding="1px" style={{
ref={ref} flex: "none",
minWidth: sizeIcon,
minHeight: sizeIcon,
maxWidth: sizeIcon,
maxHeight: sizeIcon,
padding: "1px",
...style
}}
{...rest}> {...rest}>
<Box <Flex
marginX="auto" style={{
width="100%" margin: "0 auto 0 auto",
minWidth="100%" width: "100%",
height="100%" minWidth: "100%",
color={color} height: "100%",
color: color,
}}
> >
{IconEl} {IconEl}
</Box> </Flex>
</Flex> </Flex>
); );
} }

View File

@ -1,6 +1,5 @@
import React, { ReactNode, useEffect } from 'react'; import React, { ReactNode, useEffect } from 'react';
import { Flex, Image } from '@chakra-ui/react';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import background from '@/assets/images/ikon.svg'; import background from '@/assets/images/ikon.svg';

View File

@ -1,6 +1,5 @@
import React, { ReactNode, useEffect } from 'react'; import React, { ReactNode, useEffect } from 'react';
import { Flex, FlexProps } from '@chakra-ui/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';

View File

@ -1,9 +1,5 @@
import { useState } from 'react'; import { useState } from 'react';
import {
Group,
Input,
} from '@chakra-ui/react';
import { MdSearch } from 'react-icons/md'; import { MdSearch } from 'react-icons/md';
export type SearchInputProps = { export type SearchInputProps = {

View File

@ -1,13 +1,6 @@
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import {
Box,
Flex,
HStack,
IconButton,
Text,
useDisclosure,
} from '@chakra-ui/react';
import { import {
LuAlignJustify, LuAlignJustify,
LuArrowBigLeft, LuArrowBigLeft,
@ -25,15 +18,10 @@ import { colors } from '@/theme/foundations/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';
import { MenuContent, MenuItem, MenuRoot, MenuTrigger } from '@/components/ui/menu';
import { useColorMode, useColorModeValue } from '@/components/ui/color-mode'; import { useColorMode, useColorModeValue } from '@/components/ui/color-mode';
import { import { THEME } from '@/theme/theme';
DrawerBody, import { useDisclosure } from '@/utils/disclosure';
DrawerContent, import { Button, Flex, Text } from '@/ui';
DrawerHeader,
DrawerRoot,
} from '@/components/ui/drawer';
import { Button } from '../ui/themed';
export const TOP_BAR_HEIGHT = '50px'; export const TOP_BAR_HEIGHT = '50px';
@ -87,22 +75,24 @@ export const TopBar = ({ title, children }: TopBarProps) => {
}; };
return ( return (
<Flex <Flex
position="absolute"
top={0}
left={0}
right={0}
height={TOP_BAR_HEIGHT}
alignItems="center"
justifyContent="space-between"
backgroundColor={backColor}
gap="2" gap="2"
px="2" align="center"
boxShadow={'0px 2px 4px ' + colors.back[900]} justify="space-between"
zIndex={200} style={{
position: "absolute",
top: 0,
left: 0,
right: 0,
height: TOP_BAR_HEIGHT,
backgroundColor: backColor,
padding: "0 2 0 2",
boxShadow: `0px 2px 4px ${colors.back[900]}`,
zIndex: 200,
}}
> >
<Button {...BUTTON_TOP_BAR_PROPERTY} onClick={onChangeTheme}> <Button {...BUTTON_TOP_BAR_PROPERTY} onClick={onChangeTheme}>
<LuAlignJustify /> <LuAlignJustify />
<Text paddingLeft="3px" fontWeight="bold"> <Text style={{ padding: "0 0 0 3px" }} fontWeight="bold">
Karusic Karusic
</Text> </Text>
</Button> </Button>
@ -110,77 +100,79 @@ export const TopBar = ({ title, children }: TopBarProps) => {
<Text <Text
fontSize="20px" fontSize="20px"
fontWeight="bold" fontWeight="bold"
textTransform="uppercase" style={{
marginRight="auto" textTransform: "uppercase",
userSelect="none" marginRight: "auto",
userSelect: "none",
}}
> >
{title} {title}
</Text> </Text>
)} )}
{children} {children}
<Flex right="0"> <Flex style={{ right: 0 }}>
{session?.state !== SessionState.CONNECTED && ( {session?.state !== SessionState.CONNECTED && (
<> <>
<Button {...BUTTON_TOP_BAR_PROPERTY} theme="@primary" onClick={onSignIn}> <Button {...BUTTON_TOP_BAR_PROPERTY} {...THEME.Button.primary} onClick={onSignIn}>
<LuLogIn /> <LuLogIn />
<Text paddingLeft="3px" fontWeight="bold"> <Text style={{ paddingLeft: "0 0 0 3px" }} fontWeight="bold">
Sign-in Sign-in
</Text> </Text>
</Button> </Button>
<Button <Button
{...BUTTON_TOP_BAR_PROPERTY} {...BUTTON_TOP_BAR_PROPERTY}
onClick={onSignUp} onClick={onSignUp}
disabled={true} // disabled={true}
> >
<MdMore /> <MdMore />
<Text paddingLeft="3px" fontWeight="bold"> <Text style={{ padding: "0 0 0 3px" }} fontWeight="bold">
Sign-up Sign-up
</Text> </Text>
</Button> </Button>
</> </>
)} )}
{session?.state === SessionState.CONNECTED && ( {/* {session?.state === SessionState.CONNECTED && (
<MenuRoot> <Menu.Root>
<MenuTrigger asChild> <Menu.Trigger asChild>
<IconButton <IconButton
as={IconButton} as={IconButton}
aria-label="Options" aria-label="Options"
{...BUTTON_TOP_BAR_PROPERTY} {...BUTTON_TOP_BAR_PROPERTY}
width={TOP_BAR_HEIGHT} width={TOP_BAR_HEIGHT}
><MdSupervisedUserCircle /></IconButton> ><MdSupervisedUserCircle /></IconButton>
</MenuTrigger> </Menu.Trigger>
<MenuContent> <Menu.Content>
<MenuItem value="user" valueText="user" _hover={{}} color={useColorModeValue('brand.800', 'brand.200')}> <Menu.Item value="user" valueText="user" _hover={{}} color={useColorModeValue('brand.800', 'brand.200')}>
<MdSupervisedUserCircle /> <MdSupervisedUserCircle />
<Box flex="1">Sign in as {session?.login ?? 'Fail'}</Box> <Box flex="1">Sign in as {session?.login ?? 'Fail'}</Box>
</MenuItem> </Menu.Item>
<MenuItem value="Settings" valueText="Settings" onClick={onSettings}><LuSettings />Settings</MenuItem> <Menu.Item value="Settings" valueText="Settings" onClick={onSettings}><LuSettings />Settings</Menu.Item>
<MenuItem value="Help" valueText="Help" onClick={onHelp}><MdHelp /> Help</MenuItem> <Menu.Item value="Help" valueText="Help" onClick={onHelp}><MdHelp /> Help</Menu.Item>
<MenuItem value="Sign-out" valueText="Sign-out" onClick={onSignOut}> <Menu.Item value="Sign-out" valueText="Sign-out" onClick={onSignOut}>
<LuLogOut /> Sign-out <LuLogOut /> Sign-out
</MenuItem> </Menu.Item>
{colorMode === 'light' ? ( {colorMode === 'light' ? (
<MenuItem value="set-dark" valueText="set-dark" onClick={toggleColorMode}> <Menu.Item value="set-dark" valueText="set-dark" onClick={toggleColorMode}>
<LuMoon /> Set dark mode <LuMoon /> Set dark mode
</MenuItem> </Menu.Item>
) : ( ) : (
<MenuItem value="set-light" valueText="set-light" onClick={toggleColorMode}> <Menu.Item value="set-light" valueText="set-light" onClick={toggleColorMode}>
<LuSun /> Set light mode <LuSun /> Set light mode
</MenuItem> </Menu.Item>
)} )}
</MenuContent> </Menu.Content>
</MenuRoot> </Menu.Root>
)} )} */}
</Flex> </Flex>
<DrawerRoot {/* <Drawer.Root
placement="start" placement="start"
onOpenChange={drawerDisclose.onClose} onOpenChange={drawerDisclose.onClose}
open={drawerDisclose.open} open={drawerDisclose.open}
data-testid="top-bar_drawer-root" data-testid="top-bar_drawer-root"
> >
<DrawerContent <Drawer.Content
data-testid="top-bar_drawer-content"> data-test-id="top-bar_drawer-content">
<DrawerHeader <Drawer.Header
paddingY="auto" paddingY="auto"
as="button" as="button"
onClick={drawerDisclose.onClose} onClick={drawerDisclose.onClose}
@ -195,8 +187,8 @@ export const TopBar = ({ title, children }: TopBarProps) => {
Karusic Karusic
</Text> </Text>
</HStack> </HStack>
</DrawerHeader> </Drawer.Header>
<DrawerBody paddingX="0px"> <Drawer.Body paddingX="0px">
<Button <Button
background="#00000000" background="#00000000"
borderRadius="0px" borderRadius="0px"
@ -232,9 +224,9 @@ export const TopBar = ({ title, children }: TopBarProps) => {
Add Media Add Media
</Text> </Text>
</Button> </Button>
</DrawerBody> </Drawer.Body>
</DrawerContent> </Drawer.Content>
</DrawerRoot> </Drawer.Root> */}
</Flex> </Flex>
); );
}; };

View File

@ -1,4 +1,4 @@
import { Flex, Text } from '@chakra-ui/react';
import { LuDisc3 } from 'react-icons/lu'; import { LuDisc3 } from 'react-icons/lu';
import { Album } from '@/back-api'; import { Album } from '@/back-api';

View File

@ -1,12 +1,6 @@
import { useState } from 'react';
import {
IconButton,
} from '@chakra-ui/react';
import { LuMenu } from 'react-icons/lu'; import { LuMenu } from 'react-icons/lu';
import { MenuContent, MenuItem, MenuRoot, MenuTrigger } from '../ui/menu'; import { THEME } from '@/theme/theme';
import { Button } from '../ui/themed';
import { customVariant } from '@/theme/recipes/button';
export type MenuElement = { export type MenuElement = {
name: string; name: string;
@ -17,44 +11,29 @@ export type ContextMenuProps = {
elements?: MenuElement[]; elements?: MenuElement[];
}; };
const theme = {
plop: {
bg: { _light: 'red', _dark: 'brand.300', _pink: "orange" },
_hover: { bg: { _light: 'green', _dark: 'brand.400', _pink: "black" } },
// bg: { _light: 'brand.600', _dark: 'brand.300' },
// _hover: { bg: { _light: 'brand.700', _dark: 'brand.400' } },
/*
bgActive: { _light: 'brand.600', _dark: 'brand.300' },
color: { _light: 'white', _dark: 'brand.900' },
colorHover: { _light: 'brand.800', _dark: 'brand.100' },
boxShadowHover: 'outline-over'
*/
}
};
export const ContextMenu = ({ elements }: ContextMenuProps) => { export const ContextMenu = ({ elements }: ContextMenuProps) => {
if (!elements) { if (!elements) {
return <></>; return <></>;
} }
return ( return (
<MenuRoot <Menu.Root
data-testid="context-menu"> data-testid="context-menu">
<MenuTrigger asChild <Menu.Trigger asChild
data-testid="context-menu_trigger"> data-testid="context-menu_trigger">
{/* This is very stupid, we need to set as span to prevent a button in button... WTF */} {/* This is very stupid, we need to set as span to prevent a button in button... WTF */}
<Button {...theme.plop} /*theme="@primary"*/> <Button {...THEME.Button.primary} >
<LuMenu /> <LuMenu />
</Button> </Button>
</MenuTrigger> </Menu.Trigger>
<MenuContent <Menu.Content
data-testid="context-menu_content"> data-testid="context-menu_content">
{elements?.map((data) => ( {elements?.map((data) => (
<MenuItem key={data.name} value={data.name} onClick={data.onClick} <Menu.Item key={data.name} value={data.name} onClick={data.onClick}
data-testid="context-menu_item"> data-testid="context-menu_item">
{data.name} {data.name}
</MenuItem> </Menu.Item>
))} ))}
</MenuContent> </Menu.Content>
</MenuRoot > </Menu.Root >
); );
}; };

View File

@ -3,14 +3,7 @@ import {
RefObject, RefObject,
} from 'react'; } from 'react';
import {
Box,
BoxProps,
Center,
Flex,
HStack,
Image,
} from '@chakra-ui/react';
import { import {
MdHighlightOff, MdHighlightOff,
MdUploadFile, MdUploadFile,
@ -19,6 +12,7 @@ import {
import { FormGroup } from '@/components/form/FormGroup'; import { FormGroup } from '@/components/form/FormGroup';
import { UseFormidableReturn } from '@/components/form/Formidable'; import { UseFormidableReturn } from '@/components/form/Formidable';
import { DataUrlAccess } from '@/utils/data-url-access'; import { DataUrlAccess } from '@/utils/data-url-access';
import { Flex, FlexProps } from '@/ui';
export type DragNdropProps = { export type DragNdropProps = {
onFilesSelected?: (file: File[]) => void; onFilesSelected?: (file: File[]) => void;
@ -58,40 +52,42 @@ export const DragNdrop = ({
onUriSelected(listUri); onUriSelected(listUri);
} }
}; };
return <></>;
return ( /*
<Box return (
width={width} <Box
height={height} width={width}
border="2px" height={height}
borderRadius="5px" border="2px"
borderStyle="dashed" borderRadius="5px"
onDrop={handleDrop} borderStyle="dashed"
onDragOver={(event) => event.preventDefault()} onDrop={handleDrop}
> onDragOver={(event) => event.preventDefault()}
<label htmlFor="browse"> >
<Box paddingY="15%" height="100%" cursor="pointer"> <label htmlFor="browse">
<Center> <Box paddingY="15%" height="100%" cursor="pointer">
<MdUploadFile size="50%" /> <Center>
</Center> <MdUploadFile size="50%" />
<Center> </Center>
<input <Center>
type="file" <input
hidden type="file"
id="browse" hidden
onChange={handleFileChange} id="browse"
//accept=".pdf,.docx,.pptx,.txt,.xlsx" onChange={handleFileChange}
multiple //accept=".pdf,.docx,.pptx,.txt,.xlsx"
/> multiple
Browse files />
</Center> Browse files
</Box> </Center>
</label> </Box>
</Box> </label>
); </Box>
);
*/
}; };
export type CenterIconProps = BoxProps & { export type CenterIconProps = FlexProps & {
icon: any; icon: any;
sizeIcon?: string; sizeIcon?: string;
}; };
@ -99,11 +95,13 @@ export type CenterIconProps = BoxProps & {
export const CenterIcon = ({ export const CenterIcon = ({
icon: IconEl, icon: IconEl,
sizeIcon = '15px', sizeIcon = '15px',
style,
...rest ...rest
}: CenterIconProps) => { }: CenterIconProps) => {
return ( return (
<Box position="relative" w={sizeIcon} h={sizeIcon} flex="none" {...rest}> <Flex style={{ position: "relative", width: sizeIcon, height: sizeIcon, flex: "none", ...style }}
<Box {...rest}>
{/*<Flex
as={IconEl} as={IconEl}
w={sizeIcon} w={sizeIcon}
h={sizeIcon} h={sizeIcon}
@ -111,8 +109,8 @@ export const CenterIcon = ({
top="50%" top="50%"
left="50%" left="50%"
transform="translate(-50%, -50%)" transform="translate(-50%, -50%)"
/> />*/}
</Box> </Flex>
); );
}; };
@ -143,8 +141,8 @@ export const FormCovers = ({
isModify={form.isModify[variableName]} isModify={form.isModify[variableName]}
onRestore={() => form.restoreValue({ [variableName]: true })} onRestore={() => form.restoreValue({ [variableName]: true })}
{...rest} {...rest}
> > <></>
<HStack wrap="wrap" width="full"> {/* <HStack wrap="wrap" width="full">
{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">
@ -171,7 +169,7 @@ export const FormCovers = ({
onUriSelected={onUriSelected} onUriSelected={onUriSelected}
/> />
</Flex> </Flex>
</HStack> </HStack> */}
</FormGroup> </FormGroup>
); );
}; };

View File

@ -1,6 +1,5 @@
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import { Flex, Text } from '@chakra-ui/react';
import { MdErrorOutline, MdHelpOutline, MdRefresh } from 'react-icons/md'; import { MdErrorOutline, MdHelpOutline, MdRefresh } from 'react-icons/md';
export type FormGroupProps = { export type FormGroupProps = {

View File

@ -1,7 +1,5 @@
import { RefObject } from 'react'; import { RefObject } from 'react';
import { Input } from '@chakra-ui/react';
import { FormGroup } from '@/components/form/FormGroup'; import { FormGroup } from '@/components/form/FormGroup';
import { UseFormidableReturn } from '@/components/form/Formidable'; import { UseFormidableReturn } from '@/components/form/Formidable';

View File

@ -1,8 +1,5 @@
import { RefObject } from 'react'; import { RefObject } from 'react';
import {
NumberInput,
} from '@chakra-ui/react';
import { FormGroup } from '@/components/form/FormGroup'; import { FormGroup } from '@/components/form/FormGroup';
import { UseFormidableReturn } from '@/components/form/Formidable'; import { UseFormidableReturn } from '@/components/form/Formidable';

View File

@ -1,9 +1,9 @@
import { useState } from 'react'; import { useState } from 'react';
import { Box } from '@chakra-ui/react';
import { FormSelect } from '@/components/form/FormSelect'; import { FormSelect } from '@/components/form/FormSelect';
import { useFormidable } from '@/components/form/Formidable'; import { useFormidable } from '@/components/form/Formidable';
import { Flex } from '@/ui';
export default { export default {
title: 'Components/FormSelect', title: 'Components/FormSelect',
@ -94,7 +94,7 @@ export const DarkBackground = {
render: () => { render: () => {
const form = useFormidable<BasicFormData>({}); const form = useFormidable<BasicFormData>({});
return ( return (
<Box p="4" color="white" bg="gray.800"> <Flex style={{ padding: "4", color: "white", background: "gray.800" }}>
<FormSelect <FormSelect
label="Simple Title for (DarkBackground)" label="Simple Title for (DarkBackground)"
form={form} form={form}
@ -105,7 +105,7 @@ export const DarkBackground = {
{ id: 333, name: 'third item' }, { id: 333, name: 'third item' },
]} ]}
/> />
</Box> </Flex>
); );
}, },

View File

@ -1,6 +1,5 @@
import { RefObject } from 'react'; import { RefObject } from 'react';
import { Text } from '@chakra-ui/react';
import { FormGroup } from '@/components/form/FormGroup'; import { FormGroup } from '@/components/form/FormGroup';
import { UseFormidableReturn } from '@/components/form/Formidable'; import { UseFormidableReturn } from '@/components/form/Formidable';

View File

@ -1,9 +1,9 @@
import { useState } from 'react'; import { useState } from 'react';
import { Box } from '@chakra-ui/react';
import { FormSelectMultiple } from '@/components/form/FormSelectMultiple'; import { FormSelectMultiple } from '@/components/form/FormSelectMultiple';
import { useFormidable } from '@/components/form/Formidable'; import { useFormidable } from '@/components/form/Formidable';
import { Flex } from '@/ui';
export default { export default {
title: 'Components/FormSelectMultipleMultiple', title: 'Components/FormSelectMultipleMultiple',
@ -94,7 +94,7 @@ export const DarkBackground = {
render: () => { render: () => {
const form = useFormidable<BasicFormData>({}); const form = useFormidable<BasicFormData>({});
return ( return (
<Box p="4" color="white" bg="gray.800"> <Flex style={{ padding: "4", color: "white", background: "gray.800" }}>
<FormSelectMultiple <FormSelectMultiple
label="Simple Title for (DarkBackground)" label="Simple Title for (DarkBackground)"
form={form} form={form}
@ -105,7 +105,7 @@ export const DarkBackground = {
{ id: 333, name: 'third item' }, { id: 333, name: 'third item' },
]} ]}
/> />
</Box> </Flex>
); );
}, },

View File

@ -1,6 +1,5 @@
import { RefObject } from 'react'; import { RefObject } from 'react';
import { Textarea } from '@chakra-ui/react';
import { FormGroup } from '@/components/form/FormGroup'; import { FormGroup } from '@/components/form/FormGroup';
import { UseFormidableReturn } from '@/components/form/Formidable'; import { UseFormidableReturn } from '@/components/form/Formidable';

View File

@ -1,4 +1,4 @@
import { Flex, Text } from '@chakra-ui/react';
import { LuDisc3 } from 'react-icons/lu'; import { LuDisc3 } from 'react-icons/lu';
import { Gender } from '@/back-api'; import { Gender } from '@/back-api';

View File

@ -1,10 +1,5 @@
import { useRef, useState } from 'react'; import { useRef, useState } from 'react';
import {
Flex,
Text,
useDisclosure,
} from '@chakra-ui/react';
import { import {
MdAdminPanelSettings, MdAdminPanelSettings,
MdDeleteForever, MdDeleteForever,
@ -24,8 +19,7 @@ import { useAlbumService, useSpecificAlbum } from '@/service/Album';
import { useServiceContext } from '@/service/ServiceContext'; import { useServiceContext } from '@/service/ServiceContext';
import { useCountTracksWithAlbumId } from '@/service/Track'; import { useCountTracksWithAlbumId } from '@/service/Track';
import { isNullOrUndefined } from '@/utils/validator'; import { isNullOrUndefined } from '@/utils/validator';
import { DialogBody, DialogContent, DialogFooter, DialogHeader, DialogRoot } from '@/components/ui/dialog'; import { useDisclosure } from '@/utils/disclosure';
import { Button } from '../ui/themed';
export type AlbumEditPopUpProps = {}; export type AlbumEditPopUpProps = {};
@ -135,7 +129,7 @@ export const AlbumEditPopUp = ({ }: AlbumEditPopUpProps) => {
); );
}; };
return ( return (
<DialogRoot <Dialog.Root
//initialFocusRef={initialRef} //initialFocusRef={initialRef}
//finalFocusRef={finalRef} //finalFocusRef={finalRef}
//closeOnOverlayClick={false} //closeOnOverlayClick={false}
@ -145,11 +139,11 @@ export const AlbumEditPopUp = ({ }: AlbumEditPopUpProps) => {
> >
{/* <DialogOverlay /> */} {/* <DialogOverlay /> */}
{/* <DialogCloseTrigger /> */} {/* <DialogCloseTrigger /> */}
<DialogContent> <Dialog.Content>
<DialogHeader>Edit Album</DialogHeader> <Dialog.Header>Edit Album</Dialog.Header>
{/* <DialogCloseButton ref={finalRef} /> */} {/* <DialogCloseButton ref={finalRef} /> */}
<DialogBody pb={6} gap="0px" paddingLeft="18px"> <Dialog.Body pb={6} gap="0px" paddingLeft="18px">
{admin && ( {admin && (
<> <>
<FormGroup isRequired label="Id"> <FormGroup isRequired label="Id">
@ -211,8 +205,8 @@ export const AlbumEditPopUp = ({ }: AlbumEditPopUpProps) => {
/> />
</> </>
)} )}
</DialogBody> </Dialog.Body>
<DialogFooter> <Dialog.Footer>
<Button <Button
onClick={() => setAdmin((value) => !value)} onClick={() => setAdmin((value) => !value)}
marginRight="auto" marginRight="auto"
@ -235,8 +229,8 @@ export const AlbumEditPopUp = ({ }: AlbumEditPopUpProps) => {
</Button> </Button>
)} )}
<Button onClick={onClose}>Cancel</Button> <Button onClick={onClose}>Cancel</Button>
</DialogFooter> </Dialog.Footer>
</DialogContent> </Dialog.Content>
</DialogRoot> </Dialog.Root>
); );
}; };

View File

@ -1,11 +1,6 @@
import { useRef, useState } from 'react'; import { useRef, useState } from 'react';
import {
Flex,
Text,
useDisclosure,
} from '@chakra-ui/react';
import { DialogBody, DialogContent, DialogFooter, DialogHeader, DialogRoot } from '@/components/ui/dialog';
import { import {
MdAdminPanelSettings, MdAdminPanelSettings,
MdDeleteForever, MdDeleteForever,
@ -25,7 +20,7 @@ import { useArtistService, useSpecificArtist } from '@/service/Artist';
import { useServiceContext } from '@/service/ServiceContext'; import { useServiceContext } from '@/service/ServiceContext';
import { useCountTracksOfAnArtist } from '@/service/Track'; import { useCountTracksOfAnArtist } from '@/service/Track';
import { isNullOrUndefined } from '@/utils/validator'; import { isNullOrUndefined } from '@/utils/validator';
import { Button } from '../ui/themed'; import { useDisclosure } from '@/utils/disclosure';
export type ArtistEditPopUpProps = {}; export type ArtistEditPopUpProps = {};
@ -134,110 +129,110 @@ export const ArtistEditPopUp = ({ }: ArtistEditPopUpProps) => {
); );
}; };
return ( return (
<DialogRoot // <Dialog.Root
//initialFocusRef={initialRef} // //initialFocusRef={initialRef}
//finalFocusRef={finalRef} // //finalFocusRef={finalRef}
//closeOnOverlayClick={false} // //closeOnOverlayClick={false}
onOpenChange={onClose} // onOpenChange={onClose}
open={true} // open={true}
data-testid="artist-edit-pop-up" // data-testid="artist-edit-pop-up"
> // >
{/* <DialogOverlay /> */} // {/* <DialogOverlay /> */}
<DialogContent> // <Dialog.Content>
<DialogHeader>Edit Artist</DialogHeader> // <Dialog.Header>Edit Artist</Dialog.Header>
{/* <DialogCloseButton ref={finalRef} /> */} // {/* <DialogCloseButton ref={finalRef} /> */}
<DialogBody pb={6} gap="0px" paddingLeft="18px"> // <Dialog.Body pb={6} gap="0px" paddingLeft="18px">
{admin && ( // {admin && (
<> // <>
<FormGroup isRequired label="Id"> // <FormGroup isRequired label="Id">
<Text>{dataArtist?.id}</Text> // <Text>{dataArtist?.id}</Text>
</FormGroup> // </FormGroup>
{countTracksOnAnArtist !== 0 && ( // {countTracksOnAnArtist !== 0 && (
<Flex paddingLeft="14px"> // <Flex paddingLeft="14px">
<MdWarning color="red.600" /> // <MdWarning color="red.600" />
<Text paddingLeft="6px" color="red.600" fontWeight="bold"> // <Text paddingLeft="6px" color="red.600" fontWeight="bold">
Can not remove artist {countTracksOnAnArtist} track(s) // Can not remove artist {countTracksOnAnArtist} track(s)
depend on it. // depend on it.
</Text> // </Text>
</Flex> // </Flex>
)} // )}
<FormGroup label="Action(s):"> // <FormGroup label="Action(s):">
<Button // <Button
onClick={disclosure.onOpen} // onClick={disclosure.onOpen}
marginRight="auto" // marginRight="auto"
theme="@danger" // theme="@danger"
disabled={countTracksOnAnArtist !== 0} // disabled={countTracksOnAnArtist !== 0}
> // >
<MdDeleteForever /> Remove Media // <MdDeleteForever /> Remove Media
</Button> // </Button>
</FormGroup> // </FormGroup>
<ConfirmPopUp // <ConfirmPopUp
disclosure={disclosure} // disclosure={disclosure}
title="Remove artist" // title="Remove artist"
body={`Remove Artist [${dataArtist?.id}] ${dataArtist?.name}`} // body={`Remove Artist [${dataArtist?.id}] ${dataArtist?.name}`}
confirmTitle="Remove" // confirmTitle="Remove"
onConfirm={onRemove} // onConfirm={onRemove}
/> // />
</> // </>
)} // )}
{!admin && ( // {!admin && (
<> // <>
<FormInput // <FormInput
form={form} // form={form}
variableName="name" // variableName="name"
isRequired // isRequired
label="Artist name" // label="Artist name"
ref={initialRef} // ref={initialRef}
/> // />
<FormTextarea // <FormTextarea
form={form} // form={form}
variableName="description" // variableName="description"
label="Description" // label="Description"
/> // />
<FormInput // <FormInput
form={form} // form={form}
variableName="firstName" // variableName="firstName"
label="First Name" // label="First Name"
/> // />
<FormInput form={form} variableName="surname" label="SurName" /> // <FormInput form={form} variableName="surname" label="SurName" />
<FormInput form={form} variableName="birth" label="Birth date" /> // <FormInput form={form} variableName="birth" label="Birth date" />
<FormInput form={form} variableName="death" label="Death date" /> // <FormInput form={form} variableName="death" label="Death date" />
<FormCovers // <FormCovers
form={form} // form={form}
variableName="covers" // variableName="covers"
onFilesSelected={onFilesSelected} // onFilesSelected={onFilesSelected}
onUriSelected={onUriSelected} // onUriSelected={onUriSelected}
onRemove={onRemoveCover} // onRemove={onRemoveCover}
/> // />
</> // </>
)} // )}
</DialogBody> // </Dialog.Body>
<DialogFooter> // <Dialog.Footer>
<Button // <Button
onClick={() => setAdmin((value) => !value)} // onClick={() => setAdmin((value) => !value)}
marginRight="auto" // marginRight="auto"
> // >
{admin ? ( // {admin ? (
<> // <>
<MdEdit /> // <MdEdit />
Edit // Edit
</> // </>
) : ( // ) : (
<> // <>
<MdAdminPanelSettings /> // <MdAdminPanelSettings />
Admin // Admin
</> // </>
)} // )}
</Button> // </Button>
{!admin && form.isFormModified && ( // {!admin && form.isFormModified && (
<Button colorScheme="blue" mr={3} onClick={onSave}> // <Button colorScheme="blue" mr={3} onClick={onSave}>
Save // Save
</Button> // </Button>
)} // )}
<Button onClick={onClose}>Cancel</Button> // <Button onClick={onClose}>Cancel</Button>
</DialogFooter> // </Dialog.Footer>
</DialogContent> // </Dialog.Content>
</DialogRoot> // </Dialog.Root>
); <></>);
}; };

View File

@ -1,11 +1,8 @@
import { UseDisclosureReturn } from '@/utils/disclosure';
import { useRef } from 'react'; import { useRef } from 'react';
import {
Button,
UseDisclosureReturn,
} from '@chakra-ui/react';
import { DialogBody, DialogContent, DialogFooter, DialogHeader, DialogRoot } from '@/components/ui/dialog';
export type ConfirmPopUpProps = { export type ConfirmPopUpProps = {
title: string; title: string;
body: string; body: string;
@ -27,28 +24,28 @@ export const ConfirmPopUp = ({
}; };
const cancelRef = useRef<HTMLButtonElement>(null); const cancelRef = useRef<HTMLButtonElement>(null);
return ( return (
<DialogRoot role="alertdialog" <Dialog.Root role="alertdialog"
open={disclosure.open} open={disclosure.open}
//leastDestructiveRef={cancelRef} //leastDestructiveRef={cancelRef}
onOpenChange={disclosure.onClose} onOpenChange={disclosure.onClose}
data-testid="confirm-pop-up" data-testid="confirm-pop-up"
> >
<DialogContent> <Dialog.Content>
<DialogHeader fontSize="lg" fontWeight="bold"> <Dialog.Header fontSize="lg" fontWeight="bold">
{title} {title}
</DialogHeader> </Dialog.Header>
<DialogBody>{body}</DialogBody> <Dialog.Body>{body}</Dialog.Body>
<DialogFooter> <Dialog.Footer>
<Button onClick={disclosure.onClose} ref={cancelRef}> <Button onClick={disclosure.onClose} ref={cancelRef}>
Cancel Cancel
</Button> </Button>
<Button colorScheme="red" onClick={onClickConfirm} ml={3}> <Button colorScheme="red" onClick={onClickConfirm} ml={3}>
{confirmTitle} {confirmTitle}
</Button> </Button>
</DialogFooter> </Dialog.Footer>
</DialogContent> </Dialog.Content>
</DialogRoot> </Dialog.Root>
); );
}; };

View File

@ -1,10 +1,6 @@
import { useRef, useState } from 'react'; import { useRef, useState } from 'react';
import {
Flex,
Text,
useDisclosure,
} from '@chakra-ui/react';
import { import {
MdAdminPanelSettings, MdAdminPanelSettings,
MdDeleteForever, MdDeleteForever,
@ -12,7 +8,6 @@ import {
MdWarning, MdWarning,
} from 'react-icons/md'; } from 'react-icons/md';
import { DialogBody, DialogContent, DialogFooter, DialogHeader, DialogRoot } from '@/components/ui/dialog';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
import { Gender, GenderResource } from '@/back-api'; import { Gender, GenderResource } from '@/back-api';
@ -26,7 +21,7 @@ import { useGenderService, useSpecificGender } from '@/service/Gender';
import { useServiceContext } from '@/service/ServiceContext'; import { useServiceContext } from '@/service/ServiceContext';
import { useCountTracksOfAGender } from '@/service/Track'; import { useCountTracksOfAGender } from '@/service/Track';
import { isNullOrUndefined } from '@/utils/validator'; import { isNullOrUndefined } from '@/utils/validator';
import { Button } from '../ui/themed'; import { useDisclosure } from '@/utils/disclosure';
export type GenderEditPopUpProps = {}; export type GenderEditPopUpProps = {};
@ -134,7 +129,7 @@ export const GenderEditPopUp = ({ }: GenderEditPopUpProps) => {
); );
}; };
return ( return (
<DialogRoot <Dialog.Root
//initialFocusRef={initialRef} //initialFocusRef={initialRef}
//finalFocusRef={finalRef} //finalFocusRef={finalRef}
//closeOnOverlayClick={false} //closeOnOverlayClick={false}
@ -143,11 +138,11 @@ export const GenderEditPopUp = ({ }: GenderEditPopUpProps) => {
data-testid="gender-edit-pop-up" data-testid="gender-edit-pop-up"
> >
{/* <DialogOverlay /> */} {/* <DialogOverlay /> */}
<DialogContent> <Dialog.Content>
<DialogHeader>Edit Gender</DialogHeader> <Dialog.Header>Edit Gender</Dialog.Header>
{/* <DialogCloseButton ref={finalRef} /> */} {/* <DialogCloseButton ref={finalRef} /> */}
<DialogBody pb={6} gap="0px" paddingLeft="18px"> <Dialog.Body pb={6} gap="0px" paddingLeft="18px">
{admin && ( {admin && (
<> <>
<FormGroup isRequired label="Id"> <FormGroup isRequired label="Id">
@ -204,8 +199,8 @@ export const GenderEditPopUp = ({ }: GenderEditPopUpProps) => {
/> />
</> </>
)} )}
</DialogBody> </Dialog.Body>
<DialogFooter> <Dialog.Footer>
<Button <Button
onClick={() => setAdmin((value) => !value)} onClick={() => setAdmin((value) => !value)}
marginRight="auto" marginRight="auto"
@ -228,8 +223,8 @@ export const GenderEditPopUp = ({ }: GenderEditPopUpProps) => {
</Button> </Button>
)} )}
<Button onClick={onClose}>Cancel</Button> <Button onClick={onClose}>Cancel</Button>
</DialogFooter> </Dialog.Footer>
</DialogContent> </Dialog.Content>
</DialogRoot> </Dialog.Root>
); );
}; };

View File

@ -1,13 +1,5 @@
import { useRef } from 'react'; import { useRef } from 'react';
import {
Flex,
Progress,
Text,
} from '@chakra-ui/react';
import { DialogBody, DialogContent, DialogFooter, DialogHeader, DialogRoot } from '@/components/ui/dialog';
import { Button } from '../ui/themed';
export type PopUpUploadProgressProps = { export type PopUpUploadProgressProps = {
title: string; title: string;
@ -41,7 +33,7 @@ export const PopUpUploadProgress = ({
const initialRef = useRef<HTMLButtonElement>(null); const initialRef = useRef<HTMLButtonElement>(null);
const finalRef = useRef<HTMLButtonElement>(null); const finalRef = useRef<HTMLButtonElement>(null);
return ( return (
<DialogRoot <Dialog.Root
//initialFocusRef={initialRef} //initialFocusRef={initialRef}
//finalFocusRef={finalRef} //finalFocusRef={finalRef}
//closeOnOverlayClick={false} //closeOnOverlayClick={false}
@ -50,11 +42,11 @@ export const PopUpUploadProgress = ({
data-testid="upload-progress-edit-pop-up" data-testid="upload-progress-edit-pop-up"
> >
{/* <DialogOverlay /> */} {/* <DialogOverlay /> */}
<DialogContent> <Dialog.Content>
<DialogHeader>{title}</DialogHeader> <Dialog.Header>{title}</Dialog.Header>
{/* <DialogCloseButton ref={finalRef} /> */} {/* <DialogCloseButton ref={finalRef} /> */}
<DialogBody pb={6} paddingLeft="18px"> <Dialog.Body pb={6} paddingLeft="18px">
<Flex direction="column" gap="10px"> <Flex direction="column" gap="10px">
{isFinished ? ( {isFinished ? (
<Text fontSize="20px" fontWeight="bold"> <Text fontSize="20px" fontWeight="bold">
@ -85,8 +77,8 @@ export const PopUpUploadProgress = ({
</Text> </Text>
)} )}
</Flex> </Flex>
</DialogBody> </Dialog.Body>
<DialogFooter> <Dialog.Footer>
{isFinished ? ( {isFinished ? (
<Button onClick={onClose} theme="@success"> <Button onClick={onClose} theme="@success">
Ok Ok
@ -96,8 +88,8 @@ export const PopUpUploadProgress = ({
Abort Abort
</Button> </Button>
)} )}
</DialogFooter> </Dialog.Footer>
</DialogContent> </Dialog.Content>
</DialogRoot> </Dialog.Root>
); );
}; };

View File

@ -1,11 +1,5 @@
import { useRef, useState } from 'react'; import { useRef, useState } from 'react';
import {
Text,
useDisclosure,
} from '@chakra-ui/react';
import { DialogBody, DialogContent, DialogFooter, DialogHeader, DialogRoot } from '@/components/ui/dialog';
import { MdAdminPanelSettings, MdDeleteForever, MdEdit } from 'react-icons/md'; import { MdAdminPanelSettings, MdDeleteForever, MdEdit } from 'react-icons/md';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
@ -25,7 +19,7 @@ import { useOrderedGenders } from '@/service/Gender';
import { useServiceContext } from '@/service/ServiceContext'; import { useServiceContext } from '@/service/ServiceContext';
import { useSpecificTrack, useTrackService } from '@/service/Track'; import { useSpecificTrack, useTrackService } from '@/service/Track';
import { isNullOrUndefined } from '@/utils/validator'; import { isNullOrUndefined } from '@/utils/validator';
import { Button } from '../ui/themed'; import { useDisclosure } from '@/utils/disclosure';
export type TrackEditPopUpProps = {}; export type TrackEditPopUpProps = {};
@ -87,7 +81,7 @@ export const TrackEditPopUp = ({ }: TrackEditPopUpProps) => {
); );
}; };
return ( return (
<DialogRoot <Dialog.Root
//initialFocusRef={initialRef} //initialFocusRef={initialRef}
//finalFocusRef={finalRef} //finalFocusRef={finalRef}
//closeOnOverlayClick={false} //closeOnOverlayClick={false}
@ -96,11 +90,11 @@ export const TrackEditPopUp = ({ }: TrackEditPopUpProps) => {
data-testid="track-edit-pop-up" data-testid="track-edit-pop-up"
> >
{/* <DialogOverlay /> */} {/* <DialogOverlay /> */}
<DialogContent> <Dialog.Content>
<DialogHeader>Edit Track</DialogHeader> <Dialog.Header>Edit Track</Dialog.Header>
{/* <DialogCloseButton ref={finalRef} /> */} {/* <DialogCloseButton ref={finalRef} /> */}
<DialogBody pb={6} gap="0px" paddingLeft="18px"> <Dialog.Body pb={6} gap="0px" paddingLeft="18px">
{admin && ( {admin && (
<> <>
<FormGroup isRequired label="Id"> <FormGroup isRequired label="Id">
@ -170,8 +164,8 @@ export const TrackEditPopUp = ({ }: TrackEditPopUpProps) => {
/> />
</> </>
)} )}
</DialogBody> </Dialog.Body>
<DialogFooter> <Dialog.Footer>
<Button <Button
onClick={() => setAdmin((value) => !value)} onClick={() => setAdmin((value) => !value)}
marginRight="auto" marginRight="auto"
@ -194,8 +188,8 @@ export const TrackEditPopUp = ({ }: TrackEditPopUpProps) => {
</Button> </Button>
)} )}
<Button onClick={onClose}>Cancel</Button> <Button onClick={onClose}>Cancel</Button>
</DialogFooter> </Dialog.Footer>
</DialogContent> </Dialog.Content>
</DialogRoot> </Dialog.Root>
); );
}; };

View File

@ -1,9 +1,9 @@
import { useEffect, useRef } from 'react'; import { useEffect, useRef } from 'react';
import { Box, Button, Flex, Text } from '@chakra-ui/react';
import { MdAdd } from 'react-icons/md'; import { MdAdd } from 'react-icons/md';
import { isNullOrUndefined, isNumber } from '@/utils/validator'; import { isNullOrUndefined, isNumber } from '@/utils/validator';
import { Button, Flex, Text } from '@/ui';
export type SelectListModel = { export type SelectListModel = {
id: any; id: any;
@ -65,56 +65,65 @@ export const SelectList = ({
} }
}, []); }, []);
return ( return (
<Box position="relative"> <Flex style={{ position: "relative" }}>
<Flex <Flex
direction="column" direction="column"
width="full" style={{
position="absolute" width: "full",
border="1px" position: "absolute",
borderColor="black" border: "1px",
backgroundColor="gray.700" borderColor: "black",
overflowY="auto" backgroundColor: "gray.700",
overflowX="hidden" overflowY: "auto",
maxHeight="300px" overflowX: "hidden",
zIndex={300} maxHeight: "300px",
transform="translateY(1px)" zIndex: 300,
transform: "translateY(1px)",
}}
> >
{displayedValue.length === 0 && ( {displayedValue.length === 0 && (
<Text marginX="auto" color="red.500" fontWeight="bold" marginY="10px"> <Text fontWeight="bold" color="red.500" style={{ margin: "0 auto" }}>
... No element found... ... No element found...
</Text> </Text>
)} )}
{displayedValue.map((data) => ( {displayedValue.map((data) => (
<Button <Button
key={data.id} key={data.id}
marginY="1px" style={{
borderRadius="0px" margin: "1px 0",
autoFocus={false} borderRadius: "0px",
backgroundColor={data.isSelected ? 'green.800' : '0x00000000'} //autoFocus: false,
_hover={{ backgroundColor: 'gray.400' }} backgroundColor: data.isSelected ? 'green.800' : '0x00000000',
//_hover={ backgroundColor: 'gray.400' },
}}
onClick={() => onSelectValue(data)} onClick={() => onSelectValue(data)}
ref={data.isSelected ? scrollToRef : undefined} //ref={data.isSelected ? scrollToRef : undefined}
> >
<Text marginRight="auto" autoFocus={false}> <Text style={{ margin: "0 auto", }} /*autoFocus={false}*/>
{data.name} {data.name}
</Text> </Text>
</Button> </Button>
))} ))}
{onCreate && search && search.length > 0 && ( {onCreate && search && search.length > 0 && (
<Button <Button
marginY="1px" style={{
borderRadius="0px" margin: "1px 0",
autoFocus={false} borderRadius: "0px",
_hover={{ backgroundColor: 'gray.400' }} //autoFocus:false,
//_hover={ backgroundColor: 'gray.400' }
}}
onClick={() => onCreate(search)} onClick={() => onCreate(search)}
> >
<Flex marginRight="auto"> <Flex
style={{
margin: "0 auto",
}}>
<MdAdd /> <MdAdd />
<Text autoFocus={false}>Create '{search}'</Text> <Text /*autoFocus={false}*/>Create '{search}'</Text>
</Flex> </Flex>
</Button> </Button>
)} )}
</Flex> </Flex>
</Box> </Flex>
); );
}; };

View File

@ -1,14 +1,5 @@
import { RefObject, useEffect, useMemo, useRef, useState } from 'react'; import { RefObject, useEffect, useMemo, useRef, useState } from 'react';
import {
Button,
Flex,
HStack,
Input,
Spinner,
Tag,
TagLabel,
} from '@chakra-ui/react';
import { MdEdit, MdKeyboardArrowDown, MdKeyboardArrowUp } from 'react-icons/md'; import { MdEdit, MdKeyboardArrowDown, MdKeyboardArrowUp } from 'react-icons/md';
import { SelectList, SelectListModel } from '@/components/select/SelectList'; import { SelectList, SelectListModel } from '@/components/select/SelectList';

View File

@ -1,6 +1,5 @@
import { RefObject, useEffect, useMemo, useRef, useState } from 'react'; import { RefObject, useEffect, useMemo, useRef, useState } from 'react';
import { Button, Flex, Input, Spinner } from '@chakra-ui/react';
import { import {
MdClose, MdClose,
MdEdit, MdEdit,

View File

@ -1,5 +1,4 @@
import { Flex, Text } from '@chakra-ui/react';
import { LuMusic2, LuPlay } from 'react-icons/lu';
import { Track } from '@/back-api'; import { Track } from '@/back-api';
import { Covers } from '@/components/Cover'; import { Covers } from '@/components/Cover';

View File

@ -1,7 +1,4 @@
import { Suspense } from 'react';
import { Flex, Text } from '@chakra-ui/react';
import { LuMusic2, LuPlay } from 'react-icons/lu';
import { Track } from '@/back-api'; import { Track } from '@/back-api';
import { Covers } from '@/components/Cover'; import { Covers } from '@/components/Cover';

View File

@ -1,4 +1,4 @@
import { Flex, Skeleton } from '@chakra-ui/react';
export const DisplayTrackSkeleton = () => { export const DisplayTrackSkeleton = () => {
return ( return (

View File

@ -1,17 +0,0 @@
import type { ButtonProps } from "@chakra-ui/react"
import { IconButton as ChakraIconButton } from "@chakra-ui/react"
import * as React from "react"
import { LuX } from "react-icons/lu"
export type CloseButtonProps = ButtonProps
export const CloseButton = React.forwardRef<
HTMLButtonElement,
CloseButtonProps
>(function CloseButton(props, ref) {
return (
<ChakraIconButton variant="ghost" aria-label="Close" ref={ref} {...props}>
{props.children ?? <LuX />}
</ChakraIconButton>
)
})

View File

@ -1,62 +0,0 @@
import { Dialog as ChakraDialog, Portal } from "@chakra-ui/react"
import { CloseButton } from "./close-button"
import * as React from "react"
interface DialogContentProps extends ChakraDialog.ContentProps {
portalled?: boolean
portalRef?: React.RefObject<HTMLElement>
backdrop?: boolean
}
export const DialogContent = React.forwardRef<
HTMLDivElement,
DialogContentProps
>(function DialogContent(props, ref) {
const {
children,
portalled = true,
portalRef,
backdrop = true,
...rest
} = props
return (
<Portal disabled={!portalled} container={portalRef}>
{backdrop && <ChakraDialog.Backdrop />}
<ChakraDialog.Positioner>
<ChakraDialog.Content ref={ref} {...rest} asChild={false}>
{children}
</ChakraDialog.Content>
</ChakraDialog.Positioner>
</Portal>
)
})
export const DialogCloseTrigger = React.forwardRef<
HTMLButtonElement,
ChakraDialog.CloseTriggerProps
>(function DialogCloseTrigger(props, ref) {
return (
<ChakraDialog.CloseTrigger
position="absolute"
top="2"
insetEnd="2"
{...props}
asChild
>
<CloseButton size="sm" ref={ref}>
{props.children}
</CloseButton>
</ChakraDialog.CloseTrigger>
)
})
export const DialogRoot = ChakraDialog.Root
export const DialogFooter = ChakraDialog.Footer
export const DialogHeader = ChakraDialog.Header
export const DialogBody = ChakraDialog.Body
export const DialogBackdrop = ChakraDialog.Backdrop
export const DialogTitle = ChakraDialog.Title
export const DialogDescription = ChakraDialog.Description
export const DialogTrigger = ChakraDialog.Trigger
export const DialogActionTrigger = ChakraDialog.ActionTrigger

View File

@ -1,52 +0,0 @@
import { Drawer as ChakraDrawer, Portal } from "@chakra-ui/react"
import { CloseButton } from "./close-button"
import * as React from "react"
interface DrawerContentProps extends ChakraDrawer.ContentProps {
portalled?: boolean
portalRef?: React.RefObject<HTMLElement>
offset?: ChakraDrawer.ContentProps["padding"]
}
export const DrawerContent = React.forwardRef<
HTMLDivElement,
DrawerContentProps
>(function DrawerContent(props, ref) {
const { children, portalled = true, portalRef, offset, ...rest } = props
return (
<Portal disabled={!portalled} container={portalRef}>
<ChakraDrawer.Positioner padding={offset}>
<ChakraDrawer.Content ref={ref} {...rest} asChild={false}>
{children}
</ChakraDrawer.Content>
</ChakraDrawer.Positioner>
</Portal>
)
})
export const DrawerCloseTrigger = React.forwardRef<
HTMLButtonElement,
ChakraDrawer.CloseTriggerProps
>(function DrawerCloseTrigger(props, ref) {
return (
<ChakraDrawer.CloseTrigger
position="absolute"
top="2"
insetEnd="2"
{...props}
asChild
>
<CloseButton size="sm" ref={ref} />
</ChakraDrawer.CloseTrigger>
)
})
export const DrawerTrigger = ChakraDrawer.Trigger
export const DrawerRoot = ChakraDrawer.Root
export const DrawerFooter = ChakraDrawer.Footer
export const DrawerHeader = ChakraDrawer.Header
export const DrawerBody = ChakraDrawer.Body
export const DrawerBackdrop = ChakraDrawer.Backdrop
export const DrawerDescription = ChakraDrawer.Description
export const DrawerTitle = ChakraDrawer.Title
export const DrawerActionTrigger = ChakraDrawer.ActionTrigger

View File

@ -1,110 +0,0 @@
"use client"
import { AbsoluteCenter, Menu as ChakraMenu, Portal } from "@chakra-ui/react"
import * as React from "react"
import { LuCheck, LuChevronRight } from "react-icons/lu"
interface MenuContentProps extends ChakraMenu.ContentProps {
portalled?: boolean
portalRef?: React.RefObject<HTMLElement>
}
export const MenuContent = React.forwardRef<HTMLDivElement, MenuContentProps>(
function MenuContent(props, ref) {
const { portalled = true, portalRef, ...rest } = props
return (
<Portal disabled={!portalled} container={portalRef}>
<ChakraMenu.Positioner>
<ChakraMenu.Content ref={ref} {...rest} />
</ChakraMenu.Positioner>
</Portal>
)
},
)
export const MenuArrow = React.forwardRef<
HTMLDivElement,
ChakraMenu.ArrowProps
>(function MenuArrow(props, ref) {
return (
<ChakraMenu.Arrow ref={ref} {...props}>
<ChakraMenu.ArrowTip />
</ChakraMenu.Arrow>
)
})
export const MenuCheckboxItem = React.forwardRef<
HTMLDivElement,
ChakraMenu.CheckboxItemProps
>(function MenuCheckboxItem(props, ref) {
return (
<ChakraMenu.CheckboxItem ref={ref} {...props}>
<ChakraMenu.ItemIndicator hidden={false}>
<LuCheck />
</ChakraMenu.ItemIndicator>
{props.children}
</ChakraMenu.CheckboxItem>
)
})
export const MenuRadioItem = React.forwardRef<
HTMLDivElement,
ChakraMenu.RadioItemProps
>(function MenuRadioItem(props, ref) {
const { children, ...rest } = props
return (
<ChakraMenu.RadioItem ps="8" ref={ref} {...rest}>
<AbsoluteCenter axis="horizontal" left="4" asChild>
<ChakraMenu.ItemIndicator>
<LuCheck />
</ChakraMenu.ItemIndicator>
</AbsoluteCenter>
<ChakraMenu.ItemText>{children}</ChakraMenu.ItemText>
</ChakraMenu.RadioItem>
)
})
export const MenuItemGroup = React.forwardRef<
HTMLDivElement,
ChakraMenu.ItemGroupProps
>(function MenuItemGroup(props, ref) {
const { title, children, ...rest } = props
return (
<ChakraMenu.ItemGroup ref={ref} {...rest}>
{title && (
<ChakraMenu.ItemGroupLabel userSelect="none">
{title}
</ChakraMenu.ItemGroupLabel>
)}
{children}
</ChakraMenu.ItemGroup>
)
})
export interface MenuTriggerItemProps extends ChakraMenu.ItemProps {
startIcon?: React.ReactNode
}
export const MenuTriggerItem = React.forwardRef<
HTMLDivElement,
MenuTriggerItemProps
>(function MenuTriggerItem(props, ref) {
const { startIcon, children, ...rest } = props
return (
<ChakraMenu.TriggerItem ref={ref} {...rest}>
{startIcon}
{children}
<LuChevronRight />
</ChakraMenu.TriggerItem>
)
})
export const MenuRadioItemGroup = ChakraMenu.RadioItemGroup
export const MenuContextTrigger = ChakraMenu.ContextTrigger
export const MenuRoot = ChakraMenu.Root
export const MenuSeparator = ChakraMenu.Separator
export const MenuItem = ChakraMenu.Item
export const MenuItemText = ChakraMenu.ItemText
export const MenuItemCommand = ChakraMenu.ItemCommand
export const MenuTrigger = ChakraMenu.Trigger

View File

@ -1,7 +0,0 @@
import buttonRecipe from '@/theme/recipes/button';
import { chakra } from '@chakra-ui/react';
// we export the element with the application recipe theme.
// cf doc: https://www.chakra-ui.com/docs/theming/recipes
export const Button = chakra("button", buttonRecipe)

View File

@ -1,51 +1,39 @@
"use client" "use client"
import { RestErrorResponse } from "@/back-api"; import { RestErrorResponse } from "@/back-api";
import { import { HStack } from "@/ui";
Toaster as ChakraToaster,
Portal,
Spinner,
Stack,
Toast,
createToaster,
} from "@chakra-ui/react"
export const toaster = createToaster({ // export const toaster = createToaster({
placement: "bottom-end", // placement: "bottom-end",
pauseOnPageIdle: true, // pauseOnPageIdle: true,
}) // })
export const toasterAPIError = (error: RestErrorResponse) => { // export const toasterAPIError = (error: RestErrorResponse) => {
toaster.create({ // toaster.create({
title: `[${error.status}] ${error.statusMessage}`, // title: `[${error.status}] ${error.statusMessage}`,
description: error.message, // description: error.message,
}); // });
}; // };
export const Toaster = () => { // export const Toaster = () => {
return ( // return (
<Portal> // <Portal>
<ChakraToaster toaster={toaster} insetInline={{ mdDown: "4" }}> // <ArkToaster toaster={toaster}>
{(toast) => ( // {(toast) => (
<Toast.Root width={{ md: "sm" }}> // <Toast.Root>
{toast.type === "loading" ? ( // <HStack spacing="1" style={{ width: "100%" }}>
<Spinner size="sm" color="blue.solid" /> // {toast.title && <Toast.Title>{toast.title}</Toast.Title>}
) : ( // {toast.description && (
<Toast.Indicator /> // <Toast.Description>{toast.description}</Toast.Description>
)} // )}
<Stack gap="1" flex="1" maxWidth="100%"> // </HStack>
{toast.title && <Toast.Title>{toast.title}</Toast.Title>} // {toast.action && (
{toast.description && ( // <Toast.ActionTrigger>{toast.action.label}</Toast.ActionTrigger>
<Toast.Description>{toast.description}</Toast.Description> // )}
)} // {toast.meta?.closable && <Toast.CloseTrigger />}
</Stack> // </Toast.Root>
{toast.action && ( // )}
<Toast.ActionTrigger>{toast.action.label}</Toast.ActionTrigger> // </ArkToaster>
)} // </Portal>
{toast.meta?.closable && <Toast.CloseTrigger />} // )
</Toast.Root> // }
)}
</ChakraToaster>
</Portal>
)
}

View File

@ -1,4 +1,4 @@
import { Box, Button, Center, Heading, Link, Text } from '@chakra-ui/react';
import { MdControlCamera } from 'react-icons/md'; import { MdControlCamera } from 'react-icons/md';
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter'; import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';

View File

@ -1,4 +1,4 @@
import { Box, Button, Center, Heading, Link, Text } from '@chakra-ui/react';
import { MdDangerous } from 'react-icons/md'; import { MdDangerous } from 'react-icons/md';
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter'; import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';

View File

@ -1,4 +1,4 @@
import { Box, Button, Center, Heading, Link, Text } from '@chakra-ui/react';
import { MdSignpost } from 'react-icons/md'; import { MdSignpost } from 'react-icons/md';
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter'; import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';

View File

@ -1,18 +1,12 @@
import { Button } from '@/ui';
import { useDisclosure } from '@/utils/disclosure';
import React, { FC } from 'react'; import React, { FC } from 'react';
import {
AlertDescription,
AlertRoot,
AlertTitle,
Box,
Collapsible,
useDisclosure,
} from '@chakra-ui/react';
import { import {
FallbackProps, FallbackProps,
ErrorBoundary as ReactErrorBoundary, ErrorBoundary as ReactErrorBoundary,
} from 'react-error-boundary'; } from 'react-error-boundary';
import { Button } from '@/components/ui/themed';
import { LuChevronUp, LuChevronDown } from 'react-icons/lu'; import { LuChevronUp, LuChevronDown } from 'react-icons/lu';
const ErrorFallback = ({ error }: FallbackProps) => { const ErrorFallback = ({ error }: FallbackProps) => {

View File

@ -1,4 +1,4 @@
import { createIcon } from '@chakra-ui/react';
export const DoubleArrowIcon = createIcon({ export const DoubleArrowIcon = createIcon({
displayName: 'DoubleArrowIcon', displayName: 'DoubleArrowIcon',

View File

@ -1,19 +1,14 @@
import { StrictMode } from 'react';
import ReactDOM from 'react-dom/client'; import ReactDOM from 'react-dom/client';
import App from '@/App'; import App from '@/App';
import { ColorModeProvider } from './components/ui/color-mode';
// 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>
<ColorModeProvider> // <ColorModeProvider>
<App /> <App />
</ColorModeProvider> // </ColorModeProvider>
</StrictMode> // </StrictMode>
); );
} }

View File

@ -1,6 +1,7 @@
import { AudioPlayer } from '@/components/AudioPlayer'; import { AudioPlayer } from '@/components/AudioPlayer';
import { ErrorBoundary } from '@/errors/ErrorBoundary'; import { ErrorBoundary } from '@/errors/ErrorBoundary';
import { AppRoutes } from '@/scene/AppRoutes'; import { AppRoutes } from '@/scene/AppRoutes';
import { Text } from '@/ui';
import { ServiceContextProvider } from '@/service/ServiceContext'; import { ServiceContextProvider } from '@/service/ServiceContext';
export const App = () => { export const App = () => {

View File

@ -1,4 +1,4 @@
import { createBrowserHistory } from 'history'; // import { createBrowserHistory } from 'history';
import { import {
unstable_HistoryRouter as HistoryRouter, unstable_HistoryRouter as HistoryRouter,
Route, Route,
@ -21,31 +21,31 @@ import { OnAirPage } from './onAir/OnAirPage';
export const AppRoutes = () => { export const AppRoutes = () => {
const { isReadable } = useHasRight('user'); const { isReadable } = useHasRight('user');
return ( return (
<HistoryRouter // <HistoryRouter
// @ts-expect-error // // @ts-expect-error
history={createBrowserHistory({ window })} // history={createBrowserHistory({ window })}
basename="/karusic" // basename="/karusic"
> // >
<Routes> <Routes>
{/* Need to keep it in all case, it is the only way to log-in */} {/* Need to keep it in all case, it is the only way to log-in */}
<Route path="sso/*" element={<SSORoutes />} /> <Route path="sso/*" element={<SSORoutes />} />
{isReadable ? ( {isReadable ? (
<> <>
<Route path="/" element={<HomePage />} /> <Route path="/" element={<HomePage />} />
<Route path="help" element={<HelpPage />} /> <Route path="help" element={<HelpPage />} />
<Route path="settings" element={<SettingsPage />} /> <Route path="settings" element={<SettingsPage />} />
<Route path="add" element={<AddPage />} /> <Route path="add" element={<AddPage />} />
<Route path="on-air/*" element={<OnAirPage />} /> <Route path="on-air/*" element={<OnAirPage />} />
<Route path="artist/*" element={<ArtistRoutes />} /> <Route path="artist/*" element={<ArtistRoutes />} />
<Route path="album/*" element={<AlbumRoutes />} /> <Route path="album/*" element={<AlbumRoutes />} />
<Route path="gender/*" element={<GenderRoutes />} /> <Route path="gender/*" element={<GenderRoutes />} />
<Route path="track/*" element={<TrackRoutes />} /> <Route path="track/*" element={<TrackRoutes />} />
<Route path="*" element={<Error404 />} /> <Route path="*" element={<Error404 />} />
</> </>
) : ( ) : (
<Route path="*" element={<Error401 />} /> <Route path="*" element={<Error401 />} />
)} )}
</Routes> </Routes>
</HistoryRouter> // </HistoryRouter>
); );
}; };

View File

@ -1,5 +1,4 @@
import { Box, Button, Flex, Text } from '@chakra-ui/react';
import { LuDisc3 } from 'react-icons/lu';
import { MdEdit } from 'react-icons/md'; import { MdEdit } from 'react-icons/md';
import { Route, Routes, useNavigate, useParams } from 'react-router-dom'; import { Route, Routes, useNavigate, useParams } from 'react-router-dom';
@ -10,7 +9,6 @@ import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar'; import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar';
import { AlbumEditPopUp } from '@/components/popup/AlbumEditPopUp'; import { AlbumEditPopUp } from '@/components/popup/AlbumEditPopUp';
import { TrackEditPopUp } from '@/components/popup/TrackEditPopUp'; import { TrackEditPopUp } from '@/components/popup/TrackEditPopUp';
import { DisplayTrack } from '@/components/track/DisplayTrack';
import { DisplayTrackFull } from '@/components/track/DisplayTrackFull'; import { DisplayTrackFull } from '@/components/track/DisplayTrackFull';
import { useActivePlaylistService } from '@/service/ActivePlaylist'; import { useActivePlaylistService } from '@/service/ActivePlaylist';
import { useSpecificAlbum } from '@/service/Album'; import { useSpecificAlbum } from '@/service/Album';

View File

@ -10,8 +10,7 @@ import { TopBar } from '@/components/TopBar/TopBar';
import { DisplayAlbum } from '@/components/album/DisplayAlbum'; import { DisplayAlbum } from '@/components/album/DisplayAlbum';
import { useOrderedAlbums } from '@/service/Album'; import { useOrderedAlbums } from '@/service/Album';
import { useColorModeValue } from '@/components/ui/color-mode'; import { useColorModeValue } from '@/components/ui/color-mode';
import { BASE_WRAP_SPACING, BASE_WRAP_WIDTH, BASE_WRAP_HEIGHT } from '@/constants/genericSpacing'; import { BASE_WRAP_WIDTH, BASE_WRAP_HEIGHT } from '@/constants/genericSpacing';
import { Flex, HStack } from '@chakra-ui/react';
export const AlbumsPage = () => { export const AlbumsPage = () => {
const [filterTitle, setFilterTitle] = useState<string | undefined>(undefined); const [filterTitle, setFilterTitle] = useState<string | undefined>(undefined);
@ -51,7 +50,7 @@ export const AlbumsPage = () => {
boxShadow: 'outline-over', boxShadow: 'outline-over',
bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'), bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
}} }}
onClick={() => onSelectItem(data.id)} onClick={() => onSelect.Item(data.id)}
> >
<DisplayAlbum dataAlbum={data} /> <DisplayAlbum dataAlbum={data} />
</Flex> </Flex>

View File

@ -1,6 +1,5 @@
import { Box, Button, Flex, Text } from '@chakra-ui/react';
import { LuDisc3, LuUser } from 'react-icons/lu'; import { MdEdit } from 'react-icons/md';
import { MdEdit, MdPerson } from 'react-icons/md';
import { Route, Routes, useNavigate, useParams } from 'react-router-dom'; import { Route, Routes, useNavigate, useParams } from 'react-router-dom';
import { Covers } from '@/components/Cover'; import { Covers } from '@/components/Cover';

View File

@ -1,5 +1,4 @@
import { Button, Flex, Text, HStack } from '@chakra-ui/react';
import { LuUser } from 'react-icons/lu';
import { MdEdit, MdGroup } from 'react-icons/md'; import { MdEdit, MdGroup } from 'react-icons/md';
import { Route, Routes, useNavigate, useParams } from 'react-router-dom'; import { Route, Routes, useNavigate, useParams } from 'react-router-dom';
@ -13,7 +12,7 @@ import { ArtistEditPopUp } from '@/components/popup/ArtistEditPopUp';
import { useSpecificArtist } from '@/service/Artist'; import { useSpecificArtist } from '@/service/Artist';
import { useAlbumIdsOfAnArtist } from '@/service/Track'; import { useAlbumIdsOfAnArtist } from '@/service/Track';
import { useColorModeValue } from '@/components/ui/color-mode'; import { useColorModeValue } from '@/components/ui/color-mode';
import { BASE_WRAP_HEIGHT, BASE_WRAP_SPACING, BASE_WRAP_WIDTH } from '@/constants/genericSpacing'; import { BASE_WRAP_HEIGHT, BASE_WRAP_WIDTH } from '@/constants/genericSpacing';
export const ArtistDetailPage = () => { export const ArtistDetailPage = () => {
const { artistId } = useParams(); const { artistId } = useParams();

View File

@ -1,7 +1,5 @@
import { useState } from 'react'; import { useState } from 'react';
import { Button, Flex, Text, Tooltip, HStack, Span } from '@chakra-ui/react';
import { LuUser } from 'react-icons/lu';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { Artist, Track } from '@/back-api'; import { Artist, Track } from '@/back-api';
@ -12,7 +10,7 @@ import { SearchInput } from '@/components/SearchInput';
import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar'; import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar';
import { useOrderedArtists } from '@/service/Artist'; import { useOrderedArtists } from '@/service/Artist';
import { useColorModeValue } from '@/components/ui/color-mode'; import { useColorModeValue } from '@/components/ui/color-mode';
import { BASE_WRAP_HEIGHT, BASE_WRAP_ICON_SIZE, BASE_WRAP_SPACING, BASE_WRAP_WIDTH } from '@/constants/genericSpacing'; import { BASE_WRAP_HEIGHT, BASE_WRAP_ICON_SIZE, BASE_WRAP_WIDTH } from '@/constants/genericSpacing';
import { MdOutlineForkRight } from 'react-icons/md'; import { MdOutlineForkRight } from 'react-icons/md';
import { useActivePlaylistService } from '@/service/ActivePlaylist'; import { useActivePlaylistService } from '@/service/ActivePlaylist';
import { shuffleArray } from '@/utils/arrayTools'; import { shuffleArray } from '@/utils/arrayTools';

View File

@ -1,5 +1,4 @@
import { Box, Button, Flex, Text } from '@chakra-ui/react';
import { LuDisc3 } from 'react-icons/lu';
import { MdEdit } from 'react-icons/md'; import { MdEdit } from 'react-icons/md';
import { Route, Routes, useNavigate, useParams } from 'react-router-dom'; import { Route, Routes, useNavigate, useParams } from 'react-router-dom';
@ -10,7 +9,6 @@ import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar'; import { BUTTON_TOP_BAR_PROPERTY, TopBar } from '@/components/TopBar/TopBar';
import { GenderEditPopUp } from '@/components/popup/GenderEditPopUp'; import { GenderEditPopUp } from '@/components/popup/GenderEditPopUp';
import { TrackEditPopUp } from '@/components/popup/TrackEditPopUp'; import { TrackEditPopUp } from '@/components/popup/TrackEditPopUp';
import { DisplayTrack } from '@/components/track/DisplayTrack';
import { DisplayTrackFull } from '@/components/track/DisplayTrackFull'; import { DisplayTrackFull } from '@/components/track/DisplayTrackFull';
import { useActivePlaylistService } from '@/service/ActivePlaylist'; import { useActivePlaylistService } from '@/service/ActivePlaylist';
import { useSpecificGender } from '@/service/Gender'; import { useSpecificGender } from '@/service/Gender';

View File

@ -10,7 +10,7 @@ import { TopBar } from '@/components/TopBar/TopBar';
import { DisplayGender } from '@/components/gender/DisplayGender'; import { DisplayGender } from '@/components/gender/DisplayGender';
import { useOrderedGenders } from '@/service/Gender'; import { useOrderedGenders } from '@/service/Gender';
import { useColorModeValue } from '@/components/ui/color-mode'; import { useColorModeValue } from '@/components/ui/color-mode';
import { Flex, HStack } from '@chakra-ui/react'; import { Flex, HStack } from '@/ui';
export const GendersPage = () => { export const GendersPage = () => {
const [filterTitle, setFilterTitle] = useState<string | undefined>(undefined); const [filterTitle, setFilterTitle] = useState<string | undefined>(undefined);
@ -35,20 +35,24 @@ export const GendersPage = () => {
<SearchInput onChange={setFilterTitle} /> <SearchInput onChange={setFilterTitle} />
</TopBar> </TopBar>
<PageLayout> <PageLayout>
<HStack wrap="wrap" /*spacing="20px"*/ marginX="auto" padding="20px" justify="center"> <HStack style={{
// wrap: "wrap",
/*spacing="20px"*/ margin: "0 auto 0 auto", padding: "20px", justifyContent: "center"
}}>
{dataGenders.map((data) => ( {dataGenders.map((data) => (
<Flex align="flex-start" <Flex align="flex-start"
width="270px"
height="120px"
border="1px"
borderColor="brand.900"
backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')}
key={data.id} key={data.id}
padding="5px" style={{
as="button" width: "270px",
_hover={{ height: "120px",
boxShadow: 'outline-over', border: "1px",
bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'), borderColor: "brand.900",
//backgroundColor:{useColorModeValue('#FFFFFF88', '#00000088')},
padding: "5px",
// _hover: {
// boxShadow: 'outline-over',
// bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
// }
}} }}
onClick={() => onSelectItem(data.id)} onClick={() => onSelectItem(data.id)}
> >

View File

@ -1,11 +1,5 @@
import { useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import {
Flex,
Input,
Table,
Text,
} from '@chakra-ui/react';
import { LuTrash } from 'react-icons/lu'; import { LuTrash } from 'react-icons/lu';
import { MdCloudUpload } from 'react-icons/md'; import { MdCloudUpload } from 'react-icons/md';
@ -31,7 +25,7 @@ import { useGenderService, useOrderedGenders } from '@/service/Gender';
import { useServiceContext } from '@/service/ServiceContext'; import { useServiceContext } from '@/service/ServiceContext';
import { useTrackService } from '@/service/Track'; import { useTrackService } from '@/service/Track';
import { isNullOrUndefined } from '@/utils/validator'; import { isNullOrUndefined } from '@/utils/validator';
import { Button } from '@/components/ui/themed'; import { Button, Flex, Table, Text } from '@/ui';
export class ElementList { export class ElementList {
constructor( constructor(
@ -121,7 +115,7 @@ export const AddPage = () => {
updateNeedSend(); updateNeedSend();
}; };
const removeElementFromList = (data: FileParsedElement, value: any): void => { const removeElementFromList = (data: FileParsedElement): void => {
const parsedElementTmp = [...parsedElement]; const parsedElementTmp = [...parsedElement];
for (let iii = 0; iii < parsedElementTmp.length; iii++) { for (let iii = 0; iii < parsedElementTmp.length; iii++) {
if (parsedElementTmp[iii] === data) { if (parsedElementTmp[iii] === data) {
@ -420,15 +414,17 @@ export const AddPage = () => {
<PageLayout> <PageLayout>
<Flex <Flex
direction="column" direction="column"
width="80%"
marginX="auto"
padding="10px"
gap="10px" gap="10px"
style={{
width: "80%",
margin: "0 auto 0 auto",
padding: "10px",
}}
> >
<Flex direction="column" width="full"> <Flex direction="column" style={{ width: "full" }}>
<Flex> <Flex>
<Text flex={1}>format:</Text> <Text>format:</Text>
<Text flex={4}> <Text>
The format of the media permit to automatic find meta-data: The format of the media permit to automatic find meta-data:
<br /> <br />
Artist~album#idTrack-my name of my media.webm Artist~album#idTrack-my name of my media.webm
@ -437,15 +433,15 @@ export const AddPage = () => {
</Text> </Text>
</Flex> </Flex>
<Flex> <Flex>
<Text flex={1}>Media:</Text> <Text>Media:</Text>
<Input {/* <Input
flex={4} flex={4}
type="file" type="file"
placeholder="Select a media file" placeholder="Select a media file"
accept=".webm" accept=".webm"
multiple multiple
onChange={onChangeFile} onChange={onChangeFile}
/> /> */}
</Flex> </Flex>
</Flex> </Flex>
{parsedElement && parsedElement.length !== 0 && ( {parsedElement && parsedElement.length !== 0 && (
@ -478,14 +474,12 @@ export const AddPage = () => {
suggestion={suggestedAlbum} suggestion={suggestedAlbum}
/> />
<Table.Root <Table.Root
colorPalette="striped"
colorScheme="teal"
background="gray.700" background="gray.700"
> >
<Table.Header> <Table.Header>
<Table.Row> <Table.Row>
<Table.ColumnHeader>track ID</Table.ColumnHeader> <Table.ColumnHeader>track ID</Table.ColumnHeader>
<Table.ColumnHeader width="full">Title</Table.ColumnHeader> <Table.ColumnHeader style={{ width: "full" }}>Title</Table.ColumnHeader>
<Table.ColumnHeader>actions</Table.ColumnHeader> <Table.ColumnHeader>actions</Table.ColumnHeader>
</Table.Row> </Table.Row>
</Table.Header> </Table.Header>
@ -493,7 +487,7 @@ export const AddPage = () => {
{parsedElement.map((data) => ( {parsedElement.map((data) => (
<Table.Row key={data.uniqueId}> <Table.Row key={data.uniqueId}>
<Table.Cell> <Table.Cell>
<Input {/* <Input
type="number" type="number"
pattern="[0-9]{0-4}" pattern="[0-9]{0-4}"
placeholder="e?" placeholder="e?"
@ -504,10 +498,10 @@ export const AddPage = () => {
? 'darkred' ? 'darkred'
: undefined : undefined
} }
/> /> */}
</Table.Cell> </Table.Cell>
<Table.Cell> <Table.Cell>
<Input {/* <Input
type="text" type="text"
placeholder="Name of the Media" placeholder="Name of the Media"
value={data.title} value={data.title}
@ -515,11 +509,11 @@ export const AddPage = () => {
backgroundColor={ backgroundColor={
data.title === '' ? 'darkred' : undefined data.title === '' ? 'darkred' : undefined
} }
/> /> */}
{data.nameDetected === true && ( {data.nameDetected === true && (
<> <>
<br /> <br />
<Text as="span" color="@danger"> <Text style={{ backgroundColor: "red" }}>
^^^This title already exist !!! ^^^This title already exist !!!
</Text> </Text>
</> </>
@ -527,8 +521,8 @@ export const AddPage = () => {
</Table.Cell> </Table.Cell>
<Table.Cell> <Table.Cell>
<Button <Button
onClick={(e) => onClick={() =>
removeElementFromList(data, e.target) removeElementFromList(data)
} }
> >
<LuTrash /> Remove <LuTrash /> Remove
@ -538,13 +532,14 @@ export const AddPage = () => {
))} ))}
</Table.Body> </Table.Body>
</Table.Root> </Table.Root>
<Flex marginY="15px"> <Flex style={{ margin: "15px 0 15px 0" }}>
<Button <Button
theme="@primary" //theme="@primary"
onClick={sendFile} onClick={sendFile}
disabled={!needSend} style={{
marginLeft="auto" //disabled:!needSend,
marginRight="30px" margin: "0 auto 0 30px"
}}
> >
<MdCloudUpload /> Upload <MdCloudUpload /> Upload
</Button> </Button>
@ -554,14 +549,16 @@ export const AddPage = () => {
{listFileInBdd && ( {listFileInBdd && (
<Table.Root <Table.Root
fontPalette="striped" //fontPalette="striped"
colorScheme="teal" //colorScheme="teal"
background="gray.700" style={{
background: "gray.700"
}}
> >
<Table.Header> <Table.Header>
<Table.Row> <Table.Row>
<Table.ColumnHeader>track ID</Table.ColumnHeader> <Table.ColumnHeader>track ID</Table.ColumnHeader>
<Table.ColumnHeader width="full">Title</Table.ColumnHeader> <Table.ColumnHeader style={{ width: "full" }}>Title</Table.ColumnHeader>
<Table.ColumnHeader>actions</Table.ColumnHeader> <Table.ColumnHeader>actions</Table.ColumnHeader>
</Table.Row> </Table.Row>
</Table.Header> </Table.Header>
@ -597,13 +594,13 @@ export const AddPage = () => {
<> <>
<Text fontSize="30px">Rejected:</Text> <Text fontSize="30px">Rejected:</Text>
<Table.Root <Table.Root
colorPalette="striped" //colorPalette="striped"
colorScheme="teal" //colorScheme="teal"
background="gray.700" style={{ background: "gray.700" }}
> >
<Table.Header> <Table.Header>
<Table.Row> <Table.Row>
<Table.ColumnHeader maxWidth="80%">file</Table.ColumnHeader> <Table.ColumnHeader style={{ maxWidth: "80%" }}>file</Table.ColumnHeader>
<Table.ColumnHeader>Reason</Table.ColumnHeader> <Table.ColumnHeader>Reason</Table.ColumnHeader>
</Table.Row> </Table.Row>
</Table.Header> </Table.Header>

View File

@ -1,6 +1,5 @@
import { ReactElement } from 'react'; import { ReactElement } from 'react';
import { Center, Flex, HStack, Text } from '@chakra-ui/react';
import { LuCrown, LuDisc3, LuEar, LuFileAudio } from 'react-icons/lu'; import { LuCrown, LuDisc3, LuEar, LuFileAudio } from 'react-icons/lu';
import { MdGroup } from 'react-icons/md'; import { MdGroup } from 'react-icons/md';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';

View File

@ -1,4 +1,3 @@
import { Box, Flex, Text } from '@chakra-ui/react';
import { Route, Routes, useNavigate } from 'react-router-dom'; import { Route, Routes, useNavigate } from 'react-router-dom';
import { EmptyEnd } from '@/components/EmptyEnd'; import { EmptyEnd } from '@/components/EmptyEnd';

View File

@ -1,6 +1,5 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { Center, Heading, Image, Text } from '@chakra-ui/react';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
import avatar_generic from '@/assets/images/avatar_generic.svg'; import avatar_generic from '@/assets/images/avatar_generic.svg';

View File

@ -1,11 +1,7 @@
import { ReactElement } from 'react';
import { Flex, Text, HStack } from '@chakra-ui/react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { PageLayout } from '@/components/Layout/PageLayout'; import { PageLayout } from '@/components/Layout/PageLayout';
import { TopBar } from '@/components/TopBar/TopBar'; import { TopBar } from '@/components/TopBar/TopBar';
import { DataTools, TypeCheck } from '@/utils/data-tools';
import { useColorModeValue } from '@/components/ui/color-mode'; import { useColorModeValue } from '@/components/ui/color-mode';
export const alphabet = [ export const alphabet = [

View File

@ -1,6 +1,3 @@
import { ReactElement } from 'react';
import { Box, Flex } from '@chakra-ui/react';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { EmptyEnd } from '@/components/EmptyEnd'; import { EmptyEnd } from '@/components/EmptyEnd';

View File

@ -1,4 +1,4 @@
import { useEffect, useMemo, useState } from 'react'; import { useMemo } from 'react';
import { Album, AlbumResource } from '@/back-api'; import { Album, AlbumResource } from '@/back-api';
import { useServiceContext } from '@/service/ServiceContext'; import { useServiceContext } from '@/service/ServiceContext';

View File

@ -1,4 +1,4 @@
import { useCallback, useEffect, useMemo, useState } from 'react'; import { useMemo } from 'react';
import { Track, TrackResource } from '@/back-api'; import { Track, TrackResource } from '@/back-api';
import { useServiceContext } from '@/service/ServiceContext'; import { useServiceContext } from '@/service/ServiceContext';

View File

@ -6,16 +6,13 @@ import { useServiceContext } from '@/service/ServiceContext';
import { SessionState } from '@/service/SessionState'; import { SessionState } from '@/service/SessionState';
import { isBrowser } from '@/utils/layout'; import { isBrowser } from '@/utils/layout';
import { parseToken } from '@/utils/sso'; import { parseToken } from '@/utils/sso';
import { createListCollection } from '@chakra-ui/react';
const TOKEN_KEY = 'karusic-token-key-storage'; const TOKEN_KEY = 'karusic-token-key-storage';
export const USERS_COLLECTION = createListCollection({ export const USERS_COLLECTION = [
items: [ { label: "admin", value: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIxIiwiYXBwbGljYXRpb24iOiJrYXJ1c2ljIiwiaXNzIjoiS2FyQXV0aCIsInJpZ2h0Ijp7ImthcnVzaWMiOnsiQURNSU4iOnRydWUsIlVTRVIiOnRydWV9fSwibG9naW4iOiJIZWVyb1l1aSIsImV4cCI6MTcyNDIwNjc5NCwiaWF0IjoxNzI0MTY2ODM0fQ.TEST_SIGNATURE_FOR_LOCAL_TEST_AND_TEST_E2E" },
{ label: "admin", value: "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIxIiwiYXBwbGljYXRpb24iOiJrYXJ1c2ljIiwiaXNzIjoiS2FyQXV0aCIsInJpZ2h0Ijp7ImthcnVzaWMiOnsiQURNSU4iOnRydWUsIlVTRVIiOnRydWV9fSwibG9naW4iOiJIZWVyb1l1aSIsImV4cCI6MTcyNDIwNjc5NCwiaWF0IjoxNzI0MTY2ODM0fQ.TEST_SIGNATURE_FOR_LOCAL_TEST_AND_TEST_E2E" }, { label: "NO_USER", value: "svelte" },
{ label: "NO_USER", value: "svelte" }, ];
],
})
export const USERS = { export const USERS = {
admin: admin:
'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIxIiwiYXBwbGljYXRpb24iOiJrYXJ1c2ljIiwiaXNzIjoiS2FyQXV0aCIsInJpZ2h0Ijp7ImthcnVzaWMiOnsiQURNSU4iOnRydWUsIlVTRVIiOnRydWV9fSwibG9naW4iOiJIZWVyb1l1aSIsImV4cCI6MTcyNDIwNjc5NCwiaWF0IjoxNzI0MTY2ODM0fQ.TEST_SIGNATURE_FOR_LOCAL_TEST_AND_TEST_E2E', 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIxIiwiYXBwbGljYXRpb24iOiJrYXJ1c2ljIiwiaXNzIjoiS2FyQXV0aCIsInJpZ2h0Ijp7ImthcnVzaWMiOnsiQURNSU4iOnRydWUsIlVTRVIiOnRydWV9fSwibG9naW4iOiJIZWVyb1l1aSIsImV4cCI6MTcyNDIwNjc5NCwiaWF0IjoxNzI0MTY2ODM0fQ.TEST_SIGNATURE_FOR_LOCAL_TEST_AND_TEST_E2E',

View File

@ -1,6 +1,5 @@
import { ReactElement, ReactNode } from 'react'; import { ReactElement, ReactNode } from 'react';
import { ChakraProvider, defaultSystem } from '@chakra-ui/react';
import { RenderOptions, render } from '@testing-library/react'; import { RenderOptions, render } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom'; import { BrowserRouter } from 'react-router-dom';

View File

@ -1,4 +1,3 @@
import { defineRecipe, defineStyle, RecipeVariantRecord, SystemStyleObject } from '@chakra-ui/react';
// https://medium.com/@a.heydari.dev/simplifying-chakra-ui-v3-recipes-vs-chakra-factory-a-developers-perspective-4020b62f1b4d // https://medium.com/@a.heydari.dev/simplifying-chakra-ui-v3-recipes-vs-chakra-factory-a-developers-perspective-4020b62f1b4d
@ -9,7 +8,7 @@ import { defineRecipe, defineStyle, RecipeVariantRecord, SystemStyleObject } fro
// `; // `;
export const customVariant = ({ bg, bgHover, bgActive, color, colorHover, boxShadowHover }) => { export const customVariant = ({ bg, bgHover, bgActive, color, colorHover, boxShadowHover }) => {
return defineStyle({ return {
bg, bg,
color, color,
border: '1px solid transparent', border: '1px solid transparent',
@ -29,81 +28,76 @@ export const customVariant = ({ bg, bgHover, bgActive, color, colorHover, boxSha
_active: { _active: {
bg: bgActive, bg: bgActive,
}, },
}); };
}; };
const buttonRecipe = defineRecipe({ const buttonTheme = {
variants: { primary:
theme: { customVariant({
"@primary": bg: { _light: 'brand.600', _dark: 'brand.300' },
customVariant({ bgHover: { _light: 'brand.700', _dark: 'brand.400' },
bg: { _light: 'brand.600', _dark: 'brand.300' }, bgActive: { _light: 'brand.600', _dark: 'brand.300' },
bgHover: { _light: 'brand.700', _dark: 'brand.400' }, color: { _light: 'white', _dark: 'brand.900' },
bgActive: { _light: 'brand.600', _dark: 'brand.300' }, colorHover: { _light: 'brand.800', _dark: 'brand.100' },
color: { _light: 'white', _dark: 'brand.900' }, boxShadowHover: 'outline-over'
colorHover: { _light: 'brand.800', _dark: 'brand.100' }, }),
boxShadowHover: 'outline-over' secondary:
}), customVariant({
"@secondary": bg: { _light: 'brand.100', _dark: 'brand.900' },
customVariant({ bgHover: { _light: 'brand.200', _dark: 'brand.800' },
bg: { _light: 'brand.100', _dark: 'brand.900' }, bgActive: { _light: 'brand.300', _dark: 'brand.700' },
bgHover: { _light: 'brand.200', _dark: 'brand.800' }, color: { _light: 'brand.700', _dark: 'brand.50' },
bgActive: { _light: 'brand.300', _dark: 'brand.700' }, colorHover: { _light: 'brand.800', _dark: 'brand.100' },
color: { _light: 'brand.700', _dark: 'brand.50' }, boxShadowHover: 'outline-over',
colorHover: { _light: 'brand.800', _dark: 'brand.100' }, }),
boxShadowHover: 'outline-over', danger:
}), customVariant({
"@danger": bg: { _light: 'error.600', _dark: 'error.600' },
customVariant({ bgHover: { _light: 'error.700', _dark: 'error.500' },
bg: { _light: 'error.600', _dark: 'error.600' }, bgActive: { _light: 'error.600', _dark: 'error.500' },
bgHover: { _light: 'error.700', _dark: 'error.500' }, color: { _light: 'white', _dark: 'error.900' },
bgActive: { _light: 'error.600', _dark: 'error.500' }, colorHover: { _light: 'error.700', _dark: 'error.900' },
color: { _light: 'white', _dark: 'error.900' }, boxShadowHover: 'outline-over',
colorHover: { _light: 'error.700', _dark: 'error.900' }, }),
boxShadowHover: 'outline-over', success:
}), customVariant({
"@success": bg: { _light: 'green.300', _dark: 'green.300' },
customVariant({ bgHover: { _light: 'green.400', _dark: 'green.400' },
bg: { _light: 'green.300', _dark: 'green.300' }, bgActive: { _light: 'green.500', _dark: 'green.400' },
bgHover: { _light: 'green.400', _dark: 'green.400' }, color: { _light: 'white', _dark: 'green.900' },
bgActive: { _light: 'green.500', _dark: 'green.400' }, colorHover: { _light: 'green.500', _dark: 'green.900' },
color: { _light: 'white', _dark: 'green.900' }, boxShadowHover: 'outline-over',
colorHover: { _light: 'green.500', _dark: 'green.900' }, }),
boxShadowHover: 'outline-over', progress:
}), {
bg: { _light: `brand.500`, _dark: `brand.300` },
"@progress": overflow: 'hidden',
defineStyle({ /*
bg: { _light: `brand.500`, _dark: `brand.300` }, _after: !props.isLoading
overflow: 'hidden', ? {
/* content: '""',
_after: !props.isLoading position: 'absolute',
? { top: 0,
content: '""', right: 0,
position: 'absolute', bottom: 0,
top: 0, left: 0,
right: 0, transform: 'translateX(-100%)',
bottom: 0, bgGradient: `linear(90deg, brand.100/0 0%, brand.100/2 20%, brand.100/5 60%, v.100/0`,
left: 0, }
transform: 'translateX(-100%)', : undefined,
bgGradient: `linear(90deg, brand.100/0 0%, brand.100/2 20%, brand.100/5 60%, v.100/0`, */
}
: undefined,
*/
}),
"@menu": defineStyle({
bg: 'back.100',
color: 'brand.900',
borderRadius: 0,
border: 0,
_hover: { background: 'back.300' },
_focus: { border: 'none' },
fontSize: '20px',
textTransform: 'uppercase',
}),
},
}, },
});
export default buttonRecipe; menu: {
bg: 'back.100',
color: 'brand.900',
borderRadius: 0,
border: 0,
_hover: { background: 'back.300' },
_focus: { border: 'none' },
fontSize: '20px',
textTransform: 'uppercase',
},
};
export default buttonTheme;

View File

@ -1,6 +1,6 @@
import { defineRecipe } from '@chakra-ui/react';
const drawerRecipe = defineRecipe({
const drawerRecipe = {
base: { base: {
bg: { _light: 'white', _dark: 'gray.800' }, bg: { _light: 'white', _dark: 'gray.800' },
color: { _light: 'gray.900', _dark: 'whiteAlpha.900' }, color: { _light: 'gray.900', _dark: 'whiteAlpha.900' },
@ -24,6 +24,6 @@ const drawerRecipe = defineRecipe({
defaultVariants: { defaultVariants: {
variant: 'solid', variant: 'solid',
}, },
}); };
export default drawerRecipe; export default drawerRecipe;

View File

@ -1,7 +1,7 @@
import { defineRecipe } from '@chakra-ui/react';
const flexTheme = defineRecipe({
const flexTheme = {
variants: { variants: {
variant: { variant: {
'@menu': { '@menu': {
@ -15,6 +15,6 @@ const flexTheme = defineRecipe({
}, },
}, },
}, },
}); };
export default flexTheme; export default flexTheme;

View File

@ -1,6 +1,5 @@
import { defineRecipe } from '@chakra-ui/react';
const inputTheme = defineRecipe({ const inputTheme = {
variants: { variants: {
variant: { variant: {
outline: { outline: {
@ -16,6 +15,6 @@ const inputTheme = defineRecipe({
}, },
}, },
}, },
}); };
export default inputTheme; export default inputTheme;

View File

@ -1,5 +1,3 @@
import { modalAnatomy as parts } from '@chakra-ui/anatomy';
import { createMultiStyleConfigHelpers } from '@chakra-ui/react';
const { definePartsStyle, defineMultiStyleConfig } = const { definePartsStyle, defineMultiStyleConfig } =
createMultiStyleConfigHelpers(parts.keys); createMultiStyleConfigHelpers(parts.keys);

View File

@ -1,27 +0,0 @@
import { numberInputAnatomy } from '@chakra-ui/anatomy';
import { createMultiStyleConfigHelpers } from '@chakra-ui/react';
import { getColor, mode } from '@chakra-ui/theme-tools';
const { definePartsStyle, defineMultiStyleConfig } =
createMultiStyleConfigHelpers(numberInputAnatomy.keys);
const baseStyle = definePartsStyle((props) => {
return {
field: {
border: 0,
_focusVisible: {
borderColor: {_light:'brand.500', _dark:'brand.300'},
boxShadow: `0 0 0 1px 'brand.500'`,
ring: '1px',
ringColor: {_light:'brand.500', _dark:'brand.300'},
ringOffset: '1px',
ringOffsetColor: {_light:'brand.500', _dark:'brand.300'},
},
},
};
});
export default defineMultiStyleConfig({
baseStyle,
});

View File

@ -1,6 +1,5 @@
import { defineRecipe } from '@chakra-ui/react';
const selectTheme = defineRecipe({ const selectTheme = {
variants: { variants: {
variant: { variant: {
outline: { outline: {
@ -15,6 +14,6 @@ const selectTheme = defineRecipe({
}, },
}, },
}, },
}); };
export default selectTheme; export default selectTheme;

View File

@ -1,7 +1,5 @@
import { defineRecipe } from '@chakra-ui/react';
const textAreaTheme = {
const textAreaTheme = defineRecipe({
variants: { variants: {
variant: { variant: {
outline: { outline: {
@ -14,5 +12,5 @@ const textAreaTheme = defineRecipe({
}, },
} }
}, },
}); };
export default textAreaTheme; export default textAreaTheme;

View File

@ -1,67 +0,0 @@
import { Group, VStack } from '@chakra-ui/react';
import { HiMinus, HiPlus } from 'react-icons/hi';
const meta = {
title: 'StyleGuide/Buttons',
};
export default meta;
export const Default = {
render: () => (
<Group>
<Button>Default Button</Button>
<IconButton aria-label="Add" ><HiPlus /></IconButton>
</Group>
),
};
export const Primary = {
render: () => (
<Group>
<Button theme="@primary">Primary Button</Button>
<IconButton theme="@primary" aria-label="Add" ><HiPlus /></IconButton>
</Group>
),
};
export const Secondary = {
render: () => (
<Group>
<Button theme="@secondary">Secondary Button</Button>
<IconButton theme="@secondary" aria-label="Add" ><HiPlus /></IconButton>
</Group>
),
};
export const Danger = {
render: () => (
<Group>
<Button theme="@danger">Danger Button</Button>
<IconButton theme="@danger" aria-label="Remove"><HiMinus /></IconButton>
</Group>
),
};
export const Progress = {
render: () => (
<Group>
<VStack>
<Button variant="solid" colorScheme="brand">
Progress Button with Brand ColorScheme
</Button>
<Button variant="solid" colorScheme="error">
Progress Button with Error ColorScheme
</Button>
<Button variant="solid">
Button
</Button>
<IconButton
variant="solid"
theme="@danger"
aria-label="Remove"
><HiMinus /></IconButton>
</VStack>
</Group>
),
};

View File

@ -1,66 +0,0 @@
import { Box, Flex, FlexProps, HStack } from '@chakra-ui/react';
const Color = ({ children, ...rest }: FlexProps) => (
<Flex flex="1" h="16" p="2" {...rest}>
<Box
bg="white"
display="inline-block"
px="2"
py="1"
m="auto"
fontSize="xs"
fontWeight="bold"
borderRadius="md"
>
{children}
</Box>
</Flex>
);
const Colors = ({ colorScheme = 'gray', ...rest }) => (
<HStack
// spacing="0"
overflow="hidden"
boxShadow="lg"
color={`${colorScheme}.700`}
borderRadius="md"
{...rest}
>
<Color bg={`${colorScheme}.50`}>50</Color>
<Color bg={`${colorScheme}.100`}>100</Color>
<Color bg={`${colorScheme}.200`}>200</Color>
<Color bg={`${colorScheme}.300`}>300</Color>
<Color bg={`${colorScheme}.400`}>400</Color>
<Color bg={`${colorScheme}.500`}>500</Color>
<Color bg={`${colorScheme}.600`}>600</Color>
<Color bg={`${colorScheme}.700`}>700</Color>
<Color bg={`${colorScheme}.800`}>800</Color>
<Color bg={`${colorScheme}.900`}>900</Color>
</HStack>
);
const meta = {
title: 'StyleGuide/Colors',
};
export default meta;
export const Brand = {
render: () => <Colors colorScheme="brand" />,
};
export const Gray = {
render: () => <Colors colorScheme="gray" />,
};
export const Error = {
render: () => <Colors colorScheme="error" />,
};
export const Warning = {
render: () => <Colors colorScheme="warning" />,
};
export const Success = {
render: () => <Colors colorScheme="success" />,
};

View File

@ -1,4 +0,0 @@
import { Styles } from '@chakra-ui/theme-tools';
export const styles: Styles = {
};

View File

@ -1,8 +1,7 @@
import * as recipes from './recipes'; import * as recipes from './recipes';
import { createSystem, defaultConfig, mergeConfigs, SystemConfig } from "@chakra-ui/react"
import { colors } from "./foundations/colors" import { colors } from "./foundations/colors"
const baseTheme: SystemConfig = { const baseTheme = {
globalCss: { globalCss: {
body: { body: {
overflowY: 'none', overflowY: 'none',
@ -17,7 +16,6 @@ const baseTheme: SystemConfig = {
} }
}, },
theme: { theme: {
...recipes,
tokens: { tokens: {
fonts: { fonts: {
heading: { value: `Roboto, Helvetica, Arial, "sans-serif"` }, heading: { value: `Roboto, Helvetica, Arial, "sans-serif"` },
@ -40,5 +38,11 @@ const baseTheme: SystemConfig = {
}, },
}, },
}; };
/*
const config = mergeConfigs(defaultConfig, baseTheme); const config = mergeConfigs(defaultConfig, baseTheme);
export const systemTheme = createSystem(config); export const systemTheme = createSystem(config);
*/
export const THEME = {
...recipes
};

View File

@ -1,5 +1,3 @@
import { ThemeTypings } from '@chakra-ui/react';
import { colors } from '@/theme/foundations/colors'; import { colors } from '@/theme/foundations/colors';
export type ColorSchemes = ThemeTypings['colorSchemes'] | keyof typeof colors; export type ColorSchemes = ThemeTypings['colorSchemes'] | keyof typeof colors;

27
front/src/ui/Button.tsx Normal file
View File

@ -0,0 +1,27 @@
import { ReactNode, CSSProperties } from "react";
export type ButtonProps = {
children: ReactNode;
onClick?: () => void;
style?: CSSProperties;
};
export const Button = ({ children, onClick, style }: ButtonProps) => {
return (
<button
onClick={onClick}
style={{
padding: '10px 20px',
backgroundColor: '#3182CE',
color: '#FFF',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
fontSize: '16px',
...style,
}}
>
{children}
</button>
);
};

View File

@ -0,0 +1,9 @@
import { RestErrorResponse } from "@/back-api";
export const registerAnError = (error) => {
console.error(`Detect error: ${JSON.stringify(error, null, 2)}`);
}
export const registerAnApiError = (error: RestErrorResponse) => {
console.error(`Detect error: ${JSON.stringify(error, null, 2)}`);
}

29
front/src/ui/Flex.tsx Normal file
View File

@ -0,0 +1,29 @@
import React, { CSSProperties, ReactNode } from 'react';
export type FlexProps = {
children?: ReactNode;
onClick?: () => void;
direction?: 'row' | 'column';
gap?: string | number;
justify?: CSSProperties['justifyContent'];
align?: CSSProperties['alignItems'];
style?: Omit<CSSProperties, "flexDirection" | "display" | "justifyContent" | "alignItems" | "alignItems" | "direction">
};
export const Flex = ({ children, onClick, direction = 'row', justify = 'flex-start', gap, align = 'stretch', style }: FlexProps) => {
return (
<div
onClick={onClick}
style={{
display: 'flex',
flexDirection: direction,
justifyContent: justify,
gap: gap,
alignItems: align,
...style,
}}
>
{children}
</div>
);
};

22
front/src/ui/FullPage.tsx Normal file
View File

@ -0,0 +1,22 @@
import { ReactNode, CSSProperties } from "react";
export type FullPageProps = {
children: ReactNode;
style?: CSSProperties;
};
export const FullPage = ({ children, style }: FullPageProps) => {
return (
<div
style={{
top: '0',
bottom: '0',
right: '0',
left: '0',
...style,
}}
>
{children}
</div>
);
};

24
front/src/ui/HStack.tsx Normal file
View File

@ -0,0 +1,24 @@
import { ReactNode, CSSProperties } from "react";
export type HStackProps = {
children: ReactNode;
spacing?: CSSProperties['gap'];
align?: CSSProperties['alignItems'];
style?: Omit<CSSProperties, "gap" | "alignItems">;
};
export const HStack = ({ children, spacing = '8px', align = 'flex-start', style }: HStackProps) => {
return (
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: align,
gap: spacing,
...style,
}}
>
{children}
</div>
);
};

View File

@ -0,0 +1,9 @@
import { CSSProperties, ReactNode } from "react"
export type BodyProps = {
children?: ReactNode;
style?: CSSProperties;
};
export const Body = ({ children, style }: BodyProps) => {
return <tbody style={style}>{children}</tbody>
}

View File

@ -0,0 +1,9 @@
import { CSSProperties, ReactNode } from "react"
export type CellProps = {
children?: ReactNode;
style?: CSSProperties;
};
export const Cell = ({ children, style }: CellProps) => {
return <td style={style}>{children}</td>
}

View File

@ -0,0 +1,9 @@
import { CSSProperties, ReactNode } from "react"
export type ColumnHeaderProps = {
children?: ReactNode;
style?: CSSProperties;
};
export const ColumnHeader = ({ children, style }: ColumnHeaderProps) => {
return <th style={style}>{children}</th>
}

View File

@ -0,0 +1,9 @@
import { CSSProperties, ReactNode } from "react"
export type HeaderProps = {
children?: ReactNode;
style?: CSSProperties;
};
export const Header = ({ children, style }: HeaderProps) => {
return <thead style={style}>{children}</thead>
}

View File

@ -0,0 +1,6 @@
export { Body } from './body'
export { Cell } from './cell'
export { ColumnHeader } from './columnHeader'
export { Header } from './header'
export { Root } from './root'
export { Row } from './row'

View File

@ -0,0 +1,15 @@
import { CSSProperties, ReactNode } from 'react'
export type RootProps = {
children?: ReactNode;
background?: CSSProperties['backgroundColor'];
style?: CSSProperties;
}
export const Root = ({ background, children, style }: RootProps) => {
return (<table
style={{
backgroundColor: background,
...style
}}>{children}</table>);
}

View File

@ -0,0 +1,10 @@
import { CSSProperties, ReactNode } from "react"
export type RowProps = {
children?: ReactNode;
style?: CSSProperties;
};
export const Row = ({ children, style }: RowProps) => {
return <tr style={style}>{children}</tr>
}

29
front/src/ui/Text.tsx Normal file
View File

@ -0,0 +1,29 @@
import { ReactNode, CSSProperties } from "react";
export type TextProps = {
children: ReactNode;
color?: string;
fontSize?: CSSProperties["fontSize"];
fontWeight?: CSSProperties["fontWeight"];
style?: Omit<CSSProperties, "fontSize" | "fontWeight" | "color">;
};
export const Text = ({ children,
fontSize = '16px',
fontWeight = "normal",
color = "#000000",
style,
}: TextProps) => {
return (
<span
style={{
fontSize,
color,
fontWeight,
...style,
}}
>
{children}
</span>
);
};

24
front/src/ui/VStack.tsx Normal file
View File

@ -0,0 +1,24 @@
import { ReactNode, CSSProperties } from "react";
export type VStackProps = {
children: ReactNode;
spacing?: CSSProperties['gap'];
align?: CSSProperties['alignItems'];
style?: Omit<CSSProperties, "gap" | "alignItems">;
};
export const VStack = ({ children, spacing = '8px', align = 'flex-start', style }: VStackProps) => {
return (
<div
style={{
display: 'flex',
flexDirection: 'row',
alignItems: align,
gap: spacing,
...style,
}}
>
{children}
</div>
);
};

7
front/src/ui/index.tsx Normal file
View File

@ -0,0 +1,7 @@
export * from "./Button.tsx"
export * from "./Text.tsx"
export * from "./Flex.tsx"
export * from "./HStack.tsx"
export * from "./VStack.tsx"
export * from "./FullPage.tsx"
export * as Table from "./Table"

View File

@ -7,7 +7,7 @@ import { DependencyList, useCallback, useEffect, useState } from 'react';
import { RestErrorResponse } from '@/back-api'; import { RestErrorResponse } from '@/back-api';
import { isNullOrUndefined } from '@/utils/validator'; import { isNullOrUndefined } from '@/utils/validator';
import { toasterAPIError } from '@/components/ui/toaster'; import { registerAnApiError } from '@/ui/ErrorManager';
export type DataStoreType<TYPE> = { export type DataStoreType<TYPE> = {
isLoading: boolean; isLoading: boolean;
@ -57,7 +57,7 @@ export const useDataStore = <TYPE>(
setIsLoading(false); setIsLoading(false);
}) })
.catch((error: RestErrorResponse) => { .catch((error: RestErrorResponse) => {
toasterAPIError(error); registerAnApiError(error);
console.log( console.log(
`[${restApiName}] catch error: ${JSON.stringify(error, null, 2)}` `[${restApiName}] catch error: ${JSON.stringify(error, null, 2)}`
); );
@ -116,7 +116,7 @@ export const useDataStore = <TYPE>(
resolve(responseData); resolve(responseData);
}) })
.catch((error: RestErrorResponse) => { .catch((error: RestErrorResponse) => {
toasterAPIError(error); registerAnAPIError(error);
rejects(error); rejects(error);
}); });
}); });
@ -134,7 +134,7 @@ export const useDataStore = <TYPE>(
setData(filterData); setData(filterData);
}) })
.catch((error) => { .catch((error) => {
toasterAPIError(error); registerAnApiError(error);
console.log( console.log(
`catch an error on delete: ... ${JSON.stringify(error, null, 2)}` `catch an error on delete: ... ${JSON.stringify(error, null, 2)}`
); );
@ -145,3 +145,7 @@ export const useDataStore = <TYPE>(
return { isLoading, error, data, get, gets, update, updateRaw, remove }; return { isLoading, error, data, get, gets, update, updateRaw, remove };
}; };
function registerAnAPIError(error: { name: string; message: string; time: string; status: number; statusMessage: string; oid?: string | undefined; }) {
throw new Error('Function not implemented.');
}

View File

@ -0,0 +1,18 @@
import { useState, useCallback } from "react";
export interface UseDisclosureReturn {
open: boolean;
onOpen: () => void;
onClose: () => void;
onToggle: () => void;
}
export function useDisclosure(initialState = false): UseDisclosureReturn {
const [open, setOpen] = useState(initialState);
const onOpen = useCallback(() => setOpen(true), []);
const onClose = useCallback(() => setOpen(false), []);
const onToggle = useCallback(() => setOpen((prev) => !prev), []);
return { open, onOpen, onClose, onToggle };
}

View File

@ -1,12 +1,9 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useBreakpointValue } from '@chakra-ui/react';
import { useWindowSize } from 'react-use'; import { useWindowSize } from 'react-use';
export const isBrowser: boolean = typeof window !== 'undefined'; export const isBrowser: boolean = typeof window !== 'undefined';
export const useIsMobile = () => useBreakpointValue({ base: true, md: false });
export const useIsLandscape = (): { isLandscape: boolean } => { export const useIsLandscape = (): { isLandscape: boolean } => {
const [isLandscape, setIsLandscape] = useState(false); const [isLandscape, setIsLandscape] = useState(false);
const windowsSize = useWindowSize(); const windowsSize = useWindowSize();