feat(editor): add markdown presets, heading folding and external file refresh

This commit is contained in:
2026-09-06 12:57:09 +08:00
parent 415efc4444
commit 8ad1db33f7
43 changed files with 901 additions and 54 deletions
@@ -0,0 +1,48 @@
# Markdown 语法预设与外部文件刷新
日期:2026-09-06。
## 1. 设置入口与范围
“设置 → 编辑器 → Markdown 语法预设”管理语法与编辑行为,独立于“标题样式”的字号、字体和字重设置。
支持 ATX/Setext 标题、无序列表标记、有序列表递增、代码围栏、裸链接识别、数学公式、警告框、Mermaid、代码行号、自动换行、缩进和工具栏新建代码块的默认语言。Setext 只作用于 H1/H2。提供扩展、GitHub 和基础三组内置配置,支持最多 20 个命名自定义预设,同名保存替换旧配置。
配置保存在本机 localStorage 的 `markdown-preferences`,读取时校验。静态预览即时应用;写作编辑器在下次打开时应用,避免切换设置重建正在编辑的文档。写作模式保存会统一整篇正文的语法标记,源码模式保留手写语法。关闭扩展后对应内容按普通 Markdown/代码展示。
本次不是完整复制 Typora:未提供上下标、高亮、智能标点、physics 包及导出公式选项。基础配置仍支持现有 GFM 表格等功能。
## 2. 主题与折叠
六个主题共用语义颜色和表单控件。内置浅色、深色、护眼更新为 1.3.0;纸间时光 1.8.0Ocean Blue 1.5.0Midnight Purple 2.3.0。社区预览增加语法控件和标题折叠样本。
标题箭头使用统一 CSS 形状,默认隐藏,悬停标题或键盘聚焦按钮时显示;无悬停能力的触摸设备保持可见。用户自定义标题外观独立于主题配色。
## 3. 外部文件刷新与保存保护
Web 当前采用串行后台轮询:前一次完成后间隔两秒,在窗口聚焦时也检查。隐藏页面暂停读取,卸载移除监听。此机制不是原生文件事件监听;第三阶段可由 Tauri 文件事件替代。
`GET /workspace/tree` 检查磁盘新增、删除和重命名,为新文件登记元数据及全文索引,向量任务继续后台执行。前端保留文件夹展开状态,并丢弃过期请求响应。读取失败保留旧树并显示重试入口。
当前打开且未修改的文件检测到外部正文变化后更新编辑器;存在本地编辑时保留缓冲区,停止自动保存并提示冲突。重新加载磁盘版本需要用户确认。`PATCH /notes/{note_id}` 新增可选 `expected_content_hash`(原始正文 UTF-8 SHA-256,64 位小写十六进制),保存前校验,不匹配返回 `NOTE_CONTENT_CONFLICT`,防止覆盖外部修改。
范围限制:现有文件的外部正文修改会刷新当前编辑器,但本轮目录检查不会据此重建其搜索索引;可通过重建索引同步检索内容。
## 4. 验证方法
```powershell
cd frontend
npm run test
npm run build
cd ..
backend/.venv/Scripts/python.exe -m pytest backend/tests/test_workspace.py backend/tests/test_workspace_background.py -q -p no:cacheprovider
```
手工验证:
1. 保存并重新应用命名预设,刷新后确认保留;重新打开笔记,检查 Setext、列表和代码围栏的源码。
2. 切换六个主题,在社区预览和工作区检查控件、警告框、标题箭头;移出标题后箭头隐藏,Tab 聚焦仍可操作。
3. 在系统文件管理器新增、重命名、删除 Markdown 文件,保持前端可见,确认树自动更新且目录展开状态保留。
4. 分别在正文未修改、有未保存编辑时从外部修改同一文件,验证自动加载与冲突保护;拒绝重新加载应保留编辑内容。
本次自动验证覆盖预设持久化、解析选项隔离、写作语法输出、标题折叠、树刷新竞态、外部文件登记及保存冲突。
@@ -0,0 +1,52 @@
# 标题折叠与样式开发说明
日期:2026-09-06。范围为工作区写作模式的章节折叠,以及正文标题外观偏好。
## 1. 章节边界与交互
H1–H6 标题旁在悬停时显示统一折叠箭头;键盘聚焦也显示,触摸设备保持可见。章节从标题之后开始,结束于同一容器内下一个同级或更高级标题;末尾没有后续内容的标题不显示按钮。引用等容器中的标题只影响所在容器,不折叠外部正文。
- 工具栏提供“折叠所有章节”和“展开所有章节”。
- 折叠父章节不会清空子章节的折叠状态。
- 折叠时若选区在将隐藏的正文中,光标先移到标题。
- 从大纲、查找或键盘跳到隐藏内容时,展开包含目标的章节,避免隐藏光标。
- 折叠只影响当前编辑器视图,不修改 Markdown,不触发文档脏状态,也不占用撤销历史。重开文件恢复展开;源码模式与静态预览不进行章节折叠。
实现位于 `headingFolding.ts`:插件状态保存标题位置,通过事务映射跟随文档编辑;删除或改成正文的标题会从状态中清理。Decoration 隐藏完整块,widget 提供可聚焦的折叠按钮。章节范围按标题栈计算,并按不可变文档缓存;隐藏范围合并后遍历节点,避免每个节点重复扫描全部标题。
## 2. 标题样式设置
入口为“设置 → 编辑器 → 标题样式”,主题页“编辑器外观”中也提供同一组件。
- 默认跟随当前主题,不覆盖主题字号、字体与粗细。
- 启用自定义后,分别调整 H1–H6 字号(12–72 px)和字重(400–800 的五个档位)。
- 标题字体可跟随正文,或使用系统衬线、无衬线、等宽字体。
- 面板即时预览,工作区正文和静态 Markdown 预览使用同一偏好。
- 不影响笔记属性栏的标题、侧栏大纲字号或页面标题,不改写源文件中的标题级别。
- “恢复跟随主题”清除自定义覆盖;主题页“恢复默认”也重置标题设置。
偏好由 `headingAppearance` store 保存到本机 `editor-heading-appearance`。读取时校验字体枚举、字重与字号范围;应用 CSS 前再次规范化,避免空输入、无效存储或异常大数影响布局。刷新后恢复设置,切换主题保留自定义偏好。用户显式启用的覆盖只作用于 Markdown 标题,优先于主题规则;颜色继续跟随主题。
## 3. 桌面命令预留
既有 `editorCommandService` v1 增加三个可执行 ID
| 命令 | 行为 |
| --- | --- |
| editor.heading.toggle-fold | 切换选区所在章节的折叠状态 |
| editor.heading.fold-all | 折叠所有有内容的章节 |
| editor.heading.unfold-all | 展开所有章节 |
均不需要参数,沿用活动文档、模式与冲突检查。原生快捷键仍由第三阶段容器绑定,此处不注册系统级快捷键。
## 4. 验证
```sh
cd frontend
npm run test -- src/features/editor/headingFolding.spec.ts src/features/editor/VisualMarkdownEditor.spec.ts src/features/editor/HeadingStyleSettings.spec.ts src/stores/headingAppearance.spec.ts
npm run build
```
自动检查覆盖章节边界、嵌套容器、隐藏选区迁移、父子折叠状态、大纲目标展开、序列化保持、设置保存恢复、输入校验和面板恢复默认。
手动检查:打开“功能演示 / 01 Markdown 与大纲”,依次折叠 H2 与 H1,再从大纲跳转;确认隐藏内容重新显示。打开设置调整 H1 字号与 H2 粗细,返回笔记检查外观,刷新后检查偏好仍在;关闭自定义后依次切换六个主题核对主题原有样式。