Files
jiang13-bbs/frontend/components/markdown/CodeFoldProvider.tsx
freefire 809d8f1df7 feat(settings): 后台可配置 Markdown 代码块自动折叠与阈值行数
支持开关与 0–100 行阈值(0 为无预览),经站点设置与 WS 热更新;短代码在视口内收起时不再回滚浏览位置。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-16 06:43:37 +08:00

79 lines
2.0 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import {
createContext,
useContext,
useEffect,
useState,
type ReactNode,
} from "react";
import { realtime, RT_SETTINGS_CHANGED, type RtSettingsData } from "@/lib/realtime";
export type CodeFoldConfig = {
/** 是否启用自动折叠 */
enabled: boolean;
/** 超过该行数则折叠(预览高度约同;0=无预览) */
foldLines: number;
};
const DEFAULT_CONFIG: CodeFoldConfig = { enabled: true, foldLines: 5 };
const CodeFoldContext = createContext<CodeFoldConfig>(DEFAULT_CONFIG);
/** 代码块自动折叠配置(站点设置) */
export function useCodeFoldConfig(): CodeFoldConfig {
return useContext(CodeFoldContext);
}
function clampFoldLines(n: unknown): number {
if (typeof n !== "number" || !Number.isFinite(n)) return DEFAULT_CONFIG.foldLines;
const r = Math.round(n);
if (r < 0 || r > 100) return DEFAULT_CONFIG.foldLines;
return r;
}
/**
* 根布局注入:SSR 初值 + settings:changed 热更新。
*/
export default function CodeFoldProvider({
initialEnabled = true,
initialFoldLines = 5,
children,
}: {
initialEnabled?: boolean;
initialFoldLines?: number;
children: ReactNode;
}) {
const [config, setConfig] = useState<CodeFoldConfig>(() => ({
enabled: initialEnabled !== false,
foldLines: clampFoldLines(initialFoldLines),
}));
useEffect(() => {
setConfig({
enabled: initialEnabled !== false,
foldLines: clampFoldLines(initialFoldLines),
});
}, [initialEnabled, initialFoldLines]);
useEffect(() => {
return realtime.on<RtSettingsData>(RT_SETTINGS_CHANGED, (data) => {
if (!data) return;
setConfig((prev) => ({
enabled:
typeof data.code_block_auto_fold === "boolean"
? data.code_block_auto_fold
: prev.enabled,
foldLines:
typeof data.code_block_fold_lines === "number"
? clampFoldLines(data.code_block_fold_lines)
: prev.foldLines,
}));
});
}, []);
return (
<CodeFoldContext.Provider value={config}>{children}</CodeFoldContext.Provider>
);
}