mirror of
https://github.com/jeffvli/feishin.git
synced 2026-07-22 02:16:39 +02:00
add vertical album group layout
This commit is contained in:
@@ -1233,6 +1233,7 @@
|
||||
"albumGroupConfig": "Album Group configuration",
|
||||
"albumGroupMetadata": "Metadata fields",
|
||||
"albumGroupShowFavoriteRating": "Show favorites and ratings",
|
||||
"albumGroupVerticalLayout": "Vertical layout",
|
||||
"albumImageSize": "Album image size",
|
||||
"autoFitColumns": "Auto fit columns",
|
||||
"autosize": "Autosize",
|
||||
|
||||
@@ -2,9 +2,22 @@
|
||||
display: flex;
|
||||
gap: var(--theme-spacing-xs);
|
||||
align-items: center;
|
||||
min-height: 22px;
|
||||
min-height: calc(1.875rem * var(--mantine-scale, 1));
|
||||
}
|
||||
|
||||
.hidden {
|
||||
visibility: hidden;
|
||||
.favorite {
|
||||
width: auto !important;
|
||||
min-width: 0 !important;
|
||||
height: calc(1.875rem * var(--mantine-scale, 1)) !important;
|
||||
min-height: calc(1.875rem * var(--mantine-scale, 1)) !important;
|
||||
padding-inline: var(--theme-spacing-xs);
|
||||
}
|
||||
|
||||
.rating {
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: calc(1.875rem * var(--mantine-scale, 1));
|
||||
padding-block: var(--theme-spacing-xs);
|
||||
padding-inline: var(--theme-spacing-xs) !important;
|
||||
}
|
||||
|
||||
@@ -29,17 +29,11 @@ const useAlbumGroupAlbum = (albumId: string | undefined, serverId: string | unde
|
||||
|
||||
interface AlbumGroupControlsProps {
|
||||
albumId: string | undefined;
|
||||
isGroupHovered: boolean;
|
||||
serverId: string | undefined;
|
||||
serverType: ServerType | undefined;
|
||||
}
|
||||
|
||||
export const AlbumGroupControls = ({
|
||||
albumId,
|
||||
isGroupHovered,
|
||||
serverId,
|
||||
serverType,
|
||||
}: AlbumGroupControlsProps) => {
|
||||
export const AlbumGroupControls = ({ albumId, serverId, serverType }: AlbumGroupControlsProps) => {
|
||||
const showRatingsSetting = useShowRatings();
|
||||
const detailQuery = useAlbumGroupAlbum(albumId, serverId);
|
||||
const setFavorite = useSetFavorite();
|
||||
@@ -84,13 +78,13 @@ export const AlbumGroupControls = ({
|
||||
return (
|
||||
<div className={styles.controls}>
|
||||
<ActionIcon
|
||||
className={album.userFavorite || isGroupHovered ? undefined : styles.hidden}
|
||||
className={styles.favorite}
|
||||
disabled={isMutatingFavorite}
|
||||
icon="favorite"
|
||||
iconProps={{
|
||||
color: album.userFavorite ? 'primary' : 'muted',
|
||||
fill: album.userFavorite ? 'primary' : undefined,
|
||||
size: 'md',
|
||||
size: 'xs',
|
||||
}}
|
||||
onClick={handleFavorite}
|
||||
onDoubleClick={(event) => {
|
||||
@@ -98,11 +92,11 @@ export const AlbumGroupControls = ({
|
||||
event.preventDefault();
|
||||
}}
|
||||
size="xs"
|
||||
variant="subtle"
|
||||
variant="transparent"
|
||||
/>
|
||||
{showRating && (
|
||||
<Rating
|
||||
className={album.userRating || isGroupHovered ? undefined : styles.hidden}
|
||||
className={styles.rating}
|
||||
onChange={handleRating}
|
||||
readOnly={isMutatingRating}
|
||||
size="xs"
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
padding: 0 var(--theme-spacing-xs);
|
||||
}
|
||||
|
||||
.container.vertical {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.image-container {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
@@ -50,8 +55,16 @@
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.info.enlarged-image {
|
||||
padding-top: var(--theme-spacing-xs);
|
||||
.container.vertical .image-container {
|
||||
align-self: center;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.container.vertical .info {
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.album-title {
|
||||
@@ -74,6 +87,6 @@
|
||||
|
||||
.controls-row {
|
||||
flex-shrink: 0;
|
||||
min-height: 22px;
|
||||
margin-top: var(--theme-spacing-xxs);
|
||||
min-height: calc(1.875rem * var(--mantine-scale, 1));
|
||||
margin-top: var(--theme-spacing-xs);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
useAlbumGroupImageSize,
|
||||
useAlbumGroupItems,
|
||||
useAlbumGroupShowFavoriteRating,
|
||||
useAlbumGroupVerticalLayout,
|
||||
usePlayButtonBehavior,
|
||||
} from '/@/renderer/store';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
@@ -54,7 +55,8 @@ export const AlbumGroupHeader = ({
|
||||
const { t } = useTranslation();
|
||||
const albumGroupItems = useAlbumGroupItems();
|
||||
const showFavoriteRating = useAlbumGroupShowFavoriteRating();
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
const isVerticalLayout = useAlbumGroupVerticalLayout();
|
||||
const [isImageHovered, setIsImageHovered] = useState(false);
|
||||
const [resolved, setResolved] = useState<null | { forInfoHeight: number; height: number }>(
|
||||
null,
|
||||
);
|
||||
@@ -80,10 +82,12 @@ export const AlbumGroupHeader = ({
|
||||
.filter((item) => item.content != null);
|
||||
}, [albumGroupItems, metadata, song, t]);
|
||||
|
||||
// The album group spans the combined row height, but when the image is
|
||||
// enlarged the group's last row is grown so the total reaches the img size.
|
||||
// Horizontal: info floor is max(image, row span) so metadata aligns with the image.
|
||||
// Vertical: no minHeight floor — row-span minHeight made scrollHeight report the full
|
||||
// track span (e.g. 15×40=600) instead of natural text height, then image+info overflowed
|
||||
// the reserved group height and made the virtualizer thrash at the scroll bottom.
|
||||
const infoHeight =
|
||||
groupRowCount !== undefined
|
||||
groupRowCount !== undefined && !isVerticalLayout
|
||||
? albumImageSize > 0
|
||||
? Math.max(albumImageSize, groupRowCount * rowHeight)
|
||||
: groupRowCount * rowHeight
|
||||
@@ -101,8 +105,6 @@ export const AlbumGroupHeader = ({
|
||||
? {
|
||||
aspectRatio: 'auto',
|
||||
height: `${albumImageSize}px`,
|
||||
paddingBottom: 'var(--theme-spacing-xs)',
|
||||
paddingTop: 'var(--theme-spacing-xs)',
|
||||
position: 'relative' as const,
|
||||
width: `${albumImageSize}px`,
|
||||
zIndex: 1,
|
||||
@@ -120,7 +122,12 @@ export const AlbumGroupHeader = ({
|
||||
const resolvedHeight = Math.max(infoHeight ?? 0, contentHeight);
|
||||
|
||||
if (infoHeight !== undefined) {
|
||||
setResolved({ forInfoHeight: infoHeight, height: resolvedHeight });
|
||||
setResolved((prev) => {
|
||||
if (prev?.forInfoHeight === infoHeight && prev.height === resolvedHeight) {
|
||||
return prev;
|
||||
}
|
||||
return { forInfoHeight: infoHeight, height: resolvedHeight };
|
||||
});
|
||||
}
|
||||
|
||||
// Only persist heights that exceed the image/row floor. Equal values
|
||||
@@ -145,18 +152,21 @@ export const AlbumGroupHeader = ({
|
||||
groupKey,
|
||||
groupRowCount,
|
||||
infoHeight,
|
||||
isVerticalLayout,
|
||||
metadataRows.length,
|
||||
setAlbumGroupContentHeight,
|
||||
showFavoriteRating,
|
||||
storedContentHeight,
|
||||
]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={styles.container}
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
>
|
||||
<div className={styles.imageContainer} style={imageContainerStyle}>
|
||||
<div className={clsx(styles.container, isVerticalLayout && styles.vertical)}>
|
||||
<div
|
||||
className={styles.imageContainer}
|
||||
onMouseEnter={() => setIsImageHovered(true)}
|
||||
onMouseLeave={() => setIsImageHovered(false)}
|
||||
style={imageContainerStyle}
|
||||
>
|
||||
<ItemImage
|
||||
className={imageColumnStyles.compactImage}
|
||||
enableDebounce
|
||||
@@ -166,7 +176,7 @@ export const AlbumGroupHeader = ({
|
||||
src={song?.imageUrl}
|
||||
type="table"
|
||||
/>
|
||||
{isHovered && onPlay && (
|
||||
{isImageHovered && onPlay && (
|
||||
<div className={imageColumnStyles.playButtonOverlay}>
|
||||
<PlayTooltip type={playButtonBehavior}>
|
||||
<PlayButton
|
||||
@@ -185,7 +195,7 @@ export const AlbumGroupHeader = ({
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className={clsx(styles.info, albumImageSize > 0 && styles.enlargedImage)}
|
||||
className={styles.info}
|
||||
ref={infoRef}
|
||||
style={{ minHeight: resolvedInfoHeight ?? infoHeight }}
|
||||
>
|
||||
@@ -213,7 +223,6 @@ export const AlbumGroupHeader = ({
|
||||
<div className={styles.controlsRow}>
|
||||
<AlbumGroupControls
|
||||
albumId={song?.albumId}
|
||||
isGroupHovered={isHovered}
|
||||
serverId={song?._serverId}
|
||||
serverType={song?._serverType}
|
||||
/>
|
||||
|
||||
@@ -391,22 +391,18 @@ const NonMutedColumns = [TableColumn.TITLE, TableColumn.TITLE_ARTIST, TableColum
|
||||
* 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;
|
||||
const CONTROLS_HEIGHT = 38;
|
||||
|
||||
return (
|
||||
PADDING_TOP +
|
||||
TITLE_LINE_HEIGHT * TITLE_MAX_LINES +
|
||||
Math.max(0, metadataRowCount) * METADATA_LINE_HEIGHT +
|
||||
(showControls ? CONTROLS_HEIGHT : 0)
|
||||
@@ -459,13 +455,23 @@ export function getAlbumGroupRowCount(
|
||||
return end - start + 1;
|
||||
}
|
||||
|
||||
export const ALBUM_GROUP_STACK_GAP = 12;
|
||||
|
||||
export function getAlbumGroupSpanHeight(
|
||||
groupRowCount: number,
|
||||
baseHeight: number,
|
||||
albumGroupImageSize: number,
|
||||
contentHeight = 0,
|
||||
options?: { isVertical?: boolean },
|
||||
): number {
|
||||
const rowSpanHeight = groupRowCount * baseHeight;
|
||||
const isVertical = options?.isVertical ?? false;
|
||||
|
||||
if (isVertical) {
|
||||
const imageSize = albumGroupImageSize > 0 ? albumGroupImageSize : 96;
|
||||
return Math.max(rowSpanHeight, imageSize + ALBUM_GROUP_STACK_GAP + contentHeight);
|
||||
}
|
||||
|
||||
const imageSpanHeight =
|
||||
albumGroupImageSize > 0 ? Math.max(albumGroupImageSize, rowSpanHeight) : rowSpanHeight;
|
||||
|
||||
@@ -565,9 +571,6 @@ function ClampedCell({
|
||||
// standard height and the reserved space below is left empty (uniform
|
||||
// background) for the overflowing album image.
|
||||
function getAlbumGroupClampHeight(props: ItemTableListInnerColumn): null | number {
|
||||
const albumImageSize = props.albumGroupImageSize ?? 0;
|
||||
|
||||
if (albumImageSize <= 0) return null;
|
||||
if (props.type === TableColumn.ALBUM_GROUP) return null;
|
||||
if (!isAlbumGroupingActive(props.columns)) return null;
|
||||
|
||||
@@ -583,6 +586,8 @@ function getAlbumGroupClampHeight(props: ItemTableListInnerColumn): null | numbe
|
||||
return null;
|
||||
}
|
||||
|
||||
const albumImageSize = props.albumGroupImageSize ?? 0;
|
||||
const isVertical = props.albumGroupVerticalLayout ?? false;
|
||||
const baseHeight = baseRowHeightForSize(props.size);
|
||||
const groupRowCount = getAlbumGroupRowCount(
|
||||
props.rowIndex,
|
||||
@@ -600,12 +605,18 @@ function getAlbumGroupClampHeight(props: ItemTableListInnerColumn): null | numbe
|
||||
const measuredContentHeight = groupHeightKey
|
||||
? props.albumGroupContentHeights?.get(groupHeightKey)
|
||||
: undefined;
|
||||
const contentHeight = measuredContentHeight ?? props.estimatedAlbumGroupContentHeight ?? 0;
|
||||
// Never reserve less than the estimate — early measure can miss the async
|
||||
// favorites/ratings row (AlbumGroupControls returns null until album loads).
|
||||
const contentHeight = Math.max(
|
||||
measuredContentHeight ?? 0,
|
||||
props.estimatedAlbumGroupContentHeight ?? 0,
|
||||
);
|
||||
const totalGroupHeight = getAlbumGroupSpanHeight(
|
||||
groupRowCount,
|
||||
baseHeight,
|
||||
albumImageSize,
|
||||
contentHeight,
|
||||
{ isVertical },
|
||||
);
|
||||
|
||||
// Only clamp when the row was actually grown to fit the image or wrapped text.
|
||||
|
||||
@@ -78,6 +78,7 @@ import {
|
||||
useAlbumGroupImageSize,
|
||||
useAlbumGroupItems,
|
||||
useAlbumGroupShowFavoriteRating,
|
||||
useAlbumGroupVerticalLayout,
|
||||
usePlayerStore,
|
||||
} from '/@/renderer/store';
|
||||
import { animationProps } from '/@/shared/components/animations/animation-props';
|
||||
@@ -235,6 +236,7 @@ const VirtualizedTableGrid = ({
|
||||
}: VirtualizedTableGridProps) => {
|
||||
const { enableHeader, enableRowHoverHighlight, getRowHeight, groups } = tableConfig;
|
||||
const albumGroupImageSize = useAlbumGroupImageSize();
|
||||
const albumGroupVerticalLayout = useAlbumGroupVerticalLayout();
|
||||
const hoverDelegateRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
useRowInteractionDelegate({
|
||||
@@ -396,6 +398,7 @@ const VirtualizedTableGrid = ({
|
||||
() => ({
|
||||
albumGroupContentHeights,
|
||||
albumGroupImageSize,
|
||||
albumGroupVerticalLayout,
|
||||
calculatedColumnWidths,
|
||||
cellPadding: tableConfig.cellPadding,
|
||||
columns: tableConfig.columns,
|
||||
@@ -435,6 +438,7 @@ const VirtualizedTableGrid = ({
|
||||
[
|
||||
albumGroupContentHeights,
|
||||
albumGroupImageSize,
|
||||
albumGroupVerticalLayout,
|
||||
calculatedColumnWidths,
|
||||
dataWithGroups,
|
||||
estimatedAlbumGroupContentHeight,
|
||||
@@ -746,8 +750,7 @@ const MemoizedVirtualizedTableGrid = memo(VirtualizedTableGrid, (prevProps, next
|
||||
nextProps.calculatedColumnWidths,
|
||||
) &&
|
||||
prevProps.albumGroupContentHeights === nextProps.albumGroupContentHeights &&
|
||||
prevProps.estimatedAlbumGroupContentHeight ===
|
||||
nextProps.estimatedAlbumGroupContentHeight &&
|
||||
prevProps.estimatedAlbumGroupContentHeight === nextProps.estimatedAlbumGroupContentHeight &&
|
||||
prevProps.setAlbumGroupContentHeight === nextProps.setAlbumGroupContentHeight &&
|
||||
prevProps.tableConfig === nextProps.tableConfig &&
|
||||
prevProps.data === nextProps.data &&
|
||||
@@ -788,7 +791,7 @@ export interface TableItemProps {
|
||||
adjustedRowIndexMap?: Map<number, number>;
|
||||
albumGroupContentHeights?: Map<string, number>;
|
||||
albumGroupImageSize?: number;
|
||||
estimatedAlbumGroupContentHeight?: number;
|
||||
albumGroupVerticalLayout?: boolean;
|
||||
calculatedColumnWidths?: number[];
|
||||
cellPadding?: ItemTableListProps['cellPadding'];
|
||||
columns: ItemTableListColumnConfig[];
|
||||
@@ -805,6 +808,7 @@ export interface TableItemProps {
|
||||
enableRowHoverHighlight?: ItemTableListProps['enableRowHoverHighlight'];
|
||||
enableSelection?: ItemTableListProps['enableSelection'];
|
||||
enableVerticalBorders?: ItemTableListProps['enableVerticalBorders'];
|
||||
estimatedAlbumGroupContentHeight?: number;
|
||||
getAdjustedRowIndex?: (rowIndex: number) => number;
|
||||
getGroupRenderData?: () => unknown[];
|
||||
getRowHeight: (index: number, cellProps: TableItemProps) => number;
|
||||
@@ -1312,6 +1316,7 @@ const BaseItemTableList = ({
|
||||
const albumGroupImageSize = useAlbumGroupImageSize();
|
||||
const albumGroupItems = useAlbumGroupItems();
|
||||
const albumGroupShowFavoriteRating = useAlbumGroupShowFavoriteRating();
|
||||
const albumGroupVerticalLayout = useAlbumGroupVerticalLayout();
|
||||
const albumGroupMetadataRowCount = useMemo(
|
||||
() => albumGroupItems.filter((item) => !item.disabled).length,
|
||||
[albumGroupItems],
|
||||
@@ -1319,11 +1324,10 @@ const BaseItemTableList = ({
|
||||
const estimatedAlbumGroupContentHeight = useMemo(
|
||||
() =>
|
||||
estimateAlbumGroupContentHeight({
|
||||
hasEnlargedImage: (albumGroupImageSize || 96) > 0,
|
||||
metadataRowCount: albumGroupMetadataRowCount,
|
||||
showControls: albumGroupShowFavoriteRating,
|
||||
}),
|
||||
[albumGroupImageSize, albumGroupMetadataRowCount, albumGroupShowFavoriteRating],
|
||||
[albumGroupMetadataRowCount, albumGroupShowFavoriteRating],
|
||||
);
|
||||
const baseItemCount = itemCount ?? data.length;
|
||||
const [albumGroupContentHeights, setAlbumGroupContentHeights] = useState(
|
||||
@@ -1341,7 +1345,7 @@ const BaseItemTableList = ({
|
||||
|
||||
useEffect(() => {
|
||||
setAlbumGroupContentHeights(new Map());
|
||||
}, [baseItemCount]);
|
||||
}, [albumGroupShowFavoriteRating, albumGroupVerticalLayout, baseItemCount]);
|
||||
|
||||
const totalItemCount = enableHeader ? baseItemCount + 1 : baseItemCount;
|
||||
const [centerContainerWidth, setCenterContainerWidth] = useState(0);
|
||||
@@ -1496,12 +1500,16 @@ const BaseItemTableList = ({
|
||||
: 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 contentHeight = Math.max(
|
||||
measuredContentHeight ?? 0,
|
||||
estimatedAlbumGroupContentHeight,
|
||||
);
|
||||
const totalGroupHeight = getAlbumGroupSpanHeight(
|
||||
groupRowCount,
|
||||
baseHeight,
|
||||
albumGroupImageSize,
|
||||
contentHeight,
|
||||
{ isVertical: albumGroupVerticalLayout },
|
||||
);
|
||||
const lastRowHeight = totalGroupHeight - (groupRowCount - 1) * baseHeight;
|
||||
if (lastRowHeight > baseHeight) {
|
||||
@@ -1514,6 +1522,7 @@ const BaseItemTableList = ({
|
||||
},
|
||||
[
|
||||
albumGroupImageSize,
|
||||
albumGroupVerticalLayout,
|
||||
enableHeader,
|
||||
estimatedAlbumGroupContentHeight,
|
||||
headerHeight,
|
||||
@@ -1527,6 +1536,7 @@ const BaseItemTableList = ({
|
||||
() => ({
|
||||
albumGroupContentHeights,
|
||||
albumGroupImageSize,
|
||||
albumGroupVerticalLayout,
|
||||
cellPadding,
|
||||
columns: parsedColumns,
|
||||
controls: {} as ItemControls,
|
||||
@@ -1562,6 +1572,7 @@ const BaseItemTableList = ({
|
||||
[
|
||||
albumGroupContentHeights,
|
||||
albumGroupImageSize,
|
||||
albumGroupVerticalLayout,
|
||||
cellPadding,
|
||||
dataWithGroups,
|
||||
enableAlternateRowColors,
|
||||
|
||||
@@ -78,6 +78,9 @@ export const TableConfig = ({
|
||||
const albumGroupShowFavoriteRating = useSettingsStore(
|
||||
(state) => state.general.albumGroupShowFavoriteRating,
|
||||
);
|
||||
const albumGroupVerticalLayout = useSettingsStore(
|
||||
(state) => state.general.albumGroupVerticalLayout,
|
||||
);
|
||||
const imageResTable = useSettingsStore((state) => state.general.imageRes.table);
|
||||
const { setList, setSettings } = useSettingsStoreActions();
|
||||
const [albumGroupOpen, setAlbumGroupOpen] = useState(false);
|
||||
@@ -185,6 +188,26 @@ export const TableConfig = ({
|
||||
</Text>
|
||||
),
|
||||
},
|
||||
{
|
||||
component: (
|
||||
<ListConfigBooleanControl
|
||||
onChange={(value) =>
|
||||
setSettings({
|
||||
general: {
|
||||
albumGroupVerticalLayout: value,
|
||||
},
|
||||
})
|
||||
}
|
||||
value={albumGroupVerticalLayout}
|
||||
/>
|
||||
),
|
||||
id: 'albumGroupVerticalLayout',
|
||||
label: (
|
||||
<Text fw={500} pl="md" size="sm">
|
||||
{t('table.config.general.albumGroupVerticalLayout')}
|
||||
</Text>
|
||||
),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
]
|
||||
@@ -367,6 +390,7 @@ export const TableConfig = ({
|
||||
albumGroupOpen,
|
||||
albumGroupImageSize,
|
||||
albumGroupShowFavoriteRating,
|
||||
albumGroupVerticalLayout,
|
||||
imageResTable,
|
||||
setSettings,
|
||||
]);
|
||||
|
||||
@@ -488,6 +488,7 @@ export const GeneralSettingsSchema = z.object({
|
||||
albumGroupImageSize: z.number(),
|
||||
albumGroupItems: z.array(SortableItemSchema(AlbumGroupItemSchema)),
|
||||
albumGroupShowFavoriteRating: z.boolean(),
|
||||
albumGroupVerticalLayout: z.boolean(),
|
||||
artistBackground: z.boolean(),
|
||||
artistBackgroundBlur: z.number(),
|
||||
artistItems: z.array(SortableItemSchema(ArtistItemSchema)),
|
||||
@@ -1211,6 +1212,7 @@ const initialState: SettingsState = {
|
||||
albumGroupImageSize: 0,
|
||||
albumGroupItems,
|
||||
albumGroupShowFavoriteRating: true,
|
||||
albumGroupVerticalLayout: true,
|
||||
artistBackground: true,
|
||||
artistBackgroundBlur: 3,
|
||||
artistItems,
|
||||
@@ -2727,6 +2729,9 @@ export const useAlbumGroupImageSize = () =>
|
||||
export const useAlbumGroupShowFavoriteRating = () =>
|
||||
useSettingsStore((state) => state.general.albumGroupShowFavoriteRating);
|
||||
|
||||
export const useAlbumGroupVerticalLayout = () =>
|
||||
useSettingsStore((state) => state.general.albumGroupVerticalLayout);
|
||||
|
||||
export const useVolumeWidth = () => useSettingsStore((state) => state.general.volumeWidth, shallow);
|
||||
|
||||
export const useFollowCurrentSong = () =>
|
||||
|
||||
Reference in New Issue
Block a user