(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",