redesign feature carousel

This commit is contained in:
jeffvli
2025-11-22 13:22:02 -08:00
parent e80fc1a513
commit 6a0b36cfa6
6 changed files with 612 additions and 230 deletions
@@ -1,4 +1,4 @@
import { useQuery } from '@tanstack/react-query';
import { useSuspenseQuery } from '@tanstack/react-query';
import { Suspense, useMemo, useRef } from 'react';
import { useTranslation } from 'react-i18next';
@@ -28,12 +28,12 @@ const HomeRoute = () => {
const isJellyfin = server?.type === ServerType.JELLYFIN;
const feature = useQuery(
albumQueries.list({
const feature = useSuspenseQuery({
...albumQueries.list({
options: {
enabled: homeFeature,
gcTime: 1000 * 60,
staleTime: 1000 * 60,
gcTime: 1000 * 30,
staleTime: 1000 * 30,
},
query: {
limit: 20,
@@ -43,7 +43,8 @@ const HomeRoute = () => {
},
serverId: server?.id,
}),
);
queryKey: ['home', 'feature'],
});
const featureItemsWithImage = useMemo(() => {
return feature.data?.items?.filter((item) => item.imageUrl) ?? [];
@@ -124,17 +125,13 @@ const HomeRoute = () => {
{sortedCarousel.map((carousel) => {
if (carousel.itemType === LibraryItem.ALBUM) {
return (
<Suspense
fallback={<Spinner container />}
<AlbumInfiniteCarousel
key={`carousel-${carousel.uniqueId}`}
>
<AlbumInfiniteCarousel
rowCount={1}
sortBy={carousel.sortBy}
sortOrder={carousel.sortOrder}
title={carousel.title}
/>
</Suspense>
rowCount={1}
sortBy={carousel.sortBy}
sortOrder={carousel.sortOrder}
title={carousel.title}
/>
);
}
@@ -151,4 +148,12 @@ const HomeRoute = () => {
);
};
export default HomeRoute;
const SuspensedHomeRoute = () => {
return (
<Suspense fallback={<Spinner container />}>
<HomeRoute />
</Suspense>
);
};
export default SuspensedHomeRoute;
@@ -6,7 +6,28 @@
pointer-events: none;
user-select: none;
background-image: var(--theme-overlay-subheader);
opacity: 0.7;
}
.background-overlay {
--color-from: var(--background-base-min-contrast);
--color-to: transparent;
--dither: none;
--direction-and-possibly-color-interpolation: to bottom;
position: absolute;
z-index: -1;
width: 100%;
min-height: 200px;
pointer-events: none;
user-select: none;
background-color: var(--color-from);
background-image:
linear-gradient(
var(--direction-and-possibly-color-interpolation),
var(--color-from),
var(--color-to)
),
var(--dither);
}
.background-image {
@@ -1,28 +1,71 @@
import { generateColors } from '@mantine/colors-generator';
import clsx from 'clsx';
import { useEffect, useState } from 'react';
import styles from './library-background-overlay.module.css';
import { useAppThemeColors } from '/@/renderer/themes/use-app-theme';
interface LibraryBackgroundOverlayProps {
backgroundColor?: string;
headerRef: React.RefObject<HTMLDivElement | null>;
opacity?: number;
}
export const LibraryBackgroundOverlay = ({
backgroundColor,
headerRef,
opacity = 0.7,
}: LibraryBackgroundOverlayProps) => {
const height = useHeaderHeight(headerRef);
return (
<div
className={styles.overlay}
style={{
backgroundColor,
height: height ? `${height + 64}px` : undefined,
opacity,
}}
/>
);
};
interface BackgroundOverlayProps {
backgroundColor?: string;
direction?: string;
height?: number | string;
opacity?: number;
}
export const BackgroundOverlay = ({
backgroundColor,
direction = 'to bottom',
height = '100%',
opacity,
}: BackgroundOverlayProps) => {
const theme = useAppThemeColors();
const colors = generateColors(backgroundColor || theme.color['--theme-colors-background']);
return (
<div
className={clsx(styles.backgroundOverlay)}
style={
{
'--color-from': colors[6],
'--color-to': colors[9],
'--direction-and-possibly-color-interpolation': direction,
'--dither': 'none',
backgroundColor: backgroundColor,
height,
opacity,
} as React.CSSProperties
}
/>
);
};
interface LibraryBackgroundProps {
blur?: number;
headerRef: React.RefObject<HTMLDivElement | null>;