/** * 全站动画策略:系统「减少动态效果」优先;站点总开关/子开关可进一步关闭。 * 新增性能相关动画时:CSS 挂 j13-reduce-*,JS 走 allowMotion / scrollBehavior。 */ export type MotionKind = "codeFold" | "smoothScroll" | "chrome"; export type MotionSiteConfig = { /** 界面动画总开关 */ ui_animations: boolean; /** 代码折叠高度与跟滚 */ anim_code_fold: boolean; /** 平滑滚动 */ anim_smooth_scroll: boolean; /** 装饰入场:列表/Toast/点赞/脉冲等 */ anim_chrome: boolean; }; export const DEFAULT_MOTION_CONFIG: MotionSiteConfig = { ui_animations: true, anim_code_fold: true, anim_smooth_scroll: true, anim_chrome: true, }; let siteConfig: MotionSiteConfig = { ...DEFAULT_MOTION_CONFIG }; export function getMotionSiteConfig(): MotionSiteConfig { return siteConfig; } export function motionConfigFromSettings(s: { ui_animations?: boolean; anim_code_fold?: boolean; anim_smooth_scroll?: boolean; anim_chrome?: boolean; }): MotionSiteConfig { return { ui_animations: s.ui_animations !== false, anim_code_fold: s.anim_code_fold !== false, anim_smooth_scroll: s.anim_smooth_scroll !== false, anim_chrome: s.anim_chrome !== false, }; } export function osPrefersReducedMotion(): boolean { return ( typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches ); } /** 是否允许指定类动画(OS reduce 或总开关关闭则一律否) */ export function allowMotion(kind: MotionKind = "chrome"): boolean { if (osPrefersReducedMotion()) return false; if (!siteConfig.ui_animations) return false; switch (kind) { case "codeFold": return siteConfig.anim_code_fold; case "smoothScroll": return siteConfig.anim_smooth_scroll; case "chrome": return siteConfig.anim_chrome; default: return true; } } export function scrollBehavior(): ScrollBehavior { return allowMotion("smoothScroll") ? "smooth" : "auto"; } /** 同步 documentElement class,供 CSS 与 SSR 初值一致 */ export function syncMotionHtmlClasses(cfg: MotionSiteConfig = siteConfig): void { if (typeof document === "undefined") return; const root = document.documentElement; root.classList.toggle("j13-reduce-motion", !cfg.ui_animations); root.classList.toggle( "j13-reduce-chrome", cfg.ui_animations && !cfg.anim_chrome ); } /** 应用站点动画配置(SSR 初值 / WS 热更新) */ export function applyMotionSiteConfig(cfg: MotionSiteConfig): MotionSiteConfig { siteConfig = motionConfigFromSettings(cfg); syncMotionHtmlClasses(siteConfig); return siteConfig; }