mirror of
https://github.com/KuekHaoYang/KVideo.git
synced 2026-08-12 23:33:43 +08:00
171 lines
5.3 KiB
TypeScript
171 lines
5.3 KiB
TypeScript
/**
|
|
* PopularFeatures - Main component for popular movies section
|
|
* Displays Douban movie recommendations with tag filtering and infinite scroll.
|
|
* Includes personalized "为你推荐" tag when user has 2+ watched items.
|
|
*/
|
|
|
|
'use client';
|
|
|
|
import { useState } from 'react';
|
|
import { TagManager } from './TagManager';
|
|
import { MovieGrid } from './MovieGrid';
|
|
import { useTagManager } from './hooks/useTagManager';
|
|
import { usePopularMovies } from './hooks/usePopularMovies';
|
|
import { usePersonalizedRecommendations } from './hooks/usePersonalizedRecommendations';
|
|
|
|
interface DoubanMovie {
|
|
id: string;
|
|
title: string;
|
|
cover: string;
|
|
rate: string;
|
|
url: string;
|
|
}
|
|
|
|
interface PopularFeaturesProps {
|
|
onSearch?: (query: string) => void;
|
|
}
|
|
|
|
export function PopularFeatures({ onSearch }: PopularFeaturesProps) {
|
|
const {
|
|
tags,
|
|
selectedTag,
|
|
contentType,
|
|
newTagInput,
|
|
showTagManager,
|
|
justAddedTag,
|
|
setContentType,
|
|
setSelectedTag,
|
|
setNewTagInput,
|
|
setShowTagManager,
|
|
setJustAddedTag,
|
|
handleAddTag,
|
|
handleDeleteTag,
|
|
handleRestoreDefaults,
|
|
handleDragEnd,
|
|
isLoadingTags,
|
|
} = useTagManager();
|
|
|
|
const {
|
|
movies: recommendMovies,
|
|
loading: recommendLoading,
|
|
hasMore: recommendHasMore,
|
|
hasHistory,
|
|
prefetchRef: recommendPrefetchRef,
|
|
loadMoreRef: recommendLoadMoreRef,
|
|
} = usePersonalizedRecommendations(false);
|
|
|
|
const [isRecommendSelected, setIsRecommendSelected] = useState(false);
|
|
|
|
const effectiveRecommendSelected = hasHistory && isRecommendSelected;
|
|
const isTagManagementMode = showTagManager;
|
|
|
|
const {
|
|
movies,
|
|
loading,
|
|
hasMore,
|
|
prefetchRef,
|
|
loadMoreRef,
|
|
} = usePopularMovies(
|
|
effectiveRecommendSelected ? '' : selectedTag,
|
|
tags,
|
|
contentType
|
|
);
|
|
|
|
const handleMovieClick = (movie: DoubanMovie) => {
|
|
if (onSearch) {
|
|
onSearch(movie.title);
|
|
}
|
|
};
|
|
|
|
const handleRecommendSelect = () => {
|
|
setIsRecommendSelected(true);
|
|
};
|
|
|
|
const handleRegularTagSelect = (tagId: string) => {
|
|
if (tagId === 'custom_高级' || tags.find(t => t.id === tagId)?.label === '高级') {
|
|
window.location.href = '/premium';
|
|
return;
|
|
}
|
|
setIsRecommendSelected(false);
|
|
setSelectedTag(tagId);
|
|
};
|
|
|
|
return (
|
|
<div className="animate-fade-in">
|
|
{/* Content Type Toggle (Capsule Liquid Glass - Fixed & Centered) */}
|
|
{!isTagManagementMode && !effectiveRecommendSelected && (
|
|
<div className="mb-10 flex justify-center">
|
|
<div className="relative w-80 p-1 bg-[var(--glass-bg)] border border-[var(--glass-border)] rounded-full grid grid-cols-2 backdrop-blur-2xl shadow-lg ring-1 ring-white/10 overflow-hidden">
|
|
{/* Sliding Indicator */}
|
|
<div
|
|
className="absolute top-1 bottom-1 w-[calc(50%-4px)] bg-[var(--accent-color)] rounded-full transition-transform duration-400 cubic-bezier(0.4, 0, 0.2, 1) shadow-[0_0_15px_rgba(0,122,255,0.4)]"
|
|
style={{
|
|
transform: `translateX(${contentType === 'movie' ? '4px' : 'calc(100% + 4px)'})`,
|
|
}}
|
|
/>
|
|
|
|
<button
|
|
onClick={() => setContentType('movie')}
|
|
className={`relative z-10 py-2.5 text-sm font-bold transition-colors duration-300 cursor-pointer flex justify-center items-center ${contentType === 'movie' ? 'text-white' : 'text-[var(--text-color-secondary)] hover:text-[var(--text-color)]'
|
|
}`}
|
|
>
|
|
电影
|
|
</button>
|
|
<button
|
|
onClick={() => setContentType('tv')}
|
|
className={`relative z-10 py-2.5 text-sm font-bold transition-colors duration-300 cursor-pointer flex justify-center items-center ${contentType === 'tv' ? 'text-white' : 'text-[var(--text-color-secondary)] hover:text-[var(--text-color)]'
|
|
}`}
|
|
>
|
|
电视剧
|
|
</button>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<TagManager
|
|
tags={tags}
|
|
selectedTag={effectiveRecommendSelected ? '' : selectedTag}
|
|
showTagManager={showTagManager}
|
|
newTagInput={newTagInput}
|
|
justAddedTag={justAddedTag}
|
|
onTagSelect={handleRegularTagSelect}
|
|
onTagDelete={handleDeleteTag}
|
|
onToggleManager={() => setShowTagManager(!showTagManager)}
|
|
onRestoreDefaults={handleRestoreDefaults}
|
|
onNewTagInputChange={setNewTagInput}
|
|
onAddTag={handleAddTag}
|
|
onDragEnd={handleDragEnd}
|
|
onJustAddedTagHandled={() => setJustAddedTag(false)}
|
|
isLoadingTags={isLoadingTags}
|
|
recommendTag={hasHistory ? {
|
|
label: '为你推荐',
|
|
isSelected: effectiveRecommendSelected,
|
|
onSelect: handleRecommendSelect,
|
|
} : undefined}
|
|
/>
|
|
|
|
{!isTagManagementMode && (
|
|
effectiveRecommendSelected ? (
|
|
<MovieGrid
|
|
movies={recommendMovies}
|
|
loading={recommendLoading}
|
|
hasMore={recommendHasMore}
|
|
onMovieClick={handleMovieClick}
|
|
prefetchRef={recommendPrefetchRef}
|
|
loadMoreRef={recommendLoadMoreRef}
|
|
/>
|
|
) : (
|
|
<MovieGrid
|
|
movies={movies}
|
|
loading={loading}
|
|
hasMore={hasMore}
|
|
onMovieClick={handleMovieClick}
|
|
prefetchRef={prefetchRef}
|
|
loadMoreRef={loadMoreRef}
|
|
/>
|
|
)
|
|
)}
|
|
</div>
|
|
);
|
|
}
|