feat: 书库导入导出/图片变体/书籍搜索/小组件运行时等

新增:
- 书库导入导出(library_import/library_export)及测试
- 图片变体生成(image_variants)与响应式图片(responsiveImage)
- 书籍搜索(bookSearch)+ BookSearch/LibrarySearchGrid 组件
- 小组件运行时(widgetRuntime)与静态检查(widgetLint)
- 上传缓存中间件(upload_cache)与字体 CSS 提取脚本

其它:
- 后端 handlers/services 全量调整
- 前端页面、组件、库函数与配置更新
This commit is contained in:
2026-10-01 03:06:05 +08:00
parent 7fbd6ba699
commit ff2ab286fb
141 changed files with 7527 additions and 1407 deletions

View File

@@ -83,6 +83,8 @@ type MarkdownEditorProps = {
onUploadingChange?: (uploading: boolean) => void;
/** 书级「全章节条目卡模式」:插入免壳模板、预览按隐式条目渲染 */
entriesAuto?: boolean;
/** 图片上传时标记的 source(如 library_content),默认 post */
uploadSource?: string;
};
type EditorMode = "write" | "preview";
@@ -164,6 +166,7 @@ export default function MarkdownEditor({
error,
onUploadingChange,
entriesAuto = false,
uploadSource,
}: MarkdownEditorProps) {
const taRef = useRef<HTMLTextAreaElement>(null);
const urlStyle = useUrlStyle();
@@ -466,7 +469,7 @@ export default function MarkdownEditor({
}
setUploading(true);
try {
const res = await apiUploadPostImage(file);
const res = await apiUploadPostImage(file, undefined, uploadSource);
if (!res.url) {
const msg = res.error || "上传失败";
setUploadError(msg);
@@ -1268,12 +1271,13 @@ export default function MarkdownEditor({
</div>
) : null}
</div>
<div className="flex items-center gap-2 shrink-0">
<div className="j13-md-toolbar-end flex items-center gap-2 shrink-0">
<div className="j13-md-mode" role="tablist" aria-label="编辑模式">
<button
type="button"
role="tab"
aria-selected={mode === "write"}
aria-label="编写模式"
className={mode === "write" ? "is-on" : ""}
onMouseDown={(e) => {
e.preventDefault();
@@ -1281,12 +1285,13 @@ export default function MarkdownEditor({
}}
onClick={() => setMode("write")}
>
<Pencil size={12} /> 编写
<Pencil size={12} /> <span className="j13-md-mode-text">编写</span>
</button>
<button
type="button"
role="tab"
aria-selected={mode === "preview"}
aria-label="预览模式"
className={mode === "preview" ? "is-on" : ""}
onMouseDown={(e) => {
e.preventDefault();
@@ -1294,7 +1299,7 @@ export default function MarkdownEditor({
}}
onClick={() => setMode("preview")}
>
<Eye size={12} /> 预览
<Eye size={12} /> <span className="j13-md-mode-text">预览</span>
</button>
</div>
{!toolNarrow && (