mirror of
https://github.com/KuekHaoYang/KVideo.git
synced 2026-08-12 23:33:43 +08:00
fix: polish favorites page implementation
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useRef, useCallback, useEffect, memo } from 'react';
|
||||
import { useState, useRef, useCallback, useEffect, useMemo, memo } from 'react';
|
||||
import { VideoCard } from '@/components/search/VideoCard';
|
||||
import { FavoritesEmptyState } from './FavoritesEmptyState';
|
||||
import type { FavoriteItem, Video } from '@/lib/types';
|
||||
@@ -20,16 +20,20 @@ export const FavoritesGrid = memo(function FavoritesGrid({
|
||||
const observerRef = useRef<IntersectionObserver | null>(null);
|
||||
|
||||
// Convert FavoriteItem to Video format
|
||||
const videos: Video[] = favorites.map((favorite) => ({
|
||||
vod_id: favorite.videoId,
|
||||
vod_name: favorite.title,
|
||||
vod_pic: favorite.poster,
|
||||
vod_remarks: favorite.remarks,
|
||||
vod_year: favorite.year,
|
||||
type_name: favorite.type,
|
||||
source: favorite.source,
|
||||
sourceName: favorite.sourceName,
|
||||
}));
|
||||
const videos: Video[] = useMemo(
|
||||
() =>
|
||||
favorites.map((favorite) => ({
|
||||
vod_id: favorite.videoId,
|
||||
vod_name: favorite.title,
|
||||
vod_pic: favorite.poster,
|
||||
vod_remarks: favorite.remarks,
|
||||
vod_year: favorite.year,
|
||||
type_name: favorite.type,
|
||||
source: favorite.source,
|
||||
sourceName: favorite.sourceName,
|
||||
})),
|
||||
[favorites]
|
||||
);
|
||||
|
||||
// Setup intersection observer for infinite scroll
|
||||
useEffect(() => {
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
'use client';
|
||||
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { Navbar } from '@/components/layout/Navbar';
|
||||
import { FavoritesPageHeader } from '@/components/favorites/FavoritesPageHeader';
|
||||
import { FavoritesGrid } from '@/components/favorites/FavoritesGrid';
|
||||
import { FavoritesSidebar } from '@/components/favorites/FavoritesSidebar';
|
||||
import { WatchHistorySidebar } from '@/components/history/WatchHistorySidebar';
|
||||
import { ConfirmDialog } from '@/components/ui/ConfirmDialog';
|
||||
import { useFavorites } from '@/lib/store/favorites-store';
|
||||
|
||||
interface FavoritesPageContentProps {
|
||||
isPremium?: boolean;
|
||||
}
|
||||
|
||||
export function FavoritesPageContent({
|
||||
isPremium = false,
|
||||
}: FavoritesPageContentProps) {
|
||||
const router = useRouter();
|
||||
const { favorites, clearFavorites } = useFavorites(isPremium);
|
||||
const [sortBy, setSortBy] = useState<'date' | 'title'>('date');
|
||||
const [isClearDialogOpen, setIsClearDialogOpen] = useState(false);
|
||||
|
||||
const sortedFavorites = useMemo(() => {
|
||||
if (sortBy === 'title') {
|
||||
return [...favorites].sort((a, b) => a.title.localeCompare(b.title, 'zh-CN'));
|
||||
}
|
||||
|
||||
return favorites;
|
||||
}, [favorites, sortBy]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
isPremium
|
||||
? 'min-h-screen bg-black'
|
||||
: 'min-h-screen bg-[var(--bg-color)] bg-[image:var(--bg-image)] bg-fixed'
|
||||
}
|
||||
>
|
||||
<Navbar
|
||||
onReset={() => router.push(isPremium ? '/premium' : '/')}
|
||||
isPremiumMode={isPremium}
|
||||
/>
|
||||
|
||||
<main className="max-w-7xl mx-auto px-4 py-8 space-y-8">
|
||||
<FavoritesPageHeader
|
||||
count={favorites.length}
|
||||
sortBy={sortBy}
|
||||
onSortChange={setSortBy}
|
||||
onClearAll={() => setIsClearDialogOpen(true)}
|
||||
/>
|
||||
|
||||
<FavoritesGrid favorites={sortedFavorites} isPremium={isPremium} />
|
||||
</main>
|
||||
|
||||
<FavoritesSidebar isPremium={isPremium} />
|
||||
<WatchHistorySidebar isPremium={isPremium} />
|
||||
|
||||
<ConfirmDialog
|
||||
isOpen={isClearDialogOpen}
|
||||
title="清空收藏"
|
||||
message="确定要清空所有收藏吗?此操作不可撤销。"
|
||||
confirmText="清空"
|
||||
cancelText="取消"
|
||||
onConfirm={() => {
|
||||
clearFavorites();
|
||||
setIsClearDialogOpen(false);
|
||||
}}
|
||||
onCancel={() => setIsClearDialogOpen(false)}
|
||||
dangerous
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface FavoritesPageFallbackProps {
|
||||
isPremium?: boolean;
|
||||
}
|
||||
|
||||
export function FavoritesPageFallback({
|
||||
isPremium = false,
|
||||
}: FavoritesPageFallbackProps) {
|
||||
return (
|
||||
<div
|
||||
className={`min-h-screen flex items-center justify-center${
|
||||
isPremium ? ' bg-black' : ''
|
||||
}`}
|
||||
>
|
||||
<div className="animate-spin rounded-full h-16 w-16 border-4 border-[var(--accent-color)] border-t-transparent" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -73,7 +73,7 @@ export function FavoritesPageHeader({
|
||||
onClick={onClearAll}
|
||||
className="px-4 py-2 rounded-[var(--radius-full)] bg-[var(--glass-bg)] border border-[var(--glass-border)] text-[var(--text-color)] hover:bg-[color-mix(in_srgb,var(--accent-color)_10%,transparent)] transition-all text-sm flex items-center gap-2"
|
||||
>
|
||||
<Icons.Trash2 size={16} />
|
||||
<Icons.Trash size={16} />
|
||||
清空收藏
|
||||
</button>
|
||||
)}
|
||||
|
||||
@@ -109,6 +109,7 @@ export function Navbar({ onReset, isPremiumMode = false }: NavbarProps) {
|
||||
href={favoritesHref}
|
||||
className="w-8 h-8 sm:w-10 sm:h-10 flex items-center justify-center rounded-[var(--radius-full)] bg-[var(--glass-bg)] border border-[var(--glass-border)] text-[var(--text-color)] hover:bg-[color-mix(in_srgb,var(--accent-color)_10%,transparent)] transition-all duration-200 cursor-pointer"
|
||||
aria-label="我的收藏"
|
||||
data-focusable
|
||||
>
|
||||
<Icons.Heart size={20} />
|
||||
</Link>
|
||||
|
||||
Reference in New Issue
Block a user