[FEAT] add many basic element, ux bad but build is OK
This commit is contained in:
parent
f9019ec508
commit
12223347d3
@ -29,6 +29,7 @@
|
|||||||
"*.{ts,tsx,js,jsx,json}": "prettier --write"
|
"*.{ts,tsx,js,jsx,json}": "prettier --write"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"history": "5.3.0",
|
||||||
"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",
|
||||||
|
10
front/pnpm-lock.yaml
generated
10
front/pnpm-lock.yaml
generated
@ -8,6 +8,9 @@ importers:
|
|||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
history:
|
||||||
|
specifier: 5.3.0
|
||||||
|
version: 5.3.0
|
||||||
react:
|
react:
|
||||||
specifier: 18.3.1
|
specifier: 18.3.1
|
||||||
version: 18.3.1
|
version: 18.3.1
|
||||||
@ -2372,6 +2375,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
history@5.3.0:
|
||||||
|
resolution: {integrity: sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==}
|
||||||
|
|
||||||
hoist-non-react-statics@3.3.2:
|
hoist-non-react-statics@3.3.2:
|
||||||
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
|
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
|
||||||
|
|
||||||
@ -6820,6 +6826,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
function-bind: 1.1.2
|
function-bind: 1.1.2
|
||||||
|
|
||||||
|
history@5.3.0:
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.24.7
|
||||||
|
|
||||||
hoist-non-react-statics@3.3.2:
|
hoist-non-react-statics@3.3.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
react-is: 16.13.1
|
react-is: 16.13.1
|
||||||
|
@ -22,7 +22,7 @@ import { useSpecificArtists } from '@/service/Artist';
|
|||||||
import { useSpecificGender } from '@/service/Gender';
|
import { useSpecificGender } from '@/service/Gender';
|
||||||
import { useSpecificTrack } from '@/service/Track';
|
import { useSpecificTrack } from '@/service/Track';
|
||||||
import { DataUrlAccess } from '@/utils/data-url-access';
|
import { DataUrlAccess } from '@/utils/data-url-access';
|
||||||
import { useColorModeValue } from '@/components/ui/color-mode';
|
import { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
import { isNullOrUndefined } from '@/utils/validator';
|
import { isNullOrUndefined } from '@/utils/validator';
|
||||||
import { Icon } from './Icon';
|
import { Icon } from './Icon';
|
||||||
import { Flex, Text } from '@/ui';
|
import { Flex, Text } from '@/ui';
|
||||||
@ -77,7 +77,7 @@ export const AudioPlayer = ({ }: AudioPlayerProps) => {
|
|||||||
: ''
|
: ''
|
||||||
);
|
);
|
||||||
}, [dataTrack, setMediaSource]);
|
}, [dataTrack, setMediaSource]);
|
||||||
const backColor = useColorModeValue('back.100', 'back.800');
|
const backColor = useColorThemeValue('back.100', 'back.800');
|
||||||
const configButton = {
|
const configButton = {
|
||||||
borderRadius: 'full',
|
borderRadius: 'full',
|
||||||
backgroundColor: '#00000000',
|
backgroundColor: '#00000000',
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import { ReactElement, useEffect, useState } from 'react';
|
import { CSSProperties, ReactElement, useEffect, useState } from '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';
|
import { DivProps, Flex } from '@/ui';
|
||||||
|
|
||||||
export type CoversProps = Omit<BoxProps, "iconEmpty"> & {
|
export type CoversProps = Omit<DivProps, "iconEmpty"> & {
|
||||||
data?: ObjectId[];
|
data?: ObjectId[];
|
||||||
size?: BoxProps["width"];
|
size?: CSSProperties["width"];
|
||||||
iconEmpty?: ReactElement;
|
iconEmpty?: ReactElement;
|
||||||
slideshow?: boolean;
|
slideshow?: boolean;
|
||||||
};
|
};
|
||||||
|
@ -4,6 +4,7 @@ import { useLocation } from 'react-router-dom';
|
|||||||
|
|
||||||
import background from '@/assets/images/ikon.svg';
|
import background from '@/assets/images/ikon.svg';
|
||||||
import { TOP_BAR_HEIGHT } from '@/components/TopBar/TopBar';
|
import { TOP_BAR_HEIGHT } from '@/components/TopBar/TopBar';
|
||||||
|
import { Flex } from '@/ui';
|
||||||
|
|
||||||
export type LayoutProps = React.PropsWithChildren<unknown> & {
|
export type LayoutProps = React.PropsWithChildren<unknown> & {
|
||||||
topBar?: ReactNode;
|
topBar?: ReactNode;
|
||||||
@ -19,30 +20,33 @@ export const PageLayout = ({ children }: LayoutProps) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Flex
|
<Flex
|
||||||
minH={`calc(100vh - ${TOP_BAR_HEIGHT})`}
|
style={{
|
||||||
maxH={`calc(100vh - ${TOP_BAR_HEIGHT})`}
|
position: "absolute",
|
||||||
position="absolute"
|
minHeight: `calc(100vh - ${TOP_BAR_HEIGHT})`,
|
||||||
top={TOP_BAR_HEIGHT}
|
maxHeight: `calc(100vh - ${TOP_BAR_HEIGHT})`,
|
||||||
bottom={0}
|
top: TOP_BAR_HEIGHT,
|
||||||
left={0}
|
bottom: 0,
|
||||||
right={0}
|
left: 0,
|
||||||
minWidth="300px"
|
right: 0,
|
||||||
zIndex={-1}
|
minWidth: "300px",
|
||||||
|
zIndex: -1,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Image src={background} boxSize="90%" margin="auto" opacity="30%" />
|
{/* <Image src={background} boxSize="90%" margin="auto" opacity="30%" /> */}
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
overflowX="auto"
|
style={{
|
||||||
overflowY="auto"
|
overflow: "auto",
|
||||||
minH={`calc(100vh - ${TOP_BAR_HEIGHT})`}
|
minHeight: `calc(100vh - ${TOP_BAR_HEIGHT})`,
|
||||||
maxH={`calc(100vh - ${TOP_BAR_HEIGHT})`}
|
maxHeight: `calc(100vh - ${TOP_BAR_HEIGHT})`,
|
||||||
position="absolute"
|
position: "absolute",
|
||||||
top={TOP_BAR_HEIGHT}
|
top: TOP_BAR_HEIGHT,
|
||||||
bottom={0}
|
bottom: 0,
|
||||||
left={0}
|
left: 0,
|
||||||
right={0}
|
right: 0,
|
||||||
minWidth="300px"
|
minWidth: "300px",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
import React, { ReactNode, useEffect } from 'react';
|
import { CSSProperties, useEffect } from 'react';
|
||||||
|
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
import { PageLayout } from '@/components/Layout/PageLayout';
|
import { PageLayout } from '@/components/Layout/PageLayout';
|
||||||
import { colors } from '@/theme/foundations/colors';
|
import { colors } from '@/theme/colors';
|
||||||
import { useColorModeValue } from '@/components/ui/color-mode';
|
import { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
|
import { Flex, FlexProps } from '@/ui';
|
||||||
|
|
||||||
export type LayoutProps = FlexProps & {
|
export type LayoutProps = FlexProps & {
|
||||||
children: ReactNode;
|
width?: CSSProperties['width'];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PageLayoutInfoCenter = ({
|
export const PageLayoutInfoCenter = ({
|
||||||
children,
|
children,
|
||||||
width = '25%',
|
width = "75%",
|
||||||
|
style,
|
||||||
...rest
|
...rest
|
||||||
}: LayoutProps) => {
|
}: LayoutProps) => {
|
||||||
const { pathname } = useLocation();
|
const { pathname } = useLocation();
|
||||||
@ -25,14 +27,17 @@ export const PageLayoutInfoCenter = ({
|
|||||||
<PageLayout>
|
<PageLayout>
|
||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
margin="auto"
|
style={{
|
||||||
minWidth={width}
|
margin: "auto",
|
||||||
border="back.900"
|
width,
|
||||||
borderWidth="1px"
|
border: "back.900",
|
||||||
borderRadius="8px"
|
borderWidth: "1px",
|
||||||
padding="10px"
|
borderRadius: "8px",
|
||||||
boxShadow={'0px 0px 16px ' + colors.back[900]}
|
padding: "10px",
|
||||||
backgroundColor={useColorModeValue('#FFFFFF', '#000000')}
|
boxShadow: '0px 0px 16px ' + colors.back[900],
|
||||||
|
backgroundColor: useColorThemeValue('#FFFFFF', '#000000'),
|
||||||
|
...style
|
||||||
|
}}
|
||||||
{...rest}
|
{...rest}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
@ -38,15 +38,15 @@ export const SearchInput = ({
|
|||||||
onSubmitValue(inputData);
|
onSubmitValue(inputData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (
|
return (<></>
|
||||||
<Group maxWidth="200px" marginLeft="auto" {...searchInputProperty}>
|
//<Group maxWidth="200px" marginLeft="auto" {...searchInputProperty}>
|
||||||
<MdSearch color="gray.300" />
|
// <MdSearch color="gray.300" />
|
||||||
<Input
|
// <Input
|
||||||
onFocus={onFocusKeep}
|
// onFocus={onFocusKeep}
|
||||||
onBlur={() => setTimeout(() => onFocusLost(), 200)}
|
// onBlur={() => setTimeout(() => onFocusLost(), 200)}
|
||||||
onChange={onChange}
|
// onChange={onChange}
|
||||||
onSubmit={onSubmit}
|
// onSubmit={onSubmit}
|
||||||
/>
|
// />
|
||||||
</Group>
|
//</Group>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -14,12 +14,11 @@ import { useNavigate } from 'react-router-dom';
|
|||||||
|
|
||||||
import { useServiceContext } from '@/service/ServiceContext';
|
import { useServiceContext } from '@/service/ServiceContext';
|
||||||
import { SessionState } from '@/service/SessionState';
|
import { SessionState } from '@/service/SessionState';
|
||||||
import { colors } from '@/theme/foundations/colors';
|
import { colors } from '@/theme/colors';
|
||||||
import { requestSignIn, requestSignOut, requestSignUp } from '@/utils/sso';
|
import { requestSignIn, requestSignOut, requestSignUp } from '@/utils/sso';
|
||||||
import { useSessionService } from '@/service/session';
|
import { useSessionService } from '@/service/session';
|
||||||
import { MdHelp, MdHome, MdMore, MdOutlinePlaylistPlay, MdOutlineUploadFile, MdSupervisedUserCircle } from 'react-icons/md';
|
import { MdHelp, MdHome, MdMore, MdOutlinePlaylistPlay, MdOutlineUploadFile, MdSupervisedUserCircle } from 'react-icons/md';
|
||||||
import { useColorMode, useColorModeValue } from '@/components/ui/color-mode';
|
import { useColorThemeValue, useTheme } from '@/theme/ThemeContext';
|
||||||
import { THEME } from '@/theme/theme';
|
|
||||||
import { useDisclosure } from '@/utils/disclosure';
|
import { useDisclosure } from '@/utils/disclosure';
|
||||||
import { Button, Flex, Text } from '@/ui';
|
import { Button, Flex, Text } from '@/ui';
|
||||||
|
|
||||||
@ -36,11 +35,11 @@ export type TopBarProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const TopBar = ({ title, children }: TopBarProps) => {
|
export const TopBar = ({ title, children }: TopBarProps) => {
|
||||||
const { colorMode, toggleColorMode } = useColorMode();
|
const { theme, toggleTheme } = useTheme();
|
||||||
const { clearToken } = useSessionService();
|
const { clearToken } = useSessionService();
|
||||||
|
|
||||||
const { session } = useServiceContext();
|
const { session } = useServiceContext();
|
||||||
const backColor = useColorModeValue('back.100', 'back.800');
|
const backColor = useColorThemeValue('back.100', 'back.800');
|
||||||
const drawerDisclose = useDisclosure();
|
const drawerDisclose = useDisclosure();
|
||||||
const onChangeTheme = () => {
|
const onChangeTheme = () => {
|
||||||
drawerDisclose.onOpen();
|
drawerDisclose.onOpen();
|
||||||
@ -113,7 +112,7 @@ export const TopBar = ({ title, children }: TopBarProps) => {
|
|||||||
<Flex style={{ right: 0 }}>
|
<Flex style={{ right: 0 }}>
|
||||||
{session?.state !== SessionState.CONNECTED && (
|
{session?.state !== SessionState.CONNECTED && (
|
||||||
<>
|
<>
|
||||||
<Button {...BUTTON_TOP_BAR_PROPERTY} {...THEME.Button.primary} onClick={onSignIn}>
|
<Button {...BUTTON_TOP_BAR_PROPERTY} /*{...THEME.Button.primary}*/ onClick={onSignIn}>
|
||||||
<LuLogIn />
|
<LuLogIn />
|
||||||
<Text style={{ paddingLeft: "0 0 0 3px" }} fontWeight="bold">
|
<Text style={{ paddingLeft: "0 0 0 3px" }} fontWeight="bold">
|
||||||
Sign-in
|
Sign-in
|
||||||
|
@ -5,6 +5,8 @@ import { Album } from '@/back-api';
|
|||||||
import { Covers } from '@/components/Cover';
|
import { Covers } from '@/components/Cover';
|
||||||
import { useCountTracksWithAlbumId } from '@/service/Track';
|
import { useCountTracksWithAlbumId } from '@/service/Track';
|
||||||
import { BASE_WRAP_ICON_SIZE } from '@/constants/genericSpacing';
|
import { BASE_WRAP_ICON_SIZE } from '@/constants/genericSpacing';
|
||||||
|
import { Flex, Text } from '@/ui';
|
||||||
|
import { Span } from '@/ui/Span';
|
||||||
|
|
||||||
export type DisplayAlbumProps = {
|
export type DisplayAlbumProps = {
|
||||||
dataAlbum?: Album;
|
dataAlbum?: Album;
|
||||||
@ -33,32 +35,37 @@ export const DisplayAlbum = ({ dataAlbum }: DisplayAlbumProps) => {
|
|||||||
//maxWidth="150px"
|
//maxWidth="150px"
|
||||||
height="full"
|
height="full"
|
||||||
paddingLeft="5px"
|
paddingLeft="5px"
|
||||||
overflowX="hidden"
|
style={{
|
||||||
flex={1}
|
marginRight: "auto",
|
||||||
|
overflow: "hidden",
|
||||||
|
flex: 1,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Text
|
<Span
|
||||||
as="span"
|
|
||||||
// align="left"
|
// align="left"
|
||||||
fontSize="20px"
|
fontSize="20px"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
userSelect="none"
|
userSelect="none"
|
||||||
marginRight="auto"
|
style={{
|
||||||
overflow="hidden"
|
marginRight: "auto",
|
||||||
|
overflow: "hidden",
|
||||||
|
}}
|
||||||
// noOfLines={[1, 2]}
|
// noOfLines={[1, 2]}
|
||||||
>
|
>
|
||||||
{dataAlbum?.name}
|
{dataAlbum?.name}
|
||||||
</Text>
|
</Span>
|
||||||
<Text
|
<Span
|
||||||
as="span"
|
|
||||||
// align="left"
|
// align="left"
|
||||||
fontSize="15px"
|
fontSize="15px"
|
||||||
userSelect="none"
|
userSelect="none"
|
||||||
marginRight="auto"
|
style={{
|
||||||
overflow="hidden"
|
marginRight: "auto",
|
||||||
|
overflow: "hidden",
|
||||||
|
}}
|
||||||
// noOfLines={1}
|
// noOfLines={1}
|
||||||
>
|
>
|
||||||
{countTracksOfAnAlbum} track{countTracksOfAnAlbum >= 1 && 's'}
|
{countTracksOfAnAlbum} track{countTracksOfAnAlbum >= 1 && 's'}
|
||||||
</Text>
|
</Span>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
import { LuMenu } from 'react-icons/lu';
|
import { LuMenu } from 'react-icons/lu';
|
||||||
import { THEME } from '@/theme/theme';
|
|
||||||
|
|
||||||
export type MenuElement = {
|
export type MenuElement = {
|
||||||
name: string;
|
name: string;
|
||||||
@ -12,28 +12,28 @@ export type ContextMenuProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const ContextMenu = ({ elements }: ContextMenuProps) => {
|
export const ContextMenu = ({ elements }: ContextMenuProps) => {
|
||||||
if (!elements) {
|
// if (!elements) {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
// }
|
||||||
return (
|
// return (
|
||||||
<Menu.Root
|
// <Menu.Root
|
||||||
data-testid="context-menu">
|
// data-testid="context-menu">
|
||||||
<Menu.Trigger 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.Button.primary} >
|
// <Button {...THEME.Button.primary} >
|
||||||
<LuMenu />
|
// <LuMenu />
|
||||||
</Button>
|
// </Button>
|
||||||
</Menu.Trigger>
|
// </Menu.Trigger>
|
||||||
<Menu.Content
|
// <Menu.Content
|
||||||
data-testid="context-menu_content">
|
// data-testid="context-menu_content">
|
||||||
{elements?.map((data) => (
|
// {elements?.map((data) => (
|
||||||
<Menu.Item 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}
|
||||||
</Menu.Item>
|
// </Menu.Item>
|
||||||
))}
|
// ))}
|
||||||
</Menu.Content>
|
// </Menu.Content>
|
||||||
</Menu.Root >
|
// </Menu.Root >
|
||||||
);
|
//);
|
||||||
};
|
};
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { Flex, Text } from '@/ui';
|
||||||
|
import { Span } from '@/ui/Span';
|
||||||
import { ReactNode } from 'react';
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
import { MdErrorOutline, MdHelpOutline, MdRefresh } from 'react-icons/md';
|
import { MdErrorOutline, MdHelpOutline, MdRefresh } from 'react-icons/md';
|
||||||
@ -22,20 +24,22 @@ export const FormGroup = ({
|
|||||||
onRestore,
|
onRestore,
|
||||||
}: FormGroupProps) => (
|
}: FormGroupProps) => (
|
||||||
<Flex
|
<Flex
|
||||||
borderLeftWidth="3px"
|
style={{
|
||||||
borderLeftColor={error ? 'red' : isModify ? 'blue' : '#00000000'}
|
borderLeftWidth: "3px",
|
||||||
|
borderLeftColor: error ? 'red' : isModify ? 'blue' : '#00000000',
|
||||||
|
}}
|
||||||
paddingLeft="7px"
|
paddingLeft="7px"
|
||||||
paddingY="4px"
|
padding="0 4px"
|
||||||
direction="column"
|
direction="column"
|
||||||
>
|
>
|
||||||
<Flex direction="row" width="full" gap="52px">
|
<Flex direction="row" width="full" gap="52px">
|
||||||
{!!label && (
|
{!!label && (
|
||||||
<Text marginRight="auto" fontWeight="bold">
|
<Text style={{ marginRight: "auto" }} fontWeight="bold">
|
||||||
{label}{' '}
|
{label}{' '}
|
||||||
{isRequired && (
|
{isRequired && (
|
||||||
<Text as="span" color="red.600">
|
<Span color="red.600">
|
||||||
*
|
*
|
||||||
</Text>
|
</Span>
|
||||||
)}
|
)}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
|
@ -2,6 +2,7 @@ import { RefObject } from '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';
|
||||||
|
import { Input } from '@/ui';
|
||||||
|
|
||||||
export type FormInputProps = {
|
export type FormInputProps = {
|
||||||
form: UseFormidableReturn;
|
form: UseFormidableReturn;
|
||||||
|
@ -33,7 +33,8 @@ export const FormNumber = ({
|
|||||||
onRestore={() => form.restoreValue({ [variableName]: true })}
|
onRestore={() => form.restoreValue({ [variableName]: true })}
|
||||||
{...rest}
|
{...rest}
|
||||||
>
|
>
|
||||||
<NumberInput.Root
|
<></>
|
||||||
|
{/* <NumberInput.Root
|
||||||
ref={ref}
|
ref={ref}
|
||||||
value={form.values[variableName]}
|
value={form.values[variableName]}
|
||||||
onValueChange={(value) => form.setValues({ [variableName]: value })}
|
onValueChange={(value) => form.setValues({ [variableName]: value })}
|
||||||
@ -43,7 +44,7 @@ export const FormNumber = ({
|
|||||||
max={max}
|
max={max}
|
||||||
>
|
>
|
||||||
<NumberInput.Input />
|
<NumberInput.Input />
|
||||||
</NumberInput.Root>
|
</NumberInput.Root> */}
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -4,6 +4,7 @@ import { LuDisc3 } from 'react-icons/lu';
|
|||||||
import { Gender } from '@/back-api';
|
import { Gender } from '@/back-api';
|
||||||
import { Covers } from '@/components/Cover';
|
import { Covers } from '@/components/Cover';
|
||||||
import { useCountTracksOfAGender } from '@/service/Track';
|
import { useCountTracksOfAGender } from '@/service/Track';
|
||||||
|
import { Flex, Span, Text } from '@/ui';
|
||||||
|
|
||||||
export type DisplayGenderProps = {
|
export type DisplayGenderProps = {
|
||||||
dataGender?: Gender;
|
dataGender?: Gender;
|
||||||
@ -31,31 +32,36 @@ export const DisplayGender = ({ dataGender }: DisplayGenderProps) => {
|
|||||||
maxWidth="150px"
|
maxWidth="150px"
|
||||||
height="full"
|
height="full"
|
||||||
paddingLeft="5px"
|
paddingLeft="5px"
|
||||||
overflowX="hidden"
|
style={{
|
||||||
|
overflowX: "hidden"
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Text
|
<Span
|
||||||
as="span"
|
|
||||||
alignContent="left"
|
|
||||||
fontSize="20px"
|
fontSize="20px"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
userSelect="none"
|
style={{
|
||||||
marginRight="auto"
|
userSelect: "none",
|
||||||
overflow="hidden"
|
marginRight: "auto",
|
||||||
|
overflow: "hidden",
|
||||||
|
alignContent: "left",
|
||||||
|
}}
|
||||||
|
|
||||||
//TODO: noOfLines={[1, 2]}
|
//TODO: noOfLines={[1, 2]}
|
||||||
>
|
>
|
||||||
{dataGender?.name}
|
{dataGender?.name}
|
||||||
</Text>
|
</Span>
|
||||||
<Text
|
<Span
|
||||||
as="span"
|
|
||||||
alignContent="left"
|
|
||||||
fontSize="15px"
|
fontSize="15px"
|
||||||
userSelect="none"
|
style={{
|
||||||
marginRight="auto"
|
userSelect: "none",
|
||||||
overflow="hidden"
|
marginRight: "auto",
|
||||||
|
overflow: "hidden",
|
||||||
|
alignContent: "left",
|
||||||
|
}}
|
||||||
//TODO: noOfLines={1}
|
//TODO: noOfLines={1}
|
||||||
>
|
>
|
||||||
{countTracksOnAGender} track{countTracksOnAGender >= 1 && 's'}
|
{countTracksOnAGender} track{countTracksOnAGender >= 1 && 's'}
|
||||||
</Text>
|
</Span>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
|
@ -128,109 +128,110 @@ export const AlbumEditPopUp = ({ }: AlbumEditPopUpProps) => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
return (
|
return <></>;
|
||||||
<Dialog.Root
|
// return (
|
||||||
//initialFocusRef={initialRef}
|
// <Dialog.Root
|
||||||
//finalFocusRef={finalRef}
|
// //initialFocusRef={initialRef}
|
||||||
//closeOnOverlayClick={false}
|
// //finalFocusRef={finalRef}
|
||||||
onOpenChange={onClose}
|
// //closeOnOverlayClick={false}
|
||||||
open={true}
|
// onOpenChange={onClose}
|
||||||
data-testid="album-edit-pop-up"
|
// open={true}
|
||||||
>
|
// data-testid="album-edit-pop-up"
|
||||||
{/* <DialogOverlay /> */}
|
// >
|
||||||
{/* <DialogCloseTrigger /> */}
|
// {/* <DialogOverlay /> */}
|
||||||
<Dialog.Content>
|
// {/* <DialogCloseTrigger /> */}
|
||||||
<Dialog.Header>Edit Album</Dialog.Header>
|
// <Dialog.Content>
|
||||||
{/* <DialogCloseButton ref={finalRef} /> */}
|
// <Dialog.Header>Edit Album</Dialog.Header>
|
||||||
|
// {/* <DialogCloseButton ref={finalRef} /> */}
|
||||||
|
|
||||||
<Dialog.Body 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>{dataAlbum?.id}</Text>
|
// <Text>{dataAlbum?.id}</Text>
|
||||||
</FormGroup>
|
// </FormGroup>
|
||||||
{countTracksOfAnAlbum !== 0 && (
|
// {countTracksOfAnAlbum !== 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 album {countTracksOfAnAlbum} track(s) depend
|
// Can not remove album {countTracksOfAnAlbum} track(s) depend
|
||||||
on it.
|
// 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={countTracksOfAnAlbum !== 0}
|
// disabled={countTracksOfAnAlbum !== 0}
|
||||||
>
|
// >
|
||||||
<MdDeleteForever /> Remove Media
|
// <MdDeleteForever /> Remove Media
|
||||||
</Button>
|
// </Button>
|
||||||
</FormGroup>
|
// </FormGroup>
|
||||||
<ConfirmPopUp
|
// <ConfirmPopUp
|
||||||
disclosure={disclosure}
|
// disclosure={disclosure}
|
||||||
title="Remove album"
|
// title="Remove album"
|
||||||
body={`Remove Album [${dataAlbum?.id}] ${dataAlbum?.name}`}
|
// body={`Remove Album [${dataAlbum?.id}] ${dataAlbum?.name}`}
|
||||||
confirmTitle="Remove"
|
// confirmTitle="Remove"
|
||||||
onConfirm={onRemove}
|
// onConfirm={onRemove}
|
||||||
/>
|
// />
|
||||||
</>
|
// </>
|
||||||
)}
|
// )}
|
||||||
{!admin && (
|
// {!admin && (
|
||||||
<>
|
// <>
|
||||||
<FormInput
|
// <FormInput
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="name"
|
// variableName="name"
|
||||||
isRequired
|
// isRequired
|
||||||
label="Title"
|
// label="Title"
|
||||||
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="publication"
|
// variableName="publication"
|
||||||
label="Publication"
|
// label="Publication"
|
||||||
/>
|
// />
|
||||||
<FormCovers
|
// <FormCovers
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="covers"
|
// variableName="covers"
|
||||||
onFilesSelected={onFilesSelected}
|
// onFilesSelected={onFilesSelected}
|
||||||
onUriSelected={onUriSelected}
|
// onUriSelected={onUriSelected}
|
||||||
onRemove={onRemoveCover}
|
// onRemove={onRemoveCover}
|
||||||
/>
|
// />
|
||||||
</>
|
// </>
|
||||||
)}
|
// )}
|
||||||
</Dialog.Body>
|
// </Dialog.Body>
|
||||||
<Dialog.Footer>
|
// <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>
|
||||||
</Dialog.Footer>
|
// </Dialog.Footer>
|
||||||
</Dialog.Content>
|
// </Dialog.Content>
|
||||||
</Dialog.Root>
|
// </Dialog.Root>
|
||||||
);
|
// );
|
||||||
};
|
};
|
||||||
|
@ -23,29 +23,28 @@ export const ConfirmPopUp = ({
|
|||||||
disclosure.onClose();
|
disclosure.onClose();
|
||||||
};
|
};
|
||||||
const cancelRef = useRef<HTMLButtonElement>(null);
|
const cancelRef = useRef<HTMLButtonElement>(null);
|
||||||
return (
|
return <></>;
|
||||||
<Dialog.Root role="alertdialog"
|
// return (
|
||||||
open={disclosure.open}
|
// <Dialog.Root role="alertdialog"
|
||||||
//leastDestructiveRef={cancelRef}
|
// open={disclosure.open}
|
||||||
onOpenChange={disclosure.onClose}
|
// //leastDestructiveRef={cancelRef}
|
||||||
data-testid="confirm-pop-up"
|
// onOpenChange={disclosure.onClose}
|
||||||
>
|
// data-testid="confirm-pop-up"
|
||||||
<Dialog.Content>
|
// >
|
||||||
<Dialog.Header fontSize="lg" fontWeight="bold">
|
// <Dialog.Content>
|
||||||
{title}
|
// <Dialog.Header fontSize="lg" fontWeight="bold">
|
||||||
</Dialog.Header>
|
// {title}
|
||||||
|
// </Dialog.Header>
|
||||||
<Dialog.Body>{body}</Dialog.Body>
|
// <Dialog.Body>{body}</Dialog.Body>
|
||||||
|
// <Dialog.Footer>
|
||||||
<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>
|
// </Dialog.Footer>
|
||||||
</Dialog.Footer>
|
// </Dialog.Content>
|
||||||
</Dialog.Content>
|
// </Dialog.Root>
|
||||||
</Dialog.Root>
|
// );
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
@ -128,103 +128,104 @@ export const GenderEditPopUp = ({ }: GenderEditPopUpProps) => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
return (
|
return <></>;
|
||||||
<Dialog.Root
|
// return (
|
||||||
//initialFocusRef={initialRef}
|
// <Dialog.Root
|
||||||
//finalFocusRef={finalRef}
|
// //initialFocusRef={initialRef}
|
||||||
//closeOnOverlayClick={false}
|
// //finalFocusRef={finalRef}
|
||||||
onOpenChange={onClose}
|
// //closeOnOverlayClick={false}
|
||||||
open={true}
|
// onOpenChange={onClose}
|
||||||
data-testid="gender-edit-pop-up"
|
// open={true}
|
||||||
>
|
// data-testid="gender-edit-pop-up"
|
||||||
{/* <DialogOverlay /> */}
|
// >
|
||||||
<Dialog.Content>
|
// {/* <DialogOverlay /> */}
|
||||||
<Dialog.Header>Edit Gender</Dialog.Header>
|
// <Dialog.Content>
|
||||||
{/* <DialogCloseButton ref={finalRef} /> */}
|
// <Dialog.Header>Edit Gender</Dialog.Header>
|
||||||
|
// {/* <DialogCloseButton ref={finalRef} /> */}
|
||||||
|
|
||||||
<Dialog.Body 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>{dataGender?.id}</Text>
|
// <Text>{dataGender?.id}</Text>
|
||||||
</FormGroup>
|
// </FormGroup>
|
||||||
{countTracksOnAGender !== 0 && (
|
// {countTracksOnAGender !== 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 gender {countTracksOnAGender} track(s) depend
|
// Can not remove gender {countTracksOnAGender} track(s) depend
|
||||||
on it.
|
// 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={countTracksOnAGender !== 0}
|
// disabled={countTracksOnAGender !== 0}
|
||||||
>
|
// >
|
||||||
<MdDeleteForever /> Remove gender
|
// <MdDeleteForever /> Remove gender
|
||||||
</Button>
|
// </Button>
|
||||||
</FormGroup>
|
// </FormGroup>
|
||||||
<ConfirmPopUp
|
// <ConfirmPopUp
|
||||||
disclosure={disclosure}
|
// disclosure={disclosure}
|
||||||
title="Remove gender"
|
// title="Remove gender"
|
||||||
body={`Remove gender [${dataGender?.id}] ${dataGender?.name}`}
|
// body={`Remove gender [${dataGender?.id}] ${dataGender?.name}`}
|
||||||
confirmTitle="Remove"
|
// confirmTitle="Remove"
|
||||||
onConfirm={onRemove}
|
// onConfirm={onRemove}
|
||||||
/>
|
// />
|
||||||
</>
|
// </>
|
||||||
)}
|
// )}
|
||||||
{!admin && (
|
// {!admin && (
|
||||||
<>
|
// <>
|
||||||
<FormInput
|
// <FormInput
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="name"
|
// variableName="name"
|
||||||
isRequired
|
// isRequired
|
||||||
label="Gender name"
|
// label="Gender name"
|
||||||
ref={initialRef}
|
// ref={initialRef}
|
||||||
/>
|
// />
|
||||||
<FormTextarea
|
// <FormTextarea
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="description"
|
// variableName="description"
|
||||||
label="Description"
|
// label="Description"
|
||||||
/>
|
// />
|
||||||
<FormCovers
|
// <FormCovers
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="covers"
|
// variableName="covers"
|
||||||
onFilesSelected={onFilesSelected}
|
// onFilesSelected={onFilesSelected}
|
||||||
onUriSelected={onUriSelected}
|
// onUriSelected={onUriSelected}
|
||||||
onRemove={onRemoveCover}
|
// onRemove={onRemoveCover}
|
||||||
/>
|
// />
|
||||||
</>
|
// </>
|
||||||
)}
|
// )}
|
||||||
</Dialog.Body>
|
// </Dialog.Body>
|
||||||
<Dialog.Footer>
|
// <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>
|
||||||
</Dialog.Footer>
|
// </Dialog.Footer>
|
||||||
</Dialog.Content>
|
// </Dialog.Content>
|
||||||
</Dialog.Root>
|
// </Dialog.Root>
|
||||||
);
|
// );
|
||||||
};
|
};
|
||||||
|
@ -32,64 +32,66 @@ export const PopUpUploadProgress = ({
|
|||||||
}: PopUpUploadProgressProps) => {
|
}: PopUpUploadProgressProps) => {
|
||||||
const initialRef = useRef<HTMLButtonElement>(null);
|
const initialRef = useRef<HTMLButtonElement>(null);
|
||||||
const finalRef = useRef<HTMLButtonElement>(null);
|
const finalRef = useRef<HTMLButtonElement>(null);
|
||||||
return (
|
return <></>;
|
||||||
<Dialog.Root
|
|
||||||
//initialFocusRef={initialRef}
|
|
||||||
//finalFocusRef={finalRef}
|
|
||||||
//closeOnOverlayClick={false}
|
|
||||||
onOpenChange={onClose}
|
|
||||||
open={true}
|
|
||||||
data-testid="upload-progress-edit-pop-up"
|
|
||||||
>
|
|
||||||
{/* <DialogOverlay /> */}
|
|
||||||
<Dialog.Content>
|
|
||||||
<Dialog.Header>{title}</Dialog.Header>
|
|
||||||
{/* <DialogCloseButton ref={finalRef} /> */}
|
|
||||||
|
|
||||||
<Dialog.Body pb={6} paddingLeft="18px">
|
// return (
|
||||||
<Flex direction="column" gap="10px">
|
// <Dialog.Root
|
||||||
{isFinished ? (
|
// //initialFocusRef={initialRef}
|
||||||
<Text fontSize="20px" fontWeight="bold">
|
// //finalFocusRef={finalRef}
|
||||||
All {elements.length} element have been sent
|
// //closeOnOverlayClick={false}
|
||||||
</Text>
|
// onOpenChange={onClose}
|
||||||
) : (
|
// open={true}
|
||||||
<Text fontSize="20px" fontWeight="bold">
|
// data-testid="upload-progress-edit-pop-up"
|
||||||
[{index + 1}/{elements.length}] {elements[index]}
|
// >
|
||||||
</Text>
|
// {/* <DialogOverlay /> */}
|
||||||
)}
|
// <Dialog.Content>
|
||||||
<Progress.Root
|
// <Dialog.Header>{title}</Dialog.Header>
|
||||||
colorScheme="green"
|
// {/* <DialogCloseButton ref={finalRef} /> */}
|
||||||
striped
|
|
||||||
value={currentSize}
|
// <Dialog.Body pb={6} paddingLeft="18px">
|
||||||
animated
|
// <Flex direction="column" gap="10px">
|
||||||
max={totalSize}
|
// {isFinished ? (
|
||||||
height="24px"
|
// <Text fontSize="20px" fontWeight="bold">
|
||||||
/>
|
// All {elements.length} element have been sent
|
||||||
<Flex>
|
// </Text>
|
||||||
<Text>{currentSize.toLocaleString('fr-FR')} Bytes</Text>
|
// ) : (
|
||||||
<Text marginLeft="auto">
|
// <Text fontSize="20px" fontWeight="bold">
|
||||||
{totalSize.toLocaleString('fr-FR')} Bytes
|
// [{index + 1}/{elements.length}] {elements[index]}
|
||||||
</Text>
|
// </Text>
|
||||||
</Flex>
|
// )}
|
||||||
{error && (
|
// <Progress.Root
|
||||||
<Text fontWeight="bold" color="darkred">
|
// colorScheme="green"
|
||||||
{error}
|
// striped
|
||||||
</Text>
|
// value={currentSize}
|
||||||
)}
|
// animated
|
||||||
</Flex>
|
// max={totalSize}
|
||||||
</Dialog.Body>
|
// height="24px"
|
||||||
<Dialog.Footer>
|
// />
|
||||||
{isFinished ? (
|
// <Flex>
|
||||||
<Button onClick={onClose} theme="@success">
|
// <Text>{currentSize.toLocaleString('fr-FR')} Bytes</Text>
|
||||||
Ok
|
// <Text marginLeft="auto">
|
||||||
</Button>
|
// {totalSize.toLocaleString('fr-FR')} Bytes
|
||||||
) : (
|
// </Text>
|
||||||
<Button colorScheme="red" mr={3} onClick={onAbort} ref={initialRef}>
|
// </Flex>
|
||||||
Abort
|
// {error && (
|
||||||
</Button>
|
// <Text fontWeight="bold" color="darkred">
|
||||||
)}
|
// {error}
|
||||||
</Dialog.Footer>
|
// </Text>
|
||||||
</Dialog.Content>
|
// )}
|
||||||
</Dialog.Root>
|
// </Flex>
|
||||||
);
|
// </Dialog.Body>
|
||||||
|
// <Dialog.Footer>
|
||||||
|
// {isFinished ? (
|
||||||
|
// <Button onClick={onClose} theme="@success">
|
||||||
|
// Ok
|
||||||
|
// </Button>
|
||||||
|
// ) : (
|
||||||
|
// <Button colorScheme="red" mr={3} onClick={onAbort} ref={initialRef}>
|
||||||
|
// Abort
|
||||||
|
// </Button>
|
||||||
|
// )}
|
||||||
|
// </Dialog.Footer>
|
||||||
|
// </Dialog.Content>
|
||||||
|
// </Dialog.Root>
|
||||||
|
// );
|
||||||
};
|
};
|
||||||
|
@ -80,116 +80,117 @@ export const TrackEditPopUp = ({ }: TrackEditPopUpProps) => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
return (
|
return <></>;
|
||||||
<Dialog.Root
|
// return (
|
||||||
//initialFocusRef={initialRef}
|
// <Dialog.Root
|
||||||
//finalFocusRef={finalRef}
|
// //initialFocusRef={initialRef}
|
||||||
//closeOnOverlayClick={false}
|
// //finalFocusRef={finalRef}
|
||||||
onOpenChange={onClose}
|
// //closeOnOverlayClick={false}
|
||||||
open={true}
|
// onOpenChange={onClose}
|
||||||
data-testid="track-edit-pop-up"
|
// open={true}
|
||||||
>
|
// data-testid="track-edit-pop-up"
|
||||||
{/* <DialogOverlay /> */}
|
// >
|
||||||
<Dialog.Content>
|
// {/* <DialogOverlay /> */}
|
||||||
<Dialog.Header>Edit Track</Dialog.Header>
|
// <Dialog.Content>
|
||||||
{/* <DialogCloseButton ref={finalRef} /> */}
|
// <Dialog.Header>Edit Track</Dialog.Header>
|
||||||
|
// {/* <DialogCloseButton ref={finalRef} /> */}
|
||||||
|
|
||||||
<Dialog.Body 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>{dataTrack?.id}</Text>
|
// <Text>{dataTrack?.id}</Text>
|
||||||
</FormGroup>
|
// </FormGroup>
|
||||||
<FormGroup label="Data Id">
|
// <FormGroup label="Data Id">
|
||||||
<Text>{dataTrack?.dataId}</Text>
|
// <Text>{dataTrack?.dataId}</Text>
|
||||||
</FormGroup>
|
// </FormGroup>
|
||||||
<FormGroup label="Action(s):">
|
// <FormGroup label="Action(s):">
|
||||||
<Button
|
// <Button
|
||||||
onClick={disclosure.onOpen}
|
// onClick={disclosure.onOpen}
|
||||||
marginRight="auto"
|
// marginRight="auto"
|
||||||
theme="@danger"
|
// theme="@danger"
|
||||||
>
|
// >
|
||||||
<MdDeleteForever /> Remove Media
|
// <MdDeleteForever /> Remove Media
|
||||||
</Button>
|
// </Button>
|
||||||
</FormGroup>
|
// </FormGroup>
|
||||||
<ConfirmPopUp
|
// <ConfirmPopUp
|
||||||
disclosure={disclosure}
|
// disclosure={disclosure}
|
||||||
title="Remove track"
|
// title="Remove track"
|
||||||
body={`Remove Media [${dataTrack?.id}] ${dataTrack?.name}`}
|
// body={`Remove Media [${dataTrack?.id}] ${dataTrack?.name}`}
|
||||||
confirmTitle="Remove"
|
// confirmTitle="Remove"
|
||||||
onConfirm={onRemove}
|
// onConfirm={onRemove}
|
||||||
/>
|
// />
|
||||||
</>
|
// </>
|
||||||
)}
|
// )}
|
||||||
{!admin && (
|
// {!admin && (
|
||||||
<>
|
// <>
|
||||||
<FormInput
|
// <FormInput
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="name"
|
// variableName="name"
|
||||||
isRequired
|
// isRequired
|
||||||
label="Title"
|
// label="Title"
|
||||||
ref={initialRef}
|
// ref={initialRef}
|
||||||
/>
|
// />
|
||||||
<FormTextarea
|
// <FormTextarea
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="description"
|
// variableName="description"
|
||||||
label="Description"
|
// label="Description"
|
||||||
/>
|
// />
|
||||||
<FormSelect
|
// <FormSelect
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="genderId"
|
// variableName="genderId"
|
||||||
options={dataGenders}
|
// options={dataGenders}
|
||||||
label="Gender"
|
// label="Gender"
|
||||||
/>
|
// />
|
||||||
<FormSelectMultiple
|
// <FormSelectMultiple
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="artists"
|
// variableName="artists"
|
||||||
options={dataArtist}
|
// options={dataArtist}
|
||||||
label="Artist(s)"
|
// label="Artist(s)"
|
||||||
/>
|
// />
|
||||||
<FormSelect
|
// <FormSelect
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="albumId"
|
// variableName="albumId"
|
||||||
options={dataAlbums}
|
// options={dataAlbums}
|
||||||
label="Album"
|
// label="Album"
|
||||||
/>
|
// />
|
||||||
<FormNumber
|
// <FormNumber
|
||||||
form={form}
|
// form={form}
|
||||||
variableName="track"
|
// variableName="track"
|
||||||
label="Track n°"
|
// label="Track n°"
|
||||||
step={1}
|
// step={1}
|
||||||
//defaultValue={0}
|
// //defaultValue={0}
|
||||||
min={0}
|
// min={0}
|
||||||
max={1000}
|
// max={1000}
|
||||||
/>
|
// />
|
||||||
</>
|
// </>
|
||||||
)}
|
// )}
|
||||||
</Dialog.Body>
|
// </Dialog.Body>
|
||||||
<Dialog.Footer>
|
// <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>
|
||||||
</Dialog.Footer>
|
// </Dialog.Footer>
|
||||||
</Dialog.Content>
|
// </Dialog.Content>
|
||||||
</Dialog.Root>
|
// </Dialog.Root>
|
||||||
);
|
// );
|
||||||
};
|
};
|
||||||
|
@ -4,6 +4,7 @@ import { MdEdit, MdKeyboardArrowDown, MdKeyboardArrowUp } from 'react-icons/md';
|
|||||||
|
|
||||||
import { SelectList, SelectListModel } from '@/components/select/SelectList';
|
import { SelectList, SelectListModel } from '@/components/select/SelectList';
|
||||||
import { isNullOrUndefined } from '@/utils/validator';
|
import { isNullOrUndefined } from '@/utils/validator';
|
||||||
|
import { Button, Flex, HStack, Input } from '@/ui';
|
||||||
|
|
||||||
export type SelectMultipleProps = {
|
export type SelectMultipleProps = {
|
||||||
options?: object[];
|
options?: object[];
|
||||||
@ -74,7 +75,7 @@ export const SelectMultiple = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (!options) {
|
if (!options) {
|
||||||
return <Spinner />;
|
return <></>;// TODO: <Spinner />;
|
||||||
}
|
}
|
||||||
const onChangeInput = (value: string): void => {
|
const onChangeInput = (value: string): void => {
|
||||||
setHasSuggestion(false);
|
setHasSuggestion(false);
|
||||||
@ -100,10 +101,10 @@ export const SelectMultiple = ({
|
|||||||
return (
|
return (
|
||||||
<Flex direction="column" width="full" gap="0px">
|
<Flex direction="column" width="full" gap="0px">
|
||||||
{selectedOptions && (
|
{selectedOptions && (
|
||||||
<HStack wrap="wrap" /*spacing="5px"*/ justify="left" width="full" marginBottom="2px">
|
<HStack style={{ flexWrap: "wrap", /*spacing="5px"*/ justifyContent: "left", width: "full", marginBottom: "2px" }}>
|
||||||
{selectedOptions.map((data) => (
|
{selectedOptions.map((data) => (
|
||||||
<Flex align="flex-start" key={data[keyKey]}>
|
<Flex align="flex-start" key={data[keyKey]}>
|
||||||
<Tag.Root
|
{/* <Tag.Root
|
||||||
size="md"
|
size="md"
|
||||||
key="md"
|
key="md"
|
||||||
borderRadius="5px"
|
borderRadius="5px"
|
||||||
@ -112,7 +113,7 @@ export const SelectMultiple = ({
|
|||||||
>
|
>
|
||||||
<Tag.Label>{data[keyValue] ?? `id=${data[keyKey]}`}</Tag.Label>
|
<Tag.Label>{data[keyValue] ?? `id=${data[keyKey]}`}</Tag.Label>
|
||||||
<Tag.CloseTrigger onClick={() => selectValue(data)} />
|
<Tag.CloseTrigger onClick={() => selectValue(data)} />
|
||||||
</Tag.Root>
|
</Tag.Root> */}
|
||||||
</Flex>
|
</Flex>
|
||||||
))}
|
))}
|
||||||
</HStack>
|
</HStack>
|
||||||
@ -121,19 +122,24 @@ export const SelectMultiple = ({
|
|||||||
<Flex>
|
<Flex>
|
||||||
<Input
|
<Input
|
||||||
ref={refFocus}
|
ref={refFocus}
|
||||||
width="full"
|
style={{
|
||||||
|
width: "full",
|
||||||
|
borderRadius: "5px 0 0 5px",
|
||||||
|
}}
|
||||||
onChange={(e) => onChangeInput(e.target.value)}
|
onChange={(e) => onChangeInput(e.target.value)}
|
||||||
//onSubmit={onSubmit}
|
//onSubmit={onSubmit}
|
||||||
onFocus={() => setShowList(true)}
|
// TODO: onFocus={() => setShowList(true)}
|
||||||
onBlur={() => setTimeout(() => setShowList(false), 200)}
|
// TODO: onBlur={() => setTimeout(() => setShowList(false), 200)}
|
||||||
value={showList ? (currentSearch ?? '') : hasSuggestion ? `suggest: ${currentSearch}` : ''}
|
value={showList ? (currentSearch ?? '') : hasSuggestion ? `suggest: ${currentSearch}` : ''}
|
||||||
borderRadius="5px 0 0 5px"
|
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
onClick={onOpenClose}
|
onClick={onOpenClose}
|
||||||
variant="outline"
|
//variant="outline"
|
||||||
borderRadius="0 5px 5px 0"
|
style={{
|
||||||
borderWidth="1px 1px 1px 0"
|
borderRadius: "0 5px 5px 0",
|
||||||
|
borderWidth: "1px 1px 1px 0",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{showList ? (
|
{showList ? (
|
||||||
<MdKeyboardArrowUp color="gray.300" />
|
<MdKeyboardArrowUp color="gray.300" />
|
||||||
|
@ -9,6 +9,7 @@ import {
|
|||||||
|
|
||||||
import { SelectList, SelectListModel } from '@/components/select/SelectList';
|
import { SelectList, SelectListModel } from '@/components/select/SelectList';
|
||||||
import { isNullOrUndefined } from '@/utils/validator';
|
import { isNullOrUndefined } from '@/utils/validator';
|
||||||
|
import { Button, Flex, Input } from '@/ui';
|
||||||
|
|
||||||
export type SelectSingleProps = {
|
export type SelectSingleProps = {
|
||||||
options?: object[];
|
options?: object[];
|
||||||
@ -69,7 +70,7 @@ export const SelectSingle = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
if (!transformedOption) {
|
if (!transformedOption) {
|
||||||
return <Spinner />;
|
return <></>; // TODO: <Spinner />;
|
||||||
}
|
}
|
||||||
function onChangeInput(value: string): void {
|
function onChangeInput(value: string): void {
|
||||||
setHasSuggestion(false);
|
setHasSuggestion(false);
|
||||||
@ -104,44 +105,49 @@ export const SelectSingle = ({
|
|||||||
<Flex>
|
<Flex>
|
||||||
<Input
|
<Input
|
||||||
ref={refFocus}
|
ref={refFocus}
|
||||||
width="full"
|
style={{
|
||||||
|
width: "full",
|
||||||
|
backgroundColor: showList || !selectedOptions ? undefined : 'green.500',
|
||||||
|
borderRadius: "5px 0 0 5px",
|
||||||
|
}}
|
||||||
onChange={(e) => onChangeInput(e.target.value)}
|
onChange={(e) => onChangeInput(e.target.value)}
|
||||||
onFocus={() => setShowList(true)}
|
//onFocus={() => setShowList(true)}
|
||||||
onBlur={() => setTimeout(() => setShowList(false), 200)}
|
//onBlur={() => setTimeout(() => setShowList(false), 200)}
|
||||||
value={
|
value={
|
||||||
showList ? (currentSearch ?? '') : (selectedOptions?.name ?? (hasSuggestion ? `suggest: ${currentSearch}` : ''))
|
showList ? (currentSearch ?? '') : (selectedOptions?.name ?? (hasSuggestion ? `suggest: ${currentSearch}` : ''))
|
||||||
}
|
}
|
||||||
backgroundColor={
|
|
||||||
showList || !selectedOptions ? undefined : 'green.500'
|
|
||||||
}
|
|
||||||
borderRadius="5px 0 0 5px"
|
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
onClick={onRemoveItem}
|
onClick={onRemoveItem}
|
||||||
variant="outline"
|
// TODO: variant="outline"
|
||||||
borderRadius="0 5px 5px 0"
|
style={{
|
||||||
borderWidth="1px 1px 1px 0"
|
borderRadius: "0 5px 5px 0",
|
||||||
|
borderWidth: "1px 1px 1px 0",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{selectedOptions ? (
|
{
|
||||||
<MdClose color="gray.300" />
|
selectedOptions ? (
|
||||||
) : showList ? (
|
<MdClose color="gray.300" />
|
||||||
<MdKeyboardArrowUp color="gray.300" />
|
) : showList ? (
|
||||||
) : hasSuggestion ? (
|
<MdKeyboardArrowUp color="gray.300" />
|
||||||
<MdEdit color="gray.300" />
|
) : hasSuggestion ? (
|
||||||
) : (
|
<MdEdit color="gray.300" />
|
||||||
<MdKeyboardArrowDown color="gray.300" />
|
) : (
|
||||||
)}
|
<MdKeyboardArrowDown color="gray.300" />
|
||||||
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
{showList && (
|
{
|
||||||
<SelectList
|
showList && (
|
||||||
options={transformedOption}
|
<SelectList
|
||||||
selected={selectedOptions ? [selectedOptions] : []}
|
options={transformedOption}
|
||||||
search={currentSearch}
|
selected={selectedOptions ? [selectedOptions] : []}
|
||||||
onSelectValue={selectValue}
|
search={currentSearch}
|
||||||
onCreate={createNewItem}
|
onSelectValue={selectValue}
|
||||||
/>
|
onCreate={createNewItem}
|
||||||
)}
|
/>
|
||||||
</Flex>
|
)
|
||||||
|
}
|
||||||
|
</Flex >
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -4,6 +4,7 @@ import { Track } from '@/back-api';
|
|||||||
import { Covers } from '@/components/Cover';
|
import { Covers } from '@/components/Cover';
|
||||||
import { ContextMenu, MenuElement } from '@/components/contextMenu/ContextMenu';
|
import { ContextMenu, MenuElement } from '@/components/contextMenu/ContextMenu';
|
||||||
import { useActivePlaylistService } from '@/service/ActivePlaylist';
|
import { useActivePlaylistService } from '@/service/ActivePlaylist';
|
||||||
|
import { Flex, Span } from '@/ui';
|
||||||
|
|
||||||
export type DisplayTrackProps = {
|
export type DisplayTrackProps = {
|
||||||
track: Track;
|
track: Track;
|
||||||
@ -32,23 +33,26 @@ export const DisplayTrack = ({
|
|||||||
width="full"
|
width="full"
|
||||||
height="full"
|
height="full"
|
||||||
paddingLeft="5px"
|
paddingLeft="5px"
|
||||||
overflowX="hidden"
|
style={{
|
||||||
|
overflowX: "hidden",
|
||||||
|
}}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
>
|
>
|
||||||
<Text
|
<Span
|
||||||
as="span"
|
|
||||||
alignContent="left"
|
|
||||||
fontSize="20px"
|
fontSize="20px"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
userSelect="none"
|
|
||||||
marginRight="auto"
|
|
||||||
overflow="hidden"
|
|
||||||
// TODO: noOfLines={[1, 2]}
|
|
||||||
marginY="auto"
|
|
||||||
color={trackActive?.id === track.id ? 'green.700' : undefined}
|
color={trackActive?.id === track.id ? 'green.700' : undefined}
|
||||||
|
style={{
|
||||||
|
alignContent: "left",
|
||||||
|
userSelect: "none",
|
||||||
|
marginRight: "auto",
|
||||||
|
overflow: "hidden",
|
||||||
|
// TODO: noOfLines={[1, 2]}
|
||||||
|
margin: "auto 0",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
[{track.track}] {track.name}
|
[{track.track}] {track.name}
|
||||||
</Text>
|
</Span>
|
||||||
</Flex>
|
</Flex>
|
||||||
<ContextMenu elements={contextMenu} />
|
<ContextMenu elements={contextMenu} />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -7,6 +7,7 @@ import { useActivePlaylistService } from '@/service/ActivePlaylist';
|
|||||||
import { useSpecificAlbum } from '@/service/Album';
|
import { useSpecificAlbum } from '@/service/Album';
|
||||||
import { useSpecificArtists } from '@/service/Artist';
|
import { useSpecificArtists } from '@/service/Artist';
|
||||||
import { useSpecificGender } from '@/service/Gender';
|
import { useSpecificGender } from '@/service/Gender';
|
||||||
|
import { Flex, Span } from '@/ui';
|
||||||
|
|
||||||
export type DisplayTrackProps = {
|
export type DisplayTrackProps = {
|
||||||
track: Track;
|
track: Track;
|
||||||
@ -39,69 +40,78 @@ export const DisplayTrackFull = ({
|
|||||||
width="full"
|
width="full"
|
||||||
height="full"
|
height="full"
|
||||||
paddingLeft="5px"
|
paddingLeft="5px"
|
||||||
overflowX="hidden"
|
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
|
style={{
|
||||||
|
overflowX: "hidden",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Text
|
<Span
|
||||||
as="span"
|
|
||||||
alignContent="left"
|
|
||||||
fontSize="20px"
|
fontSize="20px"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
userSelect="none"
|
|
||||||
marginRight="auto"
|
|
||||||
overflow="hidden"
|
|
||||||
// TODO: noOfLines={1}
|
|
||||||
color={trackActive?.id === track.id ? 'green.700' : undefined}
|
color={trackActive?.id === track.id ? 'green.700' : undefined}
|
||||||
|
style={{
|
||||||
|
alignContent: "left",
|
||||||
|
userSelect: "none",
|
||||||
|
marginRight: "auto",
|
||||||
|
overflow: "hidden",
|
||||||
|
// TODO: noOfLines={1}
|
||||||
|
margin: "auto 0",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{track.name} {track.track && ` [${track.track}]`}
|
{track.name} {track.track && ` [${track.track}]`}
|
||||||
</Text>
|
</Span>
|
||||||
{dataAlbum && (
|
{dataAlbum && (
|
||||||
<Text
|
<Span
|
||||||
as="span"
|
|
||||||
alignContent="left"
|
|
||||||
fontSize="15px"
|
fontSize="15px"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
userSelect="none"
|
|
||||||
marginRight="auto"
|
|
||||||
overflow="hidden"
|
|
||||||
//noOfLines={1}
|
//noOfLines={1}
|
||||||
marginY="auto"
|
|
||||||
color={trackActive?.id === track.id ? 'green.700' : undefined}
|
color={trackActive?.id === track.id ? 'green.700' : undefined}
|
||||||
|
style={{
|
||||||
|
alignContent: "left",
|
||||||
|
userSelect: "none",
|
||||||
|
marginRight: "auto",
|
||||||
|
overflow: "hidden",
|
||||||
|
// TODO: noOfLines={[1, 2]}
|
||||||
|
margin: "auto 0",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Text as="span" fontWeight="normal">Album:</Text> {dataAlbum.name}
|
<Span fontWeight="normal">Album:</Span> {dataAlbum.name}
|
||||||
</Text>
|
</Span>
|
||||||
)}
|
)}
|
||||||
{dataArtists && (
|
{dataArtists && (
|
||||||
<Text
|
<Span
|
||||||
as="span"
|
|
||||||
alignContent="left"
|
|
||||||
fontSize="15px"
|
fontSize="15px"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
userSelect="none"
|
userSelect="none"
|
||||||
marginRight="auto"
|
|
||||||
overflow="hidden"
|
|
||||||
//noOfLines={1}
|
|
||||||
marginY="auto"
|
|
||||||
color={trackActive?.id === track.id ? 'green.700' : undefined}
|
color={trackActive?.id === track.id ? 'green.700' : undefined}
|
||||||
|
style={{
|
||||||
|
alignContent: "left",
|
||||||
|
userSelect: "none",
|
||||||
|
marginRight: "auto",
|
||||||
|
overflow: "hidden",
|
||||||
|
// TODO: noOfLines={[1, 2]}
|
||||||
|
margin: "auto 0",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Text as="span" fontWeight="normal">Artist(s):</Text> {dataArtists.map((data) => data.name).join(', ')}
|
<Span fontWeight="normal">Artist(s):</Span> {dataArtists.map((data) => data.name).join(', ')}
|
||||||
</Text>
|
</Span>
|
||||||
)}
|
)}
|
||||||
{dataGender && (
|
{dataGender && (
|
||||||
<Text
|
<Span
|
||||||
as="span"
|
|
||||||
alignContent="left"
|
|
||||||
fontSize="15px"
|
fontSize="15px"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
userSelect="none"
|
|
||||||
marginRight="auto"
|
|
||||||
overflow="hidden"
|
|
||||||
//noOfLines={1}
|
|
||||||
marginY="auto"
|
|
||||||
color={trackActive?.id === track.id ? 'green.700' : undefined}
|
color={trackActive?.id === track.id ? 'green.700' : undefined}
|
||||||
|
style={{
|
||||||
|
alignContent: "left",
|
||||||
|
userSelect: "none",
|
||||||
|
marginRight: "auto",
|
||||||
|
overflow: "hidden",
|
||||||
|
// TODO: noOfLines={[1, 2]}
|
||||||
|
margin: "auto 0",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Text as="span" fontWeight="normal">Gender:</Text> {dataGender.name}
|
<Span fontWeight="normal">Gender:</Span> {dataGender.name}
|
||||||
</Text>
|
</Span>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
<ContextMenu elements={contextMenu}
|
<ContextMenu elements={contextMenu}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { Track } from '@/back-api';
|
import { Track } from '@/back-api';
|
||||||
import { Covers } from '@/components/Cover';
|
|
||||||
import { MenuElement } from '@/components/contextMenu/ContextMenu';
|
import { MenuElement } from '@/components/contextMenu/ContextMenu';
|
||||||
import { useSpecificTrack } from '@/service/Track';
|
import { useSpecificTrack } from '@/service/Track';
|
||||||
import { DisplayTrackFull } from './DisplayTrackFull';
|
import { DisplayTrackFull } from './DisplayTrackFull';
|
||||||
|
@ -1,21 +1,24 @@
|
|||||||
|
import { Flex } from "@/ui";
|
||||||
|
|
||||||
|
|
||||||
export const DisplayTrackSkeleton = () => {
|
export const DisplayTrackSkeleton = () => {
|
||||||
return (
|
return (
|
||||||
<Flex direction="row" width="full" height="full">
|
<Flex direction="row" width="full" height="full">
|
||||||
<Skeleton
|
{/* <Skeleton
|
||||||
borderRadius="0px"
|
borderRadius="0px"
|
||||||
height="50"
|
height="50"
|
||||||
width="50"
|
width="50"
|
||||||
minWidth="50"
|
minWidth="50"
|
||||||
minHeight="50"
|
minHeight="50"
|
||||||
/>
|
/> */}
|
||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
width="full"
|
width="full"
|
||||||
height="full"
|
height="full"
|
||||||
paddingLeft="5px"
|
paddingLeft="5px"
|
||||||
overflowX="hidden"
|
style={{
|
||||||
|
overflowX: "hidden"
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{/* <SkeletonText
|
{/* <SkeletonText
|
||||||
skeletonHeight="20px"
|
skeletonHeight="20px"
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
"use client"
|
|
||||||
|
|
||||||
import { ThemeProvider, useTheme, ThemeProviderProps } from "next-themes"
|
|
||||||
|
|
||||||
export interface ColorModeProviderProps extends ThemeProviderProps { }
|
|
||||||
|
|
||||||
export function ColorModeProvider(props: ColorModeProviderProps) {
|
|
||||||
return (
|
|
||||||
<ThemeProvider attribute="class" themes={['pink', 'dark', 'light']} disableTransitionOnChange {...props} />
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useColorMode() {
|
|
||||||
const { resolvedTheme, setTheme } = useTheme()
|
|
||||||
const toggleColorMode = () => {
|
|
||||||
console.log(`plop: ${resolvedTheme}`);
|
|
||||||
setTheme(resolvedTheme === "light" ? "pink" : resolvedTheme === "pink" ? "dark" : "light")
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
colorMode: resolvedTheme,
|
|
||||||
setColorMode: setTheme,
|
|
||||||
toggleColorMode,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useColorModeValue<T>(light: T, dark: T) {
|
|
||||||
const { colorMode } = useColorMode()
|
|
||||||
return colorMode === "light" ? light : dark
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
import dayjs from 'dayjs';
|
|
||||||
import 'dayjs/locale/fr';
|
|
||||||
import advancedFormat from 'dayjs/plugin/advancedFormat';
|
|
||||||
import customParseFormat from 'dayjs/plugin/customParseFormat';
|
|
||||||
import dayOfYear from 'dayjs/plugin/dayOfYear';
|
|
||||||
import duration from 'dayjs/plugin/duration';
|
|
||||||
import isBetween from 'dayjs/plugin/isBetween';
|
|
||||||
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter';
|
|
||||||
import isToday from 'dayjs/plugin/isToday';
|
|
||||||
import isTomorrow from 'dayjs/plugin/isTomorrow';
|
|
||||||
import isYesterday from 'dayjs/plugin/isYesterday';
|
|
||||||
import quarterOfYear from 'dayjs/plugin/quarterOfYear';
|
|
||||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
|
||||||
import weekOfYear from 'dayjs/plugin/weekOfYear';
|
|
||||||
|
|
||||||
dayjs.locale('fr');
|
|
||||||
dayjs.extend(relativeTime);
|
|
||||||
dayjs.extend(customParseFormat);
|
|
||||||
dayjs.extend(weekOfYear);
|
|
||||||
dayjs.extend(isSameOrAfter);
|
|
||||||
dayjs.extend(isToday);
|
|
||||||
dayjs.extend(isTomorrow);
|
|
||||||
dayjs.extend(isYesterday);
|
|
||||||
dayjs.extend(dayOfYear);
|
|
||||||
dayjs.extend(isBetween);
|
|
||||||
dayjs.extend(advancedFormat);
|
|
||||||
dayjs.extend(quarterOfYear);
|
|
||||||
dayjs.extend(duration);
|
|
@ -1,2 +0,0 @@
|
|||||||
import './axios';
|
|
||||||
import './dayjs';
|
|
@ -1,4 +1,4 @@
|
|||||||
export const BASE_WRAP_SPACING = { base: "5px", md: "10px", lg: "20px" };
|
export const BASE_WRAP_SPACING = "5px"; // { base: "5px", md: "10px", lg: "20px" };
|
||||||
export const BASE_WRAP_WIDTH = { base: "90%", md: "45%", lg: "270px" };
|
export const BASE_WRAP_WIDTH = "90%"; // { base: "90%", md: "45%", lg: "270px" };
|
||||||
export const BASE_WRAP_HEIGHT = { base: "75px", lg: "120px" };
|
export const BASE_WRAP_HEIGHT = "75px"; // { base: "75px", lg: "120px" };
|
||||||
export const BASE_WRAP_ICON_SIZE = { base: "50px", lg: "100px" };
|
export const BASE_WRAP_ICON_SIZE = "50px";// { base: "50px", lg: "100px" };
|
@ -3,24 +3,25 @@ import { MdControlCamera } from 'react-icons/md';
|
|||||||
|
|
||||||
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
|
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
|
||||||
import { TopBar } from '@/components/TopBar/TopBar';
|
import { TopBar } from '@/components/TopBar/TopBar';
|
||||||
|
import { Flex, Link, Text } from '@/ui';
|
||||||
|
|
||||||
export const Error401 = () => {
|
export const Error401 = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TopBar />
|
<TopBar />
|
||||||
<PageLayoutInfoCenter padding="25px">
|
<PageLayoutInfoCenter padding="25px" width="75%">
|
||||||
<Center>
|
<Flex align="center">
|
||||||
<MdControlCamera size="250px" color="red.600" />
|
<MdControlCamera size="250px" color="red.600" />
|
||||||
</Center>
|
</Flex>
|
||||||
<Box textAlign="center">
|
<Flex style={{ textAlign: "center" }}>
|
||||||
<Heading>Erreur 401</Heading>
|
<Text fontSize="px">Erreur 401</Text>
|
||||||
<Text color="red.600">
|
<Text color="red.600">
|
||||||
Vous n'êtes pas autorisé a accéder a ce contenu.
|
Vous n'êtes pas autorisé a accéder a ce contenu.
|
||||||
</Text>
|
</Text>
|
||||||
<Link as="a" href="/">
|
<Link href="/">
|
||||||
Retour à l'accueil
|
Retour à l'accueil
|
||||||
</Link>
|
</Link>
|
||||||
</Box>
|
</Flex>
|
||||||
</PageLayoutInfoCenter>
|
</PageLayoutInfoCenter>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -1,24 +1,26 @@
|
|||||||
|
import { MdControlCamera } from 'react-icons/md';
|
||||||
import { MdDangerous } from 'react-icons/md';
|
|
||||||
|
|
||||||
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
|
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
|
||||||
import { TopBar } from '@/components/TopBar/TopBar';
|
import { TopBar } from '@/components/TopBar/TopBar';
|
||||||
|
import { Flex, Link, Text } from '@/ui';
|
||||||
|
|
||||||
export const Error403 = () => {
|
export const Error403 = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TopBar />
|
<TopBar />
|
||||||
<PageLayoutInfoCenter padding="25px">
|
<PageLayoutInfoCenter padding="25px" width="75%">
|
||||||
<Center>
|
<Flex align="center">
|
||||||
<MdDangerous size="250px" color="orange.600" />
|
<MdControlCamera size="250px" color="red.600" />
|
||||||
</Center>
|
</Flex>
|
||||||
<Box textAlign="center">
|
<Flex style={{ textAlign: "center" }}>
|
||||||
<Heading>Erreur 401</Heading>
|
<Text fontSize="px">Erreur 403</Text>
|
||||||
<Text color="orange.600">Cette page vous est interdite</Text>
|
<Text color="red.600">
|
||||||
|
Cette page vous est interdite.
|
||||||
|
</Text>
|
||||||
<Link href="/">
|
<Link href="/">
|
||||||
Retour à l'accueil
|
Retour à l'accueil
|
||||||
</Link>
|
</Link>
|
||||||
</Box>
|
</Flex>
|
||||||
</PageLayoutInfoCenter>
|
</PageLayoutInfoCenter>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -1,26 +1,26 @@
|
|||||||
|
import { MdControlCamera } from 'react-icons/md';
|
||||||
import { MdSignpost } from 'react-icons/md';
|
|
||||||
|
|
||||||
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
|
import { PageLayoutInfoCenter } from '@/components/Layout/PageLayoutInfoCenter';
|
||||||
import { TopBar } from '@/components/TopBar/TopBar';
|
import { TopBar } from '@/components/TopBar/TopBar';
|
||||||
|
import { Flex, Link, Text } from '@/ui';
|
||||||
|
|
||||||
export const Error404 = () => {
|
export const Error404 = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TopBar />
|
<TopBar />
|
||||||
<PageLayoutInfoCenter padding="25px">
|
<PageLayoutInfoCenter padding="25px" width="75%">
|
||||||
<Center>
|
<Flex align="center">
|
||||||
<MdSignpost size="250px" />
|
<MdControlCamera size="250px" color="red.600" />
|
||||||
</Center>
|
</Flex>
|
||||||
<Box textAlign="center">
|
<Flex style={{ textAlign: "center" }}>
|
||||||
<Heading>Erreur 404</Heading>
|
<Text fontSize="px">Erreur 404</Text>
|
||||||
<Text color="gray.600">
|
<Text color="red.600">
|
||||||
Cette page n'existe plus ou l'URL a changé
|
Cette page n'existe plus ou l'URL a changé.
|
||||||
</Text>
|
</Text>
|
||||||
<Link href="/">
|
<Link href="/">
|
||||||
Retour à l'accueil
|
Retour à l'accueil
|
||||||
</Link>
|
</Link>
|
||||||
</Box>
|
</Flex>
|
||||||
</PageLayoutInfoCenter>
|
</PageLayoutInfoCenter>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Button } from '@/ui';
|
import { Button, Flex, Text } from '@/ui';
|
||||||
import { useDisclosure } from '@/utils/disclosure';
|
import { useDisclosure } from '@/utils/disclosure';
|
||||||
import React, { FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
|
|
||||||
@ -12,14 +12,16 @@ import { LuChevronUp, LuChevronDown } from 'react-icons/lu';
|
|||||||
const ErrorFallback = ({ error }: FallbackProps) => {
|
const ErrorFallback = ({ error }: FallbackProps) => {
|
||||||
const { open, onToggle } = useDisclosure();
|
const { open, onToggle } = useDisclosure();
|
||||||
return (
|
return (
|
||||||
<Box p="4" m="auto">
|
<Flex direction="column" style={{ padding: 4, margin: "auto", backgroundColor: "red.500" }}>
|
||||||
|
<Text color='red'>An unexpected error has occurred.</Text>
|
||||||
|
<Text>Message: {error.message}</Text>
|
||||||
|
{/*
|
||||||
<AlertRoot status="error" borderRadius="md">
|
<AlertRoot status="error" borderRadius="md">
|
||||||
{/* <AlertIcon /> */}
|
<Flex style={{ flex: "1" }}>
|
||||||
<Box flex="1">
|
|
||||||
<AlertTitle>An unexpected error has occurred.</AlertTitle>
|
<AlertTitle>An unexpected error has occurred.</AlertTitle>
|
||||||
<AlertDescription display="block" lineHeight="1.4">
|
<AlertDescription display="block" lineHeight="1.4">
|
||||||
<Button
|
<Button
|
||||||
theme="@secondary"
|
//theme="@secondary"
|
||||||
color="red.800"
|
color="red.800"
|
||||||
//size="sm"
|
//size="sm"
|
||||||
onClick={onToggle}
|
onClick={onToggle}
|
||||||
@ -28,15 +30,15 @@ const ErrorFallback = ({ error }: FallbackProps) => {
|
|||||||
</Button>
|
</Button>
|
||||||
<Collapsible.Root open={open}>
|
<Collapsible.Root open={open}>
|
||||||
<Collapsible.Content>
|
<Collapsible.Content>
|
||||||
<Box mt={4} fontFamily="monospace">
|
<Flex mt={4} fontFamily="monospace">
|
||||||
{error.message}
|
{error.message}
|
||||||
</Box>
|
</Flex>
|
||||||
</Collapsible.Content>
|
</Collapsible.Content>
|
||||||
</Collapsible.Root>
|
</Collapsible.Root>
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
</Box>
|
</Flex>
|
||||||
</AlertRoot>
|
</AlertRoot> */}
|
||||||
</Box>
|
</Flex >
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
|
|
||||||
|
|
||||||
export const DoubleArrowIcon = createIcon({
|
export const DoubleArrowIcon = <></>;
|
||||||
displayName: 'DoubleArrowIcon',
|
// createIcon({
|
||||||
viewBox: '0 0 24 24',
|
// displayName: 'DoubleArrowIcon',
|
||||||
path: (
|
// viewBox: '0 0 24 24',
|
||||||
<path
|
// path: (
|
||||||
fillRule="evenodd"
|
// <path
|
||||||
clipRule="evenodd"
|
// fillRule="evenodd"
|
||||||
d="M1.293 12.207a1 1 0 0 1 0-1.414l6.364-6.364A1 1 0 0 1 9.07 5.843L4.414 10.5h15.172l-4.657-4.657a1 1 0 0 1 1.414-1.414l6.364 6.364a1 1 0 0 1 0 1.414l-6.364 6.364a1 1 0 0 1-1.414-1.414l4.657-4.657H4.414l4.657 4.657a1 1 0 1 1-1.414 1.414l-6.364-6.364Z"
|
// clipRule="evenodd"
|
||||||
fill="currentColor"
|
// d="M1.293 12.207a1 1 0 0 1 0-1.414l6.364-6.364A1 1 0 0 1 9.07 5.843L4.414 10.5h15.172l-4.657-4.657a1 1 0 0 1 1.414-1.414l6.364 6.364a1 1 0 0 1 0 1.414l-6.364 6.364a1 1 0 0 1-1.414-1.414l4.657-4.657H4.414l4.657 4.657a1 1 0 1 1-1.414 1.414l-6.364-6.364Z"
|
||||||
/>
|
// fill="currentColor"
|
||||||
),
|
// />
|
||||||
});
|
// ),
|
||||||
|
// });
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
import ReactDOM from 'react-dom/client';
|
import ReactDOM from 'react-dom/client';
|
||||||
import App from '@/App';
|
import App from '@/App';
|
||||||
|
import { ThemeProvider } from './theme/ThemeContext';
|
||||||
// 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>
|
<ThemeProvider>
|
||||||
<App />
|
<App />
|
||||||
// </ColorModeProvider>
|
</ThemeProvider>
|
||||||
// </StrictMode>
|
// </StrictMode>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -13,8 +13,9 @@ 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';
|
||||||
import { useTracksOfAnAlbum } from '@/service/Track';
|
import { useTracksOfAnAlbum } from '@/service/Track';
|
||||||
import { useColorModeValue } from '@/components/ui/color-mode';
|
import { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
import { BASE_WRAP_SPACING } from '@/constants/genericSpacing';
|
import { BASE_WRAP_SPACING } from '@/constants/genericSpacing';
|
||||||
|
import { Button, Flex, Text } from '@/ui';
|
||||||
|
|
||||||
export const AlbumDetailPage = () => {
|
export const AlbumDetailPage = () => {
|
||||||
const { albumId } = useParams();
|
const { albumId } = useParams();
|
||||||
@ -45,7 +46,7 @@ export const AlbumDetailPage = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TopBar title="Album detail" />
|
<TopBar title="Album detail" />
|
||||||
<PageLayoutInfoCenter>
|
<PageLayoutInfoCenter width="75%">
|
||||||
Fail to load artist id: {albumId}
|
Fail to load artist id: {albumId}
|
||||||
</PageLayoutInfoCenter>
|
</PageLayoutInfoCenter>
|
||||||
</>
|
</>
|
||||||
@ -67,17 +68,19 @@ export const AlbumDetailPage = () => {
|
|||||||
data-testid="Album-detail-page_layout">
|
data-testid="Album-detail-page_layout">
|
||||||
<Flex
|
<Flex
|
||||||
direction="row"
|
direction="row"
|
||||||
width="80%"
|
|
||||||
marginX="auto"
|
|
||||||
padding="10px"
|
|
||||||
gap="10px"
|
gap="10px"
|
||||||
|
style={{
|
||||||
|
width: "80%",
|
||||||
|
margin: "0 auto",
|
||||||
|
padding: "10px",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Covers
|
<Covers
|
||||||
data={dataAlbum?.covers}
|
data={dataAlbum?.covers}
|
||||||
// TODO: iconEmpty={LuDisc3}
|
// TODO: iconEmpty={LuDisc3}
|
||||||
slideshow
|
slideshow
|
||||||
/>
|
/>
|
||||||
<Flex direction="column" width="80%" marginRight="auto">
|
<Flex direction="column" style={{ width: "80%", marginRight: "auto" }}>
|
||||||
<Text fontSize="24px" fontWeight="bold">
|
<Text fontSize="24px" fontWeight="bold">
|
||||||
{dataAlbum?.name}
|
{dataAlbum?.name}
|
||||||
</Text>
|
</Text>
|
||||||
@ -92,25 +95,27 @@ export const AlbumDetailPage = () => {
|
|||||||
|
|
||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
gap={BASE_WRAP_SPACING}
|
gap={BASE_WRAP_SPACING} style={{
|
||||||
marginX="auto"
|
margin: "0 auto",
|
||||||
padding="20px"
|
padding: "20px",
|
||||||
width="80%"
|
width: "80%",
|
||||||
data-testid="Album-detail-page_flex-list"
|
}}
|
||||||
|
data-test-id="Album-detail-page_flex-list"
|
||||||
>
|
>
|
||||||
{tracksOnAnAlbum?.map((data) => (
|
{tracksOnAnAlbum?.map((data) => (
|
||||||
<Box
|
<Flex
|
||||||
minWidth="100%"
|
|
||||||
//height="60px"
|
|
||||||
border="1px"
|
|
||||||
borderColor="brand.900"
|
|
||||||
backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')}
|
|
||||||
key={data.id}
|
key={data.id}
|
||||||
padding="5px"
|
style={{
|
||||||
as="button"
|
minWidth: "100%",
|
||||||
_hover={{
|
//height="60px"
|
||||||
boxShadow: 'outline-over',
|
border: "1px",
|
||||||
bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
|
borderColor: "brand.900",
|
||||||
|
backgroundColor: useColorThemeValue('#FFFFFF88', '#00000088'),
|
||||||
|
padding: "5px",
|
||||||
|
// _hover: {
|
||||||
|
// boxShadow: 'outline-over',
|
||||||
|
// bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
|
||||||
|
// }
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DisplayTrackFull
|
<DisplayTrackFull
|
||||||
@ -127,7 +132,7 @@ export const AlbumDetailPage = () => {
|
|||||||
]}
|
]}
|
||||||
data-testid="Album-detail-page_display-detail"
|
data-testid="Album-detail-page_display-detail"
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Flex>
|
||||||
))}
|
))}
|
||||||
<EmptyEnd />
|
<EmptyEnd />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -9,8 +9,9 @@ import { SearchInput } from '@/components/SearchInput';
|
|||||||
import { TopBar } from '@/components/TopBar/TopBar';
|
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 { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
import { BASE_WRAP_WIDTH, BASE_WRAP_HEIGHT } from '@/constants/genericSpacing';
|
import { BASE_WRAP_WIDTH, BASE_WRAP_HEIGHT } from '@/constants/genericSpacing';
|
||||||
|
import { Button, Flex, HStack } from '@/ui';
|
||||||
|
|
||||||
export const AlbumsPage = () => {
|
export const AlbumsPage = () => {
|
||||||
const [filterTitle, setFilterTitle] = useState<string | undefined>(undefined);
|
const [filterTitle, setFilterTitle] = useState<string | undefined>(undefined);
|
||||||
@ -24,7 +25,7 @@ export const AlbumsPage = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TopBar title="All Albums" />
|
<TopBar title="All Albums" />
|
||||||
<PageLayoutInfoCenter>No Album available</PageLayoutInfoCenter>
|
<PageLayoutInfoCenter width="75%">No Album available</PageLayoutInfoCenter>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -35,29 +36,31 @@ export const AlbumsPage = () => {
|
|||||||
<SearchInput onChange={setFilterTitle} />
|
<SearchInput onChange={setFilterTitle} />
|
||||||
</TopBar>
|
</TopBar>
|
||||||
<PageLayout>
|
<PageLayout>
|
||||||
<HStack wrap="wrap" /*spacing={BASE_WRAP_SPACING}*/ marginX="auto" padding="20px" justify="center">
|
<HStack style={{ flexWrap: "wrap", /*spacing={BASE_WRAP_SPACING}*/ margin: "0 auto", padding: "20px", justifyContent: "center" }}>
|
||||||
{dataAlbums.map((data) => (
|
{dataAlbums.map((data) => (
|
||||||
<Flex align="flex-start"
|
<Button
|
||||||
width={BASE_WRAP_WIDTH}
|
|
||||||
height={BASE_WRAP_HEIGHT}
|
|
||||||
border="1px"
|
|
||||||
borderColor="brand.900"
|
|
||||||
backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')}
|
|
||||||
key={data.id}
|
key={data.id}
|
||||||
padding="5px"
|
style={{
|
||||||
as="button"
|
width: BASE_WRAP_WIDTH,
|
||||||
_hover={{
|
height: BASE_WRAP_HEIGHT,
|
||||||
boxShadow: 'outline-over',
|
border: "1px",
|
||||||
bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
|
borderColor: "brand.900",
|
||||||
|
backgroundColor: useColorThemeValue('#FFFFFF88', '#00000088'),
|
||||||
|
padding: "5px",
|
||||||
|
// _hover={
|
||||||
|
// boxShadow: 'outline-over',
|
||||||
|
// bgColor: useColorThemeValue('#FFFFFFF7', '#000000F7'),
|
||||||
|
// }
|
||||||
|
alignContent: "flex-start",
|
||||||
}}
|
}}
|
||||||
onClick={() => onSelect.Item(data.id)}
|
onClick={() => onSelectItem(data.id)}
|
||||||
>
|
>
|
||||||
<DisplayAlbum dataAlbum={data} />
|
<DisplayAlbum dataAlbum={data} />
|
||||||
</Flex>
|
</Button>
|
||||||
))}
|
))}
|
||||||
</HStack>
|
</HStack>
|
||||||
<EmptyEnd />
|
<EmptyEnd />
|
||||||
</PageLayout>
|
</PageLayout >
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -14,7 +14,8 @@ import { useActivePlaylistService } from '@/service/ActivePlaylist';
|
|||||||
import { useSpecificAlbum } from '@/service/Album';
|
import { useSpecificAlbum } from '@/service/Album';
|
||||||
import { useSpecificArtist } from '@/service/Artist';
|
import { useSpecificArtist } from '@/service/Artist';
|
||||||
import { useTracksOfAnAlbum } from '@/service/Track';
|
import { useTracksOfAnAlbum } from '@/service/Track';
|
||||||
import { useColorModeValue } from '@/components/ui/color-mode';
|
import { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
|
import { Button, Flex, Text } from '@/ui';
|
||||||
|
|
||||||
export const ArtistAlbumDetailPage = () => {
|
export const ArtistAlbumDetailPage = () => {
|
||||||
const { artistId, albumId } = useParams();
|
const { artistId, albumId } = useParams();
|
||||||
@ -59,13 +60,18 @@ export const ArtistAlbumDetailPage = () => {
|
|||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
{...BUTTON_TOP_BAR_PROPERTY}
|
{...BUTTON_TOP_BAR_PROPERTY}
|
||||||
marginRight="auto"
|
|
||||||
|
style={{
|
||||||
|
marginRight: "auto"
|
||||||
|
}}
|
||||||
onClick={() => navigate(`/artist/${dataArtist.id}`)}
|
onClick={() => navigate(`/artist/${dataArtist.id}`)}
|
||||||
>
|
>
|
||||||
<Covers
|
<Covers
|
||||||
data={dataArtist?.covers}
|
data={dataArtist?.covers}
|
||||||
size="35px"
|
size="35px"
|
||||||
borderRadius="full"
|
style={{
|
||||||
|
borderRadius: "full",
|
||||||
|
}}
|
||||||
// TODO: iconEmpty={MdPerson}
|
// TODO: iconEmpty={MdPerson}
|
||||||
/>
|
/>
|
||||||
<Text fontSize="24px" fontWeight="bold">
|
<Text fontSize="24px" fontWeight="bold">
|
||||||
@ -86,9 +92,11 @@ export const ArtistAlbumDetailPage = () => {
|
|||||||
<PageLayout>
|
<PageLayout>
|
||||||
<Flex
|
<Flex
|
||||||
direction="row"
|
direction="row"
|
||||||
width="80%"
|
style={{
|
||||||
marginX="auto"
|
width: "80%",
|
||||||
padding="10px"
|
margin: "0 auto",
|
||||||
|
padding: "10px",
|
||||||
|
}}
|
||||||
gap="10px"
|
gap="10px"
|
||||||
>
|
>
|
||||||
<Covers
|
<Covers
|
||||||
@ -96,7 +104,8 @@ export const ArtistAlbumDetailPage = () => {
|
|||||||
// TODO: iconEmpty={LuDisc3}
|
// TODO: iconEmpty={LuDisc3}
|
||||||
slideshow
|
slideshow
|
||||||
/>
|
/>
|
||||||
<Flex direction="column" width="80%" marginRight="auto">
|
<Flex direction="column"
|
||||||
|
style={{ width: "80%", marginRight: "auto" }}>
|
||||||
<Text fontSize="24px" fontWeight="bold">
|
<Text fontSize="24px" fontWeight="bold">
|
||||||
{dataAlbum?.name}
|
{dataAlbum?.name}
|
||||||
</Text>
|
</Text>
|
||||||
@ -112,23 +121,28 @@ export const ArtistAlbumDetailPage = () => {
|
|||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
gap="20px"
|
gap="20px"
|
||||||
marginX="auto"
|
|
||||||
padding="20px"
|
style={{
|
||||||
width="80%"
|
margin: "0 auto",
|
||||||
|
padding: "20px",
|
||||||
|
width: "80%",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{tracksOnAnAlbum?.map((data) => (
|
{tracksOnAnAlbum?.map((data) => (
|
||||||
<Box
|
<Flex
|
||||||
minWidth="100%"
|
|
||||||
height="60px"
|
|
||||||
border="1px"
|
|
||||||
borderColor="brand.900"
|
|
||||||
backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')}
|
|
||||||
key={data.id}
|
key={data.id}
|
||||||
padding="5px"
|
|
||||||
as="button"
|
style={{
|
||||||
_hover={{
|
minWidth: "100%",
|
||||||
boxShadow: 'outline-over',
|
height: "60px",
|
||||||
bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
|
border: "1px",
|
||||||
|
borderColor: "brand.900",
|
||||||
|
backgroundColor: useColorThemeValue('#FFFFFF88', '#00000088'),
|
||||||
|
padding: "5px",
|
||||||
|
// _hover: {
|
||||||
|
// boxShadow: 'outline-over',
|
||||||
|
// bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
|
||||||
|
// }
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DisplayTrack
|
<DisplayTrack
|
||||||
@ -146,7 +160,7 @@ export const ArtistAlbumDetailPage = () => {
|
|||||||
{ name: 'Add Playlist', onClick: () => { } },
|
{ name: 'Add Playlist', onClick: () => { } },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Flex>
|
||||||
))}
|
))}
|
||||||
<EmptyEnd />
|
<EmptyEnd />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -11,8 +11,9 @@ import { DisplayAlbumId } from '@/components/album/DisplayAlbumId';
|
|||||||
import { ArtistEditPopUp } from '@/components/popup/ArtistEditPopUp';
|
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 { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
import { BASE_WRAP_HEIGHT, BASE_WRAP_WIDTH } from '@/constants/genericSpacing';
|
import { BASE_WRAP_HEIGHT, BASE_WRAP_WIDTH } from '@/constants/genericSpacing';
|
||||||
|
import { Button, Flex, HStack, Text } from '@/ui';
|
||||||
|
|
||||||
export const ArtistDetailPage = () => {
|
export const ArtistDetailPage = () => {
|
||||||
const { artistId } = useParams();
|
const { artistId } = useParams();
|
||||||
@ -40,7 +41,7 @@ export const ArtistDetailPage = () => {
|
|||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
{...BUTTON_TOP_BAR_PROPERTY}
|
{...BUTTON_TOP_BAR_PROPERTY}
|
||||||
marginRight="auto"
|
style={{ marginRight: "auto" }}
|
||||||
onClick={() => navigate(`/artist/all`)}
|
onClick={() => navigate(`/artist/all`)}
|
||||||
>
|
>
|
||||||
<MdGroup height="full" />
|
<MdGroup height="full" />
|
||||||
@ -63,7 +64,7 @@ export const ArtistDetailPage = () => {
|
|||||||
<Flex
|
<Flex
|
||||||
direction="row"
|
direction="row"
|
||||||
width="80%"
|
width="80%"
|
||||||
marginX="auto"
|
margin="0 auto"
|
||||||
padding="10px"
|
padding="10px"
|
||||||
gap="10px"
|
gap="10px"
|
||||||
>
|
>
|
||||||
@ -87,25 +88,27 @@ export const ArtistDetailPage = () => {
|
|||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<HStack wrap="wrap" /*spacing={BASE_WRAP_SPACING}*/ marginX="auto" padding="20px" justify="center">
|
<HStack style={{ flexWrap: "wrap", /*spacing={BASE_WRAP_SPACING}*/ margin: "0 auto", padding: "20px", justifyContent: "center" }}>
|
||||||
{albumIdsOfAnArtist?.map((data) => (
|
{albumIdsOfAnArtist?.map((data) => (
|
||||||
<Flex align="flex-start"
|
<Button
|
||||||
width={BASE_WRAP_WIDTH}
|
|
||||||
height={BASE_WRAP_HEIGHT}
|
|
||||||
border="1px"
|
|
||||||
borderColor="brand.900"
|
|
||||||
backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')}
|
|
||||||
key={data}
|
key={data}
|
||||||
padding="5px"
|
style={{
|
||||||
as="button"
|
alignContent: "flex-start",
|
||||||
_hover={{
|
width: BASE_WRAP_WIDTH,
|
||||||
boxShadow: 'outline-over',
|
height: BASE_WRAP_HEIGHT,
|
||||||
bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
|
border: "1px",
|
||||||
|
borderColor: "brand.900",
|
||||||
|
backgroundColor: useColorThemeValue('#FFFFFF88', '#00000088'),
|
||||||
|
padding: "5px",
|
||||||
|
// _hover={
|
||||||
|
// boxShadow: 'outline-over',
|
||||||
|
// bgColor: useColorThemeValue('#FFFFFFF7', '#000000F7'),
|
||||||
|
// }
|
||||||
}}
|
}}
|
||||||
onClick={() => onSelectItem(data)}
|
onClick={() => onSelectItem(data)}
|
||||||
>
|
>
|
||||||
<DisplayAlbumId id={data} key={data} />
|
<DisplayAlbumId id={data} key={data} />
|
||||||
</Flex>
|
</Button>
|
||||||
))}
|
))}
|
||||||
</HStack>
|
</HStack>
|
||||||
<EmptyEnd />
|
<EmptyEnd />
|
||||||
|
@ -9,13 +9,14 @@ import { PageLayout } from '@/components/Layout/PageLayout';
|
|||||||
import { SearchInput } from '@/components/SearchInput';
|
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 { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
import { BASE_WRAP_HEIGHT, BASE_WRAP_ICON_SIZE, 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';
|
||||||
import { useTrackService } from '@/service/Track';
|
import { useTrackService } from '@/service/Track';
|
||||||
import { DataTools, TypeCheck } from '@/utils/data-tools';
|
import { DataTools, TypeCheck } from '@/utils/data-tools';
|
||||||
|
import { Button, Flex, HStack, Span, Text } from '@/ui';
|
||||||
const LIMIT_RANDOM_VALUES = 25;
|
const LIMIT_RANDOM_VALUES = 25;
|
||||||
|
|
||||||
export const ArtistsPage = () => {
|
export const ArtistsPage = () => {
|
||||||
@ -55,27 +56,27 @@ export const ArtistsPage = () => {
|
|||||||
<>
|
<>
|
||||||
<TopBar title="All artists">
|
<TopBar title="All artists">
|
||||||
<SearchInput onChange={setFilterName} />
|
<SearchInput onChange={setFilterName} />
|
||||||
<Tooltip.Root aria-label="Random play">
|
<Button {...BUTTON_TOP_BAR_PROPERTY} onClick={onRandomPlay}>
|
||||||
<Button {...BUTTON_TOP_BAR_PROPERTY} onClick={onRandomPlay}>
|
<MdOutlineForkRight />
|
||||||
<MdOutlineForkRight />
|
</Button>
|
||||||
</Button>
|
|
||||||
</Tooltip.Root>
|
|
||||||
</TopBar>
|
</TopBar>
|
||||||
<PageLayout>
|
<PageLayout>
|
||||||
<HStack wrap="wrap" /*spacing={BASE_WRAP_SPACING}*/ marginX="auto" padding="20px" justify="center">
|
<HStack style={{ flexWrap: "wrap", /*spacing={BASE_WRAP_SPACING}*/ margin: "0 auto", padding: "20px", alignContent: "center" }}>
|
||||||
{dataArtist?.map((data) => (
|
{dataArtist?.map((data) => (
|
||||||
<Flex align="flex-start"
|
<Button
|
||||||
width={BASE_WRAP_WIDTH}
|
|
||||||
height={BASE_WRAP_HEIGHT}
|
|
||||||
border="1px"
|
|
||||||
borderColor="brand.900"
|
|
||||||
backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')}
|
|
||||||
key={data.id}
|
key={data.id}
|
||||||
padding="5px"
|
style={{
|
||||||
as="button"
|
width: BASE_WRAP_WIDTH,
|
||||||
_hover={{
|
height: BASE_WRAP_HEIGHT,
|
||||||
boxShadow: 'outline-over',
|
alignContent: "flex-start",
|
||||||
bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
|
border: "1px",
|
||||||
|
borderColor: "brand.900",
|
||||||
|
backgroundColor: useColorThemeValue('#FFFFFF88', '#00000088'),
|
||||||
|
padding: "5px",
|
||||||
|
// _hover:{
|
||||||
|
// boxShadow: 'outline-over',
|
||||||
|
// bgColor: useColorThemeValue('#FFFFFFF7', '#000000F7'),
|
||||||
|
// }
|
||||||
}}
|
}}
|
||||||
onClick={() => onSelectItem(data)}
|
onClick={() => onSelectItem(data)}
|
||||||
>
|
>
|
||||||
@ -83,7 +84,7 @@ export const ArtistsPage = () => {
|
|||||||
<Covers
|
<Covers
|
||||||
data={data.covers}
|
data={data.covers}
|
||||||
size={BASE_WRAP_ICON_SIZE}
|
size={BASE_WRAP_ICON_SIZE}
|
||||||
height="full"
|
style={{ height: "full" }}
|
||||||
// iconEmpty={LuUser}
|
// iconEmpty={LuUser}
|
||||||
/>
|
/>
|
||||||
<Flex
|
<Flex
|
||||||
@ -92,19 +93,20 @@ export const ArtistsPage = () => {
|
|||||||
maxWidth="150px"
|
maxWidth="150px"
|
||||||
height="full"
|
height="full"
|
||||||
paddingLeft="5px"
|
paddingLeft="5px"
|
||||||
overflowX="hidden"
|
style={{ overflowX: "hidden" }}
|
||||||
>
|
>
|
||||||
<Text
|
<Text
|
||||||
/*align="left"*/
|
/*align="left"*/
|
||||||
/*noOfLines={[1, 2]}*/
|
/*noOfLines={[1, 2]}*/
|
||||||
>
|
>
|
||||||
<Span
|
<Span
|
||||||
as="span"
|
|
||||||
fontSize="20px"
|
fontSize="20px"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
userSelect="none"
|
userSelect="none"
|
||||||
marginRight="auto"
|
style={{
|
||||||
overflow="hidden"
|
marginRight: "auto",
|
||||||
|
overflow: "hidden",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{data.name}
|
{data.name}
|
||||||
</Span>
|
</Span>
|
||||||
@ -112,7 +114,7 @@ export const ArtistsPage = () => {
|
|||||||
</Text>
|
</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Button>
|
||||||
))}
|
))}
|
||||||
</HStack>
|
</HStack>
|
||||||
<EmptyEnd />
|
<EmptyEnd />
|
||||||
|
@ -14,7 +14,8 @@ import { useActivePlaylistService } from '@/service/ActivePlaylist';
|
|||||||
import { useSpecificGender } from '@/service/Gender';
|
import { useSpecificGender } from '@/service/Gender';
|
||||||
import { useTracksOfAGender } from '@/service/Track';
|
import { useTracksOfAGender } from '@/service/Track';
|
||||||
//import { useTracksOfAGender } from '@/service/Track';
|
//import { useTracksOfAGender } from '@/service/Track';
|
||||||
import { useColorModeValue } from '@/components/ui/color-mode';
|
import { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
|
import { Button, Flex, Text } from '@/ui';
|
||||||
|
|
||||||
export const GenderDetailPage = () => {
|
export const GenderDetailPage = () => {
|
||||||
const { genderId } = useParams();
|
const { genderId } = useParams();
|
||||||
@ -66,17 +67,19 @@ export const GenderDetailPage = () => {
|
|||||||
<PageLayout>
|
<PageLayout>
|
||||||
<Flex
|
<Flex
|
||||||
direction="row"
|
direction="row"
|
||||||
width="80%"
|
|
||||||
marginX="auto"
|
|
||||||
padding="10px"
|
|
||||||
gap="10px"
|
gap="10px"
|
||||||
|
style={{
|
||||||
|
width: "80%",
|
||||||
|
margin: "0 auto",
|
||||||
|
padding: "10px",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Covers
|
<Covers
|
||||||
data={dataGender?.covers}
|
data={dataGender?.covers}
|
||||||
// TODO: iconEmpty={LuDisc3}
|
// TODO: iconEmpty={LuDisc3}
|
||||||
slideshow
|
slideshow
|
||||||
/>
|
/>
|
||||||
<Flex direction="column" width="80%" marginRight="auto">
|
<Flex direction="column" style={{ width: "80%", marginRight: "auto" }}>
|
||||||
<Text fontSize="24px" fontWeight="bold">
|
<Text fontSize="24px" fontWeight="bold">
|
||||||
{dataGender?.name}
|
{dataGender?.name}
|
||||||
</Text>
|
</Text>
|
||||||
@ -89,23 +92,26 @@ export const GenderDetailPage = () => {
|
|||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
gap="20px"
|
gap="20px"
|
||||||
marginX="auto"
|
style={{
|
||||||
padding="20px"
|
margin: "0 auto",
|
||||||
width="80%"
|
padding: "20px",
|
||||||
|
width: "80%",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{tracksOnAGender?.map((data) => (
|
{tracksOnAGender?.map((data) => (
|
||||||
<Box
|
<Flex
|
||||||
minWidth="100%"
|
|
||||||
//height="60px"
|
|
||||||
border="1px"
|
|
||||||
borderColor="brand.900"
|
|
||||||
backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')}
|
|
||||||
key={data.id}
|
key={data.id}
|
||||||
padding="5px"
|
style={{
|
||||||
as="button"
|
minWidth: "100%",
|
||||||
_hover={{
|
//height="60px",
|
||||||
boxShadow: 'outline-over',
|
border: "1px",
|
||||||
bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
|
borderColor: "brand.900",
|
||||||
|
backgroundColor: useColorThemeValue('#FFFFFF88', '#00000088'),
|
||||||
|
padding: "5px",
|
||||||
|
// _hover: {
|
||||||
|
// boxShadow: 'outline-over',
|
||||||
|
// bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
|
||||||
|
// }
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DisplayTrackFull
|
<DisplayTrackFull
|
||||||
@ -121,7 +127,7 @@ export const GenderDetailPage = () => {
|
|||||||
{ name: 'Add Playlist', onClick: () => { } },
|
{ name: 'Add Playlist', onClick: () => { } },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Flex>
|
||||||
))}
|
))}
|
||||||
<EmptyEnd />
|
<EmptyEnd />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -9,7 +9,7 @@ import { SearchInput } from '@/components/SearchInput';
|
|||||||
import { TopBar } from '@/components/TopBar/TopBar';
|
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 { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
import { Flex, HStack } from '@/ui';
|
import { Flex, HStack } from '@/ui';
|
||||||
|
|
||||||
export const GendersPage = () => {
|
export const GendersPage = () => {
|
||||||
|
@ -7,7 +7,8 @@ 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 { useColorModeValue } from '@/components/ui/color-mode';
|
import { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
|
import { Div, Flex, HStack, Text } from '@/ui';
|
||||||
|
|
||||||
type HomeListType = {
|
type HomeListType = {
|
||||||
id: number;
|
id: number;
|
||||||
@ -57,40 +58,43 @@ export const HomePage = () => {
|
|||||||
<>
|
<>
|
||||||
<TopBar title="Home" />
|
<TopBar title="Home" />
|
||||||
<PageLayout>
|
<PageLayout>
|
||||||
<HStack wrap="wrap" /*spacing="20px"*/ marginX="auto" padding="20px" justify="center">
|
<HStack style={{ flexWrap: "wrap", /*spacing="20px"*/ margin: "0 auto", padding: "20px", justify: "center" }}>
|
||||||
{homeList.map((data) => (
|
{homeList.map((data) => (
|
||||||
<Flex align="flex-start"
|
<Flex align="flex-start"
|
||||||
width="200px"
|
|
||||||
height="190px"
|
|
||||||
border="1px"
|
|
||||||
borderColor="brand.900"
|
|
||||||
backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')}
|
|
||||||
key={data.id}
|
key={data.id}
|
||||||
padding="5px"
|
style={{
|
||||||
as="button"
|
width: "200px",
|
||||||
_hover={{
|
height: "190px",
|
||||||
boxShadow: 'outline-over',
|
border: "1px",
|
||||||
bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
|
borderColor: "brand.900",
|
||||||
|
backgroundColor: useColorThemeValue('#FFFFFF88', '#00000088'),
|
||||||
|
padding: "5px",
|
||||||
|
// _hover:{
|
||||||
|
// boxShadow: 'outline-over',
|
||||||
|
// bgColor: useColorThemeValue('#FFFFFFF7', '#000000F7'),
|
||||||
|
// }
|
||||||
}}
|
}}
|
||||||
onClick={() => onSelectItem(data)}
|
onClick={() => onSelectItem(data)}
|
||||||
>
|
>
|
||||||
<Flex direction="column" width="full" height="full">
|
<Flex direction="column" style={{ width: "full", height: "full" }}>
|
||||||
<Center height="full">{data.icon}</Center>
|
<Div style={{ alignContent: "center", height: "full" }}>{data.icon}</Div>
|
||||||
<Center>
|
<Div style={{ alignContent: "center", height: "full" }}>
|
||||||
<Text
|
<Text
|
||||||
fontSize="25px"
|
fontSize="25px"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
textTransform="uppercase"
|
style={{
|
||||||
userSelect="none"
|
textTransform: "uppercase",
|
||||||
|
userSelect: "none",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{data.name}
|
{data.name}
|
||||||
</Text>
|
</Text>
|
||||||
</Center>
|
</Div>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
))}
|
))}
|
||||||
</HStack>
|
</HStack>
|
||||||
</PageLayout>
|
</PageLayout >
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -7,9 +7,10 @@ import { 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 { useActivePlaylistService } from '@/service/ActivePlaylist';
|
import { useActivePlaylistService } from '@/service/ActivePlaylist';
|
||||||
import { useColorModeValue } from '@/components/ui/color-mode';
|
import { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
import { BASE_WRAP_SPACING } from '@/constants/genericSpacing';
|
import { BASE_WRAP_SPACING } from '@/constants/genericSpacing';
|
||||||
import { DisplayTrackFullId } from '@/components/track/DisplayTrackFullId';
|
import { DisplayTrackFullId } from '@/components/track/DisplayTrackFullId';
|
||||||
|
import { Flex } from '@/ui';
|
||||||
|
|
||||||
export const OnAirPage = () => {
|
export const OnAirPage = () => {
|
||||||
const { playInList } = useActivePlaylistService();
|
const { playInList } = useActivePlaylistService();
|
||||||
@ -72,24 +73,27 @@ export const OnAirPage = () => {
|
|||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
gap={BASE_WRAP_SPACING}
|
gap={BASE_WRAP_SPACING}
|
||||||
marginX="auto"
|
style={{
|
||||||
padding="20px"
|
margin: "0 auto",
|
||||||
width="80%"
|
padding: "20px",
|
||||||
|
width: "80%",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{!playTrackList && <>No playing</>}
|
{!playTrackList && <>No playing</>}
|
||||||
{playTrackList && playTrackList?.map((data) => (
|
{playTrackList && playTrackList?.map((data) => (
|
||||||
<Box
|
<Flex
|
||||||
minWidth="100%"
|
|
||||||
//height="60px"
|
|
||||||
border="1px"
|
|
||||||
borderColor="brand.900"
|
|
||||||
backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')}
|
|
||||||
key={data}
|
key={data}
|
||||||
padding="5px"
|
style={{
|
||||||
as="button"
|
minWidth: "100%",
|
||||||
_hover={{
|
//height:"60px",
|
||||||
boxShadow: 'outline-over',
|
border: "1px",
|
||||||
bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
|
borderColor: "brand.900",
|
||||||
|
backgroundColor: useColorThemeValue('#FFFFFF88', '#00000088'),
|
||||||
|
padding: "5px",
|
||||||
|
// _hover: {
|
||||||
|
// boxShadow: 'outline-over',
|
||||||
|
// bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
|
||||||
|
// }
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DisplayTrackFullId
|
<DisplayTrackFullId
|
||||||
@ -110,7 +114,7 @@ export const OnAirPage = () => {
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Flex>
|
||||||
))}
|
))}
|
||||||
<EmptyEnd />
|
<EmptyEnd />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
@ -10,6 +10,8 @@ import { SessionState } from '@/service/SessionState';
|
|||||||
import { useSessionService } from '@/service/session';
|
import { useSessionService } from '@/service/session';
|
||||||
import { b64_to_utf8 } from '@/utils/sso';
|
import { b64_to_utf8 } from '@/utils/sso';
|
||||||
|
|
||||||
|
import { Flex, Text, Image } from '@/ui';
|
||||||
|
|
||||||
export const SSOPage = () => {
|
export const SSOPage = () => {
|
||||||
const { data, keepConnected, token } = useParams();
|
const { data, keepConnected, token } = useParams();
|
||||||
console.log(`- data: ${data}`);
|
console.log(`- data: ${data}`);
|
||||||
@ -46,13 +48,11 @@ export const SSOPage = () => {
|
|||||||
<>
|
<>
|
||||||
<TopBar />
|
<TopBar />
|
||||||
<PageLayoutInfoCenter width="35%" gap="15px">
|
<PageLayoutInfoCenter width="35%" gap="15px">
|
||||||
<Center w="full">
|
<Text>LOGIN (after SSO)</Text>
|
||||||
<Heading size="xl">LOGIN (after SSO) </Heading>
|
|
||||||
</Center>
|
|
||||||
|
|
||||||
<Center w="full">
|
<Flex width="full">
|
||||||
<Image src={avatar_generic} boxSize="150px" borderRadius="full" />
|
<Image href={avatar_generic} boxSize="150px" style={{ borderRadius: "full" }} />
|
||||||
</Center>
|
</Flex>
|
||||||
{token === '__CANCEL__' && (
|
{token === '__CANCEL__' && (
|
||||||
<Text>
|
<Text>
|
||||||
<b>ERROR: </b> Request cancel of connection !
|
<b>ERROR: </b> Request cancel of connection !
|
||||||
|
@ -2,7 +2,7 @@ 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 { useColorModeValue } from '@/components/ui/color-mode';
|
import { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
|
|
||||||
export const alphabet = [
|
export const alphabet = [
|
||||||
'a',
|
'a',
|
||||||
@ -50,13 +50,13 @@ export const TrackSelectionPage = () => {
|
|||||||
height="75px"
|
height="75px"
|
||||||
border="1px"
|
border="1px"
|
||||||
borderColor="brand.900"
|
borderColor="brand.900"
|
||||||
backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')}
|
backgroundColor={useColorThemeValue('#FFFFFF88', '#00000088')}
|
||||||
key={data}
|
key={data}
|
||||||
padding="5px"
|
padding="5px"
|
||||||
as="button"
|
as="button"
|
||||||
_hover={{
|
_hover={{
|
||||||
boxShadow: 'outline-over',
|
boxShadow: 'outline-over',
|
||||||
bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
|
bgColor: useColorThemeValue('#FFFFFFF7', '#000000F7'),
|
||||||
}}
|
}}
|
||||||
onClick={() => onSelectItem(data)}
|
onClick={() => onSelectItem(data)}
|
||||||
>
|
>
|
||||||
|
@ -8,7 +8,8 @@ import { DisplayTrackSkeleton } from '@/components/track/DisplayTrackSkeleton';
|
|||||||
import { alphabet } from '@/scene/track/TrackSelectionPage';
|
import { alphabet } from '@/scene/track/TrackSelectionPage';
|
||||||
import { useActivePlaylistService } from '@/service/ActivePlaylist';
|
import { useActivePlaylistService } from '@/service/ActivePlaylist';
|
||||||
import { useTracksWithStartName } from '@/service/Track';
|
import { useTracksWithStartName } from '@/service/Track';
|
||||||
import { useColorModeValue } from '@/components/ui/color-mode';
|
import { useColorThemeValue } from '@/theme/ThemeContext';
|
||||||
|
import { Flex } from '@/ui';
|
||||||
|
|
||||||
export const TracksStartLetterDetailPage = () => {
|
export const TracksStartLetterDetailPage = () => {
|
||||||
const { startLetter } = useParams();
|
const { startLetter } = useParams();
|
||||||
@ -47,50 +48,55 @@ export const TracksStartLetterDetailPage = () => {
|
|||||||
<Flex
|
<Flex
|
||||||
direction="column"
|
direction="column"
|
||||||
gap="20px"
|
gap="20px"
|
||||||
marginX="auto"
|
style={{
|
||||||
padding="20px"
|
margin: "0 auto",
|
||||||
width="80%"
|
padding: "20px",
|
||||||
|
width: "80%",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{isLoading &&
|
{isLoading &&
|
||||||
[1, 2, 3, 4]?.map((data) => (
|
[1, 2, 3, 4]?.map((data) => (
|
||||||
<Box
|
<Flex
|
||||||
minWidth="100%"
|
|
||||||
//height="60px"
|
|
||||||
border="1px"
|
|
||||||
borderColor="brand.900"
|
|
||||||
backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')}
|
|
||||||
key={data}
|
key={data}
|
||||||
padding="5px"
|
style={{
|
||||||
as="button"
|
minWidth: "100%",
|
||||||
_hover={{
|
//height:"60px",
|
||||||
boxShadow: 'outline-over',
|
border: "1px",
|
||||||
bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
|
borderColor: "brand.900",
|
||||||
|
backgroundColor: useColorThemeValue('#FFFFFF88', '#00000088'),
|
||||||
|
padding: "5px",
|
||||||
|
// _hover: {
|
||||||
|
// boxShadow: 'outline-over',
|
||||||
|
// bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
|
||||||
|
// }
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DisplayTrackSkeleton />
|
<DisplayTrackSkeleton />
|
||||||
</Box>
|
</Flex>
|
||||||
))}
|
))}
|
||||||
{!isLoading &&
|
{!isLoading &&
|
||||||
tracksStartsWith?.map((data) => (
|
tracksStartsWith?.map((data) => (
|
||||||
<Box
|
<Flex
|
||||||
minWidth="100%"
|
|
||||||
//height="60px"
|
|
||||||
border="1px"
|
|
||||||
borderColor="brand.900"
|
|
||||||
backgroundColor={useColorModeValue('#FFFFFF88', '#00000088')}
|
|
||||||
key={data.id}
|
key={data.id}
|
||||||
padding="5px"
|
style={{
|
||||||
as="button"
|
minWidth: "100%",
|
||||||
_hover={{
|
//height:"60px",
|
||||||
boxShadow: 'outline-over',
|
border: "1px",
|
||||||
bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
|
borderColor: "brand.900",
|
||||||
|
backgroundColor: useColorThemeValue('#FFFFFF88', '#00000088'),
|
||||||
|
|
||||||
|
padding: "5px",
|
||||||
|
// _hover: {
|
||||||
|
// boxShadow: 'outline-over',
|
||||||
|
// bgColor: useColorModeValue('#FFFFFFF7', '#000000F7'),
|
||||||
|
// }
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DisplayTrackFull
|
<DisplayTrackFull
|
||||||
track={data}
|
track={data}
|
||||||
onClick={() => onSelectItem(data.id)}
|
onClick={() => onSelectItem(data.id)}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Flex>
|
||||||
))}
|
))}
|
||||||
<EmptyEnd />
|
<EmptyEnd />
|
||||||
</Flex>
|
</Flex>
|
||||||
|
115
front/src/theme/ThemeContext.tsx
Normal file
115
front/src/theme/ThemeContext.tsx
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
|
||||||
|
import { createContext, useContext, useState, useEffect, CSSProperties, ReactNode, useCallback } from "react";
|
||||||
|
import { basicColor } from "./colors";
|
||||||
|
|
||||||
|
type themeContextProps = {
|
||||||
|
theme: string;
|
||||||
|
themeList: string[];
|
||||||
|
setTheme: (string) => void;
|
||||||
|
toggleTheme: () => void;
|
||||||
|
convertStyle: (style: CSSProperties) => CSSProperties,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const ThemeContext = createContext<themeContextProps>({
|
||||||
|
theme: "error",
|
||||||
|
themeList: ["error"],
|
||||||
|
setTheme: (_: string) => { },
|
||||||
|
toggleTheme: () => { },
|
||||||
|
convertStyle: (style: CSSProperties): CSSProperties => { return style; },
|
||||||
|
});
|
||||||
|
|
||||||
|
const themes = {
|
||||||
|
baseColors: {
|
||||||
|
...basicColor
|
||||||
|
},
|
||||||
|
themeColors: {
|
||||||
|
light: {
|
||||||
|
primary: "#007bff",
|
||||||
|
secondary: "#6c757d",
|
||||||
|
background: "#ffffff",
|
||||||
|
text: "#000000",
|
||||||
|
},
|
||||||
|
dark: {
|
||||||
|
primary: "#375a7f",
|
||||||
|
secondary: "#444444",
|
||||||
|
background: "#181818",
|
||||||
|
text: "#ffffff",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export function ThemeProvider({ children, themeList = ["light", "dark"] }: { children: ReactNode, themeList?: string[] }) {
|
||||||
|
const [theme, setTheme] = useState<string>(themeList[0]);
|
||||||
|
const [basicsColor, setBasicsColor] = useState<{ [key: string]: string }>({});
|
||||||
|
|
||||||
|
// update the global CSS wen theme is updated:
|
||||||
|
useEffect(() => {
|
||||||
|
// generates the colors:
|
||||||
|
const baseColor = themes.baseColors;
|
||||||
|
const newBasicsColor: { [key: string]: string } = {}
|
||||||
|
Object.entries(baseColor).forEach(([tableColorName, colorValues]) => {
|
||||||
|
Object.entries(colorValues).forEach(([key, value]) => {
|
||||||
|
const colorName = `${tableColorName}.${key}`;
|
||||||
|
newBasicsColor[colorName] = value;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
setBasicsColor(newBasicsColor);
|
||||||
|
|
||||||
|
const root = document.documentElement;
|
||||||
|
//const currentColorTheme = themes.baseColors[theme];
|
||||||
|
Object.entries(newBasicsColor).forEach(([key, value]) => {
|
||||||
|
const cssKeyValue = `--${key.replace(".", "-")}`;
|
||||||
|
console.log(` generate CSS color: ${cssKeyValue}:${value}`);
|
||||||
|
root.style.setProperty(cssKeyValue, value);
|
||||||
|
});
|
||||||
|
}, [theme, setBasicsColor]);
|
||||||
|
|
||||||
|
const toggleTheme = useCallback(() => {
|
||||||
|
console.log(`plop: ${theme}`);
|
||||||
|
setTheme((previous) => {
|
||||||
|
if (themeList.length <= 1) {
|
||||||
|
return previous;
|
||||||
|
}
|
||||||
|
for (let iii = 0; iii < themeList.length - 1; iii++) {
|
||||||
|
if (themeList[iii] == theme) {
|
||||||
|
return themeList[iii + 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return themeList[0];
|
||||||
|
})
|
||||||
|
}, [setTheme]);
|
||||||
|
|
||||||
|
const convertElementStyle = useCallback((style: CSSProperties, key: string) => {
|
||||||
|
const value = style[key];
|
||||||
|
if (typeof value !== "string") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (basicsColor[value]) {
|
||||||
|
style[key] = basicsColor[value];
|
||||||
|
}
|
||||||
|
}, [basicsColor]);
|
||||||
|
const convertStyle = useCallback((style: CSSProperties): CSSProperties => {
|
||||||
|
console.log(`plop: ${theme}`);
|
||||||
|
if (!style) {
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
const out = { ...style }
|
||||||
|
convertElementStyle(out, "background");
|
||||||
|
convertElementStyle(out, "borderColor");
|
||||||
|
convertElementStyle(out, "color");
|
||||||
|
return out;
|
||||||
|
}, [convertElementStyle]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ThemeContext.Provider value={{ theme, themeList, setTheme, toggleTheme, convertStyle }}>
|
||||||
|
{children}
|
||||||
|
</ThemeContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export const useTheme = () => useContext(ThemeContext);
|
||||||
|
|
||||||
|
export function useColorThemeValue<T>(firstTheme: T, secondTheme: T) {
|
||||||
|
const { theme, themeList } = useTheme()
|
||||||
|
return theme === themeList[0] ? firstTheme : secondTheme
|
||||||
|
}
|
125
front/src/theme/colors.ts
Normal file
125
front/src/theme/colors.ts
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
// Update me with other Tailwind colors or with https://smart-swatch.netlify.app/
|
||||||
|
const brand = {
|
||||||
|
50: '#e3edff',
|
||||||
|
100: '#b6c9fd',
|
||||||
|
200: '#88a5f7',
|
||||||
|
300: '#5a81f2',
|
||||||
|
400: '#2c5ded',
|
||||||
|
500: '#1543d4',
|
||||||
|
600: '#0d34a5',
|
||||||
|
700: '#062577',
|
||||||
|
800: '#02164a',
|
||||||
|
900: '#00071e',
|
||||||
|
};
|
||||||
|
|
||||||
|
const back = {
|
||||||
|
50: '#f2f2f2',
|
||||||
|
100: '#d9d9d9',
|
||||||
|
200: '#bfbfbf',
|
||||||
|
300: '#a6a6a6',
|
||||||
|
400: '#8c8c8c',
|
||||||
|
500: '#737373',
|
||||||
|
600: '#595959',
|
||||||
|
700: '#404040',
|
||||||
|
800: '#262626',
|
||||||
|
900: '#0d0d0d',
|
||||||
|
};
|
||||||
|
|
||||||
|
const green = {
|
||||||
|
50: '#f0fdf4',
|
||||||
|
100: '#dcfce7',
|
||||||
|
200: '#bbf7d0',
|
||||||
|
300: '#86efac',
|
||||||
|
400: '#4ade80',
|
||||||
|
500: '#22c55e',
|
||||||
|
600: '#16a34a',
|
||||||
|
700: '#15803d',
|
||||||
|
800: '#166534',
|
||||||
|
900: '#14532d',
|
||||||
|
};
|
||||||
|
const blue = {
|
||||||
|
50: '#eff6ff',
|
||||||
|
100: '#dbeafe',
|
||||||
|
200: '#bfdbfe',
|
||||||
|
300: '#93c5fd',
|
||||||
|
400: '#60a5fa',
|
||||||
|
500: '#3b82f6',
|
||||||
|
600: '#2563eb',
|
||||||
|
700: '#1d4ed8',
|
||||||
|
800: '#1e40af',
|
||||||
|
900: '#1e3a8a',
|
||||||
|
};
|
||||||
|
const orange = {
|
||||||
|
50: '#fff7ed',
|
||||||
|
100: '#ffedd5',
|
||||||
|
200: '#fed7aa',
|
||||||
|
300: '#fdba74',
|
||||||
|
400: '#fb923c',
|
||||||
|
500: '#f97316',
|
||||||
|
600: '#ea580c',
|
||||||
|
700: '#c2410c',
|
||||||
|
800: '#9a3412',
|
||||||
|
900: '#7c2d12',
|
||||||
|
};
|
||||||
|
const red = {
|
||||||
|
50: '#fef2f2',
|
||||||
|
100: '#fee2e2',
|
||||||
|
200: '#fecaca',
|
||||||
|
300: '#fca5a5',
|
||||||
|
400: '#f87171',
|
||||||
|
500: '#ef4444',
|
||||||
|
600: '#dc2626',
|
||||||
|
700: '#b91c1c',
|
||||||
|
800: '#991b1b',
|
||||||
|
900: '#7f1d1d',
|
||||||
|
};
|
||||||
|
const yellow = {
|
||||||
|
50: '#ffffda',
|
||||||
|
100: '#ffffad',
|
||||||
|
200: '#ffff7d',
|
||||||
|
300: '#ffff4b',
|
||||||
|
400: '#ffff1a',
|
||||||
|
500: '#e5e600',
|
||||||
|
600: '#b2b300',
|
||||||
|
700: '#7f8000',
|
||||||
|
800: '#4c4d00',
|
||||||
|
900: '#191b00',
|
||||||
|
};
|
||||||
|
const purple = {
|
||||||
|
50: '#ffe3ff',
|
||||||
|
100: '#ffb2ff',
|
||||||
|
200: '#ff80ff',
|
||||||
|
300: '#fe4efe',
|
||||||
|
400: '#fe20fe',
|
||||||
|
500: '#e50ce4',
|
||||||
|
600: '#b204b1',
|
||||||
|
700: '#80007f',
|
||||||
|
800: '#4e004d',
|
||||||
|
900: '#1d001c',
|
||||||
|
};
|
||||||
|
|
||||||
|
const cyan = {
|
||||||
|
50: '#d6ffff',
|
||||||
|
100: '#aaffff',
|
||||||
|
200: '#7affff',
|
||||||
|
300: '#47ffff',
|
||||||
|
400: '#1affff',
|
||||||
|
500: '#00e5e6',
|
||||||
|
600: '#00b2b3',
|
||||||
|
700: '#008081',
|
||||||
|
800: '#004d4e',
|
||||||
|
900: '#001b1d',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const basicColor = {
|
||||||
|
green, red, orange, back, blue, yellow, purple, cyan
|
||||||
|
}
|
||||||
|
|
||||||
|
export const colors = {
|
||||||
|
|
||||||
|
brand: brand,
|
||||||
|
back: back,
|
||||||
|
success: green,
|
||||||
|
error: red,
|
||||||
|
warning: orange,
|
||||||
|
} as const;
|
@ -1,110 +0,0 @@
|
|||||||
type ThemeModel = {
|
|
||||||
50: string;
|
|
||||||
100: string;
|
|
||||||
200: string;
|
|
||||||
300: string;
|
|
||||||
400: string;
|
|
||||||
500: string;
|
|
||||||
600: string;
|
|
||||||
700: string;
|
|
||||||
800: string;
|
|
||||||
900: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const back = {
|
|
||||||
50: { value: '#ebf4fa' },
|
|
||||||
100: { value: '#d1dbe0' },
|
|
||||||
200: { value: '#b6c2c9' },
|
|
||||||
300: { value: '#99aab4' },
|
|
||||||
400: { value: '#7c939e' },
|
|
||||||
500: { value: '#637985' },
|
|
||||||
600: { value: '#4d5e67' },
|
|
||||||
700: { value: '#37444a' },
|
|
||||||
800: { value: '#1f292e' },
|
|
||||||
900: { value: '#020f12' },
|
|
||||||
};
|
|
||||||
|
|
||||||
const brand = {
|
|
||||||
50: { value: '#e3edff' },
|
|
||||||
100: { value: '#b6c9fd' },
|
|
||||||
200: { value: '#88a5f7' },
|
|
||||||
300: { value: '#5a81f2' },
|
|
||||||
400: { value: '#2c5ded' },
|
|
||||||
500: { value: '#1543d4' },
|
|
||||||
600: { value: '#0d34a5' },
|
|
||||||
700: { value: '#062577' },
|
|
||||||
800: { value: '#02164a' },
|
|
||||||
900: { value: '#00071e' },
|
|
||||||
};
|
|
||||||
const normalText = {
|
|
||||||
50: { value: '#f2f2f2' },
|
|
||||||
100: { value: '#d9d9d9' },
|
|
||||||
200: { value: '#bfbfbf' },
|
|
||||||
300: { value: '#a6a6a6' },
|
|
||||||
400: { value: '#8c8c8c' },
|
|
||||||
500: { value: '#737373' },
|
|
||||||
600: { value: '#595959' },
|
|
||||||
700: { value: '#404040' },
|
|
||||||
800: { value: '#262626' },
|
|
||||||
900: { value: '#0d0d0d' },
|
|
||||||
};
|
|
||||||
|
|
||||||
const green = {
|
|
||||||
50: { value: '#f0fdf4' },
|
|
||||||
100: { value: '#dcfce7' },
|
|
||||||
200: { value: '#bbf7d0' },
|
|
||||||
300: { value: '#86efac' },
|
|
||||||
400: { value: '#4ade80' },
|
|
||||||
500: { value: '#22c55e' },
|
|
||||||
600: { value: '#16a34a' },
|
|
||||||
700: { value: '#15803d' },
|
|
||||||
800: { value: '#166534' },
|
|
||||||
900: { value: '#14532d' },
|
|
||||||
};
|
|
||||||
const blue = {
|
|
||||||
50: { value: '#eff6ff' },
|
|
||||||
100: { value: '#dbeafe' },
|
|
||||||
200: { value: '#bfdbfe' },
|
|
||||||
300: { value: '#93c5fd' },
|
|
||||||
400: { value: '#60a5fa' },
|
|
||||||
500: { value: '#3b82f6' },
|
|
||||||
600: { value: '#2563eb' },
|
|
||||||
700: { value: '#1d4ed8' },
|
|
||||||
800: { value: '#1e40af' },
|
|
||||||
900: { value: '#1e3a8a' },
|
|
||||||
};
|
|
||||||
|
|
||||||
const orange = {
|
|
||||||
50: { value: '#fff7ed' },
|
|
||||||
100: { value: '#ffedd5' },
|
|
||||||
200: { value: '#fed7aa' },
|
|
||||||
300: { value: '#fdba74' },
|
|
||||||
400: { value: '#fb923c' },
|
|
||||||
500: { value: '#f97316' },
|
|
||||||
600: { value: '#ea580c' },
|
|
||||||
700: { value: '#c2410c' },
|
|
||||||
800: { value: '#9a3412' },
|
|
||||||
900: { value: '#7c2d12' },
|
|
||||||
};
|
|
||||||
const red = {
|
|
||||||
50: { value: '#fef2f2' },
|
|
||||||
100: { value: '#fee2e2' },
|
|
||||||
200: { value: '#fecaca' },
|
|
||||||
300: { value: '#fca5a5' },
|
|
||||||
400: { value: '#f87171' },
|
|
||||||
500: { value: '#ef4444' },
|
|
||||||
600: { value: '#dc2626' },
|
|
||||||
700: { value: '#b91c1c' },
|
|
||||||
800: { value: '#991b1b' },
|
|
||||||
900: { value: '#7f1d1d' },
|
|
||||||
};
|
|
||||||
|
|
||||||
export const colors = {
|
|
||||||
// Update me with other Tailwind colors or with https://smart-swatch.netlify.app/
|
|
||||||
brand: brand,
|
|
||||||
back: back,
|
|
||||||
text: normalText,
|
|
||||||
success: green,
|
|
||||||
error: red,
|
|
||||||
warning: orange,
|
|
||||||
} as const;
|
|
@ -1,9 +0,0 @@
|
|||||||
import { colors } from './colors';
|
|
||||||
import { shadows } from './shadows';
|
|
||||||
|
|
||||||
const foundations = {
|
|
||||||
colors,
|
|
||||||
shadows,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default foundations;
|
|
@ -1,21 +0,0 @@
|
|||||||
import { colors } from './colors';
|
|
||||||
|
|
||||||
const createOutline = (colorScheme = 'gray') =>
|
|
||||||
`0 0 0 3px ${colorScheme}.500/3`;
|
|
||||||
|
|
||||||
export const shadows = {
|
|
||||||
outline: createOutline('brand'),
|
|
||||||
'outline-brand': '0 0 0 1px brand.900',
|
|
||||||
'outline-gray': createOutline('gray'),
|
|
||||||
'outline-over': `4px 4px 5px #00000088`,
|
|
||||||
'outline-darkgray': `0 0 0 3px gray.500/8`,
|
|
||||||
'outline-success': createOutline('success'),
|
|
||||||
'outline-warning': createOutline('warning'),
|
|
||||||
'outline-error': createOutline('error'),
|
|
||||||
'outline-doing': createOutline('doing'),
|
|
||||||
'outline-paused': createOutline('paused'),
|
|
||||||
layout: '0 0 24px 1px rgba(0, 0, 0, 0.05)',
|
|
||||||
smooth: 'inset 0px 0px 16px rgba(0, 0, 0, 0.05)',
|
|
||||||
// smooth-light is used for dark backgrounds
|
|
||||||
'smooth-light': 'inset 0px 0px 16px rgba(255, 255, 255, 0.1)',
|
|
||||||
};
|
|
@ -1,48 +0,0 @@
|
|||||||
import * as recipes from './recipes';
|
|
||||||
import { colors } from "./foundations/colors"
|
|
||||||
|
|
||||||
const baseTheme = {
|
|
||||||
globalCss: {
|
|
||||||
body: {
|
|
||||||
overflowY: 'none',
|
|
||||||
bg: { _light: 'back.50', _dark: 'back.700' },
|
|
||||||
color: { _light: 'text.900', _dark: 'text.50' },
|
|
||||||
fontFamily: 'Roboto, Helvetica, Arial, "sans-serif"',
|
|
||||||
},
|
|
||||||
svg: {
|
|
||||||
width: "32px",
|
|
||||||
height: "32px",
|
|
||||||
aspectRatio: "square",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
theme: {
|
|
||||||
tokens: {
|
|
||||||
fonts: {
|
|
||||||
heading: { value: `Roboto, Helvetica, Arial, "sans-serif"` },
|
|
||||||
body: { value: `Roboto, Helvetica, Arial, "sans-serif"` },
|
|
||||||
},
|
|
||||||
colors,
|
|
||||||
},
|
|
||||||
semanticTokens: {
|
|
||||||
colors: {
|
|
||||||
brand: {
|
|
||||||
solid: { value: "{colors.brand.500}" },
|
|
||||||
contrast: { value: "{colors.brand.100}" },
|
|
||||||
fg: { value: "{colors.brand.700}" },
|
|
||||||
muted: { value: "{colors.brand.100}" },
|
|
||||||
subtle: { value: "{colors.brand.200}" },
|
|
||||||
emphasized: { value: "{colors.brand.300}" },
|
|
||||||
focusRing: { value: "{colors.brand.500}" },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
/*
|
|
||||||
const config = mergeConfigs(defaultConfig, baseTheme);
|
|
||||||
export const systemTheme = createSystem(config);
|
|
||||||
*/
|
|
||||||
export const THEME = {
|
|
||||||
...recipes
|
|
||||||
};
|
|
||||||
|
|
3
front/src/types/theme.d.ts
vendored
3
front/src/types/theme.d.ts
vendored
@ -1,3 +0,0 @@
|
|||||||
import { colors } from '@/theme/foundations/colors';
|
|
||||||
|
|
||||||
export type ColorSchemes = ThemeTypings['colorSchemes'] | keyof typeof colors;
|
|
@ -1,3 +1,4 @@
|
|||||||
|
import { useTheme } from "@/theme/ThemeContext";
|
||||||
import { ReactNode, CSSProperties } from "react";
|
import { ReactNode, CSSProperties } from "react";
|
||||||
|
|
||||||
export type ButtonProps = {
|
export type ButtonProps = {
|
||||||
@ -7,19 +8,21 @@ export type ButtonProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const Button = ({ children, onClick, style }: ButtonProps) => {
|
export const Button = ({ children, onClick, style }: ButtonProps) => {
|
||||||
|
const { convertStyle } = useTheme();
|
||||||
|
const themedStyle = style ? convertStyle({
|
||||||
|
padding: '10px 20px',
|
||||||
|
backgroundColor: '#3182CE',
|
||||||
|
color: '#FFF',
|
||||||
|
border: 'none',
|
||||||
|
borderRadius: '4px',
|
||||||
|
cursor: 'pointer',
|
||||||
|
fontSize: '16px',
|
||||||
|
...style,
|
||||||
|
}) : undefined;
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
style={{
|
style={themedStyle}
|
||||||
padding: '10px 20px',
|
|
||||||
backgroundColor: '#3182CE',
|
|
||||||
color: '#FFF',
|
|
||||||
border: 'none',
|
|
||||||
borderRadius: '4px',
|
|
||||||
cursor: 'pointer',
|
|
||||||
fontSize: '16px',
|
|
||||||
...style,
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</button>
|
</button>
|
||||||
|
21
front/src/ui/Div.tsx
Normal file
21
front/src/ui/Div.tsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { useTheme } from '@/theme/ThemeContext';
|
||||||
|
import { CSSProperties, ReactNode } from 'react';
|
||||||
|
|
||||||
|
export type DivProps = {
|
||||||
|
children?: ReactNode;
|
||||||
|
onClick?: () => void;
|
||||||
|
style?: CSSProperties
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Div = ({ children, onClick, style }: DivProps) => {
|
||||||
|
const { convertStyle } = useTheme();
|
||||||
|
const themedStyle = style ? convertStyle(style) : undefined;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
onClick={onClick}
|
||||||
|
style={themedStyle}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -1,4 +1,5 @@
|
|||||||
import React, { CSSProperties, ReactNode } from 'react';
|
import React, { CSSProperties, ReactNode } from 'react';
|
||||||
|
import { Div } from './Div';
|
||||||
|
|
||||||
export type FlexProps = {
|
export type FlexProps = {
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
@ -7,12 +8,44 @@ export type FlexProps = {
|
|||||||
gap?: string | number;
|
gap?: string | number;
|
||||||
justify?: CSSProperties['justifyContent'];
|
justify?: CSSProperties['justifyContent'];
|
||||||
align?: CSSProperties['alignItems'];
|
align?: CSSProperties['alignItems'];
|
||||||
|
width?: CSSProperties['width'];
|
||||||
|
height?: CSSProperties['height'];
|
||||||
|
padding?: CSSProperties['padding'];
|
||||||
|
margin?: CSSProperties['margin'];
|
||||||
|
maxWidth?: CSSProperties['maxWidth'];
|
||||||
|
minWidth?: CSSProperties['minWidth'];
|
||||||
|
maxHeight?: CSSProperties['maxHeight'];
|
||||||
|
minHeight?: CSSProperties['maxHeight'];
|
||||||
|
paddingLeft?: CSSProperties['paddingLeft'];
|
||||||
|
paddingRight?: CSSProperties['paddingRight'];
|
||||||
|
paddingTop?: CSSProperties['paddingTop'];
|
||||||
|
paddingBottom?: CSSProperties['paddingBottom'];
|
||||||
|
marginLeft?: CSSProperties['marginLeft'];
|
||||||
|
marginRight?: CSSProperties['marginRight'];
|
||||||
|
marginTop?: CSSProperties['marginTop'];
|
||||||
|
marginBottom?: CSSProperties['marginBottom'];
|
||||||
style?: Omit<CSSProperties, "flexDirection" | "display" | "justifyContent" | "alignItems" | "alignItems" | "direction">
|
style?: Omit<CSSProperties, "flexDirection" | "display" | "justifyContent" | "alignItems" | "alignItems" | "direction">
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Flex = ({ children, onClick, direction = 'row', justify = 'flex-start', gap, align = 'stretch', style }: FlexProps) => {
|
export const Flex = ({
|
||||||
|
children,
|
||||||
|
onClick,
|
||||||
|
direction = 'row',
|
||||||
|
justify = 'flex-start',
|
||||||
|
gap,
|
||||||
|
align = 'stretch',
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
padding,
|
||||||
|
margin,
|
||||||
|
maxWidth,
|
||||||
|
minWidth,
|
||||||
|
maxHeight,
|
||||||
|
minHeight, paddingLeft, paddingRight, paddingTop, paddingBottom, marginLeft, marginRight, marginTop, marginBottom,
|
||||||
|
style }: FlexProps) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<Div
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -20,10 +53,18 @@ export const Flex = ({ children, onClick, direction = 'row', justify = 'flex-sta
|
|||||||
justifyContent: justify,
|
justifyContent: justify,
|
||||||
gap: gap,
|
gap: gap,
|
||||||
alignItems: align,
|
alignItems: align,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
padding,
|
||||||
|
margin,
|
||||||
|
maxWidth,
|
||||||
|
minWidth,
|
||||||
|
maxHeight,
|
||||||
|
minHeight, paddingLeft, paddingRight, paddingTop, paddingBottom, marginLeft, marginRight, marginTop, marginBottom,
|
||||||
...style,
|
...style,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</Div>
|
||||||
);
|
);
|
||||||
};
|
};
|
@ -1,4 +1,5 @@
|
|||||||
import { ReactNode, CSSProperties } from "react";
|
import { ReactNode, CSSProperties } from "react";
|
||||||
|
import { Div } from "./Div";
|
||||||
|
|
||||||
export type FullPageProps = {
|
export type FullPageProps = {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@ -7,7 +8,7 @@ export type FullPageProps = {
|
|||||||
|
|
||||||
export const FullPage = ({ children, style }: FullPageProps) => {
|
export const FullPage = ({ children, style }: FullPageProps) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<Div
|
||||||
style={{
|
style={{
|
||||||
top: '0',
|
top: '0',
|
||||||
bottom: '0',
|
bottom: '0',
|
||||||
@ -17,6 +18,6 @@ export const FullPage = ({ children, style }: FullPageProps) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</Div>
|
||||||
);
|
);
|
||||||
};
|
};
|
@ -1,4 +1,5 @@
|
|||||||
import { ReactNode, CSSProperties } from "react";
|
import { ReactNode, CSSProperties } from "react";
|
||||||
|
import { Div } from "./Div";
|
||||||
|
|
||||||
export type HStackProps = {
|
export type HStackProps = {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@ -9,7 +10,7 @@ export type HStackProps = {
|
|||||||
|
|
||||||
export const HStack = ({ children, spacing = '8px', align = 'flex-start', style }: HStackProps) => {
|
export const HStack = ({ children, spacing = '8px', align = 'flex-start', style }: HStackProps) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<Div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
@ -19,6 +20,6 @@ export const HStack = ({ children, spacing = '8px', align = 'flex-start', style
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</Div>
|
||||||
);
|
);
|
||||||
};
|
};
|
30
front/src/ui/Image.tsx
Normal file
30
front/src/ui/Image.tsx
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { CSSProperties, RefObject } from "react";
|
||||||
|
import { useTheme } from "@/theme/ThemeContext";
|
||||||
|
|
||||||
|
export type ImageProps = {
|
||||||
|
ref?: RefObject<any>;
|
||||||
|
href?: string;
|
||||||
|
boxSize?: string;
|
||||||
|
onChange?: (e) => void;
|
||||||
|
style?: Omit<CSSProperties, "fontSize" | "fontWeight" | "color">;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Image = ({
|
||||||
|
ref,
|
||||||
|
href,
|
||||||
|
boxSize,
|
||||||
|
onChange,
|
||||||
|
style,
|
||||||
|
}: ImageProps) => {
|
||||||
|
const { convertStyle } = useTheme();
|
||||||
|
const themedStyle = style ? convertStyle({ width: boxSize, height: boxSize, ...style }) : undefined;
|
||||||
|
return (
|
||||||
|
<image
|
||||||
|
ref={ref}
|
||||||
|
href={href}
|
||||||
|
onChange={onChange}
|
||||||
|
style={themedStyle}
|
||||||
|
>
|
||||||
|
</image>
|
||||||
|
);
|
||||||
|
};
|
29
front/src/ui/Input.tsx
Normal file
29
front/src/ui/Input.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { ReactNode, CSSProperties, RefObject } from "react";
|
||||||
|
import { Div } from "./Div";
|
||||||
|
import { useTheme } from "@/theme/ThemeContext";
|
||||||
|
|
||||||
|
export type InputProps = {
|
||||||
|
ref?: RefObject<any>;
|
||||||
|
value?: string;
|
||||||
|
onChange?: (e) => void;
|
||||||
|
style?: Omit<CSSProperties, "fontSize" | "fontWeight" | "color">;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Input = ({
|
||||||
|
ref,
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
style,
|
||||||
|
}: InputProps) => {
|
||||||
|
const { convertStyle } = useTheme();
|
||||||
|
const themedStyle = style ? convertStyle(style) : undefined;
|
||||||
|
return (
|
||||||
|
<input
|
||||||
|
ref={ref}
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
style={themedStyle}
|
||||||
|
>
|
||||||
|
</input>
|
||||||
|
);
|
||||||
|
};
|
16
front/src/ui/Link.tsx
Normal file
16
front/src/ui/Link.tsx
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { CSSProperties, ReactNode } from 'react'
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { Div } from './Div';
|
||||||
|
|
||||||
|
export type LinkProps = {
|
||||||
|
href?: string;
|
||||||
|
style?: CSSProperties;
|
||||||
|
children?: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Link = ({ href = "/", style, children }: LinkProps) => {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
return (<Div onClick={() => navigate(href)}
|
||||||
|
style={style}
|
||||||
|
> {children}</Div >);
|
||||||
|
}
|
36
front/src/ui/Span.tsx
Normal file
36
front/src/ui/Span.tsx
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { ReactNode, CSSProperties } from "react";
|
||||||
|
import { Div } from "./Div";
|
||||||
|
import { useTheme } from "@/theme/ThemeContext";
|
||||||
|
|
||||||
|
export type SpanProps = {
|
||||||
|
children: ReactNode;
|
||||||
|
color?: string;
|
||||||
|
fontSize?: CSSProperties["fontSize"];
|
||||||
|
fontWeight?: CSSProperties["fontWeight"];
|
||||||
|
userSelect?: CSSProperties["userSelect"];
|
||||||
|
style?: Omit<CSSProperties, "fontSize" | "fontWeight" | "color">;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Span = ({ children,
|
||||||
|
fontSize = '16px',
|
||||||
|
fontWeight = "normal",
|
||||||
|
color = "#000000",
|
||||||
|
userSelect,
|
||||||
|
style,
|
||||||
|
}: SpanProps) => {
|
||||||
|
const { convertStyle } = useTheme();
|
||||||
|
const themedStyle = style ? convertStyle({
|
||||||
|
fontSize,
|
||||||
|
color,
|
||||||
|
fontWeight,
|
||||||
|
userSelect,
|
||||||
|
...style,
|
||||||
|
}) : undefined;
|
||||||
|
return (
|
||||||
|
<span
|
||||||
|
style={themedStyle}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
@ -1,3 +1,4 @@
|
|||||||
|
import { useTheme } from "@/theme/ThemeContext";
|
||||||
import { CSSProperties, ReactNode } from "react"
|
import { CSSProperties, ReactNode } from "react"
|
||||||
|
|
||||||
export type BodyProps = {
|
export type BodyProps = {
|
||||||
@ -5,5 +6,7 @@ export type BodyProps = {
|
|||||||
style?: CSSProperties;
|
style?: CSSProperties;
|
||||||
};
|
};
|
||||||
export const Body = ({ children, style }: BodyProps) => {
|
export const Body = ({ children, style }: BodyProps) => {
|
||||||
return <tbody style={style}>{children}</tbody>
|
const { convertStyle } = useTheme();
|
||||||
|
const themedStyle = style ? convertStyle(style) : undefined;
|
||||||
|
return <tbody style={themedStyle}>{children}</tbody>
|
||||||
}
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
import { useTheme } from "@/theme/ThemeContext";
|
||||||
import { CSSProperties, ReactNode } from "react"
|
import { CSSProperties, ReactNode } from "react"
|
||||||
|
|
||||||
export type CellProps = {
|
export type CellProps = {
|
||||||
@ -5,5 +6,7 @@ export type CellProps = {
|
|||||||
style?: CSSProperties;
|
style?: CSSProperties;
|
||||||
};
|
};
|
||||||
export const Cell = ({ children, style }: CellProps) => {
|
export const Cell = ({ children, style }: CellProps) => {
|
||||||
return <td style={style}>{children}</td>
|
const { convertStyle } = useTheme();
|
||||||
|
const themedStyle = style ? convertStyle(style) : undefined;
|
||||||
|
return <td style={themedStyle}>{children}</td>
|
||||||
}
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
import { useTheme } from "@/theme/ThemeContext";
|
||||||
import { CSSProperties, ReactNode } from "react"
|
import { CSSProperties, ReactNode } from "react"
|
||||||
|
|
||||||
export type ColumnHeaderProps = {
|
export type ColumnHeaderProps = {
|
||||||
@ -5,5 +6,7 @@ export type ColumnHeaderProps = {
|
|||||||
style?: CSSProperties;
|
style?: CSSProperties;
|
||||||
};
|
};
|
||||||
export const ColumnHeader = ({ children, style }: ColumnHeaderProps) => {
|
export const ColumnHeader = ({ children, style }: ColumnHeaderProps) => {
|
||||||
return <th style={style}>{children}</th>
|
const { convertStyle } = useTheme();
|
||||||
|
const themedStyle = style ? convertStyle(style) : undefined;
|
||||||
|
return <th style={themedStyle}>{children}</th>
|
||||||
}
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
import { useTheme } from "@/theme/ThemeContext";
|
||||||
import { CSSProperties, ReactNode } from "react"
|
import { CSSProperties, ReactNode } from "react"
|
||||||
|
|
||||||
export type HeaderProps = {
|
export type HeaderProps = {
|
||||||
@ -5,5 +6,7 @@ export type HeaderProps = {
|
|||||||
style?: CSSProperties;
|
style?: CSSProperties;
|
||||||
};
|
};
|
||||||
export const Header = ({ children, style }: HeaderProps) => {
|
export const Header = ({ children, style }: HeaderProps) => {
|
||||||
return <thead style={style}>{children}</thead>
|
const { convertStyle } = useTheme();
|
||||||
|
const themedStyle = style ? convertStyle(style) : undefined;
|
||||||
|
return <thead style={themedStyle}>{children}</thead>
|
||||||
}
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
import { useTheme } from '@/theme/ThemeContext';
|
||||||
import { CSSProperties, ReactNode } from 'react'
|
import { CSSProperties, ReactNode } from 'react'
|
||||||
|
|
||||||
export type RootProps = {
|
export type RootProps = {
|
||||||
@ -7,9 +8,11 @@ export type RootProps = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const Root = ({ background, children, style }: RootProps) => {
|
export const Root = ({ background, children, style }: RootProps) => {
|
||||||
|
const { convertStyle } = useTheme();
|
||||||
|
const themedStyle = style ? convertStyle({
|
||||||
|
backgroundColor: background,
|
||||||
|
...style
|
||||||
|
}) : undefined;
|
||||||
return (<table
|
return (<table
|
||||||
style={{
|
style={themedStyle}>{children}</table>);
|
||||||
backgroundColor: background,
|
|
||||||
...style
|
|
||||||
}}>{children}</table>);
|
|
||||||
}
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
import { useTheme } from "@/theme/ThemeContext";
|
||||||
import { CSSProperties, ReactNode } from "react"
|
import { CSSProperties, ReactNode } from "react"
|
||||||
|
|
||||||
export type RowProps = {
|
export type RowProps = {
|
||||||
@ -6,5 +7,7 @@ export type RowProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const Row = ({ children, style }: RowProps) => {
|
export const Row = ({ children, style }: RowProps) => {
|
||||||
return <tr style={style}>{children}</tr>
|
const { convertStyle } = useTheme();
|
||||||
|
const themedStyle = style ? convertStyle(style) : undefined;
|
||||||
|
return <tr style={themedStyle}>{children}</tr>
|
||||||
}
|
}
|
@ -1,10 +1,12 @@
|
|||||||
import { ReactNode, CSSProperties } from "react";
|
import { ReactNode, CSSProperties } from "react";
|
||||||
|
import { Div } from "./Div";
|
||||||
|
|
||||||
export type TextProps = {
|
export type TextProps = {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
color?: string;
|
color?: string;
|
||||||
fontSize?: CSSProperties["fontSize"];
|
fontSize?: CSSProperties["fontSize"];
|
||||||
fontWeight?: CSSProperties["fontWeight"];
|
fontWeight?: CSSProperties["fontWeight"];
|
||||||
|
userSelect?: CSSProperties["userSelect"];
|
||||||
style?: Omit<CSSProperties, "fontSize" | "fontWeight" | "color">;
|
style?: Omit<CSSProperties, "fontSize" | "fontWeight" | "color">;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -12,18 +14,20 @@ export const Text = ({ children,
|
|||||||
fontSize = '16px',
|
fontSize = '16px',
|
||||||
fontWeight = "normal",
|
fontWeight = "normal",
|
||||||
color = "#000000",
|
color = "#000000",
|
||||||
|
userSelect,
|
||||||
style,
|
style,
|
||||||
}: TextProps) => {
|
}: TextProps) => {
|
||||||
return (
|
return (
|
||||||
<span
|
<Div
|
||||||
style={{
|
style={{
|
||||||
fontSize,
|
fontSize,
|
||||||
color,
|
color,
|
||||||
fontWeight,
|
fontWeight,
|
||||||
|
userSelect,
|
||||||
...style,
|
...style,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</span>
|
</Div>
|
||||||
);
|
);
|
||||||
};
|
};
|
29
front/src/ui/Textarea.tsx
Normal file
29
front/src/ui/Textarea.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { ReactNode, CSSProperties, RefObject } from "react";
|
||||||
|
import { Div } from "./Div";
|
||||||
|
import { useTheme } from "@/theme/ThemeContext";
|
||||||
|
|
||||||
|
export type TextareaProps = {
|
||||||
|
ref?: RefObject<any>;
|
||||||
|
value?: string;
|
||||||
|
onChange?: (e) => void;
|
||||||
|
style?: Omit<CSSProperties, "fontSize" | "fontWeight" | "color">;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Textarea = ({
|
||||||
|
ref,
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
style,
|
||||||
|
}: TextareaProps) => {
|
||||||
|
const { convertStyle } = useTheme();
|
||||||
|
const themedStyle = style ? convertStyle(style) : undefined;
|
||||||
|
return (
|
||||||
|
<textarea
|
||||||
|
ref={ref}
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}
|
||||||
|
style={themedStyle}
|
||||||
|
>
|
||||||
|
</textarea>
|
||||||
|
);
|
||||||
|
};
|
@ -1,4 +1,5 @@
|
|||||||
import { ReactNode, CSSProperties } from "react";
|
import { ReactNode, CSSProperties } from "react";
|
||||||
|
import { Div } from "./Div";
|
||||||
|
|
||||||
export type VStackProps = {
|
export type VStackProps = {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
@ -9,7 +10,7 @@ export type VStackProps = {
|
|||||||
|
|
||||||
export const VStack = ({ children, spacing = '8px', align = 'flex-start', style }: VStackProps) => {
|
export const VStack = ({ children, spacing = '8px', align = 'flex-start', style }: VStackProps) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<Div
|
||||||
style={{
|
style={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
@ -19,6 +20,6 @@ export const VStack = ({ children, spacing = '8px', align = 'flex-start', style
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</Div>
|
||||||
);
|
);
|
||||||
};
|
};
|
@ -4,4 +4,10 @@ export * from "./Flex.tsx"
|
|||||||
export * from "./HStack.tsx"
|
export * from "./HStack.tsx"
|
||||||
export * from "./VStack.tsx"
|
export * from "./VStack.tsx"
|
||||||
export * from "./FullPage.tsx"
|
export * from "./FullPage.tsx"
|
||||||
|
export * from "./Link.tsx"
|
||||||
|
export * from "./Div.tsx"
|
||||||
|
export * from "./Span.tsx"
|
||||||
|
export * from "./Input.tsx"
|
||||||
|
export * from "./Textarea.tsx"
|
||||||
|
export * from "./Image.tsx"
|
||||||
export * as Table from "./Table"
|
export * as Table from "./Table"
|
1
front/tsconfig.tsbuildinfo
Normal file
1
front/tsconfig.tsbuildinfo
Normal file
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user