From 383ffc92f05c833fa86945580b091dfe6e9c0443 Mon Sep 17 00:00:00 2001 From: mtvpls Date: Sat, 27 Dec 2025 18:10:43 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BE=8E=E5=8C=96=E7=BB=A7=E7=BB=AD=E8=A7=82?= =?UTF-8?q?=E7=9C=8B=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ContinueWatching.tsx | 17 +- src/components/FavoritesPanel.tsx | 15 +- src/components/ScrollableRow.tsx | 2 +- src/components/VideoCard.tsx | 430 ++++++++++++++++++++-------- 4 files changed, 335 insertions(+), 129 deletions(-) diff --git a/src/components/ContinueWatching.tsx b/src/components/ContinueWatching.tsx index 3bd4296..4b23c4b 100644 --- a/src/components/ContinueWatching.tsx +++ b/src/components/ContinueWatching.tsx @@ -10,8 +10,8 @@ import { subscribeToDataUpdates, } from '@/lib/db.client'; -import ScrollableRow from '@/components/ScrollableRow'; import VideoCard from '@/components/VideoCard'; +import ScrollableRow from '@/components/ScrollableRow'; interface ContinueWatchingProps { className?: string; @@ -106,16 +106,16 @@ export default function ContinueWatching({ className }: ContinueWatchingProps) { {loading ? // 加载状态显示灰色占位数据 - Array.from({ length: 6 }).map((_, index) => ( + Array.from({ length: 8 }).map((_, index) => (
-
+
-
-
+
+
)) : // 显示真实数据 @@ -124,7 +124,7 @@ export default function ContinueWatching({ className }: ContinueWatchingProps) { return (
1 ? 'tv' : ''} origin={record.origin} + orientation='horizontal' + playTime={record.play_time} + totalTime={record.total_time} />
); diff --git a/src/components/FavoritesPanel.tsx b/src/components/FavoritesPanel.tsx index 467980d..318fda8 100644 --- a/src/components/FavoritesPanel.tsx +++ b/src/components/FavoritesPanel.tsx @@ -23,7 +23,7 @@ interface FavoriteItem { source_name?: string; currentEpisode?: number; search_title?: string; - origin?: string; + origin?: 'vod' | 'live'; } interface FavoritesPanelProps { @@ -97,14 +97,13 @@ export const FavoritesPanel: React.FC = ({ // 监听收藏变化,实时移除已取消收藏的项目 useEffect(() => { - const unsubscribe = subscribeToDataUpdates(async (event) => { - if (event === 'favoritesUpdated' && isOpen) { - // 获取最新的收藏列表 - const allFavorites = await getAllFavorites(); - const currentKeys = Object.keys(allFavorites); - + const unsubscribe = subscribeToDataUpdates('favoritesUpdated', async (newFavorites: Record) => { + if (isOpen) { + // 获取最新的收藏列表的键 + const currentKeys = Object.keys(newFavorites); + // 过滤掉已经不在收藏中的项目 - setFavoriteItems((prevItems) => + setFavoriteItems((prevItems) => prevItems.filter((item) => { const key = `${item.source}+${item.id}`; return currentKeys.includes(key); diff --git a/src/components/ScrollableRow.tsx b/src/components/ScrollableRow.tsx index 4056cc6..6309a24 100644 --- a/src/components/ScrollableRow.tsx +++ b/src/components/ScrollableRow.tsx @@ -104,7 +104,7 @@ export default function ScrollableRow({ >
{children} diff --git a/src/components/VideoCard.tsx b/src/components/VideoCard.tsx index 12aa34b..e580d96 100644 --- a/src/components/VideoCard.tsx +++ b/src/components/VideoCard.tsx @@ -51,6 +51,9 @@ export interface VideoCardProps { isUpcoming?: boolean; // 是否为即将上映 seasonNumber?: number; // 季度编号 seasonName?: string; // 季度名称 + orientation?: 'vertical' | 'horizontal'; // 卡片方向 + playTime?: number; // 当前播放时间(秒) + totalTime?: number; // 总时长(秒) } export type VideoCardHandle = { @@ -84,6 +87,9 @@ const VideoCard = forwardRef(function VideoCard isUpcoming = false, seasonNumber, seasonName, + orientation = 'vertical', + playTime, + totalTime, }: VideoCardProps, ref ) { @@ -584,7 +590,11 @@ const VideoCard = forwardRef(function VideoCard > {/* 海报容器 */}
(function VideoCard }} > {/* 骨架屏 */} - {!isLoading && } + {!isLoading && } {/* 图片 */} {actualTitle} setIsLoading(true)} @@ -816,7 +826,7 @@ const VideoCard = forwardRef(function VideoCard
)} - {actualEpisodes && actualEpisodes > 1 && ( + {actualEpisodes && actualEpisodes > 1 && orientation === 'vertical' && (
(function VideoCard
); })()} -
- {/* 进度条 */} - {config.showProgress && progress !== undefined && ( -
{ - e.preventDefault(); - return false; - }} - > -
{ - e.preventDefault(); - return false; - }} - /> -
- )} - - {/* 标题与来源 */} -
{ - e.preventDefault(); - return false; - }} - > -
- { - e.preventDefault(); - return false; - }} - > - {actualTitle} - - {/* 自定义 tooltip */} -
{ - e.preventDefault(); - return false; - }} - > - {actualTitle} + {/* 横向模式:标题和进度条在海报上 */} + {orientation === 'horizontal' && ( + <> + {/* 顶部渐变遮罩 - 用于标题背景 */}
-
-
- {config.showSourceName && source_name && ( - { - e.preventDefault(); - return false; - }} - > - (function VideoCard return false; }} > - {origin === 'live' && ( - + {/* 标题 */} +
+ { + e.preventDefault(); + return false; + }} + title={actualTitle} + > + {actualTitle} + +
+ + {/* 集数信息 - 只有超过1集时才显示 */} + {currentEpisode && actualEpisodes && actualEpisodes > 1 && ( +
{ + e.preventDefault(); + return false; + }} + > + 第{currentEpisode}集 · 共{actualEpisodes}集 +
)} - {source_name} -
-
+
+ + {/* 底部渐变遮罩 - 用于进度条背景 */} +
{ + e.preventDefault(); + return false; + }} + > + {/* 进度条 */} + {config.showProgress && progress !== undefined && origin !== 'live' && ( +
+ {/* 来源和时长显示 - 在进度条上方 */} +
+ {/* 时长显示 - 左侧 */} + {from === 'playrecord' && playTime !== undefined && totalTime !== undefined && ( +
{ + e.preventDefault(); + return false; + }} + > + {(() => { + const formatTime = (seconds: number) => { + const mins = Math.floor(seconds / 60); + const secs = Math.floor(seconds % 60); + // 0分钟时不显示分钟 + if (mins === 0) { + return `${secs}秒`; + } + return `${mins}分${secs}秒`; + }; + return formatTime(playTime); + })()} +
+ )} + + {/* 来源 - 右侧 */} + {config.showSourceName && source_name && ( + { + e.preventDefault(); + return false; + }} + > + {source_name} + + )} +
+
{ + e.preventDefault(); + return false; + }} + > +
{ + e.preventDefault(); + return false; + }} + /> +
+
+ )} + + {/* 直播时只显示来源 */} + {origin === 'live' && config.showSourceName && source_name && ( +
+ { + e.preventDefault(); + return false; + }} + > + + {source_name} + +
+ )} +
+ )}
+ + {/* 竖向模式:进度条和标题在海报下方 */} + {orientation === 'vertical' && ( + <> + {/* 进度条 */} + {config.showProgress && progress !== undefined && ( +
{ + e.preventDefault(); + return false; + }} + > +
{ + e.preventDefault(); + return false; + }} + /> +
+ )} + + {/* 标题与来源 */} +
{ + e.preventDefault(); + return false; + }} + > +
+ { + e.preventDefault(); + return false; + }} + > + {actualTitle} + + {/* 自定义 tooltip */} +
{ + e.preventDefault(); + return false; + }} + > + {actualTitle} +
+
+
+ {config.showSourceName && source_name && ( + { + e.preventDefault(); + return false; + }} + > + { + e.preventDefault(); + return false; + }} + > + {origin === 'live' && ( + + )} + {source_name} + + + )} +
+ + )}
{/* 操作菜单 - 支持右键和长按触发 */}