add detail table header

This commit is contained in:
jeffvli
2026-02-09 10:08:25 -08:00
parent 42b51f104c
commit 72b2dca759
4 changed files with 162 additions and 11 deletions
@@ -1,7 +1,9 @@
.container {
position: relative;
flex: 1 1 auto;
width: 100%;
height: 100%;
min-height: 0;
overflow: auto;
}
.placeholder {
@@ -11,6 +13,76 @@
width: 100%;
}
.wrapper {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
min-height: 0;
}
.detail-list-header {
display: grid;
flex-shrink: 0;
grid-template-columns: 240px 1fr;
gap: var(--theme-spacing-md);
padding: 0 var(--theme-spacing-md);
font-size: var(--theme-font-size-sm);
color: var(--theme-colors-foreground-muted);
background-color: var(--theme-colors-background);
border-bottom: 1px solid var(--theme-colors-border);
}
.header-left {
min-width: 0;
}
.header-right {
min-width: 0;
overflow: hidden;
}
.tracks-table-header {
display: flex;
flex-wrap: nowrap;
align-items: center;
width: 100%;
min-width: 0;
}
.tracks-table-header-size-compact {
height: 32px;
min-height: 32px;
}
.tracks-table-header-size-default {
height: 40px;
min-height: 40px;
}
.tracks-table-header-size-large {
height: 48px;
min-height: 48px;
}
.track-header-cell {
min-width: 0;
padding-right: var(--theme-spacing-sm);
padding-left: var(--theme-spacing-sm);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.track-header-cell-no-h-padding {
padding-right: 0;
padding-left: 0;
}
.track-header-cell-with-vertical-border {
border-right: 1px solid var(--theme-colors-border);
}
.row {
display: grid;
grid-template-columns: 240px 1fr;
@@ -40,6 +40,7 @@ import {
SONG_TABLE_COLUMNS,
} from '/@/renderer/components/item-list/item-table-list/default-columns';
import { useItemDragDropState } from '/@/renderer/components/item-list/item-table-list/hooks/use-item-drag-drop-state';
import { columnLabelMap } from '/@/renderer/components/item-list/item-table-list/item-table-list-column';
import { ItemControls, ItemTableListColumnConfig } from '/@/renderer/components/item-list/types';
import { albumQueries } from '/@/renderer/features/albums/api/album-api';
import {
@@ -60,6 +61,7 @@ import { ItemListKey, TableColumn } from '/@/shared/types/types';
interface ItemDetailListProps {
currentPage?: number;
data?: unknown[];
enableHeader?: boolean;
getItem?: (index: number) => unknown;
internalState?: ItemListStateActions;
itemCount?: number;
@@ -601,9 +603,75 @@ const RowComponent = memo((props: RowComponentProps<RowData>): ReactElement => {
RowComponent.displayName = 'ItemDetailRow';
interface DetailListHeaderProps {
columnWidthPercents: number[];
enableVerticalBorders: boolean;
trackColumns: ItemTableListColumnConfig[];
trackTableSize: 'compact' | 'default' | 'large';
}
const DetailListHeader = memo(
({
columnWidthPercents,
enableVerticalBorders,
trackColumns,
trackTableSize,
}: DetailListHeaderProps) => {
return (
<header className={styles.detailListHeader} role="rowgroup">
<div aria-hidden className={styles.headerLeft} />
<div className={styles.headerRight}>
<div
className={clsx(styles.tracksTableHeader, {
[styles.tracksTableHeaderSizeCompact]: trackTableSize === 'compact',
[styles.tracksTableHeaderSizeDefault]: trackTableSize === 'default',
[styles.tracksTableHeaderSizeLarge]: trackTableSize === 'large',
})}
role="row"
>
{trackColumns.map((col, colIndex) => {
const percent = columnWidthPercents[colIndex] ?? 0;
const { fixedWidth, isFixedColumn } = getTrackColumnFixed(col.id);
const isLastColumn = colIndex === trackColumns.length - 1;
const style: React.CSSProperties = {
flex: isFixedColumn ? `0 0 ${fixedWidth}px` : `${percent} 1 0`,
minWidth: isFixedColumn ? fixedWidth : 0,
textAlign:
col.align === 'start'
? 'left'
: col.align === 'end'
? 'right'
: 'center',
};
return (
<div
className={clsx(styles.trackHeaderCell, {
[styles.trackHeaderCellNoHPadding]:
isNoHorizontalPaddingColumn(col.id),
[styles.trackHeaderCellWithVerticalBorder]:
enableVerticalBorders && !isLastColumn,
})}
key={col.id}
role="columnheader"
style={style}
>
{columnLabelMap[col.id] ?? ''}
</div>
);
})}
</div>
</div>
</header>
);
},
);
DetailListHeader.displayName = 'DetailListHeader';
export const ItemDetailList = ({
currentPage,
data,
enableHeader = true,
getItem,
itemCount: externalItemCount,
items,
@@ -785,14 +853,26 @@ export const ItemDetailList = ({
}, [initialize, osInstance]);
return (
<div className={styles.container} ref={containerRef}>
<List
onRowsRendered={throttledHandleRowsRendered}
rowComponent={RowComponent as (props: RowComponentProps<RowData>) => ReactElement}
rowCount={itemCount}
rowHeight={rowHeight}
rowProps={rowProps}
/>
<div className={styles.wrapper}>
{enableHeader && (
<DetailListHeader
columnWidthPercents={columnWidthPercents}
enableVerticalBorders={enableVerticalBorders}
trackColumns={trackColumns}
trackTableSize={trackTableSize}
/>
)}
<div className={styles.container} ref={containerRef}>
<List
onRowsRendered={throttledHandleRowsRendered}
rowComponent={
RowComponent as (props: RowComponentProps<RowData>) => ReactElement
}
rowCount={itemCount}
rowHeight={rowHeight}
rowProps={rowProps}
/>
</div>
</div>
);
};
@@ -885,7 +885,7 @@ export const TableColumnHeaderContainer = (
);
};
const columnLabelMap: Record<TableColumn, ReactNode | string> = {
export const columnLabelMap: Record<TableColumn, ReactNode | string> = {
[TableColumn.ACTIONS]: (
<Flex className={styles.headerIconWrapper}>
<Icon fill="default" icon="ellipsisHorizontal" />
@@ -101,7 +101,6 @@ export const AlbumListHeaderFilters = ({ toggleGenreTarget }: { toggleGenreTarge
listKey: ItemListKey.ALBUM_DETAIL,
optionsConfig: {
autoFitColumns: { hidden: true },
enableHeader: { hidden: true },
},
tableColumnsData: SONG_TABLE_COLUMNS,
}}