提升播放页带背景图下选集面板的对比度
This commit is contained in:
@@ -9666,6 +9666,7 @@ function PlayPageClient() {
|
||||
sourceSearchError={sourceSearchError}
|
||||
backgroundSourcesLoading={backgroundSourcesLoading}
|
||||
precomputedVideoInfo={precomputedVideoInfo}
|
||||
useLightTextOnBackdrop={!!tmdbBackdrop}
|
||||
onDanmakuSelect={(selection) => handleDanmakuSelect(selection, true)}
|
||||
currentDanmakuSelection={currentDanmakuSelection}
|
||||
onUploadDanmaku={handleUploadDanmaku}
|
||||
@@ -9821,11 +9822,11 @@ function PlayPageClient() {
|
||||
})}
|
||||
</div>
|
||||
{/* 评分数值 */}
|
||||
<span className='text-gray-700 dark:text-gray-300 font-semibold'>
|
||||
<span className={`font-semibold ${tmdbBackdrop ? 'text-white' : 'text-gray-700 dark:text-gray-300'}`}>
|
||||
{doubanRating.value.toFixed(1)}
|
||||
</span>
|
||||
{/* 评分人数 */}
|
||||
<span className='text-gray-500 dark:text-gray-400 text-sm'>
|
||||
<span className={`text-sm ${tmdbBackdrop ? 'text-white/80' : 'text-gray-500 dark:text-gray-400'}`}>
|
||||
({doubanRating.count.toLocaleString()}人评价)
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -62,6 +62,8 @@ interface EpisodeSelectorProps {
|
||||
onUploadDanmaku?: (comments: DanmakuComment[]) => void;
|
||||
/** 观影室房员状态 - 禁用选集和换源,但保留弹幕 */
|
||||
isRoomMember?: boolean;
|
||||
/** 外层使用 TMDB 背景图时,提升深色文字对比度 */
|
||||
useLightTextOnBackdrop?: boolean;
|
||||
/** 集数过滤配置 */
|
||||
episodeFilterConfig?: EpisodeFilterConfig | null;
|
||||
onFilterConfigUpdate?: (config: EpisodeFilterConfig) => void;
|
||||
@@ -91,11 +93,39 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
|
||||
currentDanmakuSelection,
|
||||
onUploadDanmaku,
|
||||
isRoomMember = false,
|
||||
useLightTextOnBackdrop = false,
|
||||
episodeFilterConfig = null,
|
||||
onFilterConfigUpdate,
|
||||
onShowToast,
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
const mutedTextClass = useLightTextOnBackdrop
|
||||
? 'text-white/80'
|
||||
: 'text-gray-600 dark:text-gray-300';
|
||||
const faintTextClass = useLightTextOnBackdrop
|
||||
? 'text-white/65'
|
||||
: 'text-gray-500 dark:text-gray-400';
|
||||
const inactiveTabClass = useLightTextOnBackdrop
|
||||
? 'text-white/85 hover:text-white bg-white/10 dark:bg-white/5 hover:bg-white/15 dark:hover:bg-white/10'
|
||||
: 'text-gray-700 hover:text-green-600 bg-black/5 dark:bg-white/5 dark:text-gray-300 dark:hover:text-green-400 hover:bg-black/3 dark:hover:bg-white/3';
|
||||
const inactiveActionTextClass = useLightTextOnBackdrop
|
||||
? 'text-white/85 hover:text-white'
|
||||
: 'text-gray-700 hover:text-green-600 dark:text-gray-300 dark:hover:text-green-400';
|
||||
const iconButtonClass = useLightTextOnBackdrop
|
||||
? 'text-white/85 hover:text-white hover:bg-white/15'
|
||||
: 'text-gray-700 hover:text-green-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:text-green-400 dark:hover:bg-white/20';
|
||||
const inactiveEpisodeClass = useLightTextOnBackdrop
|
||||
? 'bg-white/15 text-white border-white/10 hover:bg-white/25 hover:scale-105'
|
||||
: 'bg-gray-200 text-gray-700 border-transparent hover:bg-gray-300 hover:scale-105 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600';
|
||||
const sourceTitleClass = useLightTextOnBackdrop
|
||||
? 'text-white'
|
||||
: 'text-gray-900 dark:text-gray-100';
|
||||
const sourcePillTextClass = useLightTextOnBackdrop
|
||||
? 'text-white/85'
|
||||
: 'text-gray-700 dark:text-gray-300';
|
||||
const disabledTextClass = useLightTextOnBackdrop
|
||||
? 'text-white/45 cursor-not-allowed'
|
||||
: 'text-gray-400 dark:text-gray-500 cursor-not-allowed';
|
||||
|
||||
const parseSxxExxTitle = useCallback((title?: string) => {
|
||||
const match = title?.match(/[Ss](\d+)[Ee](\d{1,4}(?:\.\d+)?)/);
|
||||
@@ -683,7 +713,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
|
||||
${isRoomMember ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'}
|
||||
${activeTab === 'episodes'
|
||||
? 'text-green-600 dark:text-green-400'
|
||||
: 'text-gray-700 hover:text-green-600 bg-black/5 dark:bg-white/5 dark:text-gray-300 dark:hover:text-green-400 hover:bg-black/3 dark:hover:bg-white/3'
|
||||
: inactiveTabClass
|
||||
}
|
||||
`.trim()}
|
||||
>
|
||||
@@ -699,7 +729,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
|
||||
${isRoomMember ? 'cursor-not-allowed opacity-50' : 'cursor-pointer'}
|
||||
${activeTab === 'sources'
|
||||
? 'text-green-600 dark:text-green-400'
|
||||
: 'text-gray-700 hover:text-green-600 bg-black/5 dark:bg-white/5 dark:text-gray-300 dark:hover:text-green-400 hover:bg-black/3 dark:hover:bg-white/3'
|
||||
: inactiveTabClass
|
||||
}
|
||||
`.trim()}
|
||||
>
|
||||
@@ -713,7 +743,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
|
||||
className={`flex-1 py-3 px-6 text-center cursor-pointer transition-all duration-200 font-medium
|
||||
${activeTab === 'danmaku'
|
||||
? 'text-green-600 dark:text-green-400'
|
||||
: 'text-gray-700 hover:text-green-600 bg-black/5 dark:bg-white/5 dark:text-gray-300 dark:hover:text-green-400 hover:bg-black/3 dark:hover:bg-white/3'
|
||||
: inactiveTabClass
|
||||
}
|
||||
`.trim()}
|
||||
>
|
||||
@@ -758,7 +788,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
|
||||
className={`w-20 relative py-2 text-sm font-medium transition-colors whitespace-nowrap flex-shrink-0 text-center
|
||||
${isActive
|
||||
? 'text-green-500 dark:text-green-400'
|
||||
: 'text-gray-700 hover:text-green-600 dark:text-gray-300 dark:hover:text-green-400'
|
||||
: inactiveActionTextClass
|
||||
}
|
||||
`.trim()}
|
||||
>
|
||||
@@ -773,7 +803,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
|
||||
</div>
|
||||
{/* 向上/向下按钮 */}
|
||||
<button
|
||||
className='flex-shrink-0 w-8 h-8 rounded-md flex items-center justify-center text-gray-700 hover:text-green-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:text-green-400 dark:hover:bg-white/20 transition-colors transform translate-y-[-4px]'
|
||||
className={`flex-shrink-0 w-8 h-8 rounded-md flex items-center justify-center ${iconButtonClass} transition-colors transform translate-y-[-4px]`}
|
||||
onClick={() => {
|
||||
// 切换集数排序(正序/倒序)
|
||||
setDescending((prev) => !prev);
|
||||
@@ -795,7 +825,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
|
||||
</button>
|
||||
{/* 集数屏蔽配置按钮 */}
|
||||
<button
|
||||
className='flex-shrink-0 w-8 h-8 rounded-md flex items-center justify-center text-gray-700 hover:text-green-600 hover:bg-gray-100 dark:text-gray-300 dark:hover:text-green-400 dark:hover:bg-white/20 transition-colors transform translate-y-[-4px]'
|
||||
className={`flex-shrink-0 w-8 h-8 rounded-md flex items-center justify-center ${iconButtonClass} transition-colors transform translate-y-[-4px]`}
|
||||
onClick={() => setShowFilterSettings(true)}
|
||||
title='集数屏蔽设置'
|
||||
>
|
||||
@@ -825,7 +855,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
|
||||
? 'bg-green-500 text-white border-green-400 shadow-lg shadow-green-500/25 dark:bg-green-600'
|
||||
: isWatched
|
||||
? 'bg-emerald-50 text-emerald-700 border-emerald-200 hover:bg-emerald-100 hover:scale-105 dark:bg-emerald-900/20 dark:text-emerald-300 dark:border-emerald-700/60 dark:hover:bg-emerald-900/30'
|
||||
: 'bg-gray-200 text-gray-700 border-transparent hover:bg-gray-300 hover:scale-105 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600'
|
||||
: inactiveEpisodeClass
|
||||
} ${isActive ? 'cursor-default' : ''}`.trim()}
|
||||
title={isWatched && !isActive ? '已观看过' : undefined}
|
||||
aria-current={isActive ? 'true' : undefined}
|
||||
@@ -873,7 +903,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
|
||||
disabled={isRetestingAll || retestingSources.size > 0 || isInitialTesting}
|
||||
className={`text-xs font-medium transition-colors ${
|
||||
isRetestingAll || retestingSources.size > 0 || isInitialTesting
|
||||
? 'text-gray-400 dark:text-gray-500 cursor-not-allowed'
|
||||
? disabledTextClass
|
||||
: 'text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300 cursor-pointer'
|
||||
}`}
|
||||
>
|
||||
@@ -885,7 +915,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
|
||||
{sourceSearchLoading && (
|
||||
<div className='flex items-center justify-center py-8'>
|
||||
<div className='animate-spin rounded-full h-8 w-8 border-b-2 border-green-500'></div>
|
||||
<span className='ml-2 text-sm text-gray-600 dark:text-gray-300'>
|
||||
<span className={`ml-2 text-sm ${mutedTextClass}`}>
|
||||
搜索中...
|
||||
</span>
|
||||
</div>
|
||||
@@ -908,7 +938,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
|
||||
<div className='flex items-center justify-center py-8'>
|
||||
<div className='text-center'>
|
||||
<div className='text-gray-400 text-2xl mb-2'>📺</div>
|
||||
<p className='text-sm text-gray-600 dark:text-gray-300'>
|
||||
<p className={`text-sm ${mutedTextClass}`}>
|
||||
暂无可用的换源
|
||||
</p>
|
||||
</div>
|
||||
@@ -987,7 +1017,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
|
||||
{/* 标题和分辨率 - 顶部 */}
|
||||
<div className='flex items-start justify-between gap-3 h-6'>
|
||||
<div className='flex-1 min-w-0 relative group/title'>
|
||||
<h3 className='font-medium text-base truncate text-gray-900 dark:text-gray-100 leading-none'>
|
||||
<h3 className={`font-medium text-base truncate ${sourceTitleClass} leading-none`}>
|
||||
{source.title}
|
||||
</h3>
|
||||
{/* 标题级别的 tooltip - 第一个元素不显示 */}
|
||||
@@ -1039,7 +1069,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
|
||||
|
||||
{/* 源名称和集数信息 - 垂直居中 */}
|
||||
<div className='flex items-center justify-between'>
|
||||
<span className={`text-xs px-2 py-1 border rounded text-gray-700 dark:text-gray-300 ${
|
||||
<span className={`text-xs px-2 py-1 border rounded ${sourcePillTextClass} ${
|
||||
source.source === 'xiaoya' ? 'border-blue-500' : isNetdiskSource(source.source) ? 'border-purple-500' : source.source === 'openlist' || source.source === 'emby' || source.source?.startsWith('emby_')
|
||||
? 'border-yellow-500'
|
||||
: 'border-gray-500/60'
|
||||
@@ -1047,7 +1077,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
|
||||
{source.source_name}
|
||||
</span>
|
||||
{source.episodes.length > 1 && (
|
||||
<span className='text-xs text-gray-500 dark:text-gray-400 font-medium'>
|
||||
<span className={`text-xs ${faintTextClass} font-medium`}>
|
||||
{source.episodes.length} 集
|
||||
</span>
|
||||
)}
|
||||
@@ -1106,7 +1136,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
|
||||
disabled={isTesting}
|
||||
className={`text-xs font-medium transition-colors ${
|
||||
isTesting
|
||||
? 'text-gray-400 dark:text-gray-500 cursor-not-allowed'
|
||||
? disabledTextClass
|
||||
: 'text-blue-600 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300 cursor-pointer'
|
||||
}`}
|
||||
>
|
||||
@@ -1125,7 +1155,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
|
||||
{backgroundSourcesLoading && (
|
||||
<div className='flex items-center justify-center py-6 border-t border-gray-300 dark:border-gray-700'>
|
||||
<div className='animate-spin rounded-full h-6 w-6 border-b-2 border-green-500'></div>
|
||||
<span className='ml-2 text-sm text-gray-600 dark:text-gray-300'>
|
||||
<span className={`ml-2 text-sm ${mutedTextClass}`}>
|
||||
正在加载更多播放源...
|
||||
</span>
|
||||
</div>
|
||||
@@ -1139,7 +1169,7 @@ const EpisodeSelector: React.FC<EpisodeSelectorProps> = ({
|
||||
);
|
||||
}
|
||||
}}
|
||||
className='w-full text-center text-xs text-gray-500 dark:text-gray-400 hover:text-green-500 dark:hover:text-green-400 transition-colors py-2'
|
||||
className={`w-full text-center text-xs ${faintTextClass} hover:text-green-500 dark:hover:text-green-400 transition-colors py-2`}
|
||||
>
|
||||
影片匹配有误?点击去搜索
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user