Update full-width cell renderer
This commit is contained in:
parent
897af4661b
commit
35f9798bed
4 changed files with 87 additions and 22 deletions
|
@ -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 (
|
||||||
|
<Container>
|
||||||
|
<Group
|
||||||
|
position="apart"
|
||||||
|
w="100%"
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
compact
|
||||||
|
leftIcon={isSelected ? <RiCheckboxLine /> : <RiCheckboxBlankLine />}
|
||||||
|
size="md"
|
||||||
|
variant="subtle"
|
||||||
|
onClick={handleToggleDiscNodes}
|
||||||
|
>
|
||||||
|
{data.name}
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
};
|
|
@ -37,6 +37,7 @@ export * from './table-config-dropdown';
|
||||||
export * from './table-pagination';
|
export * from './table-pagination';
|
||||||
export * from './hooks/use-fixed-table-header';
|
export * from './hooks/use-fixed-table-header';
|
||||||
export * from './hooks/use-click-outside-deselect';
|
export * from './hooks/use-click-outside-deselect';
|
||||||
|
export * from './utils';
|
||||||
|
|
||||||
const TableWrapper = styled.div`
|
const TableWrapper = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
36
src/renderer/components/virtual-table/utils.ts
Normal file
36
src/renderer/components/virtual-table/utils.ts
Normal file
|
@ -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<any>[] = [];
|
||||||
|
api.forEachNode((node) => {
|
||||||
|
if (node.data.discNumber === discNumber) nodes.push(node);
|
||||||
|
});
|
||||||
|
|
||||||
|
return nodes;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const setNodeSelection = (args: {
|
||||||
|
deselectAll?: boolean;
|
||||||
|
isSelected: boolean;
|
||||||
|
nodes: RowNode<any>[];
|
||||||
|
}) => {
|
||||||
|
const { nodes, isSelected } = args;
|
||||||
|
|
||||||
|
nodes.forEach((node) => {
|
||||||
|
node.setSelected(isSelected);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const toggleNodeSelection = (args: { nodes: RowNode<any>[] }) => {
|
||||||
|
const { nodes } = args;
|
||||||
|
|
||||||
|
nodes.forEach((node) => {
|
||||||
|
if (node.isSelected()) {
|
||||||
|
node.setSelected(false);
|
||||||
|
} else {
|
||||||
|
node.setSelected(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
|
@ -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 type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
|
||||||
import { Box, Group, Stack } from '@mantine/core';
|
import { Box, Group, Stack } from '@mantine/core';
|
||||||
import { useSetState } from '@mantine/hooks';
|
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 { generatePath, useParams } from 'react-router';
|
||||||
import { useAlbumDetail } from '/@/renderer/features/albums/queries/album-detail-query';
|
import { useAlbumDetail } from '/@/renderer/features/albums/queries/album-detail-query';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
@ -32,9 +32,10 @@ import {
|
||||||
VirtualTable,
|
VirtualTable,
|
||||||
} from '/@/renderer/components/virtual-table';
|
} from '/@/renderer/components/virtual-table';
|
||||||
import { SwiperGridCarousel } from '/@/renderer/components/grid-carousel';
|
import { SwiperGridCarousel } from '/@/renderer/components/grid-carousel';
|
||||||
|
import { FullWidthDiscCell } from '/@/renderer/components/virtual-table/cells/full-width-disc-cell';
|
||||||
|
|
||||||
const isFullWidthRow = (node: RowNode) => {
|
const isFullWidthRow = (node: RowNode) => {
|
||||||
return node.id?.includes('disc-');
|
return node.id?.startsWith('disc-');
|
||||||
};
|
};
|
||||||
|
|
||||||
const ContentContainer = styled.div`
|
const ContentContainer = styled.div`
|
||||||
|
@ -125,16 +126,11 @@ export const AlbumDetailContent = ({ tableRef }: AlbumDetailContentProps) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const uniqueDiscNumbers = new Set(detailQuery.data?.songs.map((s) => s.discNumber));
|
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 })[] = [];
|
const rowData: (QueueSong | { id: string; name: string })[] = [];
|
||||||
|
|
||||||
for (const discNumber of uniqueDiscNumbers.values()) {
|
for (const discNumber of uniqueDiscNumbers.values()) {
|
||||||
const songsByDiscNumber = detailQuery.data?.songs.filter((s) => s.discNumber === discNumber);
|
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);
|
rowData.push(...songsByDiscNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,26 +331,13 @@ export const AlbumDetailContent = ({ tableRef }: AlbumDetailContentProps) => {
|
||||||
ref={tableRef}
|
ref={tableRef}
|
||||||
autoFitColumns
|
autoFitColumns
|
||||||
autoHeight
|
autoHeight
|
||||||
deselectOnClickOutside
|
|
||||||
suppressCellFocus
|
suppressCellFocus
|
||||||
suppressHorizontalScroll
|
suppressHorizontalScroll
|
||||||
suppressLoadingOverlay
|
suppressLoadingOverlay
|
||||||
suppressRowDrag
|
suppressRowDrag
|
||||||
columnDefs={columnDefs}
|
columnDefs={columnDefs}
|
||||||
enableCellChangeFlash={false}
|
enableCellChangeFlash={false}
|
||||||
fullWidthCellRenderer={(data: any) => {
|
fullWidthCellRenderer={FullWidthDiscCell}
|
||||||
if (!data.data) return null;
|
|
||||||
return (
|
|
||||||
<Group
|
|
||||||
align="center"
|
|
||||||
h="100%"
|
|
||||||
spacing="sm"
|
|
||||||
>
|
|
||||||
<RiDiscFill />
|
|
||||||
<Text>{data.data.name}</Text>
|
|
||||||
</Group>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
getRowHeight={getRowHeight}
|
getRowHeight={getRowHeight}
|
||||||
getRowId={(data) => data.data.id}
|
getRowId={(data) => data.data.id}
|
||||||
isFullWidthRow={(data) => {
|
isFullWidthRow={(data) => {
|
||||||
|
|
Reference in a new issue