import { useCallback, useSyncExternalStore, useState, type SetStateAction } from 'react'; const STORAGE_KEY = 'mujoco-platform-layout'; function readPreference(): { left: boolean; right: boolean } | null { try { const value = JSON.parse(localStorage.getItem(STORAGE_KEY) ?? 'null'); return typeof value?.left === 'boolean' && typeof value?.right === 'boolean' ? value : null; } catch { return null; } } const resolve = (next: SetStateAction, current: boolean) => typeof next === 'function' ? next(current) : next; /** 窄屏开关是临时状态;不会用临时折叠覆盖桌面偏好。侧栏始终挂载。 */ export function useSidebarLayout() { const [preference, setPreference] = useState(readPreference); const [narrowSide, setNarrowSide] = useState<'left' | 'right' | null>(null); const subscribe = useCallback((notify: () => void) => { const resize = () => { if (window.innerWidth >= 1024) setNarrowSide(null); notify(); }; window.addEventListener('resize', resize); return () => window.removeEventListener('resize', resize); }, []); const width = useSyncExternalStore(subscribe, () => window.innerWidth); const narrow = width < 1024; const desktop = preference ?? { left: width >= 1440, right: true }; // Viewer 与导入回调会长期持有 setter;不能捕获首次渲染时的屏幕宽度。 const setSide = useCallback((side: 'left' | 'right', next: SetStateAction) => { const currentWidth = window.innerWidth; if (currentWidth < 1024) { setNarrowSide((current) => resolve(next, current === side) ? side : current === side ? null : current, ); return; } setPreference((current) => { const value = current ?? { left: currentWidth >= 1440, right: true }; const updated = { ...value, [side]: resolve(next, value[side]) }; try { localStorage.setItem(STORAGE_KEY, JSON.stringify(updated)); } catch { /* 会话内仍可调整 */ } return updated; }); }, []); const setLeftOpen = useCallback( (value: SetStateAction) => setSide('left', value), [setSide], ); const setRightOpen = useCallback( (value: SetStateAction) => setSide('right', value), [setSide], ); return { width, leftOpen: narrow ? narrowSide === 'left' : desktop.left, rightOpen: narrow ? narrowSide === 'right' : desktop.right, setLeftOpen, setRightOpen, }; }