Lint all files

This commit is contained in:
jeffvli 2023-07-01 19:10:05 -07:00
parent 22af76b4d6
commit 30e52ebb54
334 changed files with 76519 additions and 75932 deletions

View file

@ -11,208 +11,208 @@ import { Album, AlbumArtist, Artist, LibraryItem } from '/@/renderer/api/types';
import { CardRows } from '/@/renderer/components/card/card-rows';
const CardWrapper = styled.div<{
link?: boolean;
link?: boolean;
}>`
padding: 1rem;
background: var(--card-default-bg);
border-radius: var(--card-default-radius);
cursor: ${({ link }) => link && 'pointer'};
transition: border 0.2s ease-in-out, background 0.2s ease-in-out;
padding: 1rem;
background: var(--card-default-bg);
border-radius: var(--card-default-radius);
cursor: ${({ link }) => link && 'pointer'};
transition: border 0.2s ease-in-out, background 0.2s ease-in-out;
&:hover {
background: var(--card-default-bg-hover);
}
&:hover div {
opacity: 1;
}
&:hover * {
&::before {
opacity: 0.5;
&:hover {
background: var(--card-default-bg-hover);
}
}
&:focus-visible {
outline: 1px solid #fff;
}
&:hover div {
opacity: 1;
}
&:hover * {
&::before {
opacity: 0.5;
}
}
&:focus-visible {
outline: 1px solid #fff;
}
`;
const StyledCard = styled.div`
display: flex;
flex-direction: column;
gap: 0.5rem;
width: 100%;
height: 100%;
padding: 0;
border-radius: var(--card-default-radius);
display: flex;
flex-direction: column;
gap: 0.5rem;
width: 100%;
height: 100%;
padding: 0;
border-radius: var(--card-default-radius);
`;
const ImageSection = styled.div`
position: relative;
display: flex;
justify-content: center;
border-radius: var(--card-default-radius);
position: relative;
display: flex;
justify-content: center;
border-radius: var(--card-default-radius);
&::before {
position: absolute;
top: 0;
left: 0;
z-index: 1;
width: 100%;
height: 100%;
background: linear-gradient(0deg, rgba(0, 0, 0, 100%) 35%, rgba(0, 0, 0, 0%) 100%);
opacity: 0;
transition: all 0.2s ease-in-out;
content: '';
user-select: none;
}
&::before {
position: absolute;
top: 0;
left: 0;
z-index: 1;
width: 100%;
height: 100%;
background: linear-gradient(0deg, rgba(0, 0, 0, 100%) 35%, rgba(0, 0, 0, 0%) 100%);
opacity: 0;
transition: all 0.2s ease-in-out;
content: '';
user-select: none;
}
`;
const Image = styled(SimpleImg)`
border-radius: var(--card-default-radius);
box-shadow: 2px 2px 10px 2px rgba(0, 0, 0, 20%);
border-radius: var(--card-default-radius);
box-shadow: 2px 2px 10px 2px rgba(0, 0, 0, 20%);
`;
const ControlsContainer = styled.div`
position: absolute;
bottom: 0;
z-index: 50;
width: 100%;
opacity: 0;
transition: all 0.2s ease-in-out;
position: absolute;
bottom: 0;
z-index: 50;
width: 100%;
opacity: 0;
transition: all 0.2s ease-in-out;
`;
const DetailSection = styled.div`
display: flex;
flex-direction: column;
display: flex;
flex-direction: column;
`;
const Row = styled.div<{ $secondary?: boolean }>`
width: 100%;
max-width: 100%;
height: 22px;
padding: 0 0.2rem;
overflow: hidden;
color: ${({ $secondary }) => ($secondary ? 'var(--main-fg-secondary)' : 'var(--main-fg)')};
white-space: nowrap;
text-overflow: ellipsis;
user-select: none;
width: 100%;
max-width: 100%;
height: 22px;
padding: 0 0.2rem;
overflow: hidden;
color: ${({ $secondary }) => ($secondary ? 'var(--main-fg-secondary)' : 'var(--main-fg)')};
white-space: nowrap;
text-overflow: ellipsis;
user-select: none;
`;
interface BaseGridCardProps {
controls: {
cardRows: CardRow<Album | Artist | AlbumArtist>[];
itemType: LibraryItem;
playButtonBehavior: Play;
route: CardRoute;
};
data: any;
handlePlayQueueAdd?: (options: PlayQueueAddOptions) => void;
loading?: boolean;
size: number;
controls: {
cardRows: CardRow<Album | Artist | AlbumArtist>[];
itemType: LibraryItem;
playButtonBehavior: Play;
route: CardRoute;
};
data: any;
handlePlayQueueAdd?: (options: PlayQueueAddOptions) => void;
loading?: boolean;
size: number;
}
export const AlbumCard = ({
loading,
size,
handlePlayQueueAdd,
data,
controls,
loading,
size,
handlePlayQueueAdd,
data,
controls,
}: BaseGridCardProps) => {
const navigate = useNavigate();
const { itemType, cardRows, route } = controls;
const navigate = useNavigate();
const { itemType, cardRows, route } = controls;
const handleNavigate = useCallback(() => {
navigate(
generatePath(
route.route,
route.slugs?.reduce((acc, slug) => {
return {
...acc,
[slug.slugProperty]: data[slug.idProperty],
};
}, {}),
),
);
}, [data, navigate, route.route, route.slugs]);
const handleNavigate = useCallback(() => {
navigate(
generatePath(
route.route,
route.slugs?.reduce((acc, slug) => {
return {
...acc,
[slug.slugProperty]: data[slug.idProperty],
};
}, {}),
),
);
}, [data, navigate, route.route, route.slugs]);
if (!loading) {
return (
<CardWrapper
link
onClick={handleNavigate}
>
<StyledCard>
<ImageSection>
{data?.imageUrl ? (
<Image
animationDuration={0.3}
height={size}
imgStyle={{ objectFit: 'cover' }}
placeholder={data?.imagePlaceholderUrl || 'var(--card-default-bg)'}
src={data?.imageUrl}
width={size}
/>
) : (
<Center
sx={{
background: 'var(--placeholder-bg)',
borderRadius: 'var(--card-default-radius)',
height: `${size}px`,
width: `${size}px`,
}}
>
<RiAlbumFill
color="var(--placeholder-fg)"
size={35}
/>
</Center>
)}
<ControlsContainer>
<CardControls
handlePlayQueueAdd={handlePlayQueueAdd}
itemData={data}
itemType={itemType}
/>
</ControlsContainer>
</ImageSection>
<DetailSection>
<CardRows
data={data}
rows={cardRows}
/>
</DetailSection>
</StyledCard>
</CardWrapper>
);
}
return (
<CardWrapper>
<StyledCard style={{ alignItems: 'center', display: 'flex' }}>
<Skeleton
visible
height={size}
radius="sm"
width={size}
>
<ImageSection />
</Skeleton>
<DetailSection style={{ width: '100%' }}>
{cardRows.map((_row: CardRow<Album>, index: number) => (
<Skeleton
visible
height={15}
my={3}
radius="md"
width={!data ? (index > 0 ? '50%' : '90%') : '100%'}
if (!loading) {
return (
<CardWrapper
link
onClick={handleNavigate}
>
<Row />
</Skeleton>
))}
</DetailSection>
</StyledCard>
</CardWrapper>
);
<StyledCard>
<ImageSection>
{data?.imageUrl ? (
<Image
animationDuration={0.3}
height={size}
imgStyle={{ objectFit: 'cover' }}
placeholder={data?.imagePlaceholderUrl || 'var(--card-default-bg)'}
src={data?.imageUrl}
width={size}
/>
) : (
<Center
sx={{
background: 'var(--placeholder-bg)',
borderRadius: 'var(--card-default-radius)',
height: `${size}px`,
width: `${size}px`,
}}
>
<RiAlbumFill
color="var(--placeholder-fg)"
size={35}
/>
</Center>
)}
<ControlsContainer>
<CardControls
handlePlayQueueAdd={handlePlayQueueAdd}
itemData={data}
itemType={itemType}
/>
</ControlsContainer>
</ImageSection>
<DetailSection>
<CardRows
data={data}
rows={cardRows}
/>
</DetailSection>
</StyledCard>
</CardWrapper>
);
}
return (
<CardWrapper>
<StyledCard style={{ alignItems: 'center', display: 'flex' }}>
<Skeleton
visible
height={size}
radius="sm"
width={size}
>
<ImageSection />
</Skeleton>
<DetailSection style={{ width: '100%' }}>
{cardRows.map((_row: CardRow<Album>, index: number) => (
<Skeleton
visible
height={15}
my={3}
radius="md"
width={!data ? (index > 0 ? '50%' : '90%') : '100%'}
>
<Row />
</Skeleton>
))}
</DetailSection>
</StyledCard>
</CardWrapper>
);
};

