diff --git a/src/renderer/components/virtual-table/cells/full-width-disc-cell.tsx b/src/renderer/components/virtual-table/cells/full-width-disc-cell.tsx new file mode 100644 index 00000000..5119d1a9 --- /dev/null +++ b/src/renderer/components/virtual-table/cells/full-width-disc-cell.tsx @@ -0,0 +1,45 @@ +import { useState } from 'react'; +import { ICellRendererParams } from '@ag-grid-community/core'; +import { Group } from '@mantine/core'; +import { RiCheckboxBlankLine, RiCheckboxLine } from 'react-icons/ri'; +import styled from 'styled-components'; +import { Button } from '/@/renderer/components/button'; +import { Paper } from '/@/renderer/components/paper'; +import { getNodesByDiscNumber, setNodeSelection } from '../utils'; + +const Container = styled(Paper)` + padding: 0.5rem 1rem; + border: 1px solid transparent; +`; + +export const FullWidthDiscCell = ({ node, data, api }: ICellRendererParams) => { + const [isSelected, setIsSelected] = useState(false); + + const handleToggleDiscNodes = () => { + if (!data) return; + const discNumber = Number(node.data.id.split('-')[1]); + const nodes = getNodesByDiscNumber({ api, discNumber }); + + setNodeSelection({ isSelected: !isSelected, nodes }); + setIsSelected((prev) => !prev); + }; + + return ( + + + + + + ); +}; diff --git a/src/renderer/components/virtual-table/index.tsx b/src/renderer/components/virtual-table/index.tsx index 908b27a8..16f74bd4 100644 --- a/src/renderer/components/virtual-table/index.tsx +++ b/src/renderer/components/virtual-table/index.tsx @@ -37,6 +37,7 @@ export * from './table-config-dropdown'; export * from './table-pagination'; export * from './hooks/use-fixed-table-header'; export * from './hooks/use-click-outside-deselect'; +export * from './utils'; const TableWrapper = styled.div` display: flex; diff --git a/src/renderer/components/virtual-table/utils.ts b/src/renderer/components/virtual-table/utils.ts new file mode 100644 index 00000000..d77470dd --- /dev/null +++ b/src/renderer/components/virtual-table/utils.ts @@ -0,0 +1,36 @@ +import { GridApi, RowNode } from '@ag-grid-community/core'; + +export const getNodesByDiscNumber = (args: { api: GridApi; discNumber: number }) => { + const { api, discNumber } = args; + + const nodes: RowNode[] = []; + api.forEachNode((node) => { + if (node.data.discNumber === discNumber) nodes.push(node); + }); + + return nodes; +}; + +export const setNodeSelection = (args: { + deselectAll?: boolean; + isSelected: boolean; + nodes: RowNode[]; +}) => { + const { nodes, isSelected } = args; + + nodes.forEach((node) => { + node.setSelected(isSelected); + }); +}; + +export const toggleNodeSelection = (args: { nodes: RowNode[] }) => { + const { nodes } = args; + + nodes.forEach((node) => { + if (node.isSelected()) { + node.setSelected(false); + } else { + node.setSelected(true); + } + }); +}; diff --git a/src/renderer/features/albums/components/album-detail-content.tsx b/src/renderer/features/albums/components/album-detail-content.tsx index e64fa2e1..c09dbc5c 100644 --- a/src/renderer/features/albums/components/album-detail-content.tsx +++ b/src/renderer/features/albums/components/album-detail-content.tsx @@ -4,7 +4,7 @@ import { ColDef, RowDoubleClickedEvent, RowHeightParams, RowNode } from '@ag-gri import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact'; import { Box, Group, Stack } from '@mantine/core'; import { useSetState } from '@mantine/hooks'; -import { RiDiscFill, RiHeartFill, RiHeartLine, RiMoreFill } from 'react-icons/ri'; +import { RiHeartFill, RiHeartLine, RiMoreFill } from 'react-icons/ri'; import { generatePath, useParams } from 'react-router'; import { useAlbumDetail } from '/@/renderer/features/albums/queries/album-detail-query'; import { Link } from 'react-router-dom'; @@ -32,9 +32,10 @@ import { VirtualTable, } from '/@/renderer/components/virtual-table'; import { SwiperGridCarousel } from '/@/renderer/components/grid-carousel'; +import { FullWidthDiscCell } from '/@/renderer/components/virtual-table/cells/full-width-disc-cell'; const isFullWidthRow = (node: RowNode) => { - return node.id?.includes('disc-'); + return node.id?.startsWith('disc-'); }; const ContentContainer = styled.div` @@ -125,16 +126,11 @@ export const AlbumDetailContent = ({ tableRef }: AlbumDetailContentProps) => { } const uniqueDiscNumbers = new Set(detailQuery.data?.songs.map((s) => s.discNumber)); - - if (uniqueDiscNumbers.size === 1) { - return detailQuery.data?.songs; - } - const rowData: (QueueSong | { id: string; name: string })[] = []; for (const discNumber of uniqueDiscNumbers.values()) { const songsByDiscNumber = detailQuery.data?.songs.filter((s) => s.discNumber === discNumber); - rowData.push({ id: `disc-${discNumber}`, name: `DISC ${discNumber}` }); + rowData.push({ id: `disc-${discNumber}`, name: `Disc ${discNumber}`.toLocaleUpperCase() }); rowData.push(...songsByDiscNumber); } @@ -335,26 +331,13 @@ export const AlbumDetailContent = ({ tableRef }: AlbumDetailContentProps) => { ref={tableRef} autoFitColumns autoHeight - deselectOnClickOutside suppressCellFocus suppressHorizontalScroll suppressLoadingOverlay suppressRowDrag columnDefs={columnDefs} enableCellChangeFlash={false} - fullWidthCellRenderer={(data: any) => { - if (!data.data) return null; - return ( - - - {data.data.name} - - ); - }} + fullWidthCellRenderer={FullWidthDiscCell} getRowHeight={getRowHeight} getRowId={(data) => data.data.id} isFullWidthRow={(data) => {