mirror of
https://github.com/KuekHaoYang/KVideo.git
synced 2026-08-12 23:33:43 +08:00
feat: Implement orientation-aware progress bar interaction for forced landscape mode on iOS and update player dependencies.
This commit is contained in:
@@ -42,9 +42,32 @@ export function DesktopVideoPlayer({
|
||||
const { fullscreenType: settingsFullscreenType } = usePlayerSettings();
|
||||
const isIOS = useIsIOS();
|
||||
|
||||
// State to track if device is in landscape mode
|
||||
const [isLandscape, setIsLandscape] = React.useState(true);
|
||||
|
||||
React.useEffect(() => {
|
||||
const checkOrientation = () => {
|
||||
// Check if width > height
|
||||
if (typeof window !== 'undefined') {
|
||||
setIsLandscape(window.innerWidth > window.innerHeight);
|
||||
}
|
||||
};
|
||||
|
||||
checkOrientation();
|
||||
window.addEventListener('resize', checkOrientation);
|
||||
window.addEventListener('orientationchange', checkOrientation);
|
||||
return () => {
|
||||
window.removeEventListener('resize', checkOrientation);
|
||||
window.removeEventListener('orientationchange', checkOrientation);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Force windowed fullscreen on iOS to avoid native player hijacking
|
||||
const fullscreenType = isIOS ? 'window' : settingsFullscreenType;
|
||||
|
||||
// Check if we need to force landscape (iOS + Fullscreen + Portrait)
|
||||
const shouldForceLandscape = data.isFullscreen && fullscreenType === 'window' && isIOS && !isLandscape;
|
||||
|
||||
// Initialize HLS Player
|
||||
useHlsPlayer({
|
||||
videoRef: refs.videoRef,
|
||||
@@ -84,7 +107,8 @@ export function DesktopVideoPlayer({
|
||||
refs,
|
||||
data,
|
||||
actions,
|
||||
fullscreenType
|
||||
fullscreenType,
|
||||
isForceLandscape: shouldForceLandscape
|
||||
});
|
||||
|
||||
// Auto-skip intro/outro and auto-next episode
|
||||
@@ -119,29 +143,6 @@ export function DesktopVideoPlayer({
|
||||
handleVideoError,
|
||||
} = logic;
|
||||
|
||||
// State to track if device is in landscape mode
|
||||
const [isLandscape, setIsLandscape] = React.useState(true);
|
||||
|
||||
React.useEffect(() => {
|
||||
const checkOrientation = () => {
|
||||
// Check if width > height
|
||||
if (typeof window !== 'undefined') {
|
||||
setIsLandscape(window.innerWidth > window.innerHeight);
|
||||
}
|
||||
};
|
||||
|
||||
checkOrientation();
|
||||
window.addEventListener('resize', checkOrientation);
|
||||
window.addEventListener('orientationchange', checkOrientation);
|
||||
return () => {
|
||||
window.removeEventListener('resize', checkOrientation);
|
||||
window.removeEventListener('orientationchange', checkOrientation);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Check if we need to force landscape (iOS + Fullscreen + Portrait)
|
||||
const shouldForceLandscape = data.isFullscreen && fullscreenType === 'window' && isIOS && !isLandscape;
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={containerRef}
|
||||
|
||||
@@ -23,30 +23,68 @@ export function DesktopSpeedMenu({
|
||||
containerRef
|
||||
}: DesktopSpeedMenuProps) {
|
||||
const buttonRef = React.useRef<HTMLButtonElement>(null);
|
||||
const [menuPosition, setMenuPosition] = React.useState({ top: 0, left: 0 });
|
||||
const menuRef = React.useRef<HTMLDivElement>(null);
|
||||
const [menuPosition, setMenuPosition] = React.useState({ top: 0, left: 0, maxHeight: 'none', openUpward: false });
|
||||
|
||||
const [isFullscreen, setIsFullscreen] = React.useState(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
const updateFullscreen = () => {
|
||||
setIsFullscreen(!!document.fullscreenElement);
|
||||
// Check both native fullscreen and window fullscreen (CSS-based)
|
||||
const nativeFullscreen = !!document.fullscreenElement;
|
||||
const windowFullscreen = containerRef.current?.closest('.is-web-fullscreen') !== null;
|
||||
setIsFullscreen(nativeFullscreen || windowFullscreen);
|
||||
};
|
||||
document.addEventListener('fullscreenchange', updateFullscreen);
|
||||
// Also check periodically for window fullscreen changes (CSS class based)
|
||||
const interval = setInterval(updateFullscreen, 500);
|
||||
updateFullscreen();
|
||||
return () => document.removeEventListener('fullscreenchange', updateFullscreen);
|
||||
}, []);
|
||||
return () => {
|
||||
document.removeEventListener('fullscreenchange', updateFullscreen);
|
||||
clearInterval(interval);
|
||||
};
|
||||
}, [containerRef]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (showSpeedMenu && buttonRef.current && containerRef.current) {
|
||||
const buttonRect = buttonRef.current.getBoundingClientRect();
|
||||
const containerRect = containerRef.current.getBoundingClientRect();
|
||||
// Calculate menu position with available space awareness
|
||||
const calculateMenuPosition = React.useCallback(() => {
|
||||
if (!buttonRef.current || !containerRef.current) return;
|
||||
|
||||
const buttonRect = buttonRef.current.getBoundingClientRect();
|
||||
const containerRect = containerRef.current.getBoundingClientRect();
|
||||
const viewportHeight = window.innerHeight;
|
||||
|
||||
// Space available below and above the button
|
||||
const spaceBelow = viewportHeight - buttonRect.bottom - 20; // 20px margin
|
||||
const spaceAbove = buttonRect.top - containerRect.top - 20;
|
||||
|
||||
// Estimate menu height (or use actual if already rendered)
|
||||
const estimatedMenuHeight = 250; // approximate height of speed menu
|
||||
const actualMenuHeight = menuRef.current?.offsetHeight || estimatedMenuHeight;
|
||||
|
||||
// Determine if we should open upward
|
||||
const openUpward = spaceBelow < Math.min(actualMenuHeight, 200) && spaceAbove > spaceBelow;
|
||||
|
||||
// Calculate max-height based on available space
|
||||
const maxHeight = openUpward
|
||||
? Math.min(spaceAbove, actualMenuHeight)
|
||||
: Math.min(spaceBelow, viewportHeight * 0.7);
|
||||
|
||||
if (openUpward) {
|
||||
setMenuPosition({
|
||||
top: buttonRect.top - containerRect.top - 10, // Position above button
|
||||
left: buttonRect.right - containerRect.left,
|
||||
maxHeight: `${maxHeight}px`,
|
||||
openUpward: true
|
||||
});
|
||||
} else {
|
||||
setMenuPosition({
|
||||
top: buttonRect.bottom - containerRect.top + 10,
|
||||
left: buttonRect.right - containerRect.left
|
||||
left: buttonRect.right - containerRect.left,
|
||||
maxHeight: `${maxHeight}px`,
|
||||
openUpward: false
|
||||
});
|
||||
}
|
||||
}, [showSpeedMenu, containerRef]);
|
||||
}, [containerRef]);
|
||||
|
||||
// Auto-close menu on scroll
|
||||
React.useEffect(() => {
|
||||
@@ -60,28 +98,33 @@ export function DesktopSpeedMenu({
|
||||
return () => window.removeEventListener('scroll', handleScroll);
|
||||
}, [showSpeedMenu, onToggleSpeedMenu]);
|
||||
|
||||
const handleToggle = () => {
|
||||
if (!showSpeedMenu && buttonRef.current && containerRef.current) {
|
||||
const buttonRect = buttonRef.current.getBoundingClientRect();
|
||||
const containerRect = containerRef.current.getBoundingClientRect();
|
||||
// Recalculate position when menu opens
|
||||
React.useEffect(() => {
|
||||
if (showSpeedMenu) {
|
||||
calculateMenuPosition();
|
||||
// Recalculate after a small delay to get actual menu height
|
||||
const timer = setTimeout(calculateMenuPosition, 50);
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [showSpeedMenu, calculateMenuPosition]);
|
||||
|
||||
setMenuPosition({
|
||||
top: buttonRect.bottom - containerRect.top + 10,
|
||||
left: buttonRect.right - containerRect.left
|
||||
});
|
||||
const handleToggle = () => {
|
||||
if (!showSpeedMenu) {
|
||||
calculateMenuPosition();
|
||||
}
|
||||
onToggleSpeedMenu();
|
||||
};
|
||||
|
||||
|
||||
const MenuContent = (
|
||||
<div
|
||||
className={`absolute z-[9999] bg-[var(--glass-bg)] backdrop-blur-[25px] saturate-[180%] rounded-[var(--radius-2xl)] border border-[var(--glass-border)] shadow-[var(--shadow-md)] p-1 sm:p-1.5 w-fit min-w-[3.5rem] sm:min-w-[4.5rem] animate-in fade-in zoom-in-95 duration-200 ${isFullscreen ? 'max-h-[60vh] overflow-y-auto' : ''
|
||||
}`}
|
||||
ref={menuRef}
|
||||
className={`absolute z-[9999] bg-[var(--glass-bg)] backdrop-blur-[25px] saturate-[180%] rounded-[var(--radius-2xl)] border border-[var(--glass-border)] shadow-[var(--shadow-md)] p-1 sm:p-1.5 w-fit min-w-[3.5rem] sm:min-w-[4.5rem] animate-in fade-in zoom-in-95 duration-200 overflow-y-auto`}
|
||||
style={{
|
||||
top: `${menuPosition.top}px`,
|
||||
top: menuPosition.openUpward ? 'auto' : `${menuPosition.top}px`,
|
||||
bottom: menuPosition.openUpward ? `calc(100% - ${menuPosition.top}px + 10px)` : 'auto',
|
||||
left: `${menuPosition.left}px`,
|
||||
transform: 'translateX(-100%)', // Align right edge
|
||||
maxHeight: isFullscreen ? menuPosition.maxHeight : 'none',
|
||||
}}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
|
||||
@@ -6,6 +6,7 @@ interface UseProgressControlsProps {
|
||||
duration: number;
|
||||
setCurrentTime: (time: number) => void;
|
||||
isDraggingProgressRef: React.MutableRefObject<boolean>;
|
||||
isRotated?: boolean;
|
||||
}
|
||||
|
||||
export function useProgressControls({
|
||||
@@ -13,19 +14,34 @@ export function useProgressControls({
|
||||
progressBarRef,
|
||||
duration,
|
||||
setCurrentTime,
|
||||
isDraggingProgressRef
|
||||
isDraggingProgressRef,
|
||||
isRotated = false
|
||||
}: UseProgressControlsProps) {
|
||||
const lastDragTimeRef = useRef<number>(0);
|
||||
|
||||
const getEventPos = useCallback((e: any, rect: DOMRect) => {
|
||||
// Handle both mouse and touch events
|
||||
const clientX = e.clientX || (e.touches && e.touches[0]?.clientX) || 0;
|
||||
const clientY = e.clientY || (e.touches && e.touches[0]?.clientY) || 0;
|
||||
|
||||
if (isRotated) {
|
||||
// When rotated 90deg, visual left->right is physical top->bottom
|
||||
// The bounding rect height is the visual width of the bar
|
||||
return Math.max(0, Math.min(1, (clientY - rect.top) / rect.height));
|
||||
} else {
|
||||
return Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));
|
||||
}
|
||||
}, [isRotated]);
|
||||
|
||||
const handleProgressClick = useCallback((e: any) => {
|
||||
if (!videoRef.current || !progressBarRef.current) return;
|
||||
const rect = progressBarRef.current.getBoundingClientRect();
|
||||
const pos = (e.clientX - rect.left) / rect.width;
|
||||
const pos = getEventPos(e, rect);
|
||||
const newTime = pos * duration;
|
||||
videoRef.current.currentTime = newTime;
|
||||
lastDragTimeRef.current = newTime; // Update ref to prevent snap-back on mouseup
|
||||
setCurrentTime(newTime);
|
||||
}, [videoRef, progressBarRef, duration, setCurrentTime]);
|
||||
}, [videoRef, progressBarRef, duration, setCurrentTime, getEventPos]);
|
||||
|
||||
const handleProgressMouseDown = useCallback((e: any) => {
|
||||
e.preventDefault();
|
||||
@@ -34,29 +50,17 @@ export function useProgressControls({
|
||||
}, [isDraggingProgressRef, handleProgressClick]);
|
||||
|
||||
const handleProgressTouchStart = useCallback((e: any) => {
|
||||
// e.preventDefault(); // Do not prevent default immediately to allow scrolling if needed, or check logic
|
||||
// But for a slider, we usually want to capture the drag.
|
||||
e.preventDefault();
|
||||
isDraggingProgressRef.current = true;
|
||||
|
||||
// Calculate new time immediately on touch start
|
||||
if (!videoRef.current || !progressBarRef.current) return;
|
||||
const rect = progressBarRef.current.getBoundingClientRect();
|
||||
const touch = e.touches[0];
|
||||
const pos = Math.max(0, Math.min(1, (touch.clientX - rect.left) / rect.width));
|
||||
const newTime = pos * duration;
|
||||
|
||||
videoRef.current.currentTime = newTime;
|
||||
lastDragTimeRef.current = newTime;
|
||||
setCurrentTime(newTime);
|
||||
}, [videoRef, progressBarRef, duration, setCurrentTime, isDraggingProgressRef]);
|
||||
handleProgressClick(e);
|
||||
}, [isDraggingProgressRef, handleProgressClick]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleProgressMouseMove = (e: MouseEvent) => {
|
||||
if (!isDraggingProgressRef.current || !progressBarRef.current || !videoRef.current) return;
|
||||
e.preventDefault();
|
||||
const rect = progressBarRef.current.getBoundingClientRect();
|
||||
const pos = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
|
||||
const pos = getEventPos(e, rect);
|
||||
const newTime = pos * duration;
|
||||
lastDragTimeRef.current = newTime;
|
||||
setCurrentTime(newTime);
|
||||
@@ -73,11 +77,10 @@ export function useProgressControls({
|
||||
|
||||
const handleProgressTouchMove = (e: TouchEvent) => {
|
||||
if (!isDraggingProgressRef.current || !progressBarRef.current || !videoRef.current) return;
|
||||
// e.preventDefault(); // Prevent scrolling while dragging progress
|
||||
if (e.cancelable) e.preventDefault();
|
||||
|
||||
const rect = progressBarRef.current.getBoundingClientRect();
|
||||
const touch = e.touches[0];
|
||||
const pos = Math.max(0, Math.min(1, (touch.clientX - rect.left) / rect.width));
|
||||
const pos = getEventPos(e, rect);
|
||||
const newTime = pos * duration;
|
||||
lastDragTimeRef.current = newTime;
|
||||
setCurrentTime(newTime);
|
||||
|
||||
@@ -23,6 +23,7 @@ interface UseDesktopPlayerLogicProps {
|
||||
data: DesktopPlayerState['data'];
|
||||
actions: DesktopPlayerState['actions'];
|
||||
fullscreenType?: 'native' | 'window';
|
||||
isForceLandscape?: boolean;
|
||||
}
|
||||
|
||||
export function useDesktopPlayerLogic({
|
||||
@@ -34,7 +35,8 @@ export function useDesktopPlayerLogic({
|
||||
refs,
|
||||
data,
|
||||
actions,
|
||||
fullscreenType = 'native'
|
||||
fullscreenType = 'native',
|
||||
isForceLandscape = false
|
||||
}: UseDesktopPlayerLogicProps) {
|
||||
const {
|
||||
videoRef, containerRef, progressBarRef, volumeBarRef,
|
||||
@@ -104,7 +106,8 @@ export function useDesktopPlayerLogic({
|
||||
|
||||
const progressControls = useProgressControls({
|
||||
videoRef, progressBarRef, duration,
|
||||
setCurrentTime, isDraggingProgressRef
|
||||
setCurrentTime, isDraggingProgressRef,
|
||||
isRotated: isForceLandscape
|
||||
});
|
||||
|
||||
const skipControls = useSkipControls({
|
||||
|
||||
Generated
+61
-61
@@ -14,10 +14,10 @@
|
||||
"@vercel/analytics": "^1.6.1",
|
||||
"hls.js": "^1.6.15",
|
||||
"lucide-react": "^0.563.0",
|
||||
"next": "16.1.4",
|
||||
"react": "19.2.3",
|
||||
"react-dom": "19.2.3",
|
||||
"zustand": "^5.0.10"
|
||||
"next": "16.1.6",
|
||||
"react": "19.2.4",
|
||||
"react-dom": "19.2.4",
|
||||
"zustand": "^5.0.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cloudflare/next-on-pages": "^1.13.16",
|
||||
@@ -26,7 +26,7 @@
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"eslint": "^9",
|
||||
"eslint-config-next": "16.1.4",
|
||||
"eslint-config-next": "16.1.6",
|
||||
"postcss": "^8.5.6",
|
||||
"tailwindcss": "^4",
|
||||
"typescript": "^5"
|
||||
@@ -1306,15 +1306,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/env": {
|
||||
"version": "16.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.4.tgz",
|
||||
"integrity": "sha512-gkrXnZyxPUy0Gg6SrPQPccbNVLSP3vmW8LU5dwEttEEC1RwDivk8w4O+sZIjFvPrSICXyhQDCG+y3VmjlJf+9A==",
|
||||
"version": "16.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz",
|
||||
"integrity": "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@next/eslint-plugin-next": {
|
||||
"version": "16.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.1.4.tgz",
|
||||
"integrity": "sha512-38WMjGP8y+1MN4bcZFs+GTcBe0iem5GGTzFE5GWW/dWdRKde7LOXH3lQT2QuoquVWyfl2S0fQRchGmeacGZ4Wg==",
|
||||
"version": "16.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.1.6.tgz",
|
||||
"integrity": "sha512-/Qq3PTagA6+nYVfryAtQ7/9FEr/6YVyvOtl6rZnGsbReGLf0jZU6gkpr1FuChAQpvV46a78p4cmHOVP8mbfSMQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1322,9 +1322,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-arm64": {
|
||||
"version": "16.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.4.tgz",
|
||||
"integrity": "sha512-T8atLKuvk13XQUdVLCv1ZzMPgLPW0+DWWbHSQXs0/3TjPrKNxTmUIhOEaoEyl3Z82k8h/gEtqyuoZGv6+Ugawg==",
|
||||
"version": "16.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.6.tgz",
|
||||
"integrity": "sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1338,9 +1338,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-x64": {
|
||||
"version": "16.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.4.tgz",
|
||||
"integrity": "sha512-AKC/qVjUGUQDSPI6gESTx0xOnOPQ5gttogNS3o6bA83yiaSZJek0Am5yXy82F1KcZCx3DdOwdGPZpQCluonuxg==",
|
||||
"version": "16.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz",
|
||||
"integrity": "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1354,9 +1354,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||
"version": "16.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.4.tgz",
|
||||
"integrity": "sha512-POQ65+pnYOkZNdngWfMEt7r53bzWiKkVNbjpmCt1Zb3V6lxJNXSsjwRuTQ8P/kguxDC8LRkqaL3vvsFrce4dMQ==",
|
||||
"version": "16.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz",
|
||||
"integrity": "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1370,9 +1370,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-musl": {
|
||||
"version": "16.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.4.tgz",
|
||||
"integrity": "sha512-3Wm0zGYVCs6qDFAiSSDL+Z+r46EdtCv/2l+UlIdMbAq9hPJBvGu/rZOeuvCaIUjbArkmXac8HnTyQPJFzFWA0Q==",
|
||||
"version": "16.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz",
|
||||
"integrity": "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1386,9 +1386,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-gnu": {
|
||||
"version": "16.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.4.tgz",
|
||||
"integrity": "sha512-lWAYAezFinaJiD5Gv8HDidtsZdT3CDaCeqoPoJjeB57OqzvMajpIhlZFce5sCAH6VuX4mdkxCRqecCJFwfm2nQ==",
|
||||
"version": "16.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz",
|
||||
"integrity": "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1402,9 +1402,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-musl": {
|
||||
"version": "16.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.4.tgz",
|
||||
"integrity": "sha512-fHaIpT7x4gA6VQbdEpYUXRGyge/YbRrkG6DXM60XiBqDM2g2NcrsQaIuj375egnGFkJow4RHacgBOEsHfGbiUw==",
|
||||
"version": "16.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz",
|
||||
"integrity": "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1418,9 +1418,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||
"version": "16.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.4.tgz",
|
||||
"integrity": "sha512-MCrXxrTSE7jPN1NyXJr39E+aNFBrQZtO154LoCz7n99FuKqJDekgxipoodLNWdQP7/DZ5tKMc/efybx1l159hw==",
|
||||
"version": "16.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz",
|
||||
"integrity": "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1434,9 +1434,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-x64-msvc": {
|
||||
"version": "16.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.4.tgz",
|
||||
"integrity": "sha512-JSVlm9MDhmTXw/sO2PE/MRj+G6XOSMZB+BcZ0a7d6KwVFZVpkHcb2okyoYFBaco6LeiL53BBklRlOrDDbOeE5w==",
|
||||
"version": "16.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz",
|
||||
"integrity": "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -3863,13 +3863,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint-config-next": {
|
||||
"version": "16.1.4",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.1.4.tgz",
|
||||
"integrity": "sha512-iCrrNolUPpn/ythx0HcyNRfUBgTkaNBXByisKUbusPGCl8DMkDXXAu7exlSTSLGTIsH9lFE/c4s/3Qiyv2qwdA==",
|
||||
"version": "16.1.6",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.1.6.tgz",
|
||||
"integrity": "sha512-vKq40io2B0XtkkNDYyleATwblNt8xuh3FWp8SpSz3pt7P01OkBFlKsJZ2mWt5WsCySlDQLckb1zMY9yE9Qy0LA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@next/eslint-plugin-next": "16.1.4",
|
||||
"@next/eslint-plugin-next": "16.1.6",
|
||||
"eslint-import-resolver-node": "^0.3.6",
|
||||
"eslint-import-resolver-typescript": "^3.5.2",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
@@ -5906,12 +5906,12 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/next": {
|
||||
"version": "16.1.4",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-16.1.4.tgz",
|
||||
"integrity": "sha512-gKSecROqisnV7Buen5BfjmXAm7Xlpx9o2ueVQRo5DxQcjC8d330dOM1xiGWc2k3Dcnz0In3VybyRPOsudwgiqQ==",
|
||||
"version": "16.1.6",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz",
|
||||
"integrity": "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@next/env": "16.1.4",
|
||||
"@next/env": "16.1.6",
|
||||
"@swc/helpers": "0.5.15",
|
||||
"baseline-browser-mapping": "^2.8.3",
|
||||
"caniuse-lite": "^1.0.30001579",
|
||||
@@ -5925,14 +5925,14 @@
|
||||
"node": ">=20.9.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@next/swc-darwin-arm64": "16.1.4",
|
||||
"@next/swc-darwin-x64": "16.1.4",
|
||||
"@next/swc-linux-arm64-gnu": "16.1.4",
|
||||
"@next/swc-linux-arm64-musl": "16.1.4",
|
||||
"@next/swc-linux-x64-gnu": "16.1.4",
|
||||
"@next/swc-linux-x64-musl": "16.1.4",
|
||||
"@next/swc-win32-arm64-msvc": "16.1.4",
|
||||
"@next/swc-win32-x64-msvc": "16.1.4",
|
||||
"@next/swc-darwin-arm64": "16.1.6",
|
||||
"@next/swc-darwin-x64": "16.1.6",
|
||||
"@next/swc-linux-arm64-gnu": "16.1.6",
|
||||
"@next/swc-linux-arm64-musl": "16.1.6",
|
||||
"@next/swc-linux-x64-gnu": "16.1.6",
|
||||
"@next/swc-linux-x64-musl": "16.1.6",
|
||||
"@next/swc-win32-arm64-msvc": "16.1.6",
|
||||
"@next/swc-win32-x64-msvc": "16.1.6",
|
||||
"sharp": "^0.34.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -6371,24 +6371,24 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "19.2.3",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
|
||||
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
|
||||
"version": "19.2.4",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
|
||||
"integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "19.2.3",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz",
|
||||
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
|
||||
"version": "19.2.4",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
|
||||
"integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"scheduler": "^0.27.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^19.2.3"
|
||||
"react": "^19.2.4"
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
@@ -7639,9 +7639,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/zustand": {
|
||||
"version": "5.0.10",
|
||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.10.tgz",
|
||||
"integrity": "sha512-U1AiltS1O9hSy3rul+Ub82ut2fqIAefiSuwECWt6jlMVUGejvf+5omLcRBSzqbRagSM3hQZbtzdeRc6QVScXTg==",
|
||||
"version": "5.0.11",
|
||||
"resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.11.tgz",
|
||||
"integrity": "sha512-fdZY+dk7zn/vbWNCYmzZULHRrss0jx5pPFiOuMZ/5HJN6Yv3u+1Wswy/4MpZEkEGhtNH+pwxZB8OKgUBPzYAGg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "kvideo",
|
||||
"version": "4.0.6",
|
||||
"version": "4.0.7",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
|
||||
Reference in New Issue
Block a user