View file

@ -11,69 +11,69 @@ import { usePlayButtonBehavior } from '/@/renderer/store/settings.store';
import { LibraryItem } from '/@/renderer/api/types';
import { useHandleGeneralContextMenu } from '/@/renderer/features/context-menu/hooks/use-handle-context-menu';
import {
ALBUM_CONTEXT_MENU_ITEMS,
ARTIST_CONTEXT_MENU_ITEMS,
ALBUM_CONTEXT_MENU_ITEMS,
ARTIST_CONTEXT_MENU_ITEMS,
} from '/@/renderer/features/context-menu/context-menu-items';
type PlayButtonType = UnstyledButtonProps & React.ComponentPropsWithoutRef<'button'>;
const PlayButton = styled.button<PlayButtonType>`
display: flex;
align-items: center;
justify-content: center;
width: 50px;
height: 50px;
background-color: rgb(255, 255, 255);
border: none;
border-radius: 50%;
opacity: 0.8;
transition: opacity 0.2s ease-in-out;
transition: scale 0.2s linear;
display: flex;
align-items: center;
justify-content: center;
width: 50px;
height: 50px;
background-color: rgb(255, 255, 255);
border: none;
border-radius: 50%;
opacity: 0.8;
transition: opacity 0.2s ease-in-out;
transition: scale 0.2s linear;
&:hover {
opacity: 1;
scale: 1.1;
}
&:hover {
opacity: 1;
scale: 1.1;
}
&:active {
opacity: 1;
scale: 1;
}
&:active {
opacity: 1;
scale: 1;
}
svg {
fill: rgb(0, 0, 0);
stroke: rgb(0, 0, 0);
}
svg {
fill: rgb(0, 0, 0);
stroke: rgb(0, 0, 0);
}
`;
const SecondaryButton = styled(_Button)`
opacity: 0.8;
transition: opacity 0.2s ease-in-out;
transition: scale 0.2s linear;
opacity: 0.8;
transition: opacity 0.2s ease-in-out;
transition: scale 0.2s linear;
&:hover {
opacity: 1;
scale: 1.1;
}
&:hover {
opacity: 1;
scale: 1.1;
}
&:active {
opacity: 1;
scale: 1;
}
&:active {
opacity: 1;
scale: 1;
}
`;
const GridCardControlsContainer = styled.div`
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
`;
const ControlsRow = styled.div`
width: 100%;
height: calc(100% / 3);
width: 100%;
height: calc(100% / 3);
`;
// const TopControls = styled(ControlsRow)`
@ -91,87 +91,87 @@ const ControlsRow = styled.div`
// `;
const BottomControls = styled(ControlsRow)`
display: flex;
align-items: flex-end;
justify-content: space-between;
padding: 1rem 0.5rem;
display: flex;
align-items: flex-end;
justify-content: space-between;
padding: 1rem 0.5rem;
`;
const FavoriteWrapper = styled.span<{ isFavorite: boolean }>`
svg {
fill: ${(props) => props.isFavorite && 'var(--primary-color)'};
}
svg {
fill: ${(props) => props.isFavorite && 'var(--primary-color)'};
}
`;
export const CardControls = ({
itemData,
itemType,
handlePlayQueueAdd,
}: {
handlePlayQueueAdd?: (options: PlayQueueAddOptions) => void;
itemData: any;
itemType: LibraryItem;
}) => {
const playButtonBehavior = usePlayButtonBehavior();
const handlePlay = (e: MouseEvent<HTMLButtonElement>, playType?: Play) => {
e.preventDefault();
e.stopPropagation();
handlePlayQueueAdd?.({
byItemType: {
id: [itemData.id],
type: itemType,
},
playType: playType || playButtonBehavior,
});
};
const handleContextMenu = useHandleGeneralContextMenu(
itemData,
itemType,
itemType === LibraryItem.ALBUM ? ALBUM_CONTEXT_MENU_ITEMS : ARTIST_CONTEXT_MENU_ITEMS,
);
handlePlayQueueAdd,
}: {
handlePlayQueueAdd?: (options: PlayQueueAddOptions) => void;
itemData: any;
itemType: LibraryItem;
}) => {
const playButtonBehavior = usePlayButtonBehavior();
return (
<GridCardControlsContainer>
<BottomControls>
<PlayButton onClick={handlePlay}>
<RiPlayFill size={25} />
</PlayButton>
<Group spacing="xs">
<SecondaryButton
disabled
p={5}
sx={{ svg: { fill: 'white !important' } }}
variant="subtle"
>
<FavoriteWrapper isFavorite={itemData?.isFavorite}>
{itemData?.isFavorite ? (
<RiHeartFill size={20} />
) : (
<RiHeartLine
color="white"
size={20}
/>
)}
</FavoriteWrapper>
</SecondaryButton>
<SecondaryButton
p={5}
sx={{ svg: { fill: 'white !important' } }}
variant="subtle"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
handleContextMenu(e, [itemData]);
}}
>
<RiMore2Fill
color="white"
size={20}
/>
</SecondaryButton>
</Group>
</BottomControls>
</GridCardControlsContainer>
);
const handlePlay = (e: MouseEvent<HTMLButtonElement>, playType?: Play) => {
e.preventDefault();
e.stopPropagation();
handlePlayQueueAdd?.({
byItemType: {
id: [itemData.id],
type: itemType,
},
playType: playType || playButtonBehavior,
});
};
const handleContextMenu = useHandleGeneralContextMenu(
itemType,
itemType === LibraryItem.ALBUM ? ALBUM_CONTEXT_MENU_ITEMS : ARTIST_CONTEXT_MENU_ITEMS,
);
return (
<GridCardControlsContainer>
<BottomControls>
<PlayButton onClick={handlePlay}>
<RiPlayFill size={25} />
</PlayButton>
<Group spacing="xs">
<SecondaryButton
disabled
p={5}
sx={{ svg: { fill: 'white !important' } }}
variant="subtle"
>
<FavoriteWrapper isFavorite={itemData?.isFavorite}>
{itemData?.isFavorite ? (
<RiHeartFill size={20} />
) : (
<RiHeartLine
color="white"
size={20}
/>
)}
</FavoriteWrapper>
</SecondaryButton>
<SecondaryButton
p={5}
sx={{ svg: { fill: 'white !important' } }}
variant="subtle"
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
handleContextMenu(e, [itemData]);
}}
>
<RiMore2Fill
color="white"
size={20}
/>
</SecondaryButton>
</Group>
</BottomControls>
</GridCardControlsContainer>
);
};

