diff --git a/components/player/DesktopVideoPlayer.tsx b/components/player/DesktopVideoPlayer.tsx index e4c0198..e7f5571 100644 --- a/components/player/DesktopVideoPlayer.tsx +++ b/components/player/DesktopVideoPlayer.tsx @@ -113,73 +113,78 @@ export function DesktopVideoPlayer({ return (
isPlaying && setShowControls(false)} > - {/* Video Element */} -
); } diff --git a/components/player/VideoPlayer.tsx b/components/player/VideoPlayer.tsx index 2d3aad0..f9b7bee 100644 --- a/components/player/VideoPlayer.tsx +++ b/components/player/VideoPlayer.tsx @@ -173,7 +173,7 @@ export function VideoPlayer({ } return ( - + {/* Mode Indicator Badge - controlled by settings */} {showModeIndicator && (
diff --git a/components/player/desktop/DesktopMoreMenu.tsx b/components/player/desktop/DesktopMoreMenu.tsx index fd41499..cea8e69 100644 --- a/components/player/desktop/DesktopMoreMenu.tsx +++ b/components/player/desktop/DesktopMoreMenu.tsx @@ -56,11 +56,21 @@ export function DesktopMoreMenu({ aggressive: '激进' }; + const [isFullscreen, setIsFullscreen] = React.useState(false); + + React.useEffect(() => { + const updateFullscreen = () => { + setIsFullscreen(!!document.fullscreenElement); + }; + document.addEventListener('fullscreenchange', updateFullscreen); + updateFullscreen(); + return () => document.removeEventListener('fullscreenchange', updateFullscreen); + }, []); + React.useEffect(() => { if (showMoreMenu && buttonRef.current && containerRef.current) { const buttonRect = buttonRef.current.getBoundingClientRect(); const containerRect = containerRef.current.getBoundingClientRect(); - setMenuPosition({ top: buttonRect.bottom - containerRect.top + 10, left: buttonRect.left - containerRect.left @@ -68,11 +78,22 @@ export function DesktopMoreMenu({ } }, [showMoreMenu, containerRef]); + // Auto-close menu on scroll + React.useEffect(() => { + if (!showMoreMenu) return; + const handleScroll = () => { + if (showMoreMenu) { + onToggleMoreMenu(); + } + }; + window.addEventListener('scroll', handleScroll, { passive: true }); + return () => window.removeEventListener('scroll', handleScroll); + }, [showMoreMenu, onToggleMoreMenu]); + const handleToggle = () => { if (!showMoreMenu && buttonRef.current && containerRef.current) { const buttonRect = buttonRef.current.getBoundingClientRect(); const containerRect = containerRef.current.getBoundingClientRect(); - setMenuPosition({ top: buttonRect.bottom - containerRect.top + 10, left: buttonRect.left - containerRect.left @@ -83,10 +104,11 @@ export function DesktopMoreMenu({ const MenuContent = (
) : ( )} {/* Divider */} -
+
{/* Show Mode Indicator Switch */} -
-
- +
+
+ 显示模式指示器
{/* Ad Filter Mode Selector */} -
-
- +
+
+ 广告过滤
{/* Custom Ad Filter Mode Selector */}
{isAdFilterOpen && ( <>
setAdFilterOpen(false)} /> -
+
{Object.entries(AD_FILTER_LABELS).map(([mode, label]) => ( ))}
@@ -184,97 +208,103 @@ export function DesktopMoreMenu({
{/* Auto Next Episode Switch */} -
-
- +
+
+ 自动下一集
{/* Skip Intro Switch */} -
-
-
- +
+
+
+ 跳过片头
{/* Expandable Input */} {autoSkipIntro && ( -
- 时长: +
+ 时长: setSkipIntroSeconds(parseInt(e.target.value) || 0)} - className="w-16 px-2 py-1 text-sm text-center bg-[var(--glass-bg)] border border-[var(--glass-border)] rounded-[var(--radius-2xl)] text-[var(--text-color)] focus:outline-none focus:border-[var(--accent-color)] no-spinner" + className="w-12 sm:w-16 px-1.5 py-0.5 sm:px-2 sm:py-1 text-xs sm:text-sm text-center bg-[var(--glass-bg)] border border-[var(--glass-border)] rounded-[var(--radius-2xl)] text-[var(--text-color)] focus:outline-none focus:border-[var(--accent-color)] no-spinner" onClick={(e) => e.stopPropagation()} /> - +
)}
{/* Skip Outro Switch */} -
-
-
- +
+
+
+ 跳过片尾
{/* Expandable Input */} {autoSkipOutro && ( -
- 剩余: +
+ 剩余: setSkipOutroSeconds(parseInt(e.target.value) || 0)} - className="w-16 px-2 py-1 text-sm text-center bg-[var(--glass-bg)] border border-[var(--glass-border)] rounded-[var(--radius-2xl)] text-[var(--text-color)] focus:outline-none focus:border-[var(--accent-color)] no-spinner" + className="w-12 sm:w-16 px-1.5 py-0.5 sm:px-2 sm:py-1 text-xs sm:text-sm text-center bg-[var(--glass-bg)] border border-[var(--glass-border)] rounded-[var(--radius-2xl)] text-[var(--text-color)] focus:outline-none focus:border-[var(--accent-color)] no-spinner" onClick={(e) => e.stopPropagation()} /> - +
)}
@@ -288,11 +318,11 @@ export function DesktopMoreMenu({ onClick={handleToggle} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave} - className="group flex items-center justify-center w-12 h-12 rounded-full bg-black/40 hover:bg-black/60 backdrop-blur-sm transition-all duration-300 hover:scale-110 active:scale-95" + className="group flex items-center justify-center w-10 h-10 sm:w-12 sm:h-12 rounded-full bg-black/40 hover:bg-black/60 backdrop-blur-sm transition-all duration-300 hover:scale-110 active:scale-95" aria-label="更多选项" title="更多选项" > - + {/* More Menu Dropdown (Portal) */} diff --git a/components/player/desktop/DesktopOverlay.tsx b/components/player/desktop/DesktopOverlay.tsx index f3fd4d7..1d98fdc 100644 --- a/components/player/desktop/DesktopOverlay.tsx +++ b/components/player/desktop/DesktopOverlay.tsx @@ -73,8 +73,8 @@ export function DesktopOverlay({ return ( <> - {/* More Menu (Top Left) */} -
+ {/* More Menu (Top Left) - Moved slightly down and lower z-index to stay below navbar */} +
- {/* Speed Menu (Top Right) */} -
+ {/* Speed Menu (Top Right) - Moved slightly down and lower z-index */} +
(null); const [menuPosition, setMenuPosition] = React.useState({ top: 0, left: 0 }); + const [isFullscreen, setIsFullscreen] = React.useState(false); + + React.useEffect(() => { + const updateFullscreen = () => { + setIsFullscreen(!!document.fullscreenElement); + }; + document.addEventListener('fullscreenchange', updateFullscreen); + updateFullscreen(); + return () => document.removeEventListener('fullscreenchange', updateFullscreen); + }, []); + React.useEffect(() => { if (showSpeedMenu && buttonRef.current && containerRef.current) { const buttonRect = buttonRef.current.getBoundingClientRect(); @@ -37,6 +48,18 @@ export function DesktopSpeedMenu({ } }, [showSpeedMenu, containerRef]); + // Auto-close menu on scroll + React.useEffect(() => { + if (!showSpeedMenu) return; + const handleScroll = () => { + if (showSpeedMenu) { + onToggleSpeedMenu(); + } + }; + window.addEventListener('scroll', handleScroll, { passive: true }); + return () => window.removeEventListener('scroll', handleScroll); + }, [showSpeedMenu, onToggleSpeedMenu]); + const handleToggle = () => { if (!showSpeedMenu && buttonRef.current && containerRef.current) { const buttonRect = buttonRef.current.getBoundingClientRect(); @@ -53,10 +76,11 @@ export function DesktopSpeedMenu({ const MenuContent = (
onSpeedChange(speed)} - className={`w-full px-4 py-1.5 rounded-[var(--radius-2xl)] text-sm font-medium transition-colors ${playbackRate === speed + className={`w-full px-3 py-1 sm:px-4 sm:py-1.5 rounded-[var(--radius-2xl)] text-xs sm:text-sm font-medium transition-colors ${playbackRate === speed ? 'bg-[var(--accent-color)] text-white' : 'text-[var(--text-color)] hover:bg-[color-mix(in_srgb,var(--accent-color)_15%,transparent)]' }`} @@ -84,7 +108,7 @@ export function DesktopSpeedMenu({ onClick={handleToggle} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave} - className="group flex items-center justify-center w-12 h-12 rounded-full bg-black/40 hover:bg-black/60 backdrop-blur-sm transition-all duration-300 hover:scale-110 active:scale-95 text-white/90 font-medium text-sm" + className="group flex items-center justify-center w-10 h-10 sm:w-12 sm:h-12 rounded-full bg-black/40 hover:bg-black/60 backdrop-blur-sm transition-all duration-300 hover:scale-110 active:scale-95 text-white/90 font-medium text-xs sm:text-sm" aria-label="播放速度" > {playbackRate}x diff --git a/package-lock.json b/package-lock.json index 706f06a..62bc253 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,19 @@ { "name": "kvideo", - "version": "4.0.0", + "version": "4.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "kvideo", - "version": "4.0.0", + "version": "4.0.1", "dependencies": { "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", "@vercel/analytics": "^1.6.1", "hls.js": "^1.6.15", - "lucide-react": "^0.562.0", + "lucide-react": "^0.563.0", "next": "16.1.4", "react": "19.2.3", "react-dom": "19.2.3", @@ -5723,9 +5723,9 @@ } }, "node_modules/lucide-react": { - "version": "0.562.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.562.0.tgz", - "integrity": "sha512-82hOAu7y0dbVuFfmO4bYF1XEwYk/mEbM5E+b1jgci/udUBEE/R7LF5Ip0CCEmXe8AybRM8L+04eP+LGZeDvkiw==", + "version": "0.563.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.563.0.tgz", + "integrity": "sha512-8dXPB2GI4dI8jV4MgUDGBeLdGk8ekfqVZ0BdLcrRzocGgG75ltNEmWS+gE7uokKF/0oSUuczNDT+g9hFJ23FkA==", "license": "ISC", "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" diff --git a/package.json b/package.json index eb05edb..592076c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "kvideo", - "version": "4.0.0", + "version": "4.0.1", "private": true, "scripts": { "dev": "next dev", @@ -15,7 +15,7 @@ "@dnd-kit/utilities": "^3.2.2", "@vercel/analytics": "^1.6.1", "hls.js": "^1.6.15", - "lucide-react": "^0.562.0", + "lucide-react": "^0.563.0", "next": "16.1.4", "react": "19.2.3", "react-dom": "19.2.3",