mirror of
https://github.com/jeffvli/feishin.git
synced 2026-07-21 18:06:30 +02:00
clamp album group title, improve height calulation
This commit is contained in:
@@ -55,9 +55,14 @@
|
||||
}
|
||||
|
||||
.album-title {
|
||||
display: -webkit-box;
|
||||
overflow: hidden;
|
||||
-webkit-line-clamp: 3;
|
||||
line-clamp: 3;
|
||||
font-weight: 500;
|
||||
overflow-wrap: anywhere;
|
||||
white-space: normal;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.metadata-row {
|
||||
|
||||
@@ -123,7 +123,13 @@ export const AlbumGroupHeader = ({
|
||||
setResolved({ forInfoHeight: infoHeight, height: resolvedHeight });
|
||||
}
|
||||
|
||||
if (groupKey !== undefined && setAlbumGroupContentHeight) {
|
||||
// Only persist heights that exceed the image/row floor. Equal values
|
||||
// still replaced the Map and re-rendered the virtualizer on mount.
|
||||
if (
|
||||
groupKey !== undefined &&
|
||||
setAlbumGroupContentHeight &&
|
||||
contentHeight > (infoHeight ?? 0)
|
||||
) {
|
||||
setAlbumGroupContentHeight(groupKey, contentHeight);
|
||||
}
|
||||
};
|
||||
@@ -135,6 +141,7 @@ export const AlbumGroupHeader = ({
|
||||
|
||||
return () => resizeObserver.disconnect();
|
||||
}, [
|
||||
albumImageSize,
|
||||
groupKey,
|
||||
groupRowCount,
|
||||
infoHeight,
|
||||
|
||||
@@ -384,6 +384,35 @@ export const ItemTableListColumn = memo(ItemTableListColumnBase, (prevProps, nex
|
||||
|
||||
const NonMutedColumns = [TableColumn.TITLE, TableColumn.TITLE_ARTIST, TableColumn.TITLE_COMBINED];
|
||||
|
||||
/**
|
||||
* Stable content-height estimate for album-group info (title + metadata + controls).
|
||||
* Used by the virtualizer before a group header mounts/measures, so scrolling in
|
||||
* new groups does not jump when measured height is written later.
|
||||
* Keep in sync with album-group-header styles (title line-clamp, metadata xs, controls).
|
||||
*/
|
||||
export function estimateAlbumGroupContentHeight({
|
||||
hasEnlargedImage,
|
||||
metadataRowCount,
|
||||
showControls,
|
||||
}: {
|
||||
hasEnlargedImage: boolean;
|
||||
metadataRowCount: number;
|
||||
showControls: boolean;
|
||||
}): number {
|
||||
const TITLE_LINE_HEIGHT = 20;
|
||||
const TITLE_MAX_LINES = 3;
|
||||
const METADATA_LINE_HEIGHT = 18;
|
||||
const CONTROLS_HEIGHT = 26;
|
||||
const PADDING_TOP = hasEnlargedImage ? 8 : 0;
|
||||
|
||||
return (
|
||||
PADDING_TOP +
|
||||
TITLE_LINE_HEIGHT * TITLE_MAX_LINES +
|
||||
Math.max(0, metadataRowCount) * METADATA_LINE_HEIGHT +
|
||||
(showControls ? CONTROLS_HEIGHT : 0)
|
||||
);
|
||||
}
|
||||
|
||||
/** Stable key for album-group content heights (survives row moves; not row index). */
|
||||
export function getAlbumGroupHeightKey(item: unknown, groupRowCount?: number): string | undefined {
|
||||
if (!item || typeof item !== 'object') return undefined;
|
||||
@@ -568,8 +597,10 @@ function getAlbumGroupClampHeight(props: ItemTableListInnerColumn): null | numbe
|
||||
);
|
||||
const groupStartItem = props.getRowItem?.(groupStartRowIndex);
|
||||
const groupHeightKey = getAlbumGroupHeightKey(groupStartItem, groupRowCount);
|
||||
const contentHeight =
|
||||
(groupHeightKey ? props.albumGroupContentHeights?.get(groupHeightKey) : undefined) ?? 0;
|
||||
const measuredContentHeight = groupHeightKey
|
||||
? props.albumGroupContentHeights?.get(groupHeightKey)
|
||||
: undefined;
|
||||
const contentHeight = measuredContentHeight ?? props.estimatedAlbumGroupContentHeight ?? 0;
|
||||
const totalGroupHeight = getAlbumGroupSpanHeight(
|
||||
groupRowCount,
|
||||
baseHeight,
|
||||
|
||||
@@ -45,6 +45,7 @@ import { useTablePaneSync } from '/@/renderer/components/item-list/item-table-li
|
||||
import { useTableRowModel } from '/@/renderer/components/item-list/item-table-list/hooks/use-table-row-model';
|
||||
import { useTableScrollToIndex } from '/@/renderer/components/item-list/item-table-list/hooks/use-table-scroll-to-index';
|
||||
import {
|
||||
estimateAlbumGroupContentHeight,
|
||||
getAlbumGroupHeightKey,
|
||||
getAlbumGroupRowCount,
|
||||
getAlbumGroupSpanHeight,
|
||||
@@ -73,7 +74,12 @@ import {
|
||||
ItemTableListColumnConfig,
|
||||
} from '/@/renderer/components/item-list/types';
|
||||
import { PlayerContext, usePlayer } from '/@/renderer/features/player/context/player-context';
|
||||
import { useAlbumGroupImageSize, usePlayerStore } from '/@/renderer/store';
|
||||
import {
|
||||
useAlbumGroupImageSize,
|
||||
useAlbumGroupItems,
|
||||
useAlbumGroupShowFavoriteRating,
|
||||
usePlayerStore,
|
||||
} from '/@/renderer/store';
|
||||
import { animationProps } from '/@/shared/components/animations/animation-props';
|
||||
import { useFocusWithin } from '/@/shared/hooks/use-focus-within';
|
||||
import { useMergedRef } from '/@/shared/hooks/use-merged-ref';
|
||||
@@ -183,6 +189,7 @@ interface VirtualizedTableGridProps {
|
||||
data: unknown[];
|
||||
dataWithGroups: (null | unknown)[];
|
||||
enableScrollShadow: boolean;
|
||||
estimatedAlbumGroupContentHeight: number;
|
||||
getItem?: (index: number) => undefined | unknown;
|
||||
headerHeight: number;
|
||||
mergedRowRef: React.Ref<HTMLDivElement>;
|
||||
@@ -208,6 +215,7 @@ const VirtualizedTableGrid = ({
|
||||
data,
|
||||
dataWithGroups,
|
||||
enableScrollShadow,
|
||||
estimatedAlbumGroupContentHeight,
|
||||
getItem,
|
||||
headerHeight,
|
||||
mergedRowRef,
|
||||
@@ -403,6 +411,7 @@ const VirtualizedTableGrid = ({
|
||||
enableRowHoverHighlight: tableConfig.enableRowHoverHighlight,
|
||||
enableSelection: tableConfig.enableSelection,
|
||||
enableVerticalBorders: tableConfig.enableVerticalBorders,
|
||||
estimatedAlbumGroupContentHeight,
|
||||
getAdjustedRowIndex,
|
||||
getGroupRenderData,
|
||||
getRowHeight: tableConfig.getRowHeight,
|
||||
@@ -428,6 +437,7 @@ const VirtualizedTableGrid = ({
|
||||
albumGroupImageSize,
|
||||
calculatedColumnWidths,
|
||||
dataWithGroups,
|
||||
estimatedAlbumGroupContentHeight,
|
||||
getAdjustedRowIndex,
|
||||
getGroupRenderData,
|
||||
getRowItem,
|
||||
@@ -736,6 +746,8 @@ const MemoizedVirtualizedTableGrid = memo(VirtualizedTableGrid, (prevProps, next
|
||||
nextProps.calculatedColumnWidths,
|
||||
) &&
|
||||
prevProps.albumGroupContentHeights === nextProps.albumGroupContentHeights &&
|
||||
prevProps.estimatedAlbumGroupContentHeight ===
|
||||
nextProps.estimatedAlbumGroupContentHeight &&
|
||||
prevProps.setAlbumGroupContentHeight === nextProps.setAlbumGroupContentHeight &&
|
||||
prevProps.tableConfig === nextProps.tableConfig &&
|
||||
prevProps.data === nextProps.data &&
|
||||
@@ -776,6 +788,7 @@ export interface TableItemProps {
|
||||
adjustedRowIndexMap?: Map<number, number>;
|
||||
albumGroupContentHeights?: Map<string, number>;
|
||||
albumGroupImageSize?: number;
|
||||
estimatedAlbumGroupContentHeight?: number;
|
||||
calculatedColumnWidths?: number[];
|
||||
cellPadding?: ItemTableListProps['cellPadding'];
|
||||
columns: ItemTableListColumnConfig[];
|
||||
@@ -1297,6 +1310,21 @@ const BaseItemTableList = ({
|
||||
const { playlistId: routePlaylistId } = useParams() as { playlistId?: string };
|
||||
const tableId = useId();
|
||||
const albumGroupImageSize = useAlbumGroupImageSize();
|
||||
const albumGroupItems = useAlbumGroupItems();
|
||||
const albumGroupShowFavoriteRating = useAlbumGroupShowFavoriteRating();
|
||||
const albumGroupMetadataRowCount = useMemo(
|
||||
() => albumGroupItems.filter((item) => !item.disabled).length,
|
||||
[albumGroupItems],
|
||||
);
|
||||
const estimatedAlbumGroupContentHeight = useMemo(
|
||||
() =>
|
||||
estimateAlbumGroupContentHeight({
|
||||
hasEnlargedImage: (albumGroupImageSize || 96) > 0,
|
||||
metadataRowCount: albumGroupMetadataRowCount,
|
||||
showControls: albumGroupShowFavoriteRating,
|
||||
}),
|
||||
[albumGroupImageSize, albumGroupMetadataRowCount, albumGroupShowFavoriteRating],
|
||||
);
|
||||
const baseItemCount = itemCount ?? data.length;
|
||||
const [albumGroupContentHeights, setAlbumGroupContentHeights] = useState(
|
||||
() => new Map<string, number>(),
|
||||
@@ -1463,10 +1491,12 @@ const BaseItemTableList = ({
|
||||
);
|
||||
const groupStartItem = cellProps.getRowItem?.(groupStartRowIndex);
|
||||
const groupHeightKey = getAlbumGroupHeightKey(groupStartItem, groupRowCount);
|
||||
const contentHeight =
|
||||
(groupHeightKey
|
||||
? cellProps.albumGroupContentHeights?.get(groupHeightKey)
|
||||
: undefined) ?? 0;
|
||||
const measuredContentHeight = groupHeightKey
|
||||
? cellProps.albumGroupContentHeights?.get(groupHeightKey)
|
||||
: undefined;
|
||||
// Prefer measured height when present; otherwise reserve with a stable
|
||||
// estimate so newly virtualized groups do not jump after mount measure.
|
||||
const contentHeight = measuredContentHeight ?? estimatedAlbumGroupContentHeight;
|
||||
const totalGroupHeight = getAlbumGroupSpanHeight(
|
||||
groupRowCount,
|
||||
baseHeight,
|
||||
@@ -1482,7 +1512,15 @@ const BaseItemTableList = ({
|
||||
|
||||
return baseHeight;
|
||||
},
|
||||
[albumGroupImageSize, enableHeader, headerHeight, rowHeight, pinnedRowCount, size],
|
||||
[
|
||||
albumGroupImageSize,
|
||||
enableHeader,
|
||||
estimatedAlbumGroupContentHeight,
|
||||
headerHeight,
|
||||
rowHeight,
|
||||
pinnedRowCount,
|
||||
size,
|
||||
],
|
||||
);
|
||||
|
||||
const scrollCellProps = useMemo<TableItemProps>(
|
||||
@@ -1500,6 +1538,7 @@ const BaseItemTableList = ({
|
||||
enableRowHoverHighlight,
|
||||
enableSelection,
|
||||
enableVerticalBorders,
|
||||
estimatedAlbumGroupContentHeight,
|
||||
getRowHeight,
|
||||
getRowItem: (rowIndex: number) => {
|
||||
if (shouldUseAccessor && getItem) {
|
||||
@@ -1532,6 +1571,7 @@ const BaseItemTableList = ({
|
||||
enableRowHoverHighlight,
|
||||
enableSelection,
|
||||
enableVerticalBorders,
|
||||
estimatedAlbumGroupContentHeight,
|
||||
getItem,
|
||||
getRowHeight,
|
||||
hasAlbumGroupColumn,
|
||||
@@ -1887,6 +1927,7 @@ const BaseItemTableList = ({
|
||||
data={data}
|
||||
dataWithGroups={dataWithGroups}
|
||||
enableScrollShadow={enableScrollShadow}
|
||||
estimatedAlbumGroupContentHeight={estimatedAlbumGroupContentHeight}
|
||||
getItem={getItem}
|
||||
headerHeight={headerHeight}
|
||||
mergedRowRef={mergedRowRef}
|
||||
|
||||
Reference in New Issue
Block a user