mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-09 20:29:36 +02:00
add item card skeleton
This commit is contained in:
@@ -67,7 +67,6 @@
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
line-height: 1.6;
|
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|
||||||
a {
|
a {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import styles from './item-card.module.css';
|
|||||||
import { AppRoute } from '/@/renderer/router/routes';
|
import { AppRoute } from '/@/renderer/router/routes';
|
||||||
import { Image } from '/@/shared/components/image/image';
|
import { Image } from '/@/shared/components/image/image';
|
||||||
import { Separator } from '/@/shared/components/separator/separator';
|
import { Separator } from '/@/shared/components/separator/separator';
|
||||||
|
import { Skeleton } from '/@/shared/components/skeleton/skeleton';
|
||||||
import { Text } from '/@/shared/components/text/text';
|
import { Text } from '/@/shared/components/text/text';
|
||||||
import {
|
import {
|
||||||
Album,
|
Album,
|
||||||
@@ -31,8 +32,9 @@ type DataRow = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
interface ItemCardProps {
|
interface ItemCardProps {
|
||||||
data: Album | AlbumArtist | Artist | Playlist | Song;
|
data: Album | AlbumArtist | Artist | Playlist | Song | undefined;
|
||||||
isRound?: boolean;
|
isRound?: boolean;
|
||||||
|
itemType: LibraryItem;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
onItemExpand?: () => void;
|
onItemExpand?: () => void;
|
||||||
onItemSelect?: () => void;
|
onItemSelect?: () => void;
|
||||||
@@ -43,17 +45,18 @@ interface ItemCardProps {
|
|||||||
export const ItemCard = ({
|
export const ItemCard = ({
|
||||||
data,
|
data,
|
||||||
isRound,
|
isRound,
|
||||||
|
itemType,
|
||||||
onClick,
|
onClick,
|
||||||
onItemExpand,
|
onItemExpand,
|
||||||
onItemSelect,
|
onItemSelect,
|
||||||
type = 'poster',
|
type = 'poster',
|
||||||
withControls,
|
withControls,
|
||||||
}: ItemCardProps) => {
|
}: ItemCardProps) => {
|
||||||
const imageUrl = getImageUrl(data);
|
|
||||||
const rows = getDataRows(data);
|
|
||||||
|
|
||||||
const [showControls, setShowControls] = useState(false);
|
const [showControls, setShowControls] = useState(false);
|
||||||
|
|
||||||
|
const imageUrl = getImageUrl(data);
|
||||||
|
const rows = getDataRows(itemType);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'compact':
|
case 'compact':
|
||||||
return (
|
return (
|
||||||
@@ -61,6 +64,7 @@ export const ItemCard = ({
|
|||||||
data={data}
|
data={data}
|
||||||
imageUrl={imageUrl}
|
imageUrl={imageUrl}
|
||||||
isRound={isRound}
|
isRound={isRound}
|
||||||
|
itemType={itemType}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
onItemExpand={onItemExpand}
|
onItemExpand={onItemExpand}
|
||||||
onItemSelect={onItemSelect}
|
onItemSelect={onItemSelect}
|
||||||
@@ -76,6 +80,7 @@ export const ItemCard = ({
|
|||||||
data={data}
|
data={data}
|
||||||
imageUrl={imageUrl}
|
imageUrl={imageUrl}
|
||||||
isRound={isRound}
|
isRound={isRound}
|
||||||
|
itemType={itemType}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
onItemExpand={onItemExpand}
|
onItemExpand={onItemExpand}
|
||||||
onItemSelect={onItemSelect}
|
onItemSelect={onItemSelect}
|
||||||
@@ -92,6 +97,7 @@ export const ItemCard = ({
|
|||||||
data={data}
|
data={data}
|
||||||
imageUrl={imageUrl}
|
imageUrl={imageUrl}
|
||||||
isRound={isRound}
|
isRound={isRound}
|
||||||
|
itemType={itemType}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
onItemExpand={onItemExpand}
|
onItemExpand={onItemExpand}
|
||||||
onItemSelect={onItemSelect}
|
onItemSelect={onItemSelect}
|
||||||
@@ -123,24 +129,41 @@ const CompactItemCard = ({
|
|||||||
showControls,
|
showControls,
|
||||||
withControls,
|
withControls,
|
||||||
}: ItemCardDerivativeProps) => {
|
}: ItemCardDerivativeProps) => {
|
||||||
|
if (data) {
|
||||||
|
return (
|
||||||
|
<div className={clsx(styles.container, styles.compact)}>
|
||||||
|
<div
|
||||||
|
className={clsx(styles.imageContainer, { [styles.isRound]: isRound })}
|
||||||
|
onClick={onClick}
|
||||||
|
onMouseEnter={() => withControls && setShowControls(true)}
|
||||||
|
onMouseLeave={() => withControls && setShowControls(false)}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
className={clsx(styles.image, { [styles.isRound]: isRound })}
|
||||||
|
src={imageUrl}
|
||||||
|
/>
|
||||||
|
<AnimatePresence>
|
||||||
|
{withControls && showControls && <ItemCardControls type="compact" />}
|
||||||
|
</AnimatePresence>
|
||||||
|
<div className={clsx(styles.detailContainer, styles.compact)}>
|
||||||
|
{rows.map((row) => (
|
||||||
|
<ItemCardRow data={data!} key={row.id} row={row} type="compact" />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx(styles.container, styles.compact)}>
|
<div className={clsx(styles.container, styles.compact)}>
|
||||||
<div
|
<div className={clsx(styles.imageContainer, { [styles.isRound]: isRound })}>
|
||||||
className={clsx(styles.imageContainer, { [styles.isRound]: isRound })}
|
<Skeleton className={styles.image} enableAnimation={false} />
|
||||||
onClick={onClick}
|
|
||||||
onMouseEnter={() => withControls && setShowControls(true)}
|
|
||||||
onMouseLeave={() => withControls && setShowControls(false)}
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
className={clsx(styles.image, { [styles.isRound]: isRound })}
|
|
||||||
src={imageUrl}
|
|
||||||
/>
|
|
||||||
<AnimatePresence>
|
|
||||||
{withControls && showControls && <ItemCardControls type="compact" />}
|
|
||||||
</AnimatePresence>
|
|
||||||
<div className={clsx(styles.detailContainer, styles.compact)}>
|
<div className={clsx(styles.detailContainer, styles.compact)}>
|
||||||
{rows.map((row) => (
|
{rows.map((row) => (
|
||||||
<ItemCardRow data={data} key={row.id} row={row} type="compact" />
|
<div className={styles.row} key={row.id}>
|
||||||
|
|
||||||
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -160,28 +183,43 @@ const DefaultItemCard = ({
|
|||||||
showControls,
|
showControls,
|
||||||
withControls,
|
withControls,
|
||||||
}: ItemCardDerivativeProps) => {
|
}: ItemCardDerivativeProps) => {
|
||||||
|
if (data) {
|
||||||
|
return (
|
||||||
|
<div className={clsx(styles.container)}>
|
||||||
|
<div
|
||||||
|
className={clsx(styles.imageContainer, { [styles.isRound]: isRound })}
|
||||||
|
onClick={onClick}
|
||||||
|
onDoubleClick={onItemExpand}
|
||||||
|
onMouseEnter={() => withControls && setShowControls(true)}
|
||||||
|
onMouseLeave={() => withControls && setShowControls(false)}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
className={clsx(styles.image, { [styles.isRound]: isRound })}
|
||||||
|
src={imageUrl}
|
||||||
|
/>
|
||||||
|
<AnimatePresence>
|
||||||
|
{withControls && showControls && <ItemCardControls type="default" />}
|
||||||
|
</AnimatePresence>
|
||||||
|
</div>
|
||||||
|
<div className={styles.detailContainer}>
|
||||||
|
{rows.map((row) => (
|
||||||
|
<ItemCardRow data={data!} key={row.id} row={row} type="default" />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx(styles.container)}>
|
<div className={clsx(styles.container)}>
|
||||||
<div
|
<div className={clsx(styles.imageContainer, { [styles.isRound]: isRound })}>
|
||||||
className={clsx(styles.imageContainer, { [styles.isRound]: isRound })}
|
<Skeleton className={styles.image} enableAnimation={false} />
|
||||||
onClick={onClick}
|
|
||||||
onDoubleClick={onItemExpand}
|
|
||||||
onMouseEnter={() => withControls && setShowControls(true)}
|
|
||||||
onMouseLeave={() => withControls && setShowControls(false)}
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
className={clsx(styles.image, { [styles.isRound]: isRound })}
|
|
||||||
src={imageUrl}
|
|
||||||
/>
|
|
||||||
<AnimatePresence>
|
|
||||||
{withControls && showControls && <ItemCardControls type="default" />}
|
|
||||||
</AnimatePresence>
|
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.detailContainer}>
|
<div className={styles.detailContainer}>
|
||||||
{rows.map((row) => (
|
{rows.map((row) => (
|
||||||
<Fragment key={row.id}>
|
<div className={styles.row} key={row.id}>
|
||||||
<ItemCardRow data={data} row={row} type="default" />
|
|
||||||
</Fragment>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -200,35 +238,48 @@ const PosterItemCard = ({
|
|||||||
showControls,
|
showControls,
|
||||||
withControls,
|
withControls,
|
||||||
}: ItemCardDerivativeProps) => {
|
}: ItemCardDerivativeProps) => {
|
||||||
|
if (data) {
|
||||||
|
return (
|
||||||
|
<div className={clsx(styles.container, styles.poster)}>
|
||||||
|
<div
|
||||||
|
className={clsx(styles.imageContainer, { [styles.isRound]: isRound })}
|
||||||
|
onClick={onClick}
|
||||||
|
onMouseEnter={() => withControls && setShowControls(true)}
|
||||||
|
onMouseLeave={() => withControls && setShowControls(false)}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
className={clsx(styles.image, { [styles.isRound]: isRound })}
|
||||||
|
src={imageUrl}
|
||||||
|
/>
|
||||||
|
<AnimatePresence>
|
||||||
|
{withControls && showControls && <ItemCardControls type="poster" />}
|
||||||
|
</AnimatePresence>
|
||||||
|
</div>
|
||||||
|
<div className={styles.detailContainer}>
|
||||||
|
{rows.map((row) => (
|
||||||
|
<ItemCardRow data={data!} key={row.id} row={row} type="poster" />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx(styles.container, styles.poster)}>
|
<div className={clsx(styles.container, styles.poster)}>
|
||||||
<div
|
<div className={clsx(styles.imageContainer, { [styles.isRound]: isRound })}>
|
||||||
className={clsx(styles.imageContainer, { [styles.isRound]: isRound })}
|
<Skeleton className={clsx(styles.image, { [styles.isRound]: isRound })} />
|
||||||
onClick={onClick}
|
|
||||||
onMouseEnter={() => withControls && setShowControls(true)}
|
|
||||||
onMouseLeave={() => withControls && setShowControls(false)}
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
className={clsx(styles.image, { [styles.isRound]: isRound })}
|
|
||||||
src={imageUrl}
|
|
||||||
/>
|
|
||||||
<AnimatePresence>
|
|
||||||
{withControls && showControls && <ItemCardControls type="poster" />}
|
|
||||||
</AnimatePresence>
|
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.detailContainer}>
|
<div className={styles.detailContainer}>
|
||||||
{rows.map((row) => (
|
{rows.map((row) => (
|
||||||
<Fragment key={row.id}>
|
<ItemCardRow data={undefined} key={row.id} row={row} type="poster" />
|
||||||
<ItemCardRow data={data} row={row} type="poster" />
|
|
||||||
</Fragment>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getDataRows = (data: Album | AlbumArtist | Artist | Playlist | Song): DataRow[] => {
|
const getDataRows = (itemType: LibraryItem): DataRow[] => {
|
||||||
switch (data.itemType) {
|
switch (itemType) {
|
||||||
case LibraryItem.ALBUM:
|
case LibraryItem.ALBUM:
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@@ -274,11 +325,13 @@ const getDataRows = (data: Album | AlbumArtist | Artist | Playlist | Song): Data
|
|||||||
return [{ format: (data) => (data as Playlist).name, id: 'name' }];
|
return [{ format: (data) => (data as Playlist).name, id: 'name' }];
|
||||||
case LibraryItem.SONG:
|
case LibraryItem.SONG:
|
||||||
return [{ format: (data) => (data as Song).name, id: 'name' }];
|
return [{ format: (data) => (data as Song).name, id: 'name' }];
|
||||||
|
default:
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getImageUrl = (data: Album | AlbumArtist | Artist | Playlist | Song) => {
|
const getImageUrl = (data: Album | AlbumArtist | Artist | Playlist | Song | undefined) => {
|
||||||
if ('imageUrl' in data) {
|
if (data && 'imageUrl' in data) {
|
||||||
return data.imageUrl || undefined;
|
return data.imageUrl || undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,10 +343,25 @@ const ItemCardRow = ({
|
|||||||
row,
|
row,
|
||||||
type,
|
type,
|
||||||
}: {
|
}: {
|
||||||
data: Album | AlbumArtist | Artist | Playlist | Song;
|
data: Album | AlbumArtist | Artist | Playlist | Song | undefined;
|
||||||
row: DataRow;
|
row: DataRow;
|
||||||
type?: 'compact' | 'default' | 'poster';
|
type?: 'compact' | 'default' | 'poster';
|
||||||
}) => {
|
}) => {
|
||||||
|
if (!data) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={clsx(styles.row, {
|
||||||
|
[styles.compact]: type === 'compact',
|
||||||
|
[styles.default]: type === 'default',
|
||||||
|
[styles.muted]: row.isMuted,
|
||||||
|
[styles.poster]: type === 'poster',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Text
|
<Text
|
||||||
className={clsx(styles.row, {
|
className={clsx(styles.row, {
|
||||||
|
|||||||
Reference in New Issue
Block a user