View file

@ -8,205 +8,208 @@ import { AppRoute } from '/@/renderer/router/routes';
import { CardRow } from '/@/renderer/types';
const Row = styled.div<{ $secondary?: boolean }>`
width: 100%;
max-width: 100%;
height: 22px;
padding: 0 0.2rem;
overflow: hidden;
color: ${({ $secondary }) => ($secondary ? 'var(--main-fg-secondary)' : 'var(--main-fg)')};
white-space: nowrap;
text-overflow: ellipsis;
user-select: none;
width: 100%;
max-width: 100%;
height: 22px;
padding: 0 0.2rem;
overflow: hidden;
color: ${({ $secondary }) => ($secondary ? 'var(--main-fg-secondary)' : 'var(--main-fg)')};
white-space: nowrap;
text-overflow: ellipsis;
user-select: none;
`;
interface CardRowsProps {
data: any;
rows: CardRow<Album>[] | CardRow<Artist>[] | CardRow<AlbumArtist>[];
data: any;
rows: CardRow<Album>[] | CardRow<Artist>[] | CardRow<AlbumArtist>[];
}
export const CardRows = ({ data, rows }: CardRowsProps) => {
return (
<>
{rows.map((row, index: number) => {
if (row.arrayProperty && row.route) {
return (
<Row
key={`row-${row.property}-${index}`}
$secondary={index > 0}
>
{data[row.property].map((item: any, itemIndex: number) => (
<React.Fragment key={`${data.id}-${item.id}`}>
{itemIndex > 0 && (
<Text
$noSelect
$secondary
sx={{
display: 'inline-block',
padding: '0 2px 0 1px',
}}
>
,
</Text>
)}{' '}
<Text
$link
$noSelect
$secondary={index > 0}
component={Link}
overflow="hidden"
size={index > 0 ? 'sm' : 'md'}
to={generatePath(
row.route!.route,
row.route!.slugs?.reduce((acc, slug) => {
return {
...acc,
[slug.slugProperty]: data[row.property][itemIndex][slug.idProperty],
};
}, {}),
)}
onClick={(e) => e.stopPropagation()}
>
{row.arrayProperty && item[row.arrayProperty]}
</Text>
</React.Fragment>
))}
</Row>
);
}
return (
<>
{rows.map((row, index: number) => {
if (row.arrayProperty && row.route) {
return (
<Row
key={`row-${row.property}-${index}`}
$secondary={index > 0}
>
{data[row.property].map((item: any, itemIndex: number) => (
<React.Fragment key={`${data.id}-${item.id}`}>
{itemIndex > 0 && (
<Text
$noSelect
$secondary
sx={{
display: 'inline-block',
padding: '0 2px 0 1px',
}}
>
,
</Text>
)}{' '}
<Text
$link
$noSelect
$secondary={index > 0}
component={Link}
overflow="hidden"
size={index > 0 ? 'sm' : 'md'}
to={generatePath(
row.route!.route,
row.route!.slugs?.reduce((acc, slug) => {
return {
...acc,
[slug.slugProperty]:
data[row.property][itemIndex][
slug.idProperty
],
};
}, {}),
)}
onClick={(e) => e.stopPropagation()}
>
{row.arrayProperty && item[row.arrayProperty]}
</Text>
</React.Fragment>
))}
</Row>
);
}
if (row.arrayProperty) {
return (
<Row key={`row-${row.property}`}>
{data[row.property].map((item: any) => (
<Text
key={`${data.id}-${item.id}`}
$noSelect
$secondary={index > 0}
overflow="hidden"
size={index > 0 ? 'sm' : 'md'}
>
{row.arrayProperty && item[row.arrayProperty]}
</Text>
))}
</Row>
);
}
if (row.arrayProperty) {
return (
<Row key={`row-${row.property}`}>
{data[row.property].map((item: any) => (
<Text
key={`${data.id}-${item.id}`}
$noSelect
$secondary={index > 0}
overflow="hidden"
size={index > 0 ? 'sm' : 'md'}
>
{row.arrayProperty && item[row.arrayProperty]}
</Text>
))}
</Row>
);
}
return (
<Row key={`row-${row.property}`}>
{row.route ? (
<Text
$link
$noSelect
component={Link}
overflow="hidden"
to={generatePath(
row.route.route,
row.route.slugs?.reduce((acc, slug) => {
return {
...acc,
[slug.slugProperty]: data[slug.idProperty],
};
}, {}),
)}
onClick={(e) => e.stopPropagation()}
>
{data && data[row.property]}
</Text>
) : (
<Text
$noSelect
$secondary={index > 0}
overflow="hidden"
size={index > 0 ? 'sm' : 'md'}
>
{data && data[row.property]}
</Text>
)}
</Row>
);
})}
</>
);
return (
<Row key={`row-${row.property}`}>
{row.route ? (
<Text
$link
$noSelect
component={Link}
overflow="hidden"
to={generatePath(
row.route.route,
row.route.slugs?.reduce((acc, slug) => {
return {
...acc,
[slug.slugProperty]: data[slug.idProperty],
};
}, {}),
)}
onClick={(e) => e.stopPropagation()}
>
{data && data[row.property]}
</Text>
) : (
<Text
$noSelect
$secondary={index > 0}
overflow="hidden"
size={index > 0 ? 'sm' : 'md'}
>
{data && data[row.property]}
</Text>
)}
</Row>
);
})}
</>
);
};
export const ALBUM_CARD_ROWS: { [key: string]: CardRow<Album> } = {
albumArtists: {
arrayProperty: 'name',
property: 'albumArtists',
route: {
route: AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL,
slugs: [{ idProperty: 'id', slugProperty: 'albumArtistId' }],
albumArtists: {
arrayProperty: 'name',
property: 'albumArtists',
route: {
route: AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL,
slugs: [{ idProperty: 'id', slugProperty: 'albumArtistId' }],
},
},
},
artists: {
arrayProperty: 'name',
property: 'artists',
route: {
route: AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL,
slugs: [{ idProperty: 'id', slugProperty: 'albumArtistId' }],
artists: {
arrayProperty: 'name',
property: 'artists',
route: {
route: AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL,
slugs: [{ idProperty: 'id', slugProperty: 'albumArtistId' }],
},
},
},
createdAt: {
property: 'createdAt',
},
duration: {
property: 'duration',
},
lastPlayedAt: {
property: 'lastPlayedAt',
},
name: {
property: 'name',
route: {
route: AppRoute.LIBRARY_ALBUMS_DETAIL,
slugs: [{ idProperty: 'id', slugProperty: 'albumId' }],
createdAt: {
property: 'createdAt',
},
duration: {
property: 'duration',
},
lastPlayedAt: {
property: 'lastPlayedAt',
},
name: {
property: 'name',
route: {
route: AppRoute.LIBRARY_ALBUMS_DETAIL,
slugs: [{ idProperty: 'id', slugProperty: 'albumId' }],
},
},
playCount: {
property: 'playCount',
},
rating: {
property: 'userRating',
},
releaseDate: {
property: 'releaseDate',
},
releaseYear: {
property: 'releaseYear',
},
songCount: {
property: 'songCount',
},
},
playCount: {
property: 'playCount',
},
rating: {
property: 'userRating',
},
releaseDate: {
property: 'releaseDate',
},
releaseYear: {
property: 'releaseYear',
},
songCount: {
property: 'songCount',
},
};
export const ALBUMARTIST_CARD_ROWS: { [key: string]: CardRow<AlbumArtist> } = {
albumCount: {
property: 'albumCount',
},
duration: {
property: 'duration',
},
genres: {
property: 'genres',
},
lastPlayedAt: {
property: 'lastPlayedAt',
},
name: {
property: 'name',
route: {
route: AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL,
slugs: [{ idProperty: 'id', slugProperty: 'albumArtistId' }],
albumCount: {
property: 'albumCount',
},
duration: {
property: 'duration',
},
genres: {
property: 'genres',
},
lastPlayedAt: {
property: 'lastPlayedAt',
},
name: {
property: 'name',
route: {
route: AppRoute.LIBRARY_ALBUM_ARTISTS_DETAIL,
slugs: [{ idProperty: 'id', slugProperty: 'albumArtistId' }],
},
},
playCount: {
property: 'playCount',
},
rating: {
property: 'userRating',
},
songCount: {
property: 'songCount',
},
},
playCount: {
property: 'playCount',
},
rating: {
property: 'userRating',
},
songCount: {
property: 'songCount',
},
};

View file

@ -10,197 +10,197 @@ import { GridCardControls } from '/@/renderer/components/virtual-grid/grid-card/
import { CardRow, PlayQueueAddOptions, Play, CardRoute } from '/@/renderer/types';
interface BaseGridCardProps {
controls: {
cardRows: CardRow<Album>[] | CardRow<Artist>[] | CardRow<AlbumArtist>[];
handleFavorite: (options: {
id: string[];
isFavorite: boolean;
itemType: LibraryItem;
serverId: string;
}) => void;
handlePlayQueueAdd: ((options: PlayQueueAddOptions) => void) | undefined;
itemType: LibraryItem;
playButtonBehavior: Play;
route: CardRoute;
};
data: any;
isLoading?: boolean;
controls: {
cardRows: CardRow<Album>[] | CardRow<Artist>[] | CardRow<AlbumArtist>[];
handleFavorite: (options: {
id: string[];
isFavorite: boolean;
itemType: LibraryItem;
serverId: string;
}) => void;
handlePlayQueueAdd: ((options: PlayQueueAddOptions) => void) | undefined;
itemType: LibraryItem;
playButtonBehavior: Play;
route: CardRoute;
};
data: any;
isLoading?: boolean;
}
const PosterCardContainer = styled.div<{ $isHidden?: boolean }>`
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
overflow: hidden;
opacity: ${({ $isHidden }) => ($isHidden ? 0 : 1)};
pointer-events: auto;
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
overflow: hidden;
opacity: ${({ $isHidden }) => ($isHidden ? 0 : 1)};
pointer-events: auto;
.card-controls {
opacity: 0;
}
.card-controls {
opacity: 0;
}
`;
const ImageContainerStyles = css`
position: relative;
display: flex;
align-items: center;
aspect-ratio: 1/1;
overflow: hidden;
background: var(--card-default-bg);
border-radius: var(--card-poster-radius);
position: relative;
display: flex;
align-items: center;
aspect-ratio: 1/1;
overflow: hidden;
background: var(--card-default-bg);
border-radius: var(--card-poster-radius);
&::before {
position: absolute;
top: 0;
left: 0;
z-index: 1;
width: 100%;
height: 100%;
background: linear-gradient(0deg, rgba(0, 0, 0, 100%) 35%, rgba(0, 0, 0, 0%) 100%);
opacity: 0;
transition: all 0.2s ease-in-out;
content: '';
user-select: none;
}
&:hover {
&::before {
opacity: 0.5;
position: absolute;
top: 0;
left: 0;
z-index: 1;
width: 100%;
height: 100%;
background: linear-gradient(0deg, rgba(0, 0, 0, 100%) 35%, rgba(0, 0, 0, 0%) 100%);
opacity: 0;
transition: all 0.2s ease-in-out;
content: '';
user-select: none;
}
}
&:hover .card-controls {
opacity: 1;
}
&:hover {
&::before {
opacity: 0.5;
}
}
&:hover .card-controls {
opacity: 1;
}
`;
const ImageContainer = styled(Link)<{ $isFavorite?: boolean }>`
${ImageContainerStyles}
${ImageContainerStyles}
`;
const ImageContainerSkeleton = styled.div`
${ImageContainerStyles}
${ImageContainerStyles}
`;
const Image = styled(SimpleImg)`
width: 100%;
max-width: 100%;
height: 100% !important;
max-height: 100%;
border: 0;
width: 100%;
max-width: 100%;
height: 100% !important;
max-height: 100%;
border: 0;
img {
height: 100%;
object-fit: cover;
}
img {
height: 100%;
object-fit: cover;
}
`;
const DetailContainer = styled.div`
margin-top: 0.5rem;
margin-top: 0.5rem;
`;
export const PosterCard = ({
data,
controls,
isLoading,
uniqueId,
data,
controls,
isLoading,
uniqueId,
}: BaseGridCardProps & { uniqueId: string }) => {
if (!isLoading) {
const path = generatePath(
controls.route.route,
controls.route.slugs?.reduce((acc, slug) => {
return {
...acc,
[slug.slugProperty]: data[slug.idProperty],
};
}, {}),
);
if (!isLoading) {
const path = generatePath(
controls.route.route,
controls.route.slugs?.reduce((acc, slug) => {
return {
...acc,
[slug.slugProperty]: data[slug.idProperty],
};
}, {}),
);
let Placeholder = RiAlbumFill;
let Placeholder = RiAlbumFill;
switch (controls.itemType) {
case LibraryItem.ALBUM:
Placeholder = RiAlbumFill;
break;
case LibraryItem.ARTIST:
Placeholder = RiUserVoiceFill;
break;
case LibraryItem.ALBUM_ARTIST:
Placeholder = RiUserVoiceFill;
break;
case LibraryItem.PLAYLIST:
Placeholder = RiPlayListFill;
break;
default:
Placeholder = RiAlbumFill;
break;
switch (controls.itemType) {
case LibraryItem.ALBUM:
Placeholder = RiAlbumFill;
break;
case LibraryItem.ARTIST:
Placeholder = RiUserVoiceFill;
break;
case LibraryItem.ALBUM_ARTIST:
Placeholder = RiUserVoiceFill;
break;
case LibraryItem.PLAYLIST:
Placeholder = RiPlayListFill;
break;
default:
Placeholder = RiAlbumFill;
break;
}
return (
<PosterCardContainer key={`${uniqueId}-${data.id}`}>
<ImageContainer
$isFavorite={data?.userFavorite}
to={path}
>
{data?.imageUrl ? (
<Image
importance="auto"
placeholder={data?.imagePlaceholderUrl || 'var(--card-default-bg)'}
src={data?.imageUrl}
/>
) : (
<Center
sx={{
background: 'var(--placeholder-bg)',
borderRadius: 'var(--card-default-radius)',
height: '100%',
width: '100%',
}}
>
<Placeholder
color="var(--placeholder-fg)"
size={35}
/>
</Center>
)}
<GridCardControls
handleFavorite={controls.handleFavorite}
handlePlayQueueAdd={controls.handlePlayQueueAdd}
itemData={data}
itemType={controls.itemType}
/>
</ImageContainer>
<DetailContainer>
<CardRows
data={data}
rows={controls.cardRows}
/>
</DetailContainer>
</PosterCardContainer>
);
}
return (
<PosterCardContainer key={`${uniqueId}-${data.id}`}>
<ImageContainer
$isFavorite={data?.userFavorite}
to={path}
>
{data?.imageUrl ? (
<Image
importance="auto"
placeholder={data?.imagePlaceholderUrl || 'var(--card-default-bg)'}
src={data?.imageUrl}
/>
) : (
<Center
sx={{
background: 'var(--placeholder-bg)',
borderRadius: 'var(--card-default-radius)',
height: '100%',
width: '100%',
}}
>
<Placeholder
color="var(--placeholder-fg)"
size={35}
/>
</Center>
)}
<GridCardControls
handleFavorite={controls.handleFavorite}
handlePlayQueueAdd={controls.handlePlayQueueAdd}
itemData={data}
itemType={controls.itemType}
/>
</ImageContainer>
<DetailContainer>
<CardRows
data={data}
rows={controls.cardRows}
/>
</DetailContainer>
</PosterCardContainer>
);
}
return (
<PosterCardContainer key={`placeholder-${uniqueId}-${data.id}`}>
<Skeleton
visible
radius="sm"
>
<ImageContainerSkeleton />
</Skeleton>
<DetailContainer>
<Stack spacing="sm">
{controls.cardRows.map((row, index) => (
<PosterCardContainer key={`placeholder-${uniqueId}-${data.id}`}>
<Skeleton
key={`${index}-${row.arrayProperty}`}
visible
height={14}
radius="sm"
/>
))}
</Stack>
</DetailContainer>
</PosterCardContainer>
);
visible
radius="sm"
>
<ImageContainerSkeleton />
</Skeleton>
<DetailContainer>
<Stack spacing="sm">
{controls.cardRows.map((row, index) => (
<Skeleton
key={`${index}-${row.arrayProperty}`}
visible
height={14}
radius="sm"
/>
))}
</Stack>
</DetailContainer>
</PosterCardContainer>
);
};