diff --git a/src/renderer/components/item-list/helpers/use-item-list-column-reorder.ts b/src/renderer/components/item-list/helpers/use-item-list-column-reorder.ts index 9d54560ae..328ba26d2 100644 --- a/src/renderer/components/item-list/helpers/use-item-list-column-reorder.ts +++ b/src/renderer/components/item-list/helpers/use-item-list-column-reorder.ts @@ -7,14 +7,19 @@ import { ItemListKey, TableColumn } from '/@/shared/types/types'; interface UseItemListColumnReorderProps { itemListKey: ItemListKey; + tableKey?: 'detail' | 'main'; } -export const useItemListColumnReorder = ({ itemListKey }: UseItemListColumnReorderProps) => { +export const useItemListColumnReorder = ({ + itemListKey, + tableKey = 'main', +}: UseItemListColumnReorderProps) => { const { setList } = useSettingsStoreActions(); const handleColumnReordered = useCallback( (columnIdFrom: TableColumn, columnIdTo: TableColumn, edge: Edge | null) => { - const columns = useSettingsStore.getState().lists[itemListKey]?.table.columns; + const list = useSettingsStore.getState().lists[itemListKey]; + const columns = tableKey === 'detail' ? list?.detail?.columns : list?.table?.columns; if (!columns) { return; @@ -83,13 +88,20 @@ export const useItemListColumnReorder = ({ itemListKey }: UseItemListColumnReord // Insert the column at the new position newColumns.splice(newIndex, 0, updatedMovedColumn); - setList(itemListKey, { - table: { - columns: newColumns, - }, - }); + if (tableKey === 'detail') { + type SetListData = Parameters< + ReturnType['setList'] + >[1]; + setList(itemListKey, { detail: { columns: newColumns } } as SetListData); + } else { + setList(itemListKey, { + table: { + columns: newColumns, + }, + }); + } }, - [itemListKey, setList], + [itemListKey, setList, tableKey], ); return { handleColumnReordered }; diff --git a/src/renderer/components/item-list/helpers/use-item-list-column-resize.ts b/src/renderer/components/item-list/helpers/use-item-list-column-resize.ts index 1b79edf9e..bfe87bcbb 100644 --- a/src/renderer/components/item-list/helpers/use-item-list-column-resize.ts +++ b/src/renderer/components/item-list/helpers/use-item-list-column-resize.ts @@ -5,11 +5,18 @@ import { ItemListKey, TableColumn } from '/@/shared/types/types'; interface UseItemListColumnResizeProps { itemListKey: ItemListKey; + tableKey?: 'detail' | 'main'; } -export const useItemListColumnResize = ({ itemListKey }: UseItemListColumnResizeProps) => { +export const useItemListColumnResize = ({ + itemListKey, + tableKey = 'main', +}: UseItemListColumnResizeProps) => { const { setList } = useSettingsStoreActions(); - const columns = useSettingsStore((state) => state.lists[itemListKey]?.table.columns); + const columns = useSettingsStore((state) => { + const list = state.lists[itemListKey]; + return tableKey === 'detail' ? list?.detail?.columns : list?.table?.columns; + }); const handleColumnResized = useCallback( (columnId: TableColumn, width: number) => { @@ -19,13 +26,20 @@ export const useItemListColumnResize = ({ itemListKey }: UseItemListColumnResize column.id === columnId ? { ...column, width } : column, ); - setList(itemListKey, { - table: { - columns: updatedColumns, - }, - }); + if (tableKey === 'detail') { + type SetListData = Parameters< + ReturnType['setList'] + >[1]; + setList(itemListKey, { detail: { columns: updatedColumns } } as SetListData); + } else { + setList(itemListKey, { + table: { + columns: updatedColumns, + }, + }); + } }, - [columns, itemListKey, setList], + [columns, itemListKey, setList, tableKey], ); return { handleColumnResized }; diff --git a/src/renderer/components/item-list/item-detail-list/item-detail.module.css b/src/renderer/components/item-list/item-detail-list/item-detail.module.css index 49cf02d3d..c849f44c3 100644 --- a/src/renderer/components/item-list/item-detail-list/item-detail.module.css +++ b/src/renderer/components/item-list/item-detail-list/item-detail.module.css @@ -66,6 +66,8 @@ } .track-header-cell { + display: flex; + align-items: center; min-width: 0; padding-right: var(--theme-spacing-sm); padding-left: var(--theme-spacing-sm); diff --git a/src/renderer/components/item-list/item-detail-list/item-detail.tsx b/src/renderer/components/item-list/item-detail-list/item-detail.tsx index c176501b0..753659c71 100644 --- a/src/renderer/components/item-list/item-detail-list/item-detail.tsx +++ b/src/renderer/components/item-list/item-detail-list/item-detail.tsx @@ -724,7 +724,7 @@ export const ItemDetailList = ({ const internalState = useItemListState(getDataFn, extractRowIdSong); - const tableConfig = useSettingsStore((state) => state.lists[ItemListKey.ALBUM_DETAIL]?.table); + const tableConfig = useSettingsStore((state) => state.lists[ItemListKey.ALBUM]?.detail); const trackColumns = useMemo((): ItemTableListColumnConfig[] => { const raw = tableConfig?.columns; if (raw && raw.length > 0) { diff --git a/src/renderer/components/item-list/types.ts b/src/renderer/components/item-list/types.ts index cb7c8565f..53d27fd17 100644 --- a/src/renderer/components/item-list/types.ts +++ b/src/renderer/components/item-list/types.ts @@ -98,7 +98,7 @@ export interface ItemListTableComponentProps extends ItemListComponentPr enableRowHoverHighlight?: boolean; enableSelection?: boolean; enableVerticalBorders?: boolean; - size?: 'compact' | 'default'; + size?: 'compact' | 'default' | 'large'; } export interface ItemTableListColumnConfig { diff --git a/src/renderer/features/albums/components/album-list-content.tsx b/src/renderer/features/albums/components/album-list-content.tsx index aa5b1e86d..18f29b7f5 100644 --- a/src/renderer/features/albums/components/album-list-content.tsx +++ b/src/renderer/features/albums/components/album-list-content.tsx @@ -74,13 +74,16 @@ export const AlbumListContent = () => { }; const AlbumListSuspenseContainer = () => { - const { display, grid, itemsPerPage, pagination, table } = useListSettings(ItemListKey.ALBUM); + const { detail, display, grid, itemsPerPage, pagination, table } = useListSettings( + ItemListKey.ALBUM, + ); const { customFilters } = useListContext(); return ( }> { export type OverrideAlbumListQuery = Omit, 'limit' | 'startIndex'>; export const AlbumListView = ({ + detail, display, grid, itemsPerPage, overrideQuery, pagination, table, -}: ItemListSettings & { overrideQuery?: OverrideAlbumListQuery }) => { +}: ItemListSettings & { + detail?: ItemListSettings['detail']; + overrideQuery?: OverrideAlbumListQuery; +}) => { const server = useCurrentServer(); const { pageKey } = useListContext(); @@ -196,6 +203,7 @@ export const AlbumListView = ({ case ListPaginationType.INFINITE: { return ( {} +interface AlbumListInfiniteDetailProps extends ItemListComponentProps { + enableHeader?: boolean; +} export const AlbumListInfiniteDetail = ({ + enableHeader = true, itemsPerPage = 100, query = { sortBy: AlbumListSort.NAME, @@ -49,6 +52,7 @@ export const AlbumListInfiniteDetail = ({ return ( {} +interface AlbumListPaginatedDetailProps extends ItemListComponentProps { + enableHeader?: boolean; +} export const AlbumListPaginatedDetail = ({ + enableHeader = true, itemsPerPage = 100, query = { sortBy: AlbumListSort.NAME, @@ -59,7 +62,11 @@ export const AlbumListPaginatedDetail = ({ pageCount={pageCount} totalItemCount={totalItemCount} > - + ); }; diff --git a/src/renderer/features/shared/components/list-config-menu.tsx b/src/renderer/features/shared/components/list-config-menu.tsx index 2f3903792..af418e653 100644 --- a/src/renderer/features/shared/components/list-config-menu.tsx +++ b/src/renderer/features/shared/components/list-config-menu.tsx @@ -73,9 +73,9 @@ export const ListConfigBooleanControl = ({ }; export interface ListConfigMenuDetailConfig { - listKey: ItemListKey; optionsConfig?: ListConfigMenuOptionsConfig['detail']; tableColumnsData: { label: string; value: string }[]; + tableKey: 'detail'; } export interface ListConfigMenuDisplayTypeConfig { @@ -196,9 +196,10 @@ const Config = ({ return ( ); } diff --git a/src/renderer/features/shared/components/table-config.tsx b/src/renderer/features/shared/components/table-config.tsx index 3862cf720..702226c26 100644 --- a/src/renderer/features/shared/components/table-config.tsx +++ b/src/renderer/features/shared/components/table-config.tsx @@ -21,7 +21,12 @@ import { ListConfigBooleanControl, ListConfigTable, } from '/@/renderer/features/shared/components/list-config-menu'; -import { ItemListSettings, useSettingsStore, useSettingsStoreActions } from '/@/renderer/store'; +import { + type DataTableProps, + ItemListSettings, + useSettingsStore, + useSettingsStoreActions, +} from '/@/renderer/store'; import { ActionIcon, ActionIconGroup } from '/@/shared/components/action-icon/action-icon'; import { Badge } from '/@/shared/components/badge/badge'; import { Checkbox } from '/@/shared/components/checkbox/checkbox'; @@ -53,6 +58,7 @@ interface TableConfigProps { }; }; tableColumnsData: { label: string; value: string }[]; + tableKey?: 'detail' | 'main'; } export const TableConfig = ({ @@ -61,12 +67,28 @@ export const TableConfig = ({ listKey, optionsConfig, tableColumnsData, + tableKey = 'main', }: TableConfigProps) => { const { t } = useTranslation(); const list = useSettingsStore((state) => state.lists[listKey]) as ItemListSettings; const { setList } = useSettingsStoreActions(); + const table = tableKey === 'detail' ? (list?.detail ?? list?.table) : list?.table; + + const setTableUpdate = useCallback( + (patch: Partial) => { + if (tableKey === 'detail') { + setList(listKey, { detail: patch } as Parameters< + ReturnType['setList'] + >[1]); + } else { + setList(listKey, { table: patch }); + } + }, + [listKey, setList, tableKey], + ); + const advancedSettings = useMemo(() => { const allOptions = [ { @@ -159,7 +181,7 @@ export const TableConfig = ({ }) } size="sm" - value={list.table.size} + value={table.size} w="100%" /> ), @@ -171,8 +193,8 @@ export const TableConfig = ({ { component: ( setList(listKey, { table: { enableHeader: e } })} - value={list.table.enableHeader} + onChange={(e) => setTableUpdate({ enableHeader: e })} + value={table.enableHeader} /> ), id: 'enableHeader', @@ -183,10 +205,8 @@ export const TableConfig = ({ { component: ( - setList(listKey, { table: { enableRowHoverHighlight: e } }) - } - value={list.table.enableRowHoverHighlight} + onChange={(e) => setTableUpdate({ enableRowHoverHighlight: e })} + value={table.enableRowHoverHighlight} /> ), id: 'enableRowHoverHighlight', @@ -197,10 +217,8 @@ export const TableConfig = ({ { component: ( - setList(listKey, { table: { enableAlternateRowColors: e } }) - } - value={list.table.enableAlternateRowColors} + onChange={(e) => setTableUpdate({ enableAlternateRowColors: e })} + value={table.enableAlternateRowColors} /> ), id: 'enableAlternateRowColors', @@ -211,10 +229,8 @@ export const TableConfig = ({ { component: ( - setList(listKey, { table: { enableHorizontalBorders: e } }) - } - value={list.table.enableHorizontalBorders} + onChange={(e) => setTableUpdate({ enableHorizontalBorders: e })} + value={table.enableHorizontalBorders} /> ), id: 'enableHorizontalBorders', @@ -225,8 +241,8 @@ export const TableConfig = ({ { component: ( setList(listKey, { table: { enableVerticalBorders: e } })} - value={list.table.enableVerticalBorders} + onChange={(e) => setTableUpdate({ enableVerticalBorders: e })} + value={table.enableVerticalBorders} /> ), id: 'enableVerticalBorders', @@ -237,8 +253,10 @@ export const TableConfig = ({ { component: ( setList(listKey, { table: { autoFitColumns: e } })} - value={list.table.autoFitColumns} + onChange={(e) => setTableUpdate({ autoFitColumns: e })} + value={ + tableKey === 'main' ? (table as DataTableProps).autoFitColumns : false + } /> ), id: 'autoFitColumns', @@ -258,7 +276,18 @@ export const TableConfig = ({ return option; }) .filter((option): option is NonNullable => option !== null); - }, [extraOptions, listKey, optionsConfig, setList, t, list]); + }, [ + t, + list.pagination, + list.itemsPerPage, + table, + tableKey, + extraOptions, + setList, + listKey, + setTableUpdate, + optionsConfig, + ]); return ( <> @@ -267,8 +296,8 @@ export const TableConfig = ({ setList(listKey, { table: { columns } })} - value={list.table.columns} + onChange={(columns) => setTableUpdate({ columns })} + value={table.columns} /> ); diff --git a/src/renderer/store/settings.store.ts b/src/renderer/store/settings.store.ts index c742e62cd..a211a7757 100644 --- a/src/renderer/store/settings.store.ts +++ b/src/renderer/store/settings.store.ts @@ -206,7 +206,18 @@ const ItemTableListPropsSchema = z.object({ size: z.enum(['compact', 'default', 'large']), }); +const ItemDetailListPropsSchema = z.object({ + columns: z.array(ItemTableListColumnConfigSchema), + enableAlternateRowColors: z.boolean(), + enableHeader: z.boolean(), + enableHorizontalBorders: z.boolean(), + enableRowHoverHighlight: z.boolean(), + enableVerticalBorders: z.boolean(), + size: z.enum(['compact', 'default', 'large']), +}); + const ItemListConfigSchema = z.object({ + detail: ItemDetailListPropsSchema.optional(), display: z.nativeEnum(ListDisplayType), grid: z.object({ itemGap: z.enum(['lg', 'md', 'sm', 'xl', 'xs']), @@ -790,7 +801,9 @@ export type DataGridProps = { }; export type DataTableProps = z.infer; +export type ItemDetailListProps = z.infer; export type ItemListSettings = { + detail?: ItemDetailListProps; display: ListDisplayType; grid: DataGridProps; itemsPerPage: number; @@ -1163,6 +1176,30 @@ const initialState: SettingsState = { }, }, [LibraryItem.ALBUM]: { + detail: { + columns: pickTableColumns({ + autoSizeColumns: [], + columns: SONG_TABLE_COLUMNS, + columnWidths: { + [TableColumn.DURATION]: 100, + [TableColumn.TITLE]: 400, + [TableColumn.TRACK_NUMBER]: 50, + [TableColumn.USER_FAVORITE]: 60, + }, + enabledColumns: [ + TableColumn.TRACK_NUMBER, + TableColumn.TITLE, + TableColumn.DURATION, + TableColumn.USER_FAVORITE, + ], + }), + enableAlternateRowColors: false, + enableHeader: true, + enableHorizontalBorders: false, + enableRowHoverHighlight: true, + enableVerticalBorders: false, + size: 'compact', + }, display: ListDisplayType.GRID, grid: { itemGap: 'sm', @@ -1737,6 +1774,23 @@ export const useSettingsStore = createWithEqualityFn()( delete data.table; } + if (listState && data.detail) { + if (!listState.detail) { + const t = listState.table; + listState.detail = { + columns: t.columns, + enableAlternateRowColors: false, + enableHeader: t.enableHeader, + enableHorizontalBorders: t.enableHorizontalBorders, + enableRowHoverHighlight: t.enableRowHoverHighlight, + enableVerticalBorders: t.enableVerticalBorders, + size: t.size, + }; + } + Object.assign(listState.detail, data.detail); + delete data.detail; + } + if (listState && data.grid) { Object.assign(listState.grid, data.grid); delete data.grid; @@ -2092,7 +2146,7 @@ export const useSettingsStore = createWithEqualityFn()( return persistedState; }, name: 'store_settings', - version: 24, + version: 25, }, ), );