diff --git a/README.md b/README.md index 47dd62d..54ac3fe 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ **在线体验:[https://kvideo.pages.dev/](https://kvideo.pages.dev/)** -[![Version](https://img.shields.io/badge/Version-4.6.0-blue?style=for-the-badge)](https://github.com/KuekHaoYang/KVideo) +[![Version](https://img.shields.io/badge/Version-4.7.0-blue?style=for-the-badge)](https://github.com/KuekHaoYang/KVideo) [![Next.js](https://img.shields.io/badge/Next.js-16.1-black?style=for-the-badge&logo=next.js)](https://nextjs.org/) [![React](https://img.shields.io/badge/React-19.2-blue?style=for-the-badge&logo=react)](https://react.dev/) [![Tailwind CSS](https://img.shields.io/badge/Tailwind-4.0-38B2AC?style=for-the-badge&logo=tailwind-css)](https://tailwindcss.com/) diff --git a/app/page.tsx b/app/page.tsx index 7102e61..a4fe980 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -40,8 +40,8 @@ function HomePage() { {/* Glass Navbar */} - {/* Search Form - Separate from navbar */} -
diff --git a/app/styles/base.css b/app/styles/base.css index 027aa69..1828392 100644 --- a/app/styles/base.css +++ b/app/styles/base.css @@ -1,4 +1,4 @@ -/* Base Styles */ +/* Base Styles - Liquid Glass Design System v5 */ *, *::before, *::after { @@ -46,7 +46,7 @@ select:focus-visible { /* Scrollbar Styles */ ::-webkit-scrollbar { - width: 10px; + width: 8px; } ::-webkit-scrollbar-track { @@ -54,21 +54,19 @@ select:focus-visible { } ::-webkit-scrollbar-thumb { - background: rgba(128, 128, 128, 0.5); - background: color-mix(in srgb, var(--glass-bg) 80%, transparent); + background: color-mix(in srgb, var(--text-color) 15%, transparent); border-radius: var(--radius-full); border: 2px solid transparent; background-clip: padding-box; } ::-webkit-scrollbar-thumb:hover { - background: rgba(0, 122, 255, 0.6); - background: color-mix(in srgb, var(--accent-color) 60%, transparent); + background: color-mix(in srgb, var(--accent-color) 50%, transparent); background-clip: padding-box; } .search-history-dropdown::-webkit-scrollbar { - width: 6px; + width: 5px; } .search-history-dropdown::-webkit-scrollbar-track { @@ -76,8 +74,7 @@ select:focus-visible { } .search-history-dropdown::-webkit-scrollbar-thumb { - background: rgba(128, 128, 128, 0.5); - background: color-mix(in srgb, var(--glass-bg) 80%, transparent); + background: color-mix(in srgb, var(--text-color) 15%, transparent); border-radius: var(--radius-full); } @@ -114,13 +111,8 @@ nav:where(.sticky, .fixed), transform: translateZ(0); } -/* [class*="grid"]>* { - content-visibility: auto; - contain-intrinsic-size: auto 400px; -} */ - [class*="grid"]>a { - animation: fadeInUp 0.2s ease-out; + animation: fadeInUp 0.25s cubic-bezier(0.22, 0.68, 0, 1); } @supports (content-visibility: auto) { @@ -137,12 +129,10 @@ body.scrolling * { pointer-events: none !important; } -.group:hover img, .glass-card, nav { transform: translateZ(0); backface-visibility: hidden; - perspective: 1000px; } [class*="badge"], @@ -160,7 +150,7 @@ nav { body.tv-mode [data-focusable]:focus { outline: 3px solid var(--accent-color); outline-offset: 4px; - box-shadow: 0 0 0 6px rgba(0, 122, 255, 0.2); + box-shadow: 0 0 0 6px color-mix(in srgb, var(--accent-color) 20%, transparent); transform: scale(1.03); transition: transform 0.15s ease-out, box-shadow 0.15s ease-out; } @@ -184,4 +174,4 @@ body.tv-mode [class*="gap-3"] { body.tv-mode [class*="gap-4"] { gap: 1.5rem; -} \ No newline at end of file +} diff --git a/app/styles/effects.css b/app/styles/effects.css index dc74acf..3c779f2 100644 --- a/app/styles/effects.css +++ b/app/styles/effects.css @@ -1,4 +1,4 @@ -/* Effects - Liquid Glass Design System */ +/* Effects - Liquid Glass Design System v5 */ @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } @@ -20,7 +20,7 @@ @keyframes bounce-subtle { 0%, 100% { transform: translateY(0); } - 50% { transform: translateY(-5px); } + 50% { transform: translateY(-4px); } } @keyframes shimmer { @@ -44,15 +44,43 @@ 50% { background-position: 100% 50%; } } +@keyframes glow-pulse { + 0%, 100% { box-shadow: 0 0 8px color-mix(in srgb, var(--accent-color) 20%, transparent); } + 50% { box-shadow: 0 0 20px color-mix(in srgb, var(--accent-color) 40%, transparent); } +} + /* Lensing inner-glow effect for interactive elements */ .glass-glow:hover { box-shadow: - 0 8px 24px var(--shadow-color), - inset 0 1px 0 rgba(255, 255, 255, 0.15); + var(--shadow-lg), + inset 0 1px 0 rgba(255, 255, 255, 0.1); } .glass-glow:focus-visible { box-shadow: - 0 0 0 3px color-mix(in srgb, var(--accent-color) 30%, transparent), - inset 0 1px 0 rgba(255, 255, 255, 0.15); + 0 0 0 3px color-mix(in srgb, var(--accent-color) 25%, transparent), + inset 0 1px 0 rgba(255, 255, 255, 0.1); +} + +/* Hover lift effect */ +.hover-lift { + transition: transform var(--transition-fluid), box-shadow var(--transition-fluid); +} + +.hover-lift:hover { + transform: translateY(-3px); + box-shadow: var(--shadow-lg); +} + +/* Subtle scale on hover */ +.hover-scale { + transition: transform var(--transition-snappy); +} + +.hover-scale:hover { + transform: scale(1.03); +} + +.hover-scale:active { + transform: scale(0.97); } diff --git a/app/styles/glass.css b/app/styles/glass.css index e405061..cf9e918 100644 --- a/app/styles/glass.css +++ b/app/styles/glass.css @@ -1,8 +1,8 @@ -/* Glass Components - Liquid Glass Design System */ +/* Glass Components - Liquid Glass Design System v5 */ .glass-card { background: var(--glass-bg); - backdrop-filter: blur(25px) saturate(180%); - -webkit-backdrop-filter: blur(25px) saturate(180%); + backdrop-filter: blur(20px) saturate(180%); + -webkit-backdrop-filter: blur(20px) saturate(180%); border-radius: var(--radius-2xl); box-shadow: var(--shadow-md); border: 1px solid var(--glass-border); @@ -11,16 +11,16 @@ } .glass-card:hover { - transform: translateY(-5px) scale(1.02); - box-shadow: 0 8px 24px var(--shadow-color); + transform: translateY(-4px); + box-shadow: var(--shadow-lg); z-index: 10; } .glass-input { width: 100%; background: var(--glass-bg); - backdrop-filter: blur(10px) saturate(150%); - -webkit-backdrop-filter: blur(10px) saturate(150%); + backdrop-filter: blur(12px) saturate(160%); + -webkit-backdrop-filter: blur(12px) saturate(160%); border: 1px solid var(--glass-border); border-radius: var(--radius-2xl); color: var(--text-color); @@ -30,7 +30,8 @@ .glass-input:focus { outline: none; border-color: var(--accent-color); - box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-color) 30%, transparent); + box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-color) 20%, transparent), + var(--shadow-md); } .glass-button { @@ -41,30 +42,28 @@ color: white; border: none; border-radius: var(--radius-2xl); - padding: 0.75rem 1.25rem; + padding: 0.75rem 1.5rem; font-weight: 600; cursor: pointer; - transition: all 0.2s ease; - box-shadow: var(--shadow-sm); + transition: all var(--transition-snappy); + box-shadow: 0 2px 8px color-mix(in srgb, var(--accent-color) 35%, transparent); } .glass-button:hover { - transform: translateY(-2px); - filter: brightness(1.1); - box-shadow: 0 4px 8px var(--shadow-color); + transform: translateY(-1px); + background: var(--accent-hover, var(--accent-color)); + box-shadow: 0 4px 16px color-mix(in srgb, var(--accent-color) 40%, transparent); } .glass-button:active { - transform: translateY(0) scale(0.98); - filter: brightness(0.95); + transform: translateY(0) scale(0.97); } .glass-button:disabled { background-color: var(--text-color-secondary); - opacity: 0.5; + opacity: 0.4; cursor: not-allowed; transform: none; - filter: none; box-shadow: none; } @@ -72,33 +71,45 @@ display: inline-flex; align-items: center; justify-content: center; - padding: 0.25rem 0.75rem; + padding: 0.2rem 0.625rem; border-radius: var(--radius-full); - font-size: 0.8rem; + font-size: 0.75rem; font-weight: 600; background-color: var(--accent-color); color: white; + letter-spacing: 0.01em; } .glass-badge-secondary { background: var(--glass-bg); + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); border: 1px solid var(--glass-border); color: var(--text-color); } /* Glass backdrop for modals/drawers */ .glass-backdrop { - background-color: rgba(0, 0, 0, 0.3); - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); + background-color: rgba(0, 0, 0, 0.4); + backdrop-filter: blur(12px) saturate(120%); + -webkit-backdrop-filter: blur(12px) saturate(120%); } /* Glass popover/dropdown */ .glass-popover { background: var(--glass-bg); - backdrop-filter: blur(25px) saturate(180%); - -webkit-backdrop-filter: blur(25px) saturate(180%); + backdrop-filter: blur(20px) saturate(180%); + -webkit-backdrop-filter: blur(20px) saturate(180%); border-radius: var(--radius-2xl); - box-shadow: var(--shadow-md); + box-shadow: var(--shadow-lg); border: 1px solid var(--glass-border); } + +/* Glass surface - subtle inner highlight */ +.glass-surface { + background: var(--glass-bg); + backdrop-filter: blur(20px) saturate(180%); + -webkit-backdrop-filter: blur(20px) saturate(180%); + border: 1px solid var(--glass-border); + border-radius: var(--radius-2xl); +} diff --git a/app/styles/transitions.css b/app/styles/transitions.css index 0d44c78..6147ba7 100644 --- a/app/styles/transitions.css +++ b/app/styles/transitions.css @@ -1,57 +1,27 @@ -/* Transitions - Liquid Glass Design System */ +/* Transitions - Liquid Glass Design System v5 */ @keyframes fade-in { - from { - opacity: 0; - transform: translateY(10px); - } - to { - opacity: 1; - transform: translateY(0); - } + from { opacity: 0; transform: translateY(8px); } + to { opacity: 1; transform: translateY(0); } } @keyframes slide-up { - from { - opacity: 0; - transform: translateY(20px); - } - to { - opacity: 1; - transform: translateY(0); - } + from { opacity: 0; transform: translateY(16px); } + to { opacity: 1; transform: translateY(0); } } @keyframes scale-in { - 0% { - opacity: 0; - transform: scale(0.95) translateY(10px); - } - 100% { - opacity: 1; - transform: scale(1) translateY(0); - } + 0% { opacity: 0; transform: scale(0.96) translateY(8px); } + 100% { opacity: 1; transform: scale(1) translateY(0); } } @keyframes scale-out { - 0% { - opacity: 1; - transform: scale(1) translateY(0); - } - 100% { - opacity: 0; - transform: scale(0.95) translateY(-10px); - } + 0% { opacity: 1; transform: scale(1) translateY(0); } + 100% { opacity: 0; transform: scale(0.96) translateY(-8px); } } @keyframes slideIn { - from { - opacity: 0; - transform: translateY(-10px) scale(0.95); - } - to { - opacity: 1; - transform: translateY(0) scale(1); - } + from { opacity: 0; transform: translateY(-8px) scale(0.97); } + to { opacity: 1; transform: translateY(0) scale(1); } } @keyframes fadeIn { @@ -64,41 +34,56 @@ to { transform: translateX(0); } } +@keyframes slideInLeft { + from { transform: translateX(-100%); } + to { transform: translateX(0); } +} + @keyframes fadeInUp { - from { - opacity: 0; - transform: translateY(8px); - } - to { - opacity: 1; - transform: translateY(0); - } + from { opacity: 0; transform: translateY(6px); } + to { opacity: 1; transform: translateY(0); } } @keyframes toast-in { - from { - opacity: 0; - transform: translateY(20px); - } - to { - opacity: 1; - transform: translateY(0); - } + from { opacity: 0; transform: translateY(16px) scale(0.97); } + to { opacity: 1; transform: translateY(0) scale(1); } +} + +@keyframes sidebar-enter { + from { opacity: 0; transform: translateX(100%); } + to { opacity: 1; transform: translateX(0); } +} + +@keyframes sidebar-enter-left { + from { opacity: 0; transform: translateX(-100%); } + to { opacity: 1; transform: translateX(0); } } /* Utility animation classes */ .animate-fade-in { - animation: fade-in 0.4s cubic-bezier(0.2, 0.8, 0.2, 1); + animation: fade-in 0.35s cubic-bezier(0.22, 0.68, 0, 1); } .animate-slide-up { - animation: slide-up 0.3s cubic-bezier(0.2, 0.8, 0.2, 1); + animation: slide-up 0.3s cubic-bezier(0.22, 0.68, 0, 1); } .animate-scale-in { - animation: scale-in 0.3s cubic-bezier(0.2, 0.8, 0.2, 1); + animation: scale-in 0.3s cubic-bezier(0.22, 0.68, 0, 1); } .animate-toast-in { - animation: toast-in 0.5s cubic-bezier(0.2, 0.8, 0.2, 1); + animation: toast-in 0.4s cubic-bezier(0.22, 0.68, 0, 1); } + +/* Staggered children animation */ +.stagger-children > * { + animation: fadeInUp 0.3s cubic-bezier(0.22, 0.68, 0, 1) backwards; +} + +.stagger-children > *:nth-child(1) { animation-delay: 0ms; } +.stagger-children > *:nth-child(2) { animation-delay: 40ms; } +.stagger-children > *:nth-child(3) { animation-delay: 80ms; } +.stagger-children > *:nth-child(4) { animation-delay: 120ms; } +.stagger-children > *:nth-child(5) { animation-delay: 160ms; } +.stagger-children > *:nth-child(6) { animation-delay: 200ms; } diff --git a/app/styles/variables.css b/app/styles/variables.css index 99edb7f..60ac745 100644 --- a/app/styles/variables.css +++ b/app/styles/variables.css @@ -1,33 +1,42 @@ -/* CSS Custom Properties - Liquid Glass Design System */ +/* CSS Custom Properties - Liquid Glass Design System v5 */ :root { - --font-family-system: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif; + --font-family-system: "SF Pro Display", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans SC", sans-serif; /* Light Mode Palette */ --bg-color-light: #f0f2f5; - --bg-image-light: linear-gradient(120deg, #fdfbfb 0%, #ebedee 100%); - --text-color-light: #1d1d1f; - --text-color-secondary-light: #6e6e73; - --accent-color-light: #007aff; - --glass-bg-light: rgba(242, 242, 247, 0.8); - --glass-border-light: rgba(255, 255, 255, 0.5); - --shadow-color-light: rgba(0, 0, 0, 0.1); + --bg-image-light: linear-gradient(135deg, #fdfbfb 0%, #e8ecf1 50%, #f0f2f5 100%); + --text-color-light: #1a1a2e; + --text-color-secondary-light: #64748b; + --accent-color-light: #2563eb; + --accent-hover-light: #1d4ed8; + --glass-bg-light: rgba(255, 255, 255, 0.72); + --glass-border-light: rgba(255, 255, 255, 0.45); + --shadow-color-light: rgba(0, 0, 0, 0.08); /* Dark Mode Palette */ - --bg-color-dark: #121212; - --bg-image-dark: linear-gradient(120deg, #272B30 0%, #121212 100%); - --text-color-dark: #f5f5f7; - --text-color-secondary-dark: #8e8e93; - --accent-color-dark: #0a84ff; - --glass-bg-dark: rgba(28, 28, 30, 0.75); - --glass-border-dark: rgba(60, 60, 60, 0.7); - --shadow-color-dark: rgba(0, 0, 0, 0.3); + --bg-color-dark: #0a0a0f; + --bg-image-dark: linear-gradient(135deg, #0a0a0f 0%, #141420 50%, #0d0d14 100%); + --text-color-dark: #f0f0f5; + --text-color-secondary-dark: #7c8298; + --accent-color-dark: #3b82f6; + --accent-hover-dark: #60a5fa; + --glass-bg-dark: rgba(22, 22, 35, 0.78); + --glass-border-dark: rgba(255, 255, 255, 0.06); + --shadow-color-dark: rgba(0, 0, 0, 0.45); /* Universal Variables */ + --radius-xs: 0.5rem; + --radius-sm: 0.75rem; + --radius-md: 1rem; + --radius-lg: 1.25rem; --radius-2xl: 1.5rem; --radius-full: 9999px; - --shadow-sm: 0 2px 4px var(--shadow-color); - --shadow-md: 0 4px 12px var(--shadow-color); - --transition-fluid: 0.4s cubic-bezier(0.2, 0.8, 0.2, 1); + --shadow-sm: 0 1px 3px var(--shadow-color), 0 1px 2px var(--shadow-color); + --shadow-md: 0 4px 16px var(--shadow-color), 0 2px 4px var(--shadow-color); + --shadow-lg: 0 8px 32px var(--shadow-color), 0 4px 8px var(--shadow-color); + --transition-fluid: 0.35s cubic-bezier(0.22, 0.68, 0, 1); + --transition-spring: 0.5s cubic-bezier(0.34, 1.56, 0.64, 1); + --transition-snappy: 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94); /* Active Theme Variables (default: light) */ --bg-color: var(--bg-color-light); @@ -35,12 +44,12 @@ --text-color: var(--text-color-light); --text-color-secondary: var(--text-color-secondary-light); --accent-color: var(--accent-color-light); + --accent-hover: var(--accent-hover-light); --glass-bg: var(--glass-bg-light); --glass-border: var(--glass-border-light); --shadow-color: var(--shadow-color-light); - --background: #f0f2f5; - --foreground: #1d1d1f; + --foreground: #1a1a2e; } body { @@ -49,6 +58,7 @@ body { --text-color: var(--text-color-light); --text-color-secondary: var(--text-color-secondary-light); --accent-color: var(--accent-color-light); + --accent-hover: var(--accent-hover-light); --glass-bg: var(--glass-bg-light); --glass-border: var(--glass-border-light); --shadow-color: var(--shadow-color-light); @@ -58,8 +68,7 @@ body { background-attachment: fixed; color: var(--text-color); font-family: var(--font-family-system); - transition: background 0.3s ease; - + transition: background 0.4s ease; -webkit-overflow-scrolling: touch; overscroll-behavior-y: none; } @@ -71,10 +80,10 @@ body.dark, --text-color: var(--text-color-dark); --text-color-secondary: var(--text-color-secondary-dark); --accent-color: var(--accent-color-dark); + --accent-hover: var(--accent-hover-dark); --glass-bg: var(--glass-bg-dark); --glass-border: var(--glass-border-dark); --shadow-color: var(--shadow-color-dark); - - --background: #121212; - --foreground: #f5f5f7; + --background: #0a0a0f; + --foreground: #f0f0f5; } diff --git a/components/favorites/FavoritesSidebar.tsx b/components/favorites/FavoritesSidebar.tsx index 9a5b711..bd71c6f 100644 --- a/components/favorites/FavoritesSidebar.tsx +++ b/components/favorites/FavoritesSidebar.tsx @@ -1,8 +1,3 @@ -/** - * FavoritesSidebar - Main favorites sidebar component - * Positioned on the left side of the screen (opposite to WatchHistorySidebar) - */ - 'use client'; import { useState, useEffect, useRef } from 'react'; @@ -27,12 +22,10 @@ export function FavoritesSidebar({ isPremium = false }: { isPremium?: boolean }) const sidebarRef = useRef(null); const cleanupFocusTrapRef = useRef<(() => void) | null>(null); - // Setup focus trap when sidebar opens useEffect(() => { if (isOpen && sidebarRef.current) { cleanupFocusTrapRef.current = trapFocus(sidebarRef.current); } - return () => { if (cleanupFocusTrapRef.current) { cleanupFocusTrapRef.current(); @@ -41,24 +34,14 @@ export function FavoritesSidebar({ isPremium = false }: { isPremium?: boolean }) }; }, [isOpen]); - // Handle escape key to close sidebar useEffect(() => { const handleEscape = (e: KeyboardEvent) => { - if (e.key === 'Escape' && isOpen) { - setIsOpen(false); - } - }; - - if (isOpen) { - document.addEventListener('keydown', handleEscape); - } - - return () => { - document.removeEventListener('keydown', handleEscape); + if (e.key === 'Escape' && isOpen) setIsOpen(false); }; + if (isOpen) document.addEventListener('keydown', handleEscape); + return () => document.removeEventListener('keydown', handleEscape); }, [isOpen]); - // Handle delete confirmation const handleDeleteItem = (videoId: string | number, source: string) => { setDeleteConfirm({ isOpen: true, videoId: String(videoId), source }); }; @@ -68,15 +51,8 @@ export function FavoritesSidebar({ isPremium = false }: { isPremium?: boolean }) }; const confirmDelete = () => { - if (deleteConfirm.isClearAll) { - clearFavorites(); - } else if (deleteConfirm.videoId && deleteConfirm.source) { - removeFavorite(deleteConfirm.videoId, deleteConfirm.source); - } - setDeleteConfirm({ isOpen: false }); - }; - - const cancelDelete = () => { + if (deleteConfirm.isClearAll) clearFavorites(); + else if (deleteConfirm.videoId && deleteConfirm.source) removeFavorite(deleteConfirm.videoId, deleteConfirm.source); setDeleteConfirm({ isOpen: false }); }; @@ -85,16 +61,16 @@ export function FavoritesSidebar({ isPremium = false }: { isPremium?: boolean }) {/* Toggle Button - Left side */} {/* Backdrop */} {isOpen && (
setIsOpen(false)} /> )} @@ -109,36 +85,21 @@ export function FavoritesSidebar({ isPremium = false }: { isPremium?: boolean }) transform: isOpen ? 'translate3d(0, 0, 0)' : 'translate3d(-100%, 0, 0)', willChange: isOpen ? 'transform' : 'auto' }} - className={`fixed top-0 left-0 bottom-0 w-[85%] sm:w-[90%] max-w-[420px] z-[2000] bg-[var(--glass-bg)] backdrop-blur-[8px] saturate-[120%] border-r border-[var(--glass-border)] rounded-tr-[var(--radius-2xl)] rounded-br-[var(--radius-2xl)] p-6 flex flex-col shadow-[0_8px_32px_rgba(0,0,0,0.2)] transition-transform duration-250 ease-out`} + className="fixed top-0 left-0 bottom-0 w-[85%] sm:w-[90%] max-w-[400px] z-[2000] bg-[var(--glass-bg)] backdrop-blur-[20px] saturate-[160%] [-webkit-backdrop-filter:blur(20px)_saturate(160%)] border-r border-[var(--glass-border)] rounded-r-[var(--radius-2xl)] p-5 sm:p-6 flex flex-col shadow-[var(--shadow-lg)] transition-transform duration-300 [transition-timing-function:cubic-bezier(0.22,0.68,0,1)]" > setIsOpen(false)} /> - - - - 0} - onClearAll={handleClearAll} - /> + + 0} onClearAll={handleClearAll} /> - {/* Watch History Sidebar - Right side */} - {/* Confirm Dialog */} setDeleteConfirm({ isOpen: false })} confirmText="确定" cancelText="取消" variant="danger" diff --git a/components/history/WatchHistorySidebar.tsx b/components/history/WatchHistorySidebar.tsx index 4d6bf6e..b8ee9ad 100644 --- a/components/history/WatchHistorySidebar.tsx +++ b/components/history/WatchHistorySidebar.tsx @@ -1,8 +1,3 @@ -/** - * Watch History Sidebar Component - * 观看历史侧边栏组件 - Main layout and state management - */ - 'use client'; import { useState, useEffect, useRef } from 'react'; @@ -25,12 +20,10 @@ export function WatchHistorySidebar({ isPremium = false }: { isPremium?: boolean const sidebarRef = useRef(null); const cleanupFocusTrapRef = useRef<(() => void) | null>(null); - // Setup focus trap when sidebar opens useEffect(() => { if (isOpen && sidebarRef.current) { cleanupFocusTrapRef.current = trapFocus(sidebarRef.current); } - return () => { if (cleanupFocusTrapRef.current) { cleanupFocusTrapRef.current(); @@ -39,24 +32,14 @@ export function WatchHistorySidebar({ isPremium = false }: { isPremium?: boolean }; }, [isOpen]); - // Handle escape key to close sidebar useEffect(() => { const handleEscape = (e: KeyboardEvent) => { - if (e.key === 'Escape' && isOpen) { - setIsOpen(false); - } - }; - - if (isOpen) { - document.addEventListener('keydown', handleEscape); - } - - return () => { - document.removeEventListener('keydown', handleEscape); + if (e.key === 'Escape' && isOpen) setIsOpen(false); }; + if (isOpen) document.addEventListener('keydown', handleEscape); + return () => document.removeEventListener('keydown', handleEscape); }, [isOpen]); - // Handle delete confirmation const handleDeleteItem = (showIdentifier: string) => { setDeleteConfirm({ isOpen: true, showIdentifier }); }; @@ -66,15 +49,8 @@ export function WatchHistorySidebar({ isPremium = false }: { isPremium?: boolean }; const confirmDelete = () => { - if (deleteConfirm.isClearAll) { - clearHistory(); - } else if (deleteConfirm.showIdentifier) { - removeFromHistory(deleteConfirm.showIdentifier); - } - setDeleteConfirm({ isOpen: false }); - }; - - const cancelDelete = () => { + if (deleteConfirm.isClearAll) clearHistory(); + else if (deleteConfirm.showIdentifier) removeFromHistory(deleteConfirm.showIdentifier); setDeleteConfirm({ isOpen: false }); }; @@ -83,16 +59,16 @@ export function WatchHistorySidebar({ isPremium = false }: { isPremium?: boolean {/* Toggle Button */} {/* Backdrop */} {isOpen && (
setIsOpen(false)} /> )} @@ -107,33 +83,19 @@ export function WatchHistorySidebar({ isPremium = false }: { isPremium?: boolean transform: isOpen ? 'translate3d(0, 0, 0)' : 'translate3d(100%, 0, 0)', willChange: isOpen ? 'transform' : 'auto' }} - className={`fixed top-0 right-0 bottom-0 w-[85%] sm:w-[90%] max-w-[420px] z-[2000] bg-[var(--glass-bg)] backdrop-blur-[8px] saturate-[120%] border-l border-[var(--glass-border)] rounded-tl-[var(--radius-2xl)] rounded-bl-[var(--radius-2xl)] p-6 flex flex-col shadow-[0_8px_32px_rgba(0,0,0,0.2)] transition-transform duration-250 ease-out`} + className="fixed top-0 right-0 bottom-0 w-[85%] sm:w-[90%] max-w-[400px] z-[2000] bg-[var(--glass-bg)] backdrop-blur-[20px] saturate-[160%] [-webkit-backdrop-filter:blur(20px)_saturate(160%)] border-l border-[var(--glass-border)] rounded-l-[var(--radius-2xl)] p-5 sm:p-6 flex flex-col shadow-[var(--shadow-lg)] transition-transform duration-300 [transition-timing-function:cubic-bezier(0.22,0.68,0,1)]" > setIsOpen(false)} /> - - - - 0} - onClearAll={handleClearAll} - /> + + 0} onClearAll={handleClearAll} /> - {/* Confirm Dialog */} setDeleteConfirm({ isOpen: false })} confirmText="删除" cancelText="取消" variant="danger" diff --git a/components/home/PopularFeatures.tsx b/components/home/PopularFeatures.tsx index 597110d..d9384cf 100644 --- a/components/home/PopularFeatures.tsx +++ b/components/home/PopularFeatures.tsx @@ -93,29 +93,25 @@ export function PopularFeatures({ onSearch }: PopularFeaturesProps) { return (
- {/* Content Type Toggle (Capsule Liquid Glass - Fixed & Centered) */} + {/* Content Type Toggle */} {!effectiveRecommendSelected && ( -
-
- {/* Sliding Indicator */} +
+
- diff --git a/components/layout/Navbar.tsx b/components/layout/Navbar.tsx index ad8c2e0..24d2262 100644 --- a/components/layout/Navbar.tsx +++ b/components/layout/Navbar.tsx @@ -28,94 +28,84 @@ export function Navbar({ onReset, isPremiumMode = false }: NavbarProps) { }; const iconBtnClass = ` - w-8 h-8 sm:w-10 sm:h-10 + w-9 h-9 sm:w-10 sm:h-10 flex items-center justify-center rounded-[var(--radius-full)] bg-[var(--glass-bg)] + backdrop-blur-[8px] + [-webkit-backdrop-filter:blur(8px)] border border-[var(--glass-border)] - text-[var(--text-color)] - hover:bg-[color-mix(in_srgb,var(--accent-color)_10%,transparent)] + text-[var(--text-color-secondary)] + hover:text-[var(--text-color)] + hover:bg-[color-mix(in_srgb,var(--accent-color)_8%,var(--glass-bg))] + hover:border-[color-mix(in_srgb,var(--accent-color)_15%,var(--glass-border))] transition-all duration-200 cursor-pointer `; return ( -