mirror of
https://github.com/KuekHaoYang/KVideo.git
synced 2026-08-14 16:23:43 +08:00
feat: Add cursor-pointer to interactive elements for improved user experience.
This commit is contained in:
@@ -14,8 +14,9 @@ export function ThemeSwitcher() {
|
||||
w-9 h-9
|
||||
rounded-[var(--radius-full)]
|
||||
transition-all duration-200
|
||||
${theme === 'light'
|
||||
? 'bg-[var(--accent-color)] text-white scale-105'
|
||||
cursor-pointer
|
||||
${theme === 'light'
|
||||
? 'bg-[var(--accent-color)] text-white scale-105'
|
||||
: 'text-[var(--text-color-secondary)] hover:bg-[color-mix(in_srgb,var(--text-color)_10%,transparent)]'
|
||||
}
|
||||
`}
|
||||
@@ -40,8 +41,9 @@ export function ThemeSwitcher() {
|
||||
w-9 h-9
|
||||
rounded-[var(--radius-full)]
|
||||
transition-all duration-200
|
||||
${theme === 'dark'
|
||||
? 'bg-[var(--accent-color)] text-white scale-105'
|
||||
cursor-pointer
|
||||
${theme === 'dark'
|
||||
? 'bg-[var(--accent-color)] text-white scale-105'
|
||||
: 'text-[var(--text-color-secondary)] hover:bg-[color-mix(in_srgb,var(--text-color)_10%,transparent)]'
|
||||
}
|
||||
`}
|
||||
@@ -58,8 +60,9 @@ export function ThemeSwitcher() {
|
||||
w-9 h-9
|
||||
rounded-[var(--radius-full)]
|
||||
transition-all duration-200
|
||||
${theme === 'system'
|
||||
? 'bg-[var(--accent-color)] text-white scale-105'
|
||||
cursor-pointer
|
||||
${theme === 'system'
|
||||
? 'bg-[var(--accent-color)] text-white scale-105'
|
||||
: 'text-[var(--text-color-secondary)] hover:bg-[color-mix(in_srgb,var(--text-color)_10%,transparent)]'
|
||||
}
|
||||
`}
|
||||
|
||||
@@ -18,7 +18,7 @@ export function HistoryHeader({ onClose }: HistoryHeaderProps) {
|
||||
</div>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="p-2 hover:bg-[var(--glass-bg)] rounded-full transition-colors"
|
||||
className="p-2 hover:bg-[var(--glass-bg)] rounded-full transition-colors cursor-pointer"
|
||||
aria-label="关闭"
|
||||
>
|
||||
<Icons.X size={24} className="text-[var(--text-color-secondary)]" />
|
||||
|
||||
@@ -98,7 +98,7 @@ export function HistoryItem({
|
||||
e.stopPropagation();
|
||||
onRemove();
|
||||
}}
|
||||
className="opacity-0 group-hover:opacity-100 transition-opacity p-2 hover:bg-[var(--glass-bg)] rounded-full self-start"
|
||||
className="opacity-0 group-hover:opacity-100 transition-opacity p-2 hover:bg-[var(--glass-bg)] rounded-full self-start cursor-pointer"
|
||||
aria-label="删除"
|
||||
>
|
||||
<Icons.Trash size={16} className="text-[var(--text-color-secondary)]" />
|
||||
|
||||
@@ -84,7 +84,7 @@ export function WatchHistorySidebar() {
|
||||
{/* Toggle Button */}
|
||||
<button
|
||||
onClick={() => setIsOpen(true)}
|
||||
className="fixed right-6 top-1/2 -translate-y-1/2 z-40 bg-[var(--glass-bg)] backdrop-blur-[8px] saturate-[120%] border border-[var(--glass-border)] rounded-[var(--radius-2xl)] shadow-[var(--shadow-md)] p-3 hover:scale-105 transition-transform duration-200"
|
||||
className="fixed right-6 top-1/2 -translate-y-1/2 z-40 bg-[var(--glass-bg)] backdrop-blur-[8px] saturate-[120%] border border-[var(--glass-border)] rounded-[var(--radius-2xl)] shadow-[var(--shadow-md)] p-3 hover:scale-105 transition-transform duration-200 cursor-pointer"
|
||||
aria-label="打开观看历史"
|
||||
>
|
||||
<Icons.History size={24} className="text-[var(--text-color)]" />
|
||||
|
||||
@@ -46,7 +46,7 @@ export function TagManager({
|
||||
<div className="mb-6 flex items-center justify-between">
|
||||
<button
|
||||
onClick={onToggleManager}
|
||||
className="text-sm text-[var(--text-color-secondary)] hover:text-[var(--accent-color)] transition-colors flex items-center gap-2"
|
||||
className="text-sm text-[var(--text-color-secondary)] hover:text-[var(--accent-color)] transition-colors flex items-center gap-2 cursor-pointer"
|
||||
>
|
||||
<Icons.Tag size={16} />
|
||||
{showTagManager ? '完成' : '管理标签'}
|
||||
@@ -54,7 +54,7 @@ export function TagManager({
|
||||
{showTagManager && (
|
||||
<button
|
||||
onClick={onRestoreDefaults}
|
||||
className="text-sm text-[var(--text-color-secondary)] hover:text-[var(--accent-color)] transition-colors flex items-center gap-2"
|
||||
className="text-sm text-[var(--text-color-secondary)] hover:text-[var(--accent-color)] transition-colors flex items-center gap-2 cursor-pointer"
|
||||
>
|
||||
<Icons.RefreshCw size={16} />
|
||||
恢复默认
|
||||
@@ -75,7 +75,7 @@ export function TagManager({
|
||||
/>
|
||||
<button
|
||||
onClick={onAddTag}
|
||||
className="px-6 py-2 bg-[var(--accent-color)] text-white font-semibold hover:opacity-90 transition-opacity rounded-[var(--radius-2xl)]"
|
||||
className="px-6 py-2 bg-[var(--accent-color)] text-white font-semibold hover:opacity-90 transition-opacity rounded-[var(--radius-2xl)] cursor-pointer"
|
||||
>
|
||||
添加
|
||||
</button>
|
||||
@@ -89,7 +89,7 @@ export function TagManager({
|
||||
<button
|
||||
onClick={() => onTagSelect(tag.id)}
|
||||
className={`
|
||||
px-6 py-2.5 text-sm font-semibold transition-all whitespace-nowrap rounded-[var(--radius-full)]
|
||||
px-6 py-2.5 text-sm font-semibold transition-all whitespace-nowrap rounded-[var(--radius-full)] cursor-pointer
|
||||
${selectedTag === tag.id
|
||||
? 'bg-[var(--accent-color)] text-white shadow-md scale-105'
|
||||
: 'bg-[var(--glass-bg)] backdrop-blur-xl text-[var(--text-color)] border border-[var(--glass-border)] hover:border-[var(--accent-color)] hover:scale-105'
|
||||
@@ -104,7 +104,7 @@ export function TagManager({
|
||||
e.stopPropagation();
|
||||
onTagDelete(tag.id);
|
||||
}}
|
||||
className="absolute -top-2 -right-2 w-6 h-6 bg-red-500 text-white flex items-center justify-center hover:bg-red-600 transition-colors rounded-[var(--radius-full)]"
|
||||
className="absolute -top-2 -right-2 w-6 h-6 bg-red-500 text-white flex items-center justify-center hover:bg-red-600 transition-colors rounded-[var(--radius-full)] cursor-pointer"
|
||||
>
|
||||
<Icons.X size={14} />
|
||||
</button>
|
||||
|
||||
@@ -40,7 +40,7 @@ export function Navbar({ onReset }: NavbarProps) {
|
||||
<div className="flex items-center gap-3">
|
||||
<Link
|
||||
href="/settings"
|
||||
className="w-10 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"
|
||||
className="w-10 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="设置"
|
||||
>
|
||||
<svg className="w-5 h-5" viewBox="0 -960 960 960" fill="currentColor">
|
||||
|
||||
@@ -30,9 +30,9 @@ export function EpisodeList({ episodes, currentEpisode, onEpisodeClick }: Episod
|
||||
orientation: 'vertical',
|
||||
onNavigate: useCallback((index: number) => {
|
||||
buttonRefs.current[index]?.focus();
|
||||
buttonRefs.current[index]?.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'nearest'
|
||||
buttonRefs.current[index]?.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'nearest'
|
||||
});
|
||||
}, []),
|
||||
onSelect: useCallback((index: number) => {
|
||||
@@ -52,7 +52,7 @@ export function EpisodeList({ episodes, currentEpisode, onEpisodeClick }: Episod
|
||||
)}
|
||||
</h3>
|
||||
|
||||
<div
|
||||
<div
|
||||
ref={listRef}
|
||||
className="max-h-[400px] sm:max-h-[600px] overflow-y-auto space-y-2 pr-2"
|
||||
role="radiogroup"
|
||||
@@ -76,7 +76,7 @@ export function EpisodeList({ episodes, currentEpisode, onEpisodeClick }: Episod
|
||||
aria-current={currentEpisode === index ? 'true' : undefined}
|
||||
aria-label={`${episode.name || `第 ${index + 1} 集`}${currentEpisode === index ? ',当前播放' : ''}`}
|
||||
className={`
|
||||
w-full px-3 py-2 sm:px-4 sm:py-3 rounded-[var(--radius-2xl)] text-left transition-[var(--transition-fluid)]
|
||||
w-full px-3 py-2 sm:px-4 sm:py-3 rounded-[var(--radius-2xl)] text-left transition-[var(--transition-fluid)] cursor-pointer
|
||||
${currentEpisode === index
|
||||
? 'bg-[var(--accent-color)] text-white shadow-[0_4px_12px_color-mix(in_srgb,var(--accent-color)_50%,transparent)] brightness-110'
|
||||
: 'bg-[var(--glass-bg)] hover:bg-[var(--glass-hover)] text-[var(--text-color)] border border-[var(--glass-border)]'
|
||||
|
||||
@@ -15,7 +15,7 @@ export function PlayerNavbar() {
|
||||
<div className="flex items-center gap-2 sm:gap-4 min-w-0">
|
||||
<button
|
||||
onClick={() => router.push('/')}
|
||||
className="flex items-center justify-center hover:opacity-80 transition-opacity flex-shrink-0"
|
||||
className="flex items-center justify-center hover:opacity-80 transition-opacity flex-shrink-0 cursor-pointer"
|
||||
title="返回首页"
|
||||
>
|
||||
<Image
|
||||
@@ -38,7 +38,7 @@ export function PlayerNavbar() {
|
||||
<div className="flex items-center gap-3">
|
||||
<Link
|
||||
href="/settings"
|
||||
className="w-10 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"
|
||||
className="w-10 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="设置"
|
||||
>
|
||||
<svg className="w-5 h-5" viewBox="0 -960 960 960" fill="currentColor">
|
||||
|
||||
@@ -62,7 +62,7 @@ export function DesktopOverlay({
|
||||
<div className="absolute inset-0 flex items-center justify-center pointer-events-none">
|
||||
<button
|
||||
onClick={onTogglePlay}
|
||||
className="pointer-events-auto w-20 h-20 rounded-full bg-[var(--glass-bg)] backdrop-blur-[25px] saturate-[180%] border border-[var(--glass-border)] flex items-center justify-center transition-all duration-300 hover:scale-110 hover:bg-[var(--accent-color)] shadow-[var(--shadow-md)] will-change-transform"
|
||||
className="pointer-events-auto w-20 h-20 rounded-full bg-[var(--glass-bg)] backdrop-blur-[25px] saturate-[180%] border border-[var(--glass-border)] flex items-center justify-center transition-all duration-300 hover:scale-110 hover:bg-[var(--accent-color)] shadow-[var(--shadow-md)] will-change-transform cursor-pointer"
|
||||
aria-label="Play"
|
||||
>
|
||||
<Icons.Play size={32} className="text-white ml-1" />
|
||||
|
||||
@@ -35,7 +35,7 @@ export function MobileMoreMenu({
|
||||
e.stopPropagation();
|
||||
onCopyLink();
|
||||
}}
|
||||
className="w-full px-4 py-3 text-left text-sm text-white hover:bg-white/20 flex items-center gap-3 transition-all touch-manipulation"
|
||||
className="w-full px-4 py-3 text-left text-sm text-white hover:bg-white/20 flex items-center gap-3 transition-all touch-manipulation cursor-pointer"
|
||||
style={{ WebkitTapHighlightColor: 'transparent' }}
|
||||
>
|
||||
<Icons.Link size={18} />
|
||||
@@ -50,7 +50,7 @@ export function MobileMoreMenu({
|
||||
e.stopPropagation();
|
||||
onToggleVolumeMenu();
|
||||
}}
|
||||
className="w-full px-4 py-3 text-left text-sm text-white hover:bg-white/20 flex items-center gap-3 transition-all touch-manipulation"
|
||||
className="w-full px-4 py-3 text-left text-sm text-white hover:bg-white/20 flex items-center gap-3 transition-all touch-manipulation cursor-pointer"
|
||||
style={{ WebkitTapHighlightColor: 'transparent' }}
|
||||
>
|
||||
{isMuted || volume === 0 ? <Icons.VolumeX size={18} /> : <Icons.Volume2 size={18} />}
|
||||
@@ -63,7 +63,7 @@ export function MobileMoreMenu({
|
||||
e.stopPropagation();
|
||||
onToggleSpeedMenu();
|
||||
}}
|
||||
className="w-full px-4 py-3 text-left text-sm text-white hover:bg-white/20 flex items-center gap-3 transition-all touch-manipulation"
|
||||
className="w-full px-4 py-3 text-left text-sm text-white hover:bg-white/20 flex items-center gap-3 transition-all touch-manipulation cursor-pointer"
|
||||
style={{ WebkitTapHighlightColor: 'transparent' }}
|
||||
>
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
@@ -80,7 +80,7 @@ export function MobileMoreMenu({
|
||||
e.stopPropagation();
|
||||
onTogglePiP();
|
||||
}}
|
||||
className="w-full px-4 py-3 text-left text-sm text-white hover:bg-white/20 flex items-center gap-3 transition-all touch-manipulation"
|
||||
className="w-full px-4 py-3 text-left text-sm text-white hover:bg-white/20 flex items-center gap-3 transition-all touch-manipulation cursor-pointer"
|
||||
style={{ WebkitTapHighlightColor: 'transparent' }}
|
||||
>
|
||||
<Icons.PictureInPicture size={18} />
|
||||
|
||||
@@ -30,7 +30,7 @@ export function MobileSpeedMenu({
|
||||
e.stopPropagation();
|
||||
onSpeedChange(speed);
|
||||
}}
|
||||
className={`px-3 py-1.5 rounded-[var(--radius-full)] text-xs font-medium transition-colors ${playbackRate === speed
|
||||
className={`px-3 py-1.5 rounded-[var(--radius-full)] text-xs font-medium transition-colors cursor-pointer ${playbackRate === speed
|
||||
? 'bg-[var(--accent-color)] text-white'
|
||||
: 'bg-white/20 text-white hover:bg-white/30'
|
||||
}`}
|
||||
@@ -41,7 +41,7 @@ export function MobileSpeedMenu({
|
||||
</div>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="text-white/60 hover:text-white text-xs mt-2"
|
||||
className="text-white/60 hover:text-white text-xs mt-2 cursor-pointer"
|
||||
>
|
||||
关闭
|
||||
</button>
|
||||
@@ -59,7 +59,7 @@ export function MobileSpeedMenu({
|
||||
e.stopPropagation();
|
||||
onSpeedChange(speed);
|
||||
}}
|
||||
className={`px-3 py-1.5 rounded-[var(--radius-full)] text-xs font-medium transition-colors whitespace-nowrap ${playbackRate === speed
|
||||
className={`px-3 py-1.5 rounded-[var(--radius-full)] text-xs font-medium transition-colors whitespace-nowrap cursor-pointer ${playbackRate === speed
|
||||
? 'bg-[var(--accent-color)] text-white'
|
||||
: 'bg-white/20 text-white hover:bg-white/30'
|
||||
}`}
|
||||
|
||||
@@ -44,7 +44,7 @@ export function MobileVolumeMenu({
|
||||
</span>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="text-white/60 hover:text-white text-xs"
|
||||
className="text-white/60 hover:text-white text-xs cursor-pointer"
|
||||
>
|
||||
关闭
|
||||
</button>
|
||||
|
||||
@@ -87,7 +87,7 @@ export function SearchBox({ onSearch, onClear, initialQuery = '' }: SearchBoxPro
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleClear}
|
||||
className="p-2 text-[var(--text-color)] opacity-70 hover:opacity-100 transition-opacity touch-manipulation"
|
||||
className="p-2 text-[var(--text-color)] opacity-70 hover:opacity-100 transition-opacity touch-manipulation cursor-pointer"
|
||||
aria-label="清除搜索"
|
||||
>
|
||||
<Icons.X size={20} />
|
||||
|
||||
@@ -23,7 +23,7 @@ export function SearchHistoryHeader({ onClearAll }: SearchHistoryHeaderProps) {
|
||||
e.stopPropagation();
|
||||
onClearAll();
|
||||
}}
|
||||
className="text-xs text-[var(--accent-color)] hover:underline transition-all"
|
||||
className="text-xs text-[var(--accent-color)] hover:underline transition-all cursor-pointer"
|
||||
aria-label="清除所有历史"
|
||||
>
|
||||
清除全部
|
||||
|
||||
@@ -14,12 +14,12 @@ interface SourceBadgeItemProps {
|
||||
innerRef?: (el: HTMLButtonElement | null) => void;
|
||||
}
|
||||
|
||||
export function SourceBadgeItem({
|
||||
export function SourceBadgeItem({
|
||||
id,
|
||||
name,
|
||||
count,
|
||||
isSelected,
|
||||
onToggle,
|
||||
name,
|
||||
count,
|
||||
isSelected,
|
||||
onToggle,
|
||||
isFocused = false,
|
||||
onFocus,
|
||||
innerRef,
|
||||
@@ -51,9 +51,9 @@ export function SourceBadgeItem({
|
||||
transition-all duration-200 ease-out
|
||||
hover:scale-105 hover:shadow-[var(--shadow-sm)]
|
||||
active:scale-95 snap-start
|
||||
focus:outline-none
|
||||
${isSelected
|
||||
? 'bg-[var(--accent-color)] text-white border-[var(--accent-color)] shadow-md'
|
||||
focus:outline-none cursor-pointer
|
||||
${isSelected
|
||||
? 'bg-[var(--accent-color)] text-white border-[var(--accent-color)] shadow-md'
|
||||
: 'bg-[var(--glass-bg)] text-[var(--text-color)] border-[var(--glass-border)] hover:border-[var(--accent-color)]'
|
||||
}
|
||||
`}
|
||||
@@ -61,8 +61,8 @@ export function SourceBadgeItem({
|
||||
<span>{name}</span>
|
||||
<span className={`
|
||||
px-2 py-0.5 rounded-full text-xs font-semibold
|
||||
${isSelected
|
||||
? 'bg-white/20 text-white'
|
||||
${isSelected
|
||||
? 'bg-white/20 text-white'
|
||||
: 'bg-[var(--accent-color)]/10 text-[var(--accent-color)]'
|
||||
}
|
||||
`}>
|
||||
|
||||
@@ -103,7 +103,7 @@ export function SourceBadgeList({ sources, selectedSources, onToggleSource }: So
|
||||
<button
|
||||
onClick={() => setIsExpanded(!isExpanded)}
|
||||
className="mt-2 text-xs text-[var(--text-color-secondary)] hover:text-[var(--accent-color)]
|
||||
flex items-center gap-1 transition-colors self-start"
|
||||
flex items-center gap-1 transition-colors self-start cursor-pointer"
|
||||
>
|
||||
<span>{isExpanded ? '收起' : '展开更多'}</span>
|
||||
<Icons.ChevronDown
|
||||
|
||||
@@ -13,11 +13,11 @@ interface TypeBadgeItemProps {
|
||||
innerRef?: (el: HTMLButtonElement | null) => void;
|
||||
}
|
||||
|
||||
export function TypeBadgeItem({
|
||||
type,
|
||||
count,
|
||||
isSelected,
|
||||
onToggle,
|
||||
export function TypeBadgeItem({
|
||||
type,
|
||||
count,
|
||||
isSelected,
|
||||
onToggle,
|
||||
isFocused = false,
|
||||
onFocus,
|
||||
innerRef,
|
||||
@@ -49,9 +49,9 @@ export function TypeBadgeItem({
|
||||
transition-all duration-200 ease-out
|
||||
hover:scale-105 hover:shadow-[var(--shadow-sm)]
|
||||
active:scale-95 snap-start
|
||||
focus:outline-none
|
||||
${isSelected
|
||||
? 'bg-[var(--accent-color)] text-white border-[var(--accent-color)] shadow-md'
|
||||
focus:outline-none cursor-pointer
|
||||
${isSelected
|
||||
? 'bg-[var(--accent-color)] text-white border-[var(--accent-color)] shadow-md'
|
||||
: 'bg-[var(--glass-bg)] text-[var(--text-color)] border-[var(--glass-border)] hover:border-[var(--accent-color)]'
|
||||
}
|
||||
`}
|
||||
@@ -59,8 +59,8 @@ export function TypeBadgeItem({
|
||||
<span>{type}</span>
|
||||
<span className={`
|
||||
px-2 py-0.5 rounded-full text-xs font-semibold
|
||||
${isSelected
|
||||
? 'bg-white/20 text-white'
|
||||
${isSelected
|
||||
? 'bg-white/20 text-white'
|
||||
: 'bg-[var(--accent-color)]/10 text-[var(--accent-color)]'
|
||||
}
|
||||
`}>
|
||||
|
||||
@@ -100,7 +100,7 @@ export function TypeBadgeList({ badges, selectedTypes, onToggleType }: TypeBadge
|
||||
<button
|
||||
onClick={() => setIsExpanded(!isExpanded)}
|
||||
className="mt-2 text-xs text-[var(--text-color-secondary)] hover:text-[var(--accent-color)]
|
||||
flex items-center gap-1 transition-colors self-start"
|
||||
flex items-center gap-1 transition-colors self-start cursor-pointer"
|
||||
>
|
||||
<span>{isExpanded ? '收起' : '展开更多'}</span>
|
||||
<Icons.ChevronDown
|
||||
|
||||
@@ -11,7 +11,7 @@ export function DataSettings({ onExport, onImport, onReset }: DataSettingsProps)
|
||||
<div className="space-y-3">
|
||||
<button
|
||||
onClick={onExport}
|
||||
className="w-full px-6 py-4 rounded-[var(--radius-2xl)] bg-[var(--glass-bg)] border border-[var(--glass-border)] text-[var(--text-color)] font-medium hover:bg-[color-mix(in_srgb,var(--accent-color)_10%,transparent)] transition-all duration-200 flex items-center justify-between"
|
||||
className="w-full px-6 py-4 rounded-[var(--radius-2xl)] bg-[var(--glass-bg)] border border-[var(--glass-border)] text-[var(--text-color)] font-medium hover:bg-[color-mix(in_srgb,var(--accent-color)_10%,transparent)] transition-all duration-200 flex items-center justify-between cursor-pointer"
|
||||
>
|
||||
<span>导出设置</span>
|
||||
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
@@ -21,7 +21,7 @@ export function DataSettings({ onExport, onImport, onReset }: DataSettingsProps)
|
||||
|
||||
<button
|
||||
onClick={onImport}
|
||||
className="w-full px-6 py-4 rounded-[var(--radius-2xl)] bg-[var(--glass-bg)] border border-[var(--glass-border)] text-[var(--text-color)] font-medium hover:bg-[color-mix(in_srgb,var(--accent-color)_10%,transparent)] transition-all duration-200 flex items-center justify-between"
|
||||
className="w-full px-6 py-4 rounded-[var(--radius-2xl)] bg-[var(--glass-bg)] border border-[var(--glass-border)] text-[var(--text-color)] font-medium hover:bg-[color-mix(in_srgb,var(--accent-color)_10%,transparent)] transition-all duration-200 flex items-center justify-between cursor-pointer"
|
||||
>
|
||||
<span>导入设置</span>
|
||||
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
@@ -31,7 +31,7 @@ export function DataSettings({ onExport, onImport, onReset }: DataSettingsProps)
|
||||
|
||||
<button
|
||||
onClick={onReset}
|
||||
className="w-full px-6 py-4 rounded-[var(--radius-2xl)] bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 text-red-600 dark:text-red-400 font-medium hover:bg-red-100 dark:hover:bg-red-900/30 transition-all duration-200 flex items-center justify-between"
|
||||
className="w-full px-6 py-4 rounded-[var(--radius-2xl)] bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 text-red-600 dark:text-red-400 font-medium hover:bg-red-100 dark:hover:bg-red-900/30 transition-all duration-200 flex items-center justify-between cursor-pointer"
|
||||
>
|
||||
<span>清除所有数据</span>
|
||||
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
|
||||
@@ -7,7 +7,7 @@ export function SettingsHeader() {
|
||||
<div className="mb-8">
|
||||
<button
|
||||
onClick={() => router.back()}
|
||||
className="inline-flex items-center gap-2 text-[var(--accent-color)] hover:underline mb-4"
|
||||
className="inline-flex items-center gap-2 text-[var(--accent-color)] hover:underline mb-4 cursor-pointer"
|
||||
>
|
||||
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
<path d="M19 12H5M12 19l-7-7 7-7" />
|
||||
|
||||
@@ -18,7 +18,7 @@ export function SortSettings({ sortBy, onSortChange }: SortSettingsProps) {
|
||||
<button
|
||||
key={option}
|
||||
onClick={() => onSortChange(option)}
|
||||
className={`px-4 py-3 rounded-[var(--radius-2xl)] border text-left font-medium transition-all duration-200 ${sortBy === option
|
||||
className={`px-4 py-3 rounded-[var(--radius-2xl)] border text-left font-medium transition-all duration-200 cursor-pointer ${sortBy === option
|
||||
? 'bg-[var(--accent-color)] border-[var(--accent-color)] text-white'
|
||||
: 'bg-[var(--glass-bg)] border-[var(--glass-border)] text-[var(--text-color)] hover:bg-[color-mix(in_srgb,var(--accent-color)_10%,transparent)]'
|
||||
}`}
|
||||
|
||||
@@ -78,7 +78,7 @@ export function SourceManager({
|
||||
<button
|
||||
onClick={() => handlePriorityChange(source.id, 'up')}
|
||||
disabled={index === 0}
|
||||
className="w-8 h-8 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)] disabled:opacity-30 disabled:cursor-not-allowed transition-all duration-200"
|
||||
className="w-8 h-8 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)] disabled:opacity-30 disabled:cursor-not-allowed transition-all duration-200 cursor-pointer"
|
||||
aria-label="Move up"
|
||||
>
|
||||
<svg className="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
@@ -89,7 +89,7 @@ export function SourceManager({
|
||||
<button
|
||||
onClick={() => handlePriorityChange(source.id, 'down')}
|
||||
disabled={index === sources.length - 1}
|
||||
className="w-8 h-8 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)] disabled:opacity-30 disabled:cursor-not-allowed transition-all duration-200"
|
||||
className="w-8 h-8 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)] disabled:opacity-30 disabled:cursor-not-allowed transition-all duration-200 cursor-pointer"
|
||||
aria-label="Move down"
|
||||
>
|
||||
<svg className="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
@@ -101,7 +101,7 @@ export function SourceManager({
|
||||
{onEdit && !defaultIds.includes(source.id) && (
|
||||
<button
|
||||
onClick={() => onEdit(source)}
|
||||
className="w-8 h-8 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"
|
||||
className="w-8 h-8 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="Edit source"
|
||||
>
|
||||
<svg className="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
@@ -114,7 +114,7 @@ export function SourceManager({
|
||||
{/* Delete Button */}
|
||||
<button
|
||||
onClick={() => handleDelete(source.id)}
|
||||
className="w-8 h-8 flex items-center justify-center rounded-[var(--radius-full)] bg-[var(--glass-bg)] border border-[var(--glass-border)] text-red-500 hover:bg-red-50 dark:hover:bg-red-900/20 transition-all duration-200"
|
||||
className="w-8 h-8 flex items-center justify-center rounded-[var(--radius-full)] bg-[var(--glass-bg)] border border-[var(--glass-border)] text-red-500 hover:bg-red-50 dark:hover:bg-red-900/20 transition-all duration-200 cursor-pointer"
|
||||
aria-label="Delete source"
|
||||
>
|
||||
<svg className="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
|
||||
@@ -64,13 +64,13 @@ export function SourceSettings({
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={onRestoreDefaults}
|
||||
className="px-4 py-2 rounded-[var(--radius-2xl)] bg-[var(--glass-bg)] border border-[var(--glass-border)] text-[var(--text-color)] text-sm font-medium hover:bg-[color-mix(in_srgb,var(--accent-color)_10%,transparent)] transition-all duration-200"
|
||||
className="px-4 py-2 rounded-[var(--radius-2xl)] bg-[var(--glass-bg)] border border-[var(--glass-border)] text-[var(--text-color)] text-sm font-medium hover:bg-[color-mix(in_srgb,var(--accent-color)_10%,transparent)] transition-all duration-200 cursor-pointer"
|
||||
>
|
||||
恢复默认
|
||||
</button>
|
||||
<button
|
||||
onClick={onAddSource}
|
||||
className="px-4 py-2 rounded-[var(--radius-2xl)] bg-[var(--accent-color)] text-white text-sm font-semibold hover:brightness-110 hover:-translate-y-0.5 shadow-[var(--shadow-sm)] transition-all duration-200"
|
||||
className="px-4 py-2 rounded-[var(--radius-2xl)] bg-[var(--accent-color)] text-white text-sm font-semibold hover:brightness-110 hover:-translate-y-0.5 shadow-[var(--shadow-sm)] transition-all duration-200 cursor-pointer"
|
||||
>
|
||||
+ 添加源
|
||||
</button>
|
||||
@@ -110,7 +110,7 @@ export function SourceSettings({
|
||||
{!searchQuery && sources.length > 10 && (
|
||||
<button
|
||||
onClick={() => setShowAllSources(!showAllSources)}
|
||||
className="w-full mt-4 px-4 py-3 rounded-[var(--radius-2xl)] bg-[var(--glass-bg)] border border-[var(--glass-border)] text-[var(--text-color)] text-sm font-medium hover:bg-[color-mix(in_srgb,var(--accent-color)_10%,transparent)] transition-all duration-200"
|
||||
className="w-full mt-4 px-4 py-3 rounded-[var(--radius-2xl)] bg-[var(--glass-bg)] border border-[var(--glass-border)] text-[var(--text-color)] text-sm font-medium hover:bg-[color-mix(in_srgb,var(--accent-color)_10%,transparent)] transition-all duration-200 cursor-pointer"
|
||||
>
|
||||
{showAllSources ? '收起' : `显示全部 (${sources.length})`}
|
||||
</button>
|
||||
|
||||
@@ -5,14 +5,14 @@ interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(({
|
||||
variant = 'primary',
|
||||
children,
|
||||
className = '',
|
||||
...props
|
||||
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(({
|
||||
variant = 'primary',
|
||||
children,
|
||||
className = '',
|
||||
...props
|
||||
}, ref) => {
|
||||
const baseStyles = "inline-flex items-center justify-center px-4 py-2.5 md:px-6 md:py-3 font-semibold text-sm md:text-base transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed min-h-[44px] touch-manipulation";
|
||||
|
||||
const baseStyles = "inline-flex items-center justify-center px-4 py-2.5 md:px-6 md:py-3 font-semibold text-sm md:text-base transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed min-h-[44px] touch-manipulation cursor-pointer";
|
||||
|
||||
const variants = {
|
||||
primary: `
|
||||
bg-[var(--accent-color)]
|
||||
@@ -42,7 +42,7 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(({
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
<button
|
||||
ref={ref}
|
||||
className={`${baseStyles} ${variants[variant]} ${className}`}
|
||||
{...props}
|
||||
|
||||
@@ -15,7 +15,7 @@ export function ModalHeader({ title, onClose }: ModalHeaderProps) {
|
||||
</h3>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="w-8 h-8 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"
|
||||
className="w-8 h-8 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="关闭"
|
||||
>
|
||||
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
||||
|
||||
Reference in New Issue
Block a user