mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-16 21:50:35 +02:00
normalize controls onto lists
This commit is contained in:
@@ -75,6 +75,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
.play-button.disabled,
|
||||
.play-button.loading {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
}
|
||||
|
||||
.play-button.primary {
|
||||
left: 50%;
|
||||
width: 25%;
|
||||
|
||||
@@ -4,7 +4,9 @@ import { MouseEvent } from 'react';
|
||||
|
||||
import styles from './item-card-controls.module.css';
|
||||
|
||||
import { ItemListStateActions } from '/@/renderer/components/item-list/helpers/item-list-state';
|
||||
import { ItemControls } from '/@/renderer/components/item-list/types';
|
||||
import { useIsPlayerFetching } from '/@/renderer/features/player/context/player-context';
|
||||
import { animationVariants } from '/@/shared/components/animations/animation-variants';
|
||||
import { AppIcon, Icon } from '/@/shared/components/icon/icon';
|
||||
import { Rating } from '/@/shared/components/rating/rating';
|
||||
@@ -19,7 +21,8 @@ import {
|
||||
import { Play } from '/@/shared/types/types';
|
||||
|
||||
interface ItemCardControlsProps {
|
||||
controls: ItemControls;
|
||||
controls?: ItemControls;
|
||||
internalState?: ItemListStateActions;
|
||||
item: Album | AlbumArtist | Artist | Playlist | Song | undefined;
|
||||
itemType: LibraryItem;
|
||||
type?: 'compact' | 'default' | 'poster';
|
||||
@@ -48,58 +51,152 @@ const containerProps = {
|
||||
|
||||
export const ItemCardControls = ({
|
||||
controls,
|
||||
internalState,
|
||||
item,
|
||||
itemType,
|
||||
type = 'default',
|
||||
}: ItemCardControlsProps) => {
|
||||
const isPlayerFetching = useIsPlayerFetching();
|
||||
|
||||
return (
|
||||
<motion.div className={clsx(styles.container)} {...containerProps[type]}>
|
||||
<PlayButton
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
controls?.onPlay?.(item, itemType, Play.NOW, e);
|
||||
}}
|
||||
/>
|
||||
<SecondaryPlayButton
|
||||
className={styles.left}
|
||||
icon="mediaPlayNext"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
controls?.onPlay?.(item, itemType, Play.NEXT, e);
|
||||
}}
|
||||
/>
|
||||
<SecondaryPlayButton
|
||||
className={styles.right}
|
||||
icon="mediaPlayLast"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
controls?.onPlay?.(item, itemType, Play.LAST, e);
|
||||
}}
|
||||
/>
|
||||
<SecondaryButton
|
||||
className={styles.favorite}
|
||||
icon="favorite"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
controls?.onFavorite?.(item, itemType, e);
|
||||
}}
|
||||
/>
|
||||
<Rating className={styles.rating} size="xs" />
|
||||
<SecondaryButton
|
||||
className={styles.options}
|
||||
icon="ellipsisHorizontal"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
controls?.onMore?.(item, itemType, e);
|
||||
}}
|
||||
/>
|
||||
{controls?.onItemExpand && (
|
||||
{controls?.onPlay && (
|
||||
<>
|
||||
<PlayButton
|
||||
disabled={isPlayerFetching}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
controls?.onPlay?.({
|
||||
event: e,
|
||||
internalState,
|
||||
item,
|
||||
itemType,
|
||||
playType: Play.NOW,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<SecondaryPlayButton
|
||||
className={styles.left}
|
||||
icon="mediaPlayNext"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
controls?.onPlay?.({
|
||||
event: e,
|
||||
internalState,
|
||||
item,
|
||||
itemType,
|
||||
playType: Play.NEXT,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<SecondaryPlayButton
|
||||
className={styles.right}
|
||||
icon="mediaPlayLast"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
controls?.onPlay?.({
|
||||
event: e,
|
||||
internalState,
|
||||
item,
|
||||
itemType,
|
||||
playType: Play.LAST,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{controls?.onFavorite && (
|
||||
<SecondaryButton
|
||||
className={styles.favorite}
|
||||
icon="favorite"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newFavorite = !(item as { userFavorite: boolean }).userFavorite;
|
||||
controls?.onFavorite?.({
|
||||
event: e,
|
||||
favorite: newFavorite,
|
||||
internalState,
|
||||
item,
|
||||
itemType,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{controls?.onRating && (
|
||||
<Rating
|
||||
className={styles.rating}
|
||||
onChange={(rating) => {
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
let newRating = rating;
|
||||
|
||||
if (rating === (item as { userRating: number }).userRating) {
|
||||
newRating = 0;
|
||||
}
|
||||
|
||||
controls?.onRating?.({
|
||||
event: null,
|
||||
internalState,
|
||||
item,
|
||||
itemType,
|
||||
rating: newRating,
|
||||
});
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
size="xs"
|
||||
/>
|
||||
)}
|
||||
{controls?.onMore && (
|
||||
<SecondaryButton
|
||||
className={styles.options}
|
||||
icon="ellipsisHorizontal"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
controls?.onMore?.({
|
||||
event: e,
|
||||
internalState,
|
||||
item,
|
||||
itemType,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{controls?.onExpand && (
|
||||
<SecondaryButton
|
||||
className={styles.expand}
|
||||
icon="arrowDownS"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
controls?.onItemExpand?.(item, itemType, e);
|
||||
controls?.onExpand?.({
|
||||
event: e,
|
||||
internalState,
|
||||
item,
|
||||
itemType,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@@ -107,12 +204,26 @@ export const ItemCardControls = ({
|
||||
);
|
||||
};
|
||||
|
||||
const PlayButton = ({ onClick }: { onClick?: (e: MouseEvent<HTMLButtonElement>) => void }) => {
|
||||
const PlayButton = ({
|
||||
disabled,
|
||||
loading,
|
||||
onClick,
|
||||
}: {
|
||||
disabled?: boolean;
|
||||
loading?: boolean;
|
||||
onClick?: (e: MouseEvent<HTMLButtonElement>) => void;
|
||||
}) => {
|
||||
return (
|
||||
<button
|
||||
className={clsx(styles.playButton, styles.primary)}
|
||||
className={clsx(styles.playButton, styles.primary, {
|
||||
[styles.disabled]: disabled,
|
||||
})}
|
||||
disabled={disabled}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
if (disabled || loading) {
|
||||
return;
|
||||
}
|
||||
onClick?.(e);
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -6,6 +6,7 @@ import { generatePath, Link } from 'react-router';
|
||||
import styles from './item-card.module.css';
|
||||
|
||||
import { ItemCardControls } from '/@/renderer/components/item-card/item-card-controls';
|
||||
import { ItemListStateActions } from '/@/renderer/components/item-list/helpers/item-list-state';
|
||||
import { ItemControls } from '/@/renderer/components/item-list/types';
|
||||
import { AppRoute } from '/@/renderer/router/routes';
|
||||
import { Image } from '/@/shared/components/image/image';
|
||||
@@ -21,24 +22,26 @@ import {
|
||||
Song,
|
||||
} from '/@/shared/types/domain-types';
|
||||
|
||||
type DataRow = {
|
||||
format: (data: Album | AlbumArtist | Artist | Playlist | Song) => ReactNode | string;
|
||||
id: string;
|
||||
isMuted?: boolean;
|
||||
};
|
||||
|
||||
interface ItemCardProps {
|
||||
controls: ItemControls;
|
||||
export interface ItemCardProps {
|
||||
controls?: ItemControls;
|
||||
data: Album | AlbumArtist | Artist | Playlist | Song | undefined;
|
||||
internalState?: ItemListStateActions;
|
||||
isRound?: boolean;
|
||||
itemType: LibraryItem;
|
||||
type?: 'compact' | 'default' | 'poster';
|
||||
withControls?: boolean;
|
||||
}
|
||||
|
||||
type DataRow = {
|
||||
format: (data: Album | AlbumArtist | Artist | Playlist | Song) => ReactNode | string;
|
||||
id: string;
|
||||
isMuted?: boolean;
|
||||
};
|
||||
|
||||
export const ItemCard = ({
|
||||
controls,
|
||||
data,
|
||||
internalState,
|
||||
isRound,
|
||||
itemType,
|
||||
type = 'poster',
|
||||
@@ -54,6 +57,7 @@ export const ItemCard = ({
|
||||
controls={controls}
|
||||
data={data}
|
||||
imageUrl={imageUrl}
|
||||
internalState={internalState}
|
||||
isRound={isRound}
|
||||
itemType={itemType}
|
||||
rows={rows}
|
||||
@@ -66,6 +70,7 @@ export const ItemCard = ({
|
||||
controls={controls}
|
||||
data={data}
|
||||
imageUrl={imageUrl}
|
||||
internalState={internalState}
|
||||
isRound={isRound}
|
||||
itemType={itemType}
|
||||
rows={rows}
|
||||
@@ -79,6 +84,7 @@ export const ItemCard = ({
|
||||
controls={controls}
|
||||
data={data}
|
||||
imageUrl={imageUrl}
|
||||
internalState={internalState}
|
||||
isRound={isRound}
|
||||
itemType={itemType}
|
||||
rows={rows}
|
||||
@@ -89,8 +95,9 @@ export const ItemCard = ({
|
||||
};
|
||||
|
||||
export interface ItemCardDerivativeProps extends Omit<ItemCardProps, 'type'> {
|
||||
controls: ItemControls;
|
||||
controls?: ItemControls;
|
||||
imageUrl: string | undefined;
|
||||
internalState?: ItemListStateActions;
|
||||
rows: DataRow[];
|
||||
}
|
||||
|
||||
@@ -119,7 +126,7 @@ const CompactItemCard = ({
|
||||
};
|
||||
|
||||
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
|
||||
controls?.onClick?.(data, itemType, e);
|
||||
// controls?.onClick?.(data, itemType, e);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -195,7 +202,7 @@ const DefaultItemCard = ({
|
||||
};
|
||||
|
||||
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
|
||||
controls?.onClick?.(data, itemType, e);
|
||||
// controls?.onClick?.(data, itemType, e);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -250,6 +257,7 @@ const PosterItemCard = ({
|
||||
controls,
|
||||
data,
|
||||
imageUrl,
|
||||
internalState,
|
||||
isRound,
|
||||
itemType,
|
||||
rows,
|
||||
@@ -271,7 +279,7 @@ const PosterItemCard = ({
|
||||
};
|
||||
|
||||
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
|
||||
controls?.onClick?.(data, itemType, e);
|
||||
// controls?.onClick?.(data, itemType, e);
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -289,6 +297,7 @@ const PosterItemCard = ({
|
||||
{withControls && showControls && data && (
|
||||
<ItemCardControls
|
||||
controls={controls}
|
||||
internalState={internalState}
|
||||
item={data}
|
||||
itemType={itemType}
|
||||
type="poster"
|
||||
|
||||
Reference in New Issue
Block a user