[FEAT] better covers, Icons and work on better display for the phones

This commit is contained in:
Edouard DUPIN 2024-09-15 14:54:17 +02:00
parent 031f5650e4
commit 6be185d435
15 changed files with 113 additions and 60 deletions

View File

@ -27,7 +27,6 @@
"*.{ts,tsx,js,jsx,json}": "prettier --write"
},
"dependencies": {
"framer-motion": "11.5.4",
"@chakra-ui/anatomy": "2.2.2",
"@chakra-ui/cli": "2.4.1",
"@chakra-ui/react": "2.8.2",

View File

@ -1,28 +1,47 @@
import { ReactElement, useEffect, useState } from 'react';
import { Box, BoxProps, Flex } from '@chakra-ui/react';
import { As, Box, BoxProps, Flex, StyleProps } from '@chakra-ui/react';
import { Image } from '@chakra-ui/react';
import { DataUrlAccess } from '@/utils/data-url-access';
import { Icon } from './Icon';
export type CoversProps = BoxProps & {
data?: string[];
size?: string;
iconEmpty?: ReactElement;
size?: StyleProps["width"];
iconEmpty?: As;
slideshow?: boolean;
};
export const Covers = ({
data,
iconEmpty,
size = '100px',
slideshow = false,
...rest
}: CoversProps) => {
const [currentImageIndex, setCurrentImageIndex] = useState(0);
const [previousImageIndex, setPreviousImageIndex] = useState(0);
const [topOpacity, setTopOpacity] = useState(0.0);
useEffect(() => {
if (!slideshow) {
return;
}
const interval = setInterval(() => {
setPreviousImageIndex(currentImageIndex);
setTopOpacity(0.0);
setTimeout(() => {
setCurrentImageIndex((prevIndex) => (prevIndex + 1) % (data?.length ?? 1));
setTopOpacity(1.0);
}, 1500);
}, 3000);
return () => clearInterval(interval);
}, [slideshow, data]);
if (!data || data.length < 1) {
if (iconEmpty) {
return iconEmpty;
return <Icon icon={iconEmpty} sizeIcon={size} />;
} else {
return (
<Box
@ -38,24 +57,13 @@ export const Covers = ({
);
}
}
if (data.length == 1) {
if (slideshow === false || data.length === 1) {
const url = DataUrlAccess.getThumbnailUrl(data[0]);
return <Image loading="lazy" src={url} boxSize={size} {...rest} />;
return <Image loading="lazy" src={url} maxWidth={size} boxSize={size} {...rest} />;
}
useEffect(() => {
const interval = setInterval(() => {
setPreviousImageIndex(currentImageIndex);
setTopOpacity(0.0);
setTimeout(() => {
setCurrentImageIndex((prevIndex) => (prevIndex + 1) % data.length);
setTopOpacity(1.0);
}, 1500);
}, 3000);
return () => clearInterval(interval);
}, []);
const urlCurrent = DataUrlAccess.getThumbnailUrl(data[currentImageIndex]);
const urlPrevious = DataUrlAccess.getThumbnailUrl(data[previousImageIndex]);
return <Flex position="relative" {...rest} maxWidth={size} width={size} height={size} overflow="hidden" border="1px">
return <Flex position="relative" {...rest} maxWidth={size} width={size} height={size} overflow="hidden">
<Image
src={urlPrevious}
loading="lazy"
@ -79,7 +87,6 @@ export const Covers = ({
transition="opacity 0.5s ease-in-out"
opacity={topOpacity}
zIndex={2}
border="1px"
/>
</Flex>
};

View File

@ -0,0 +1,42 @@
import {
As,
Box,
BoxProps,
Icon as ChakraIcon,
IconProps as ChakraIconProps,
Flex,
FlexProps,
forwardRef,
LayoutProps,
} from '@chakra-ui/react';
export type IconProps = FlexProps & {
icon: As;
color?: string;
sizeIcon?: LayoutProps['width'];
};
export const Icon = forwardRef<IconProps, 'span'>(
({ icon: IconEl, color, sizeIcon = '1em', ...rest }, ref) => {
return (
<Flex flex="none"
minWidth={sizeIcon}
minHeight={sizeIcon}
maxWidth={sizeIcon}
maxHeight={sizeIcon}
align="center"
padding="1%"
ref={ref}
{...rest}>
<Box
marginX="auto"
as={IconEl}
width="100%"
minWidth="100%"
height="100%"
color={color}
/>
</Flex>
);
}
);

View File

@ -27,6 +27,7 @@ export const PageLayout = ({ children }: LayoutProps) => {
bottom={0}
left={0}
right={0}
minWidth="300px"
zIndex={-1}
>
<Image src={background} boxSize="90%" margin="auto" opacity="30%" />
@ -42,6 +43,7 @@ export const PageLayout = ({ children }: LayoutProps) => {
bottom={0}
left={0}
right={0}
minWidth="300px"
>
{children}
</Flex>

View File

@ -4,6 +4,7 @@ import { LuDisc3 } from 'react-icons/lu';
import { Album } from '@/back-api';
import { Covers } from '@/components/Cover';
import { useCountTracksWithAlbumId } from '@/service/Track';
import { BASE_WRAP_ICON_SIZE } from '@/constants/genericSpacing';
export type DisplayAlbumProps = {
dataAlbum?: Album;
@ -21,18 +22,18 @@ export const DisplayAlbum = ({ dataAlbum }: DisplayAlbumProps) => {
<Flex direction="row" width="full" height="full">
<Covers
data={dataAlbum?.covers}
size="100"
height="full"
size={BASE_WRAP_ICON_SIZE}
flex={1}
iconEmpty={<LuDisc3 size="100" height="full" />}
iconEmpty={LuDisc3}
/>
<Flex
direction="column"
width="150px"
maxWidth="150px"
//maxWidth="150px"
height="full"
paddingLeft="5px"
overflowX="hidden"
flex={1}
>
<Text
as="span"

View File

@ -23,7 +23,7 @@ export const DisplayGender = ({ dataGender }: DisplayGenderProps) => {
data={dataGender?.covers}
size="100"
height="full"
iconEmpty={<LuDisc3 size="100" height="full" />}
iconEmpty={LuDisc3}
/>
<Flex
direction="column"

View File

@ -24,11 +24,7 @@ export const DisplayTrack = ({
size="50"
height="full"
iconEmpty={
trackActive?.id === track.id ? (
<LuPlay size="50" height="full" />
) : (
<LuMusic2 size="50" height="full" />
)
trackActive?.id === track.id ? LuPlay : LuMusic2
}
onClick={onClick}
/>

View File

@ -6,7 +6,6 @@ import { LuMusic2, LuPlay } from 'react-icons/lu';
import { Track } from '@/back-api';
import { Covers } from '@/components/Cover';
import { ContextMenu, MenuElement } from '@/components/contextMenu/ContextMenu';
import { DisplayTrackSkeleton } from '@/components/track/DisplayTrackSkeleton';
import { useActivePlaylistService } from '@/service/ActivePlaylist';
import { useSpecificAlbum } from '@/service/Album';
import { useSpecificArtists } from '@/service/Artist';
@ -31,14 +30,9 @@ export const DisplayTrackFull = ({
<Covers
data={track?.covers}
size="50"
//height="full"
marginY="auto"
iconEmpty={
trackActive?.id === track.id ? (
<LuPlay size="50" />
) : (
<LuMusic2 size="50" />
)
trackActive?.id === track.id ? LuPlay : LuMusic2
}
onClick={onClick}
/>
@ -76,7 +70,7 @@ export const DisplayTrackFull = ({
marginY="auto"
color={trackActive?.id === track.id ? 'green.700' : undefined}
>
Album {dataAlbum.name}
<Text as="span" fontWeight="normal">Album:</Text> {dataAlbum.name}
</Text>
)}
{dataArtists && (
@ -92,7 +86,7 @@ export const DisplayTrackFull = ({
marginY="auto"
color={trackActive?.id === track.id ? 'green.700' : undefined}
>
Artist(s): {dataArtists.map((data) => data.name).join(', ')}
<Text as="span" fontWeight="normal">Artist(s):</Text> {dataArtists.map((data) => data.name).join(', ')}
</Text>
)}
{dataGender && (
@ -108,7 +102,7 @@ export const DisplayTrackFull = ({
marginY="auto"
color={trackActive?.id === track.id ? 'green.700' : undefined}
>
Gender: {dataGender.name}
<Text as="span" fontWeight="normal">Gender:</Text> {dataGender.name}
</Text>
)}
</Flex>

View File

@ -0,0 +1,4 @@
export const BASE_WRAP_SPACING = { base: "5px", md: "10px", lg: "20px" };
export const BASE_WRAP_WIDTH = { base: "90%", md: "45%", lg: "270px" };
export const BASE_WRAP_HEIGHT = { base: "75px", lg: "120px" };
export const BASE_WRAP_ICON_SIZE = { base: "50px", lg: "100px" };

View File

@ -16,6 +16,7 @@ import { useActivePlaylistService } from '@/service/ActivePlaylist';
import { useSpecificAlbum } from '@/service/Album';
import { useTracksOfAnAlbum } from '@/service/Track';
import { useThemeMode } from '@/utils/theme-tools';
import { BASE_WRAP_SPACING } from '@/constants/genericSpacing';
export const AlbumDetailPage = () => {
const { albumId } = useParams();
@ -75,7 +76,8 @@ export const AlbumDetailPage = () => {
>
<Covers
data={dataAlbum?.covers}
iconEmpty={<LuDisc3 size="100" height="full" />}
iconEmpty={LuDisc3}
slideshow
/>
<Flex direction="column" width="80%" marginRight="auto">
<Text fontSize="24px" fontWeight="bold">
@ -92,7 +94,7 @@ export const AlbumDetailPage = () => {
<Flex
direction="column"
gap="20px"
gap={BASE_WRAP_SPACING}
marginX="auto"
padding="20px"
width="80%"
@ -122,7 +124,7 @@ export const AlbumDetailPage = () => {
navigate(`/album/${albumId}/edit-track/${data.id}`);
},
},
{ name: 'Add Playlist', onClick: () => {} },
{ name: 'Add Playlist', onClick: () => { } },
]}
/>
</Box>

View File

@ -11,6 +11,7 @@ import { TopBar } from '@/components/TopBar/TopBar';
import { DisplayAlbum } from '@/components/album/DisplayAlbum';
import { useOrderedAlbums } from '@/service/Album';
import { useThemeMode } from '@/utils/theme-tools';
import { BASE_WRAP_SPACING, BASE_WRAP_WIDTH, BASE_WRAP_HEIGHT } from '@/constants/genericSpacing';
export const AlbumsPage = () => {
const [filterTitle, setFilterTitle] = useState<string | undefined>(undefined);
@ -36,11 +37,11 @@ export const AlbumsPage = () => {
<SearchInput onChange={setFilterTitle} />
</TopBar>
<PageLayout>
<Wrap spacing="20px" marginX="auto" padding="20px" justify="center">
<Wrap spacing={BASE_WRAP_SPACING} marginX="auto" padding="20px" justify="center">
{dataAlbums.map((data) => (
<WrapItem
width="270px"
height="120px"
width={BASE_WRAP_WIDTH}
height={BASE_WRAP_HEIGHT}
border="1px"
borderColor="brand.900"
backgroundColor={mode('#FFFFFF88', '#00000088')}

View File

@ -68,7 +68,7 @@ export const ArtistAlbumDetailPage = () => {
data={dataArtist?.covers}
size="35px"
borderRadius="full"
iconEmpty={<MdPerson height="full" />}
iconEmpty={MdPerson}
/>
<Text fontSize="24px" fontWeight="bold">
{dataArtist?.name}
@ -95,7 +95,8 @@ export const ArtistAlbumDetailPage = () => {
>
<Covers
data={dataAlbum?.covers}
iconEmpty={<LuDisc3 size="100" height="full" />}
iconEmpty={LuDisc3}
slideshow
/>
<Flex direction="column" width="80%" marginRight="auto">
<Text fontSize="24px" fontWeight="bold">
@ -144,7 +145,7 @@ export const ArtistAlbumDetailPage = () => {
);
},
},
{ name: 'Add Playlist', onClick: () => {} },
{ name: 'Add Playlist', onClick: () => { } },
]}
/>
</Box>

View File

@ -13,6 +13,7 @@ import { ArtistEditPopUp } from '@/components/popup/ArtistEditPopUp';
import { useSpecificArtist } from '@/service/Artist';
import { useAlbumIdsOfAnArtist } from '@/service/Track';
import { useThemeMode } from '@/utils/theme-tools';
import { BASE_WRAP_HEIGHT, BASE_WRAP_SPACING, BASE_WRAP_WIDTH } from '@/constants/genericSpacing';
export const ArtistDetailPage = () => {
const { artistId } = useParams();
@ -70,7 +71,8 @@ export const ArtistDetailPage = () => {
>
<Covers
data={dataArtist?.covers}
iconEmpty={<LuUser size="100" height="full" />}
iconEmpty={LuUser}
slideshow
/>
<Flex direction="column" width="80%" marginRight="auto">
<Text fontSize="24px" fontWeight="bold">
@ -87,11 +89,11 @@ export const ArtistDetailPage = () => {
</Flex>
</Flex>
<Wrap spacing="20px" marginX="auto" padding="20px" justify="center">
<Wrap spacing={BASE_WRAP_SPACING} marginX="auto" padding="20px" justify="center">
{albumIdsOfAnArtist?.map((data) => (
<WrapItem
width="270px"
height="120px"
width={BASE_WRAP_WIDTH}
height={BASE_WRAP_HEIGHT}
border="1px"
borderColor="brand.900"
backgroundColor={mode('#FFFFFF88', '#00000088')}

View File

@ -12,6 +12,7 @@ import { SearchInput } from '@/components/SearchInput';
import { TopBar } from '@/components/TopBar/TopBar';
import { useArtistService, useOrderedArtists } from '@/service/Artist';
import { useThemeMode } from '@/utils/theme-tools';
import { BASE_WRAP_HEIGHT, BASE_WRAP_ICON_SIZE, BASE_WRAP_SPACING, BASE_WRAP_WIDTH } from '@/constants/genericSpacing';
export const ArtistsPage = () => {
const { mode } = useThemeMode();
@ -27,11 +28,11 @@ export const ArtistsPage = () => {
<SearchInput onChange={setFilterName} />
</TopBar>
<PageLayout>
<Wrap spacing="20px" marginX="auto" padding="20px" justify="center">
<Wrap spacing={BASE_WRAP_SPACING} marginX="auto" padding="20px" justify="center">
{dataArtist?.map((data) => (
<WrapItem
width="270px"
height="120px"
width={BASE_WRAP_WIDTH}
height={BASE_WRAP_HEIGHT}
border="1px"
borderColor="brand.900"
backgroundColor={mode('#FFFFFF88', '#00000088')}
@ -47,9 +48,9 @@ export const ArtistsPage = () => {
<Flex direction="row" width="full" height="full">
<Covers
data={data.covers}
size="100"
size={BASE_WRAP_ICON_SIZE}
height="full"
iconEmpty={<LuUser size="100" height="full" />}
iconEmpty={LuUser}
/>
<Flex
direction="column"

View File

@ -76,7 +76,8 @@ export const GenderDetailPage = () => {
>
<Covers
data={dataGender?.covers}
iconEmpty={<LuDisc3 size="100" height="full" />}
iconEmpty={LuDisc3}
slideshow
/>
<Flex direction="column" width="80%" marginRight="auto">
<Text fontSize="24px" fontWeight="bold">
@ -120,7 +121,7 @@ export const GenderDetailPage = () => {
navigate(`/gender/${genderId}/edit-track/${data.id}`);
},
},
{ name: 'Add Playlist', onClick: () => {} },
{ name: 'Add Playlist', onClick: () => { } },
]}
/>
</Box>