mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-09 20:29:36 +02:00
support scroll sync on sticky table header and groups
This commit is contained in:
+153
-1
@@ -1,5 +1,5 @@
|
|||||||
import { useInView } from 'motion/react';
|
import { useInView } from 'motion/react';
|
||||||
import { RefObject, useMemo } from 'react';
|
import { RefObject, useEffect, useMemo, useRef } from 'react';
|
||||||
|
|
||||||
import { useWindowSettings } from '/@/renderer/store/settings.store';
|
import { useWindowSettings } from '/@/renderer/store/settings.store';
|
||||||
import { Platform } from '/@/shared/types/types';
|
import { Platform } from '/@/shared/types/types';
|
||||||
@@ -8,12 +8,26 @@ export const useStickyTableHeader = ({
|
|||||||
containerRef,
|
containerRef,
|
||||||
enabled,
|
enabled,
|
||||||
headerRef,
|
headerRef,
|
||||||
|
mainGridRef,
|
||||||
|
pinnedLeftColumnRef,
|
||||||
|
pinnedRightColumnRef,
|
||||||
|
stickyHeaderMainRef,
|
||||||
}: {
|
}: {
|
||||||
containerRef: RefObject<HTMLDivElement | null>;
|
containerRef: RefObject<HTMLDivElement | null>;
|
||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
headerRef: RefObject<HTMLDivElement | null>;
|
headerRef: RefObject<HTMLDivElement | null>;
|
||||||
|
mainGridRef?: RefObject<HTMLDivElement | null>;
|
||||||
|
pinnedLeftColumnRef?: RefObject<HTMLDivElement | null>;
|
||||||
|
pinnedRightColumnRef?: RefObject<HTMLDivElement | null>;
|
||||||
|
stickyHeaderMainRef?: RefObject<HTMLDivElement | null>;
|
||||||
}) => {
|
}) => {
|
||||||
const { windowBarStyle } = useWindowSettings();
|
const { windowBarStyle } = useWindowSettings();
|
||||||
|
const isScrollingRef = useRef({
|
||||||
|
main: false,
|
||||||
|
pinnedLeft: false,
|
||||||
|
pinnedRight: false,
|
||||||
|
stickyHeader: false,
|
||||||
|
});
|
||||||
|
|
||||||
const topMargin =
|
const topMargin =
|
||||||
windowBarStyle === Platform.WINDOWS || windowBarStyle === Platform.MACOS
|
windowBarStyle === Platform.WINDOWS || windowBarStyle === Platform.MACOS
|
||||||
@@ -36,6 +50,144 @@ export const useStickyTableHeader = ({
|
|||||||
return windowBarStyle === Platform.WINDOWS || windowBarStyle === Platform.MACOS ? 95 : 65;
|
return windowBarStyle === Platform.WINDOWS || windowBarStyle === Platform.MACOS ? 95 : 65;
|
||||||
}, [windowBarStyle]);
|
}, [windowBarStyle]);
|
||||||
|
|
||||||
|
// Sync scroll between sticky header and main grid/pinned columns
|
||||||
|
useEffect(() => {
|
||||||
|
if (!shouldShowStickyHeader || !stickyHeaderMainRef?.current || !mainGridRef?.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stickyMainSection = stickyHeaderMainRef.current;
|
||||||
|
const mainGrid = mainGridRef.current.childNodes[0] as HTMLDivElement;
|
||||||
|
const pinnedLeft = pinnedLeftColumnRef?.current?.childNodes[0] as HTMLDivElement | null;
|
||||||
|
const pinnedRight = pinnedRightColumnRef?.current?.childNodes[0] as HTMLDivElement | null;
|
||||||
|
|
||||||
|
if (!mainGrid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync initial scroll position when sticky header becomes visible
|
||||||
|
const syncInitialScroll = () => {
|
||||||
|
const scrollLeft = mainGrid.scrollLeft;
|
||||||
|
const scrollTop = mainGrid.scrollTop;
|
||||||
|
|
||||||
|
// Sync horizontal scroll position
|
||||||
|
stickyMainSection.scrollTo({
|
||||||
|
behavior: 'instant',
|
||||||
|
left: scrollLeft,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sync vertical scroll position with pinned columns
|
||||||
|
if (pinnedLeft) {
|
||||||
|
pinnedLeft.scrollTo({
|
||||||
|
behavior: 'instant',
|
||||||
|
top: scrollTop,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (pinnedRight) {
|
||||||
|
pinnedRight.scrollTo({
|
||||||
|
behavior: 'instant',
|
||||||
|
top: scrollTop,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Sync initial position after a frame to ensure elements are ready
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
requestAnimationFrame(syncInitialScroll);
|
||||||
|
});
|
||||||
|
|
||||||
|
const syncScroll = (e: Event) => {
|
||||||
|
const target = e.currentTarget as HTMLDivElement;
|
||||||
|
const scrollLeft = target.scrollLeft;
|
||||||
|
const scrollTop = target.scrollTop;
|
||||||
|
|
||||||
|
// Sync horizontal scroll from main grid to sticky header main section
|
||||||
|
if (target === mainGrid && !isScrollingRef.current.stickyHeader) {
|
||||||
|
isScrollingRef.current.stickyHeader = true;
|
||||||
|
stickyMainSection.scrollTo({
|
||||||
|
behavior: 'instant',
|
||||||
|
left: scrollLeft,
|
||||||
|
});
|
||||||
|
isScrollingRef.current.stickyHeader = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync horizontal scroll from sticky header to main grid
|
||||||
|
if (target === stickyMainSection && !isScrollingRef.current.main) {
|
||||||
|
isScrollingRef.current.main = true;
|
||||||
|
mainGrid.scrollTo({
|
||||||
|
behavior: 'instant',
|
||||||
|
left: scrollLeft,
|
||||||
|
});
|
||||||
|
isScrollingRef.current.main = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync vertical scroll from main grid to pinned columns
|
||||||
|
if (target === mainGrid) {
|
||||||
|
if (pinnedLeft && !isScrollingRef.current.pinnedLeft) {
|
||||||
|
isScrollingRef.current.pinnedLeft = true;
|
||||||
|
pinnedLeft.scrollTo({
|
||||||
|
behavior: 'instant',
|
||||||
|
top: scrollTop,
|
||||||
|
});
|
||||||
|
isScrollingRef.current.pinnedLeft = false;
|
||||||
|
}
|
||||||
|
if (pinnedRight && !isScrollingRef.current.pinnedRight) {
|
||||||
|
isScrollingRef.current.pinnedRight = true;
|
||||||
|
pinnedRight.scrollTo({
|
||||||
|
behavior: 'instant',
|
||||||
|
top: scrollTop,
|
||||||
|
});
|
||||||
|
isScrollingRef.current.pinnedRight = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync vertical scroll from pinned columns to main grid
|
||||||
|
if (pinnedLeft && target === pinnedLeft && !isScrollingRef.current.main) {
|
||||||
|
isScrollingRef.current.main = true;
|
||||||
|
mainGrid.scrollTo({
|
||||||
|
behavior: 'instant',
|
||||||
|
top: scrollTop,
|
||||||
|
});
|
||||||
|
isScrollingRef.current.main = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pinnedRight && target === pinnedRight && !isScrollingRef.current.main) {
|
||||||
|
isScrollingRef.current.main = true;
|
||||||
|
mainGrid.scrollTo({
|
||||||
|
behavior: 'instant',
|
||||||
|
top: scrollTop,
|
||||||
|
});
|
||||||
|
isScrollingRef.current.main = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mainGrid.addEventListener('scroll', syncScroll);
|
||||||
|
stickyMainSection.addEventListener('scroll', syncScroll);
|
||||||
|
if (pinnedLeft) {
|
||||||
|
pinnedLeft.addEventListener('scroll', syncScroll);
|
||||||
|
}
|
||||||
|
if (pinnedRight) {
|
||||||
|
pinnedRight.addEventListener('scroll', syncScroll);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
mainGrid.removeEventListener('scroll', syncScroll);
|
||||||
|
stickyMainSection.removeEventListener('scroll', syncScroll);
|
||||||
|
if (pinnedLeft) {
|
||||||
|
pinnedLeft.removeEventListener('scroll', syncScroll);
|
||||||
|
}
|
||||||
|
if (pinnedRight) {
|
||||||
|
pinnedRight.removeEventListener('scroll', syncScroll);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [
|
||||||
|
shouldShowStickyHeader,
|
||||||
|
mainGridRef,
|
||||||
|
pinnedLeftColumnRef,
|
||||||
|
pinnedRightColumnRef,
|
||||||
|
stickyHeaderMainRef,
|
||||||
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
shouldShowStickyHeader,
|
shouldShowStickyHeader,
|
||||||
stickyTop,
|
stickyTop,
|
||||||
|
|||||||
@@ -67,12 +67,10 @@
|
|||||||
z-index: 15;
|
z-index: 15;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
padding: 0 2rem;
|
overflow: hidden;
|
||||||
margin: 0 -2rem;
|
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
background-color: var(--theme-colors-background);
|
background-color: var(--theme-colors-background);
|
||||||
border-bottom: 1px solid var(--theme-colors-border);
|
border-bottom: 1px solid var(--theme-colors-border);
|
||||||
box-shadow: 0 -1px 0 0 var(--theme-colors-border);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.sticky-header-row {
|
.sticky-header-row {
|
||||||
@@ -93,8 +91,8 @@
|
|||||||
z-index: 15;
|
z-index: 15;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
padding: 0 2rem;
|
padding: 0;
|
||||||
margin: 0 -2rem;
|
margin: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
background-color: var(--theme-colors-background);
|
background-color: var(--theme-colors-background);
|
||||||
border-bottom: 1px solid var(--theme-colors-border);
|
border-bottom: 1px solid var(--theme-colors-border);
|
||||||
@@ -104,7 +102,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: var(--theme-colors-background);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.sticky-group-row-section {
|
.sticky-group-row-section {
|
||||||
@@ -112,7 +109,6 @@
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
pointer-events: auto;
|
pointer-events: auto;
|
||||||
background-color: var(--theme-colors-background);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.item-table-pinned-rows-grid-container.with-header::after {
|
.item-table-pinned-rows-grid-container.with-header::after {
|
||||||
|
|||||||
@@ -845,57 +845,45 @@ export const ItemTableList = ({
|
|||||||
const handleRef = useRef<ItemListHandle | null>(null);
|
const handleRef = useRef<ItemListHandle | null>(null);
|
||||||
const containerFocusRef = useRef<HTMLDivElement | null>(null);
|
const containerFocusRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
|
const stickyHeaderRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
const stickyGroupRowRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
const stickyHeaderLeftRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
const stickyHeaderMainRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
const stickyHeaderRightRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
const { shouldShowStickyHeader, stickyTop } = useStickyTableHeader({
|
const { shouldShowStickyHeader, stickyTop } = useStickyTableHeader({
|
||||||
containerRef: containerFocusRef,
|
containerRef: containerFocusRef,
|
||||||
enabled: enableHeader && enableStickyHeader,
|
enabled: enableHeader && enableStickyHeader,
|
||||||
headerRef: pinnedRowRef,
|
headerRef: pinnedRowRef,
|
||||||
|
mainGridRef: rowRef,
|
||||||
|
pinnedLeftColumnRef,
|
||||||
|
pinnedRightColumnRef,
|
||||||
|
stickyHeaderMainRef,
|
||||||
});
|
});
|
||||||
|
|
||||||
const stickyHeaderRef = useRef<HTMLDivElement | null>(null);
|
// Update position and width of sticky header (scroll sync is handled in the hook)
|
||||||
const stickyGroupRowRef = useRef<HTMLDivElement | null>(null);
|
|
||||||
|
|
||||||
// Sync scroll position and update position of sticky header
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (!shouldShowStickyHeader || !stickyHeaderRef.current || !containerFocusRef.current) {
|
||||||
!shouldShowStickyHeader ||
|
|
||||||
!stickyHeaderRef.current ||
|
|
||||||
!rowRef.current ||
|
|
||||||
!containerFocusRef.current
|
|
||||||
) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const stickyHeader = stickyHeaderRef.current;
|
const stickyHeader = stickyHeaderRef.current;
|
||||||
const stickyMainSection = stickyHeader.querySelector(
|
|
||||||
`.${styles.stickyHeaderSection}`,
|
|
||||||
) as HTMLDivElement;
|
|
||||||
const mainGrid = rowRef.current.childNodes[0] as HTMLDivElement;
|
|
||||||
const container = containerFocusRef.current;
|
const container = containerFocusRef.current;
|
||||||
|
|
||||||
if (!stickyMainSection || !mainGrid || !container) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const updatePosition = () => {
|
const updatePosition = () => {
|
||||||
const containerRect = container.getBoundingClientRect();
|
const containerRect = container.getBoundingClientRect();
|
||||||
stickyHeader.style.left = `${containerRect.left}px`;
|
stickyHeader.style.left = `${containerRect.left}px`;
|
||||||
};
|
stickyHeader.style.width = `${containerRect.width}px`;
|
||||||
|
|
||||||
const syncScroll = () => {
|
|
||||||
stickyMainSection.scrollLeft = mainGrid.scrollLeft;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
updatePosition();
|
updatePosition();
|
||||||
syncScroll();
|
|
||||||
|
|
||||||
window.addEventListener('resize', updatePosition);
|
window.addEventListener('resize', updatePosition);
|
||||||
window.addEventListener('scroll', updatePosition, true);
|
window.addEventListener('scroll', updatePosition, true);
|
||||||
mainGrid.addEventListener('scroll', syncScroll);
|
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener('resize', updatePosition);
|
window.removeEventListener('resize', updatePosition);
|
||||||
window.removeEventListener('scroll', updatePosition, true);
|
window.removeEventListener('scroll', updatePosition, true);
|
||||||
mainGrid.removeEventListener('scroll', syncScroll);
|
|
||||||
};
|
};
|
||||||
}, [shouldShowStickyHeader]);
|
}, [shouldShowStickyHeader]);
|
||||||
|
|
||||||
@@ -1516,6 +1504,36 @@ export const ItemTableList = ({
|
|||||||
// Show sticky group row whenever it should be shown
|
// Show sticky group row whenever it should be shown
|
||||||
const shouldRenderStickyGroupRow = shouldShowStickyGroupRow;
|
const shouldRenderStickyGroupRow = shouldShowStickyGroupRow;
|
||||||
|
|
||||||
|
// Update position and width of sticky group row
|
||||||
|
useEffect(() => {
|
||||||
|
if (
|
||||||
|
!shouldRenderStickyGroupRow ||
|
||||||
|
!stickyGroupRowRef.current ||
|
||||||
|
!containerFocusRef.current
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stickyGroupRow = stickyGroupRowRef.current;
|
||||||
|
const container = containerFocusRef.current;
|
||||||
|
|
||||||
|
const updatePosition = () => {
|
||||||
|
const containerRect = container.getBoundingClientRect();
|
||||||
|
stickyGroupRow.style.left = `${containerRect.left}px`;
|
||||||
|
stickyGroupRow.style.width = `${containerRect.width}px`;
|
||||||
|
};
|
||||||
|
|
||||||
|
updatePosition();
|
||||||
|
|
||||||
|
window.addEventListener('resize', updatePosition);
|
||||||
|
window.addEventListener('scroll', updatePosition, true);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('resize', updatePosition);
|
||||||
|
window.removeEventListener('scroll', updatePosition, true);
|
||||||
|
};
|
||||||
|
}, [shouldRenderStickyGroupRow]);
|
||||||
|
|
||||||
const getDataFn = useCallback(() => {
|
const getDataFn = useCallback(() => {
|
||||||
const result: (null | unknown)[] = enableHeader ? [null] : [];
|
const result: (null | unknown)[] = enableHeader ? [null] : [];
|
||||||
|
|
||||||
@@ -1829,8 +1847,16 @@ export const ItemTableList = ({
|
|||||||
<div className={styles.stickyHeaderRow}>
|
<div className={styles.stickyHeaderRow}>
|
||||||
{pinnedLeftColumnCount > 0 && (
|
{pinnedLeftColumnCount > 0 && (
|
||||||
<div
|
<div
|
||||||
className={styles.stickyHeaderSection}
|
className={clsx(
|
||||||
style={{ width: `${pinnedLeftWidth}px` }}
|
styles.stickyHeaderSection,
|
||||||
|
styles.stickyHeaderPinnedLeft,
|
||||||
|
)}
|
||||||
|
ref={stickyHeaderLeftRef}
|
||||||
|
style={{
|
||||||
|
flex: '0 1 auto',
|
||||||
|
minWidth: `${pinnedLeftWidth}px`,
|
||||||
|
overflow: 'hidden',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{parsedColumns
|
{parsedColumns
|
||||||
.filter((col) => col.pinned === 'left')
|
.filter((col) => col.pinned === 'left')
|
||||||
@@ -1855,33 +1881,62 @@ export const ItemTableList = ({
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className={styles.stickyHeaderSection} style={{ width: `${mainWidth}px` }}>
|
<div
|
||||||
{parsedColumns
|
className={clsx(
|
||||||
.filter((col) => col.pinned === null)
|
styles.stickyHeaderSection,
|
||||||
.map((col) => {
|
styles.stickyHeaderMain,
|
||||||
const columnIndex = parsedColumns.findIndex((c) => c === col);
|
styles.noScrollbar,
|
||||||
return (
|
)}
|
||||||
<CellComponent
|
ref={stickyHeaderMainRef}
|
||||||
ariaAttributes={{
|
style={{
|
||||||
'aria-colindex': columnIndex + 1,
|
flex: '1 1 auto',
|
||||||
role: 'gridcell',
|
minWidth: 0,
|
||||||
}}
|
overflowX: 'auto',
|
||||||
columnIndex={columnIndex}
|
overflowY: 'hidden',
|
||||||
key={col.id}
|
}}
|
||||||
rowIndex={0}
|
>
|
||||||
style={{
|
<div
|
||||||
height: headerHeight,
|
style={{
|
||||||
width: calculatedColumnWidths[columnIndex],
|
display: 'flex',
|
||||||
}}
|
minWidth: `${mainWidth}px`,
|
||||||
{...stickyHeaderItemProps}
|
}}
|
||||||
/>
|
>
|
||||||
);
|
{parsedColumns
|
||||||
})}
|
.filter((col) => col.pinned === null)
|
||||||
|
.map((col) => {
|
||||||
|
const columnIndex = parsedColumns.findIndex((c) => c === col);
|
||||||
|
return (
|
||||||
|
<CellComponent
|
||||||
|
ariaAttributes={{
|
||||||
|
'aria-colindex': columnIndex + 1,
|
||||||
|
role: 'gridcell',
|
||||||
|
}}
|
||||||
|
columnIndex={columnIndex}
|
||||||
|
key={col.id}
|
||||||
|
rowIndex={0}
|
||||||
|
style={{
|
||||||
|
flexShrink: 0,
|
||||||
|
height: headerHeight,
|
||||||
|
width: calculatedColumnWidths[columnIndex],
|
||||||
|
}}
|
||||||
|
{...stickyHeaderItemProps}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{pinnedRightColumnCount > 0 && (
|
{pinnedRightColumnCount > 0 && (
|
||||||
<div
|
<div
|
||||||
className={styles.stickyHeaderSection}
|
className={clsx(
|
||||||
style={{ width: `${pinnedRightWidth}px` }}
|
styles.stickyHeaderSection,
|
||||||
|
styles.stickyHeaderPinnedRight,
|
||||||
|
)}
|
||||||
|
ref={stickyHeaderRightRef}
|
||||||
|
style={{
|
||||||
|
flex: '0 1 auto',
|
||||||
|
minWidth: `${pinnedRightWidth}px`,
|
||||||
|
overflow: 'hidden',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{parsedColumns
|
{parsedColumns
|
||||||
.filter((col) => col.pinned === 'right')
|
.filter((col) => col.pinned === 'right')
|
||||||
@@ -2003,7 +2058,13 @@ export const ItemTableList = ({
|
|||||||
)}
|
)}
|
||||||
<div
|
<div
|
||||||
className={styles.stickyGroupRowSection}
|
className={styles.stickyGroupRowSection}
|
||||||
style={{ width: `${mainWidth}px` }}
|
style={{
|
||||||
|
marginLeft: pinnedLeftColumnCount > 0 ? 0 : '-2rem',
|
||||||
|
marginRight: '-2rem',
|
||||||
|
paddingLeft: pinnedLeftColumnCount > 0 ? 0 : '2rem',
|
||||||
|
paddingRight: '2rem',
|
||||||
|
width: `${mainWidth}px`,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@@ -2025,9 +2086,7 @@ export const ItemTableList = ({
|
|||||||
height: groupRowHeight,
|
height: groupRowHeight,
|
||||||
width: `${pinnedRightWidth}px`,
|
width: `${pinnedRightWidth}px`,
|
||||||
}}
|
}}
|
||||||
>
|
/>
|
||||||
{groupContent}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -552,7 +552,7 @@ const AlbumDetailSongsTable = ({ songs }: AlbumDetailSongsTableProps) => {
|
|||||||
id={`disc-${discGroup.discNumber}`}
|
id={`disc-${discGroup.discNumber}`}
|
||||||
indeterminate={isSomeSelected}
|
indeterminate={isSomeSelected}
|
||||||
label={
|
label={
|
||||||
<Text component="label" size="sm">
|
<Text component="label" size="sm" truncate>
|
||||||
{t('common.disc', { postProcess: 'sentenceCase' })}{' '}
|
{t('common.disc', { postProcess: 'sentenceCase' })}{' '}
|
||||||
{discGroup.discNumber}
|
{discGroup.discNumber}
|
||||||
{discGroup.discSubtitle && ` - ${discGroup.discSubtitle}`}
|
{discGroup.discSubtitle && ` - ${discGroup.discSubtitle}`}
|
||||||
|
|||||||
Reference in New Issue
Block a user