fix: 修复后台文章计数为0 + 分类编辑补全描述字段 + CSP放行外部图片 + 更新关于页描述
- 文章管理:计数请求补 page=1 参数,命中分页接口返回正确的 total - 分类管理:编辑模式新增描述输入框,保存时一并提交 description - CSP:img-src 加入 https: 允许加载外部图片 - 关于页:数据存储描述从 JSON 文件更正为 SQLite 数据库 - Footer:添加 ICP 备案号
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef } from "react";
|
||||
import gsap from "gsap";
|
||||
import { ScrollTrigger } from "gsap/ScrollTrigger";
|
||||
|
||||
gsap.registerPlugin(ScrollTrigger);
|
||||
|
||||
/**
|
||||
* GSAP 动画的统一入口。
|
||||
*
|
||||
* 核心原则:
|
||||
* 1. 尊重 prefers-reduced-motion —— 开启时直接跳过动画,内容保持可见。
|
||||
* 2. 在 gsap.context 内执行,卸载时自动 revert,避免泄露。
|
||||
*
|
||||
* 用法:
|
||||
* const ref = useGsapAnimation<HTMLElement>((scope, isReduced) => {
|
||||
* if (isReduced) return;
|
||||
* gsap.from(".item", { y: 40, opacity: 0, stagger: 0.1, scrollTrigger: {...} });
|
||||
* });
|
||||
*/
|
||||
export function useGsapAnimation<T extends HTMLElement = HTMLElement>(
|
||||
setup: (scope: T, isReduced: boolean) => void,
|
||||
deps: unknown[] = []
|
||||
) {
|
||||
const ref = useRef<T>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const el = ref.current;
|
||||
if (!el) return;
|
||||
const isReduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||
const ctx = gsap.context(() => setup(el, isReduced), el);
|
||||
return () => ctx.revert();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, deps);
|
||||
|
||||
return ref;
|
||||
}
|
||||
Reference in New Issue
Block a user