import { useCallback, useEffect, useState } from "react"; /** comments:评论;works:TA的作品;list:搜索结果 / hashtag / 标签列表 */ export type SidePanelTab = "comments" | "works" | "list"; // 侧栏开关沿用评论区原来的 localStorage 键;停在哪个标签页、是否处于作者模式只在本次会话内记住, // 这样下次从首页点进来不会莫名其妙停在作者模式。 // 切换作品时播放页会整体重新挂载,靠这些存储把状态带到下一个作品。 const OPEN_KEY = "aweme_player_comments_open"; const TAB_KEY = "aweme_player_panel_tab"; const AUTHOR_MODE_KEY = "aweme_player_author_mode"; function readStorage(storage: () => Storage, key: string): string | null { try { return storage().getItem(key); } catch { return null; } } function writeStorage( storage: () => Storage, key: string, value: string | null, ) { try { if (value === null) storage().removeItem(key); else storage().setItem(key, value); } catch {} } const local = () => window.localStorage; const session = () => window.sessionStorage; export function isPortraitViewport(): boolean { return ( typeof window !== "undefined" && window.matchMedia("(orientation: portrait)").matches ); } /** * 侧栏状态与作者模式。 * 作者模式和侧栏开关是分开的:打开「TA的作品」进入作者模式(上下切换在该作者的作品里移动), * 关掉侧栏不会退出,只有点顶部提示的 ✕、或切到「搜索结果 / #hashtag」列表才退出。 */ export function useSidePanelState(authorSecUid: string | undefined) { const [open, setOpen] = useState(false); const [tab, setTab] = useState("comments"); // 处于作者模式时记下是哪位作者;切到别的作者的作品(例如浏览器后退)时自动不生效 const [authorModeFor, setAuthorModeFor] = useState(null); const [restored, setRestored] = useState(false); const [mounted, setMounted] = useState(false); useEffect(() => { setOpen(readStorage(local, OPEN_KEY) === "true"); const savedTab = readStorage(session, TAB_KEY); setTab(savedTab === "works" || savedTab === "list" ? savedTab : "comments"); setAuthorModeFor(readStorage(session, AUTHOR_MODE_KEY)); setRestored(true); // 恢复完成后再开启过渡动画,避免进入页面时侧栏滑入 requestAnimationFrame(() => { requestAnimationFrame(() => setMounted(true)); }); }, []); useEffect(() => { if (!restored) return; writeStorage(local, OPEN_KEY, String(open)); writeStorage(session, TAB_KEY, tab); writeStorage(session, AUTHOR_MODE_KEY, authorModeFor); }, [open, tab, authorModeFor, restored]); // 切到哪个列表标签页,上下切换就改用哪个列表的顺序;「评论」不影响顺序 const applyTabMode = useCallback( (nextTab: SidePanelTab) => { if (nextTab === "works" && authorSecUid) setAuthorModeFor(authorSecUid); else if (nextTab === "list") setAuthorModeFor(null); }, [authorSecUid], ); const selectTab = useCallback( (nextTab: SidePanelTab) => { setTab(nextTab); applyTabMode(nextTab); }, [applyTabMode], ); const show = useCallback( (nextTab: SidePanelTab) => { selectTab(nextTab); setOpen(true); }, [selectTab], ); const close = useCallback(() => setOpen(false), []); /** 打开到指定标签页;已经打开在这个标签页时则关闭(关闭不影响顺序) */ const toggle = useCallback( (nextTab: SidePanelTab) => { if (open && tab === nextTab) close(); else show(nextTab); }, [close, open, show, tab], ); const exitAuthorMode = useCallback(() => setAuthorModeFor(null), []); return { open, tab, mounted, /** 上下切换在当前作者的作品里移动 */ authorMode: Boolean(authorSecUid) && authorModeFor === authorSecUid, /** 已从存储里恢复完状态(之后才能安全地自动打开侧栏) */ restored, selectTab, show, close, toggle, exitAuthorMode, }; }