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 (
+
+
+ : }
+ size="md"
+ variant="subtle"
+ onClick={handleToggleDiscNodes}
+ >
+ {data.name}
+
+
+
+ );
+};
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) => {