1fa1984703
feat(editor): 点语言标签编辑可运行代码块的语言与配置
...
openRunnableModal 新增编辑模式(editPos + currentInfo):
- 回填当前块的 lang + overrides(解析 info string)
- 标题改「编辑」、按钮改「保存」
- 确认用 setNodeMarkup 原地更新 language 属性(保留块内代码)
CodeBlockNodeView 的语言标签在 runnable 块上可点击(绿字 hover 提示),
点击触发编辑模式(getPos 传 NodeView)。update() 在 language 变化时同步
刷新 <code> 的 class,让高亮按新语言重算。
补 4 个编辑模式用例(回填/标题/保存走 setNodeMarkup/改语言写入)。
Playwright 验证:python→node 编辑后 lang 标签与 code class 同步更新。
2026-07-07 16:12:11 +08:00
9c8ab791d9
fix(editor): codeBlock 内 Backspace 在 lowlight decoration 重建后失效
...
根因:CodeBlockLowlight 的 lowlight 插件在 codeBlock 内容变化后重新高亮,
重建 <code> 内 text node(包成 <span class=hljs-...>)。重建过程导致 DOM
selection 错位到 <pre>(contentDOM 父元素)而非 <code> 内文本,后续 Backspace
删不掉剩余字符,块删空后也无法删除整个 codeBlock。
文档层 ProseMirror selection($anchor)始终正确,只是 DOM 层不同步。用独立
Extension + handleKeyDown plugin prop 接管 codeBlock 内的 Backspace:基于
文档 pos 直接删除字符(不依赖 DOM selection),或在块空时 setNodeMarkup
转段落。handleKeyDown 优先级高于 keymap,能覆盖父类 CodeBlock 的同名 shortcut
(在 CodeBlockLowlight.extend 里 addKeyboardShortcuts 无法覆盖父类,故独立扩展)。
经 Playwright 真实浏览器逐键验证:输入 ab → 删 b → 删 a(此前失败) → 删块,
全链路正常。与 NodeView 无关(禁用 NodeView 同样复现,根因在 lowlight decoration)。
2026-07-07 14:05:53 +08:00
763edc300d
feat(editor): NodeView 适配 onRunCode 协议(extractLang + overridesJson 提取)
...
runCode 改传纯语言名(extractLang) + overrides JSON 字符串(extractOverridesJson),
对齐 Task 4 Rust 桥接 RunCodeOptsJs(language/source/overrides_json):
- highlight.ts: 新增 extractOverridesJson,对齐后端 parse_fence_info 取以 { 开头的 token
- code-block-view.ts: RunCodeOpts 加 overridesJson 字段,runCode 改传 extractLang/extractOverridesJson 提取结果
- index.ts: EditorOptions.onRunCode 类型同步加 overridesJson
- 测试: extractOverridesJson 6 例 + code-block-view 点击断言更新(纯语言名 + overridesJson)
2026-07-06 18:17:33 +08:00
6e5ff72a29
feat(editor): 挂载 CodeBlockNodeView + editor.storage 注入 onRunCode
...
CodeBlockLowlight.extend({ addNodeView }) 接入自定义 NodeView。
EditorOptions 新增 onRunCode 字段;编辑器初始化时挂到 editor.storage,
NodeView 经 storage key 读取(仿 upload-coordinator 范式)。
2026-07-06 18:00:15 +08:00
4de48cd16c
style(editor): biome 修正 import 排序(highlight/index)
...
TDD 阶段子代理未跑 biome check --write,补齐 import 字母序以过 make lint。
2026-07-06 15:53:16 +08:00
e86fe0767d
feat(editor): 用 CodeBlockLowlight 替换 StarterKit 自带 CodeBlock
...
禁用 StarterKit codeBlock,引入 CodeBlockLowlight + lowlight 实例。
代码块现在有实时语法高亮(ProseMirror decoration),language 属性
仍承载完整 info string(markdown 往返不变)。
2026-07-06 15:48:02 +08:00
a47e1e6027
refactor(build): workspace 根迁移至 libs/,Makefile 整合 lint/fix
...
将 pnpm workspace 根从项目根移到 libs/,项目根保持纯 Rust,JS 工作区自治:
- package.json/pnpm-workspace.yaml/pnpm-lock.yaml/biome.json 迁入 libs/
- pnpm-workspace.yaml glob 从 'libs/*' 改为 '*'(已在 libs/ 内)
- biome.json 关闭 vcs.useIgnoreFile(libs/ 无独立 .gitignore,
files.includes 已显式排除 node_modules/dist)
- Makefile 所有 pnpm/biome 调用加 'cd libs &&' 前缀
Makefile 同步整合 lint/fix(替代独立 clippy/fix target):
- make lint = biome check (libs) + cargo clippy
- make fix = biome format --write (libs) + cargo fix
- 删除 8 个 build-*-incremental/build-* target,改为 build-libs 聚合 +
build-<name> 用 pnpm --filter 单库便利 target
修复 biome 格式化回归:tiptap-editor/src/index.ts:83 的 sourceTextarea!.value
被 biome 误转为可选链 ?.,导致 TS2345(string | undefined 不匹配 string),
已还原为非空断言。
2026-07-02 18:02:52 +08:00
b1b1c88a74
chore(biome): 引入 Biome v2.5 monorepo 配置并格式化全量源码
...
新增根 biome.json(v2.5,v2 起原生支持 monorepo,子包自动向上查找):
- formatter: 2 空格缩进、单引号、行宽 100、LF、尾逗号、箭头函数括号
(匹配现有代码风格)
- linter: recommended preset + 项目化裁剪
- useTemplate/useTemplate off(geometry.ts 故意保留字符串拼接,
且测试用精确浮点断言锁定行为)
- noNonNullAssertion off(测试与 DOM 访问里的 ! 是惯用写法)
- noConsole off(4 个 lib 用 console.error/warn 做错误上报)
- CSS 关闭 noDescendingSpecificity/noDuplicateProperties
(手写 CSS 的 fallback 模式)
- useImportType/useNodejsImportProtocol/noUnusedVariables warn
- vcs.useIgnoreFile 自动读 .gitignore;排除 public/target/node_modules/
dist/.dioxus/static + Tailwind 入口 input.css(含 @theme 等 Biome 无法
解析的 at-rules)
首次格式化覆盖 29 个源文件:import 排序、node: 协议、引号/缩进统一,
并修复 index.ts 两处 forEach 回调隐式返回值(useIterableCallbackReturn)。
90 个 vitest 用例全绿,确认无语义改动。
2026-07-02 17:54:46 +08:00
4a76397af8
feat(editor): 支持 - [ ] 手动输入创建任务列表
...
Tiptap 官方 TaskItem 的 input rule 只匹配 [ ] 不含 marker,且 StarterKit
的 BulletList input rule /^\s*([-+*])\s$/ 在用户打 - 时就抢先触发,把这行
变成无序列表;后续的 [ ] 沦为字面文本,getMarkdown 序列化时转义成 \[ \],
前台无法渲染成 checkbox。
- 新增 TaskInputRule 扩展,priority 1000 抢在 BulletList(默认 100)之前,
正则 /^(\s*-\s)\[( |x|X)\]\s$/ 匹配 - [ ] / - [x],
wrappingInputRule 包裹成 taskList > taskItem(findWrapping 自动补齐两层)
- 仅识别减号 marker(* + 仍走 BulletList),Enter 续行复用 TaskItem 内置
splitListItem,不重复实现
- 新增 task-input-rule 测试(真实 Editor + happy-dom):覆盖未勾选/已勾选/
大写 X/不误判普通列表/星号 marker
2026-07-02 13:56:11 +08:00
fb31ecb5ae
fix(tiptap): expose EditorOptions as runtime class for wasm-bindgen
...
EditorOptions was a TS interface (erased at runtime), but the Rust
wasm-bindgen extern uses #[wasm_bindgen(constructor)] which generates
'new EditorOptions()' — requiring a global constructor.
Vite 5/Rollup accidentally leaked the name into IIFE global scope,
masking this. Vite 8/Rolldown strictly erases interfaces, exposing it
as 'EditorOptions is not defined'.
Fix: make EditorOptions a class (retains runtime constructor) and mount
it on window, since the IIFE bundle name is taken by TiptapEditor.
2026-06-24 10:27:07 +08:00
d099db4140
refactor(tiptap): move coordinator to editor.storage, drop dead Markdown html option
2026-06-23 18:39:38 +08:00
a3896c24a5
refactor(write): replace all js_sys::eval with tiptap_bridge bindings
...
write.rs changes (Tasks 7-11):
- use_drop: EditorHandle::drop replaces eval destroy + global reset (#1 )
- init use_effect: closure-driven bridge.create replaces eval initEditor
script + 100ms ready polling (#2/#3/#4/#5)
- getMarkdown: read via EditorHandle instead of eval (#8 )
- delete upload polling use_future: driven by onUploadEvent closure (#6/#7)
- removeUploadByUploadId: call via EditorHandle instead of eval (#9 )
Bridge fixes during integration:
- UploadCountsJs: drop Copy derive (wasm_bindgen types can't be Copy)
- split module: shared types compile on both targets, wasm externs gated
- add WritableExt/Readable/Writable trait imports for .write()/.set()
- use FnMut closures (Signal write/set take &mut self)
- consume_upload_event takes &mut Signal params
Also: remove stale window.__tiptap_content in index.ts source-mode handler.
2026-06-23 11:25:06 +08:00
92cfda7d5a
refactor(tiptap): EditorOptions onReady/onUploadEvent callbacks replace polling
2026-06-23 10:52:30 +08:00
cee4f3f3ef
fix(upload): address code review findings
...
final code review 后的修复:
1. blob 检查收紧(Important): md.contains("blob:") 误伤合法讨论 blob URL
的代码块/正文,改为检测 markdown 图片语法 ](blob: 才算占位符泄漏
2. 重试错误原地更新(Minor): seen_error_ids 去重逻辑导致重试后再失败时
顶部提示停留在旧错误文案;改为已存在 id 时原地更新 message
3. destroy 清理 coordinatorRef(Minor): destroy() 调 setUploadCoordinator(null),
避免 NodeView 指向已销毁的 coordinator(防御性)
4. 删除 NodeView 未用的 editor 字段(Nit): 死代码清理
验证: cargo test (384 passed) / clippy (本次零警告) / dx check / tiptap build 全过
2026-06-22 15:49:23 +08:00
34c8b47436
feat(editor): route slash-command image upload through coordinator
...
- slash-command.ts: SlashCommandOptions 加 onInsertUploading option
- slash-command.ts: 上传图片命令优先走 onInsertUploading(coordinator 占位符+上传),
退回 uploadFn 直接上传(无占位符)
- index.ts: SlashCommand.configure 注入 onInsertUploading,
闭包延迟读取 this.coordinator(在 editor 创建后才实例化)
2026-06-22 15:30:39 +08:00
5d527778a5
feat(editor): wire UploadCoordinator and custom Image in TiptapEditorInstance
...
- index.ts: 替换 Image.configure 为 UploadImage(自定义扩展+NodeView)
- index.ts: editor 创建后实例化 UploadCoordinator 并注入 NodeView
- index.ts: FileHandler onPaste/onDrop 改走 coordinator.insertUploading
- index.ts: 暴露 removeUploadByUploadId 供 Rust ×关闭调用
- index.ts: destroy 清理 coordinator
- upload-image.ts: 修正 import 来源(Image 来自 extension-image, mergeAttributes 来自 core)
2026-06-22 15:28:40 +08:00
6ff37322b2
feat(editor): add image upload to slash command and build tiptap in make dev
...
斜杠命令图片上传 + Makefile dev 构建修复
1. 斜杠命令接入图片上传管线
- slash-command.ts: SlashCommand 扩展改为 Extension.create<Options>,
新增 onImageUpload 选项;原单一"图片"命令拆成两个:
· "上传图片"(📤 ): 仅在 onImageUpload 可用时出现,触发原生文件选择器
(accept 限定 jpeg/png/gif/webp,与 upload 端点 MIME 一致),
上传成功后 setImage 插入,失败 console.error(与 FileHandler 一致)
· "图片链接"(🖼): 保留原 window.prompt URL 方式
- index.ts: SlashCommand.configure({ onImageUpload }) 透传宿主回调,
复用 write.rs 已注入的 /api/upload 管线,无需 Rust 端改动
2. Makefile: make dev 不再忽略 tiptap 构建
- 根因: 原 dev target 只起 tailwindcss watch + dx serve,从不构建
tiptap 编辑器,导致 dev server 始终 serve 上次 make build 残留的
旧 editor.js(本次新增的"上传图片"命令在 dev 下永远不生效)
- 新增 build-editor-incremental target (跳过 npm ci,直接 vite build,~1s)
- dev 现在依赖 build-editor-incremental,启动前先增量构建编辑器
3. Makefile: clean 不再删 public/tiptap
- public/tiptap 是跨子项目(npm)构建产物,删除后必须重跑 make build-editor
(含 npm ci) 才能恢复;原 clean 会删它是陷阱(make clean && make dev
会导致编辑器直接消失)。现在 clean 只清 Rust 产物和缓存
2026-06-22 14:18:05 +08:00
6ce8915e6c
fix(editor): 修复 focus() 把源码视图滚动到底部
...
切换到源码模式时 sourceTextarea.focus() 会触发浏览器将光标
所在行滚动进可视区域,光标默认在内容末尾,导致 textarea 被
拉到底部覆盖已设的滚动位置。改为 focus 后立即恢复 scrollTop。
同时移除调试日志。
2026-06-16 16:13:46 +08:00
ae6d80c9cc
fix(editor): 修复滚动比例同步失效导致切换到底部
...
原 syncScrollRatio 封装在 display:'none' 之后重复读取源容器
scrollTop,此时浏览器已将其归零,导致比例计算为 0。改为提前
读取比例并直接应用,移除二次封装与调试日志。
2026-06-16 15:58:50 +08:00
914f168551
fix(editor): 切换视图时按滚动比例同步位置
...
修复切回富文本时编辑器滚动到底部的问题:移除 commands.focus()
(会强制滚动到光标位置),改用滚动比例跨模式同步,富文本与源码
视图按相同比例定位,保持视觉位置一致。
2026-06-16 15:53:28 +08:00
480aa92bb4
feat(editor): 新增 Markdown 源码视图切换
...
在 Tiptap 编辑器右上角增加 </> 悬浮按钮,支持在富文本与
Markdown 源码视图间双向切换,内容自动同步。getMarkdown() 在
源码模式下返回 textarea 内容,使 Rust 端提交逻辑无需改动。
2026-06-16 15:50:09 +08:00
078e9b1da1
fix(tiptap-editor): configure link via StarterKit to avoid duplicate extension warning
2026-06-05 18:19:24 +08:00
ad208a4603
fix(tiptap-editor): correct setContent call signature for markdown parsing
2026-06-05 18:05:47 +08:00
26eb62c2ae
fix(upload): disable default body limit and fix error object serialization
2026-06-05 16:52:52 +08:00
c2c7b46958
fix(tiptap-editor): use insertContentAt with drop position in onDrop handler
...
Previously dropped images were inserted at the current cursor position
instead of the actual drop position. Now uses insertContentAt(pos, ...)
to place images at the correct location.
2026-06-05 15:21:38 +08:00
00c5a880f4
feat(editor): add FileHandler extension for image paste/drop upload
2026-06-05 15:19:31 +08:00
a8704e199f
feat(editor): add slash command, table, task list, image and link extensions
...
- Add @tiptap/suggestion-based slash command menu with 12 commands
- Add TableKit for table support (3x3 with header)
- Add Image extension with base64 support
- Add Link extension with autolink and paste detection
- Add TaskList/TaskItem extensions for checklists
- Upgrade all tiptap packages from 3.23.6 to 3.25.0
- Add CSS styles for all new features including dark theme
2026-06-05 10:20:47 +08:00
f6d60520eb
集成 Tiptap Markdown 编辑器到文章撰写页面
...
- 新增 libs/tiptap-editor/ 打包子项目(Tiptap Core + StarterKit + Markdown)
- 构建产物输出到 public/tiptap/
- 替换原有的 textarea + pulldown_cmark 预览为 WYSIWYG 编辑器
- Makefile 新增 build-editor target
- Dioxus.toml 引入 editor.js 和 editor.css
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 17:46:04 +08:00