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/)**
-[](https://github.com/KuekHaoYang/KVideo)
+[](https://github.com/KuekHaoYang/KVideo)
[](https://nextjs.org/)
[](https://react.dev/)
[](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 (
-