From 3c996407d5517766fd9b08453ef816bf960ddee4 Mon Sep 17 00:00:00 2001 From: jeffvli Date: Sat, 8 Nov 2025 14:28:22 -0800 Subject: [PATCH] normalize controls onto lists --- .../item-card/item-card-controls.module.css | 7 + .../item-card/item-card-controls.tsx | 199 ++++++++++++++---- .../components/item-card/item-card.tsx | 33 +-- .../item-list/helpers/item-list-controls.ts | 192 ++++++++--------- .../item-list/helpers/item-list-state.ts | 7 +- .../item-detail-list/item-detail-list.tsx | 2 +- .../item-grid-list/item-grid-list.tsx | 81 +++---- .../columns/favorite-column.tsx | 45 +--- .../item-table-list/columns/rating-column.tsx | 35 +-- .../columns/row-index-column.tsx | 6 +- .../item-table-list-column.tsx | 47 ++--- .../item-table-list/item-table-list.tsx | 19 +- src/renderer/components/item-list/types.ts | 68 +++--- .../components/expanded-album-list-item.tsx | 2 +- src/renderer/store/settings.store.ts | 5 +- 15 files changed, 401 insertions(+), 347 deletions(-) diff --git a/src/renderer/components/item-card/item-card-controls.module.css b/src/renderer/components/item-card/item-card-controls.module.css index c9d961e45..8684fa9ac 100644 --- a/src/renderer/components/item-card/item-card-controls.module.css +++ b/src/renderer/components/item-card/item-card-controls.module.css @@ -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%; diff --git a/src/renderer/components/item-card/item-card-controls.tsx b/src/renderer/components/item-card/item-card-controls.tsx index de7390c2f..23a153f8b 100644 --- a/src/renderer/components/item-card/item-card-controls.tsx +++ b/src/renderer/components/item-card/item-card-controls.tsx @@ -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 ( - { - e.stopPropagation(); - controls?.onPlay?.(item, itemType, Play.NOW, e); - }} - /> - { - e.stopPropagation(); - controls?.onPlay?.(item, itemType, Play.NEXT, e); - }} - /> - { - e.stopPropagation(); - controls?.onPlay?.(item, itemType, Play.LAST, e); - }} - /> - { - e.stopPropagation(); - controls?.onFavorite?.(item, itemType, e); - }} - /> - - { - e.stopPropagation(); - controls?.onMore?.(item, itemType, e); - }} - /> - {controls?.onItemExpand && ( + {controls?.onPlay && ( + <> + { + e.stopPropagation(); + + if (!item) { + return; + } + + controls?.onPlay?.({ + event: e, + internalState, + item, + itemType, + playType: Play.NOW, + }); + }} + /> + { + e.stopPropagation(); + + if (!item) { + return; + } + + controls?.onPlay?.({ + event: e, + internalState, + item, + itemType, + playType: Play.NEXT, + }); + }} + /> + { + e.stopPropagation(); + + if (!item) { + return; + } + + controls?.onPlay?.({ + event: e, + internalState, + item, + itemType, + playType: Play.LAST, + }); + }} + /> + + )} + {controls?.onFavorite && ( + { + e.stopPropagation(); + + if (!item) { + return; + } + + const newFavorite = !(item as { userFavorite: boolean }).userFavorite; + controls?.onFavorite?.({ + event: e, + favorite: newFavorite, + internalState, + item, + itemType, + }); + }} + /> + )} + {controls?.onRating && ( + { + 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 && ( + { + e.stopPropagation(); + controls?.onMore?.({ + event: e, + internalState, + item, + itemType, + }); + }} + /> + )} + {controls?.onExpand && ( { 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) => void }) => { +const PlayButton = ({ + disabled, + loading, + onClick, +}: { + disabled?: boolean; + loading?: boolean; + onClick?: (e: MouseEvent) => void; +}) => { return (