From e8ea0da25ccdd8892747ac3f6a4fa0200baeb62e Mon Sep 17 00:00:00 2001 From: shinya Date: Tue, 19 Aug 2025 00:13:35 +0800 Subject: [PATCH] feat: right click menu --- src/components/VideoCard.tsx | 367 ++++++++++++++++++++++++++++++----- 1 file changed, 322 insertions(+), 45 deletions(-) diff --git a/src/components/VideoCard.tsx b/src/components/VideoCard.tsx index 3cf4f87..3038b63 100644 --- a/src/components/VideoCard.tsx +++ b/src/components/VideoCard.tsx @@ -459,9 +459,18 @@ const VideoCard = forwardRef(function VideoCard pointerEvents: 'auto', } as React.CSSProperties} onContextMenu={(e) => { - // 阻止右键菜单和长按上下文菜单 + // 阻止默认右键菜单 e.preventDefault(); e.stopPropagation(); + + // 右键弹出操作菜单 + setShowMobileActions(true); + + // 异步检查收藏状态,不阻塞菜单显示 + if (from === 'search' && !isAggregate && actualSource && actualId && searchFavorited === null) { + checkSearchFavoriteStatus(); + } + return false; }} @@ -472,7 +481,18 @@ const VideoCard = forwardRef(function VideoCard }} > {/* 海报容器 */} -
+
{ + e.preventDefault(); + return false; + }} + > {/* 骨架屏 */} {!isLoading && } {/* 图片 */} @@ -512,16 +532,47 @@ const VideoCard = forwardRef(function VideoCard /> {/* 悬浮遮罩 */} -
+
{ + e.preventDefault(); + return false; + }} + /> {/* 播放按钮 - Touch设备隐藏,非Touch设备显示 */} {config.showPlayButton && !isTouch && ( -
+
{ + e.preventDefault(); + return false; + }} + > { + e.preventDefault(); + return false; + }} />
)} @@ -530,12 +581,32 @@ const VideoCard = forwardRef(function VideoCard {/* 操作按钮 - Touch设备隐藏,非Touch设备显示 */} {(config.showHeart || config.showCheckCircle) && !isTouch && ( -
+
{ + e.preventDefault(); + return false; + }} + > {config.showCheckCircle && ( { + e.preventDefault(); + return false; + }} /> )} {config.showHeart && ( @@ -546,6 +617,15 @@ const VideoCard = forwardRef(function VideoCard ? 'fill-red-600 stroke-red-600' : 'fill-transparent stroke-white hover:stroke-red-400' } hover:scale-[1.1]`} + style={{ + WebkitUserSelect: 'none', + userSelect: 'none', + WebkitTouchCallout: 'none', + } as React.CSSProperties} + onContextMenu={(e) => { + e.preventDefault(); + return false; + }} /> )}
@@ -553,23 +633,56 @@ const VideoCard = forwardRef(function VideoCard {/* 年份徽章 */} {config.showYear && actualYear && actualYear !== 'unknown' && actualYear.trim() !== '' && ( -
+
{ + e.preventDefault(); + return false; + }} + > {actualYear}
)} {/* 徽章 */} {config.showRating && rate && ( -
+
{ + e.preventDefault(); + return false; + }} + > {rate}
)} {actualEpisodes && actualEpisodes > 1 && ( -
+
{ + e.preventDefault(); + return false; + }} + > {currentEpisode ? `${currentEpisode}/${actualEpisodes}` : actualEpisodes} @@ -588,9 +701,37 @@ const VideoCard = forwardRef(function VideoCard rel='noopener noreferrer' onClick={(e) => e.stopPropagation()} className='absolute top-2 left-2 opacity-0 -translate-x-2 transition-all duration-300 ease-in-out delay-100 group-hover:opacity-100 group-hover:translate-x-0' + style={{ + WebkitUserSelect: 'none', + userSelect: 'none', + WebkitTouchCallout: 'none', + } as React.CSSProperties} + onContextMenu={(e) => { + e.preventDefault(); + return false; + }} > -
- +
{ + e.preventDefault(); + return false; + }} + > +
)} @@ -601,9 +742,38 @@ const VideoCard = forwardRef(function VideoCard const sourceCount = uniqueSources.length; return ( -
-
-
+
{ + e.preventDefault(); + return false; + }} + > +
+
{ + e.preventDefault(); + return false; + }} + > {sourceCount}
@@ -628,8 +798,30 @@ const VideoCard = forwardRef(function VideoCard const remainingCount = sortedSources.length - maxDisplayCount; return ( -
-
+
{ + e.preventDefault(); + return false; + }} + > +
{ + e.preventDefault(); + return false; + }} + > {/* 单列布局 */}
{displaySources.map((sourceName, index) => ( @@ -665,29 +857,118 @@ const VideoCard = forwardRef(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} -
+
{config.showSourceName && source_name && ( - - + { + e.preventDefault(); + return false; + }} + > + { + e.preventDefault(); + return false; + }} + > {source_name} @@ -695,23 +976,19 @@ const VideoCard = forwardRef(function VideoCard
- {/* 移动端操作菜单 */} - {isMobile && ( - setShowMobileActions(false)} - title={actualTitle} - poster={processImageUrl(actualPoster)} - actions={mobileActions} - sources={isAggregate && dynamicSourceNames ? Array.from(new Set(dynamicSourceNames)) : undefined} - isAggregate={isAggregate} - sourceName={source_name} - currentEpisode={currentEpisode} - totalEpisodes={actualEpisodes} - /> - )} - - + {/* 操作菜单 - 支持右键和长按触发 */} + setShowMobileActions(false)} + title={actualTitle} + poster={processImageUrl(actualPoster)} + actions={mobileActions} + sources={isAggregate && dynamicSourceNames ? Array.from(new Set(dynamicSourceNames)) : undefined} + isAggregate={isAggregate} + sourceName={source_name} + currentEpisode={currentEpisode} + totalEpisodes={actualEpisodes} + /> ); }