Add swiper card / update virt cards

This commit is contained in:
jeffvli 2023-05-17 17:11:33 -07:00
parent d8130f48e2
commit 58d912065b
5 changed files with 278 additions and 45 deletions

View file

@ -21,7 +21,7 @@ const Row = styled.div<{ $secondary?: boolean }>`
interface CardRowsProps {
data: any;
rows: CardRow<Album | Artist | AlbumArtist>[];
rows: CardRow<Album>[] | CardRow<Artist>[] | CardRow<AlbumArtist>[];
}
export const CardRows = ({ data, rows }: CardRowsProps) => {

View file

@ -0,0 +1,206 @@
import { Center, Stack } from '@mantine/core';
import { RiAlbumFill, RiPlayListFill, RiUserVoiceFill } from 'react-icons/ri';
import { generatePath, Link } from 'react-router-dom';
import { SimpleImg } from 'react-simple-img';
import styled, { css } from 'styled-components';
import { Album, AlbumArtist, Artist, LibraryItem } from '/@/renderer/api/types';
import { CardRows } from '/@/renderer/components/card';
import { Skeleton } from '/@/renderer/components/skeleton';
import { GridCardControls } from '/@/renderer/components/virtual-grid/grid-card/grid-card-controls';
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;
}
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;
.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);
&::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;
}
}
&:hover .card-controls {
opacity: 1;
}
`;
const ImageContainer = styled(Link)<{ $isFavorite?: boolean }>`
${ImageContainerStyles}
`;
const ImageContainerSkeleton = styled.div`
${ImageContainerStyles}
`;
const Image = styled(SimpleImg)`
width: 100%;
max-width: 100%;
height: 100% !important;
max-height: 100%;
border: 0;
img {
height: 100%;
object-fit: cover;
}
`;
const DetailContainer = styled.div`
margin-top: 0.5rem;
`;
export const PosterCard = ({
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],
};
}, {}),
);
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;
}
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) => (
<Skeleton
key={`${index}-${row.arrayProperty}`}
visible
height={14}
radius="sm"
/>
))}
</Stack>
</DetailContainer>
</PosterCardContainer>
);
};