From ad34d8553ec23e35120c15c48271ed53904cf7d9 Mon Sep 17 00:00:00 2001 From: Egor Date: Fri, 4 Oct 2024 05:22:51 +0300 Subject: [PATCH] Add play button to song table album cover, like it is in grid (#772) * Add play button to song table album cover, like it is in grid * Fix: play button caused error for albums and artists tables --- .../cells/combined-title-cell-controls.tsx | 84 +++++++++++++++++++ .../cells/combined-title-cell.tsx | 19 ++++- .../virtual-table/hooks/use-virtual-table.ts | 1 + .../components/virtual-table/index.tsx | 1 + 4 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 src/renderer/components/virtual-table/cells/combined-title-cell-controls.tsx diff --git a/src/renderer/components/virtual-table/cells/combined-title-cell-controls.tsx b/src/renderer/components/virtual-table/cells/combined-title-cell-controls.tsx new file mode 100644 index 00000000..5bf3537c --- /dev/null +++ b/src/renderer/components/virtual-table/cells/combined-title-cell-controls.tsx @@ -0,0 +1,84 @@ +import React, { MouseEvent } from 'react'; +import type { UnstyledButtonProps } from '@mantine/core'; +import { RiPlayFill } from 'react-icons/ri'; +import styled from 'styled-components'; +import { Play } from '/@/renderer/types'; +import { usePlayButtonBehavior } from '/@/renderer/store/settings.store'; +import { LibraryItem } from '/@/renderer/api/types'; +import { usePlayQueueAdd } from '/@/renderer/features/player'; + +type PlayButtonType = UnstyledButtonProps & React.ComponentPropsWithoutRef<'button'>; + +const PlayButton = styled.button` + position: absolute; + display: flex; + align-items: center; + justify-content: center; + width: 30px; + height: 30px; + background-color: rgb(255 255 255); + border: none; + border-radius: 50%; + opacity: 0.8; + transition: scale 0.1s ease-in-out; + + &:hover { + opacity: 1; + scale: 1.1; + } + + &:active { + opacity: 1; + scale: 1; + } + + svg { + fill: rgb(0 0 0); + stroke: rgb(0 0 0); + } +`; + +const ListConverControlsContainer = styled.div` + position: absolute; + z-index: 100; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; +`; + +export const ListCoverControls = ({ + itemData, + itemType, +}: { + itemData: any; + itemType: LibraryItem; +}) => { + const playButtonBehavior = usePlayButtonBehavior(); + const handlePlayQueueAdd = usePlayQueueAdd(); + + const handlePlay = async (e: MouseEvent, playType?: Play) => { + e.preventDefault(); + e.stopPropagation(); + + handlePlayQueueAdd?.({ + byItemType: { + id: [itemData.id], + type: itemType, + }, + playType: playType || playButtonBehavior, + }); + }; + + return ( + <> + + + + + + + ); +}; diff --git a/src/renderer/components/virtual-table/cells/combined-title-cell.tsx b/src/renderer/components/virtual-table/cells/combined-title-cell.tsx index 6d94afa3..b2b344da 100644 --- a/src/renderer/components/virtual-table/cells/combined-title-cell.tsx +++ b/src/renderer/components/virtual-table/cells/combined-title-cell.tsx @@ -7,11 +7,12 @@ import { generatePath } from 'react-router'; import { Link } from 'react-router-dom'; import { SimpleImg } from 'react-simple-img'; import styled from 'styled-components'; -import type { AlbumArtist, Artist } from '/@/renderer/api/types'; +import { AlbumArtist, Artist } from '/@/renderer/api/types'; import { Text } from '/@/renderer/components/text'; import { AppRoute } from '/@/renderer/router/routes'; import { Skeleton } from '/@/renderer/components/skeleton'; import { SEPARATOR_STRING } from '/@/renderer/api/utils'; +import { ListCoverControls } from '/@/renderer/components/virtual-table/cells/combined-title-cell-controls'; const CellContainer = styled(motion.div)<{ height: number }>` display: grid; @@ -24,6 +25,16 @@ const CellContainer = styled(motion.div)<{ height: number }>` max-width: 100%; height: 100%; letter-spacing: 0.5px; + + .card-controls { + opacity: 0; + } + + &:hover { + .card-controls { + opacity: 1; + } + } `; const ImageWrapper = styled.div` @@ -48,7 +59,7 @@ const StyledImage = styled(SimpleImg)` } `; -export const CombinedTitleCell = ({ value, rowIndex, node }: ICellRendererParams) => { +export const CombinedTitleCell = ({ value, rowIndex, node, context }: ICellRendererParams) => { const artists = useMemo(() => { if (!value) return null; return value.artists?.length ? value.artists : value.albumArtists; @@ -102,6 +113,10 @@ export const CombinedTitleCell = ({ value, rowIndex, node }: ICellRendererParams /> )} + >({ const onCellContextMenu = useHandleTableContextMenu(itemType, contextMenu); const context = { + itemType, onCellContextMenu, }; diff --git a/src/renderer/components/virtual-table/index.tsx b/src/renderer/components/virtual-table/index.tsx index fc02696c..42717eec 100644 --- a/src/renderer/components/virtual-table/index.tsx +++ b/src/renderer/components/virtual-table/index.tsx @@ -361,6 +361,7 @@ const tableColumns: { [key: string]: ColDef } = { ? { albumArtists: params.data?.albumArtists, artists: params.data?.artists, + id: params.data?.id, imagePlaceholderUrl: params.data?.imagePlaceholderUrl, imageUrl: params.data?.imageUrl, name: params.data?.name,