mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-07 20:40:15 +02:00
revert to old feature carousel style (#1412)
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
import { useSuspenseInfiniteQuery } from '@tanstack/react-query';
|
||||
import { useEffect, useMemo, useRef } from 'react';
|
||||
|
||||
import { api } from '/@/renderer/api';
|
||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||
import { SingleFeatureCarousel } from '/@/renderer/components/feature-carousel/single-feature-carousel';
|
||||
import { useCurrentServerId } from '/@/renderer/store';
|
||||
import { Album, AlbumListResponse, AlbumListSort, SortOrder } from '/@/shared/types/domain-types';
|
||||
|
||||
interface InfiniteAlbumSingleFeatureCarouselProps {
|
||||
itemLimit?: number;
|
||||
}
|
||||
|
||||
export const AlbumInfiniteSingleFeatureCarousel = ({
|
||||
itemLimit = 20,
|
||||
}: InfiniteAlbumSingleFeatureCarouselProps) => {
|
||||
const serverId = useCurrentServerId();
|
||||
const loadMoreTriggeredRef = useRef(false);
|
||||
|
||||
const { data, fetchNextPage, hasNextPage, isFetchingNextPage } =
|
||||
useSuspenseInfiniteQuery<AlbumListResponse>({
|
||||
getNextPageParam: (lastPage, _allPages, lastPageParam) => {
|
||||
if (lastPage.items.length < itemLimit) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const nextPageParam = Number(lastPageParam) + itemLimit;
|
||||
|
||||
return String(nextPageParam);
|
||||
},
|
||||
initialPageParam: '0',
|
||||
queryFn: ({ pageParam, signal }) => {
|
||||
return api.controller.getAlbumList({
|
||||
apiClientProps: { serverId, signal },
|
||||
query: {
|
||||
limit: itemLimit,
|
||||
sortBy: AlbumListSort.RANDOM,
|
||||
sortOrder: SortOrder.DESC,
|
||||
startIndex: Number(pageParam),
|
||||
},
|
||||
});
|
||||
},
|
||||
queryKey: queryKeys.albums.infiniteList(serverId, {
|
||||
sortBy: AlbumListSort.RANDOM,
|
||||
sortOrder: SortOrder.DESC,
|
||||
}),
|
||||
});
|
||||
|
||||
// Flatten all pages and filter for albums with images
|
||||
const albumsWithImages = useMemo(() => {
|
||||
const allAlbums = data.pages.flatMap((page: AlbumListResponse) => page.items);
|
||||
// Filter for albums with images and remove duplicates by ID
|
||||
const uniqueAlbums = new Map<string, Album>();
|
||||
for (const album of allAlbums) {
|
||||
if (album.imageId && !uniqueAlbums.has(album.id)) {
|
||||
uniqueAlbums.set(album.id, album);
|
||||
}
|
||||
}
|
||||
return Array.from(uniqueAlbums.values());
|
||||
}, [data.pages]);
|
||||
|
||||
const handleNearEnd = () => {
|
||||
if (hasNextPage && !isFetchingNextPage && !loadMoreTriggeredRef.current) {
|
||||
loadMoreTriggeredRef.current = true;
|
||||
fetchNextPage().finally(() => {
|
||||
loadMoreTriggeredRef.current = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
albumsWithImages.length < itemLimit * 2 &&
|
||||
hasNextPage &&
|
||||
!isFetchingNextPage &&
|
||||
!loadMoreTriggeredRef.current
|
||||
) {
|
||||
loadMoreTriggeredRef.current = true;
|
||||
fetchNextPage().finally(() => {
|
||||
loadMoreTriggeredRef.current = false;
|
||||
});
|
||||
}
|
||||
}, [albumsWithImages.length, hasNextPage, isFetchingNextPage, fetchNextPage, itemLimit]);
|
||||
|
||||
if (albumsWithImages.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <SingleFeatureCarousel data={albumsWithImages} onNearEnd={handleNearEnd} />;
|
||||
};
|
||||
@@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { NativeScrollArea } from '/@/renderer/components/native-scroll-area/native-scroll-area';
|
||||
import { AlbumInfiniteCarousel } from '/@/renderer/features/albums/components/album-infinite-carousel';
|
||||
import { AlbumInfiniteFeatureCarousel } from '/@/renderer/features/home/components/album-infinite-feature-carousel';
|
||||
import { AlbumInfiniteSingleFeatureCarousel } from '/@/renderer/features/home/components/album-infinite-single-feature-carousel';
|
||||
import { FeaturedGenres } from '/@/renderer/features/home/components/featured-genres';
|
||||
import { AnimatedPage } from '/@/renderer/features/shared/components/animated-page';
|
||||
import { LibraryContainer } from '/@/renderer/features/shared/components/library-container';
|
||||
@@ -113,7 +114,7 @@ const HomeRoute = () => {
|
||||
pt={windowBarStyle === Platform.WEB ? '5rem' : '3rem'}
|
||||
px="2rem"
|
||||
>
|
||||
{homeFeature && <AlbumInfiniteFeatureCarousel />}
|
||||
{homeFeature && <AlbumInfiniteSingleFeatureCarousel />}
|
||||
{sortedItems.map((item) => {
|
||||
if (item.id === HomeItem.GENRES) {
|
||||
return <FeaturedGenres key="featured-genres" />;
|
||||
|
||||
@@ -180,7 +180,7 @@ export const LibraryHeader = forwardRef(
|
||||
},
|
||||
);
|
||||
|
||||
const isAsianCharacter = (char: string): boolean => {
|
||||
export const isAsianCharacter = (char: string): boolean => {
|
||||
const codePoint = char.codePointAt(0);
|
||||
|
||||
if (!codePoint) return false;
|
||||
@@ -207,7 +207,7 @@ const isAsianCharacter = (char: string): boolean => {
|
||||
return false;
|
||||
};
|
||||
|
||||
const calculateWeightedLength = (str: string): number => {
|
||||
export const calculateWeightedLength = (str: string): number => {
|
||||
let length = 0;
|
||||
for (const char of str) {
|
||||
length += isAsianCharacter(char) ? 2.5 : 1;
|
||||
@@ -215,7 +215,7 @@ const calculateWeightedLength = (str: string): number => {
|
||||
return length;
|
||||
};
|
||||
|
||||
const calculateTitleSize = (title: string) => {
|
||||
export const calculateTitleSize = (title: string) => {
|
||||
const titleLength = calculateWeightedLength(title);
|
||||
let baseSize = '3dvw';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user