feat: Add cursor-pointer to interactive elements for improved user experience.

This commit is contained in:
kuekhaoyang
2025-11-24 18:23:19 +08:00
parent 71bf1ba06d
commit 6ec795ed01
25 changed files with 79 additions and 76 deletions
+9 -6
View File
@@ -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)]'
}
`}
+1 -1
View File
@@ -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)]" />
+1 -1
View File
@@ -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)]" />
+1 -1
View File
@@ -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)]" />
+5 -5
View File
@@ -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>
+1 -1
View File
@@ -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">
+5 -5
View File
@@ -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)]'
+2 -2
View File
@@ -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">
+1 -1
View File
@@ -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" />
+4 -4
View File
@@ -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} />
+3 -3
View File
@@ -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>
+1 -1
View File
@@ -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} />
+1 -1
View File
@@ -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="清除所有历史"
>
+10 -10
View File
@@ -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)]'
}
`}>
+1 -1
View File
@@ -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
+10 -10
View File
@@ -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)]'
}
`}>
+1 -1
View File
@@ -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
+3 -3
View File
@@ -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">
+1 -1
View File
@@ -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" />
+1 -1
View File
@@ -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)]'
}`}
+4 -4
View File
@@ -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">
+3 -3
View File
@@ -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>
+8 -8
View File
@@ -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}
+1 -1
View File
@@ -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">