mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-14 20:40:21 +02:00
extract play button from item card and add long press animation
This commit is contained in:
@@ -45,44 +45,7 @@
|
||||
margin-bottom: var(--theme-spacing-lg);
|
||||
}
|
||||
|
||||
.play-button {
|
||||
all: unset;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #fff;
|
||||
border: none;
|
||||
border-radius: 100%;
|
||||
opacity: 0.8;
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
transition: opacity 0.1s ease-in-out;
|
||||
transition: transform 0.1s ease-in-out;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
transform: translate(-50%, -50%) scale(1.1);
|
||||
}
|
||||
|
||||
&:active {
|
||||
opacity: 1;
|
||||
transform: translate(-50%, -50%) scale(0.9);
|
||||
}
|
||||
|
||||
svg {
|
||||
stroke: rgb(0 0 0);
|
||||
}
|
||||
}
|
||||
|
||||
.play-button.disabled,
|
||||
.play-button.loading {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
}
|
||||
|
||||
.play-button.primary {
|
||||
.primary {
|
||||
left: 50%;
|
||||
width: 25%;
|
||||
height: 25%;
|
||||
@@ -92,36 +55,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
.play-button.secondary {
|
||||
.secondary {
|
||||
width: 15%;
|
||||
height: 15%;
|
||||
}
|
||||
|
||||
.play-button.left {
|
||||
.left {
|
||||
left: 25%;
|
||||
}
|
||||
|
||||
.play-button.right {
|
||||
left: 75%;
|
||||
}
|
||||
|
||||
.play-button.left-top {
|
||||
top: 40%;
|
||||
left: 25%;
|
||||
}
|
||||
|
||||
.play-button.left-bottom {
|
||||
top: 60%;
|
||||
left: 25%;
|
||||
}
|
||||
|
||||
.play-button.right-bottom {
|
||||
top: 60%;
|
||||
left: 75%;
|
||||
}
|
||||
|
||||
.play-button.right-top {
|
||||
top: 40%;
|
||||
.right {
|
||||
left: 75%;
|
||||
}
|
||||
|
||||
@@ -130,7 +73,7 @@
|
||||
position: absolute;
|
||||
padding: var(--theme-spacing-md);
|
||||
border-radius: var(--theme-radius-md);
|
||||
opacity: 0.8;
|
||||
opacity: 1;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
transition: scale 0.2s linear;
|
||||
|
||||
|
||||
@@ -6,14 +6,13 @@ 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 { PlayButton } from '/@/renderer/features/shared/components/play-button';
|
||||
import { useIsMutatingCreateFavorite } from '/@/renderer/features/shared/mutations/create-favorite-mutation';
|
||||
import { useIsMutatingDeleteFavorite } from '/@/renderer/features/shared/mutations/delete-favorite-mutation';
|
||||
import { useIsMutatingRating } from '/@/renderer/features/shared/mutations/set-rating-mutation';
|
||||
import { animationVariants } from '/@/shared/components/animations/animation-variants';
|
||||
import { AppIcon, Icon, IconProps } from '/@/shared/components/icon/icon';
|
||||
import { Rating } from '/@/shared/components/rating/rating';
|
||||
import { useLongPress } from '/@/shared/hooks/use-long-press';
|
||||
import {
|
||||
Album,
|
||||
AlbumArtist,
|
||||
@@ -236,15 +235,19 @@ export const ItemCardControls = ({
|
||||
<motion.div className={clsx(styles.container)} {...containerProps[type]}>
|
||||
{controls?.onPlay && (
|
||||
<>
|
||||
<PlayButton onClick={playNowHandler} onLongPress={playShuffleHandler} />
|
||||
<SecondaryPlayButton
|
||||
className={styles.left}
|
||||
<PlayButton
|
||||
classNames={clsx(styles.primary)}
|
||||
onClick={playNowHandler}
|
||||
onLongPress={playShuffleHandler}
|
||||
/>
|
||||
<PlayButton
|
||||
classNames={clsx(styles.secondary, styles.left)}
|
||||
icon="mediaPlayNext"
|
||||
onClick={playNextHandler}
|
||||
onLongPress={playNextShuffleHandler}
|
||||
/>
|
||||
<SecondaryPlayButton
|
||||
className={styles.right}
|
||||
<PlayButton
|
||||
classNames={clsx(styles.secondary, styles.right)}
|
||||
icon="mediaPlayLast"
|
||||
onClick={playLastHandler}
|
||||
onLongPress={playLastShuffleHandler}
|
||||
@@ -340,128 +343,6 @@ const RatingButton = memo(
|
||||
(prev, next) => prev.rating === next.rating,
|
||||
);
|
||||
|
||||
const PlayButton = memo(
|
||||
({
|
||||
loading,
|
||||
onClick,
|
||||
onLongPress,
|
||||
}: {
|
||||
loading?: boolean;
|
||||
onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
||||
onLongPress?: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
||||
}) => {
|
||||
const isPlayerFetching = useIsPlayerFetching();
|
||||
|
||||
const disabled = isPlayerFetching || loading;
|
||||
|
||||
const longPressHandlers = useLongPress<HTMLButtonElement>({
|
||||
onClick: (e) => {
|
||||
if (disabled || loading) {
|
||||
return;
|
||||
}
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
onClick?.(e as React.MouseEvent<HTMLButtonElement>);
|
||||
},
|
||||
onLongPress: (e) => {
|
||||
if (disabled || loading) {
|
||||
return;
|
||||
}
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
onLongPress?.(e as React.MouseEvent<HTMLButtonElement>);
|
||||
},
|
||||
});
|
||||
|
||||
const handleMouseDown = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.stopPropagation();
|
||||
longPressHandlers.onMouseDown?.(e);
|
||||
};
|
||||
|
||||
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
className={clsx(styles.playButton, styles.primary, {
|
||||
[styles.disabled]: disabled,
|
||||
})}
|
||||
disabled={disabled}
|
||||
onClick={handleClick}
|
||||
onMouseDown={handleMouseDown}
|
||||
onMouseLeave={longPressHandlers.onMouseLeave}
|
||||
onMouseUp={longPressHandlers.onMouseUp}
|
||||
onTouchCancel={longPressHandlers.onTouchCancel}
|
||||
onTouchEnd={longPressHandlers.onTouchEnd}
|
||||
onTouchStart={longPressHandlers.onTouchStart}
|
||||
>
|
||||
<Icon icon="mediaPlay" size="lg" />
|
||||
</button>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
const SecondaryPlayButton = memo(
|
||||
({
|
||||
className,
|
||||
icon,
|
||||
onClick,
|
||||
onLongPress,
|
||||
}: {
|
||||
className?: string;
|
||||
icon: keyof typeof AppIcon;
|
||||
onClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
||||
onLongPress?: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
||||
}) => {
|
||||
const isPlayerFetching = useIsPlayerFetching();
|
||||
|
||||
const disabled = isPlayerFetching;
|
||||
|
||||
const longPressHandlers = useLongPress<HTMLButtonElement>({
|
||||
onClick: (e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
onClick?.(e as React.MouseEvent<HTMLButtonElement>);
|
||||
},
|
||||
onLongPress: (e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
onLongPress?.(e as React.MouseEvent<HTMLButtonElement>);
|
||||
},
|
||||
});
|
||||
|
||||
const handleMouseDown = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.stopPropagation();
|
||||
longPressHandlers.onMouseDown?.(e);
|
||||
};
|
||||
|
||||
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
className={clsx(styles.playButton, styles.secondary, className, {
|
||||
[styles.disabled]: disabled,
|
||||
})}
|
||||
disabled={disabled}
|
||||
onClick={handleClick}
|
||||
onMouseDown={handleMouseDown}
|
||||
onMouseLeave={longPressHandlers.onMouseLeave}
|
||||
onMouseUp={longPressHandlers.onMouseUp}
|
||||
onTouchCancel={longPressHandlers.onTouchCancel}
|
||||
onTouchEnd={longPressHandlers.onTouchEnd}
|
||||
onTouchStart={longPressHandlers.onTouchStart}
|
||||
>
|
||||
<Icon icon={icon} size="lg" />
|
||||
</button>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
interface SecondaryButtonProps {
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
|
||||
Reference in New Issue
Block a user