1107 Commits

Author SHA1 Message Date
xfy
60bfee7f36 feat(build): inject git/rustc/build-time info and print on startup
新增 build.rs 在编译期采集构建元信息(version / git describe / commit
hash / 提交时间 / rustc 版本 / 编译时刻),通过 cargo:rustc-env 注入,
由 src/build_info.rs 用 env! 宏在编译期内联读取,零运行时开销。

启动时(main() tracing 初始化之后)调用 log_build_info() 分 4 行打印
这些字段,方便定位线上跑的是哪个二进制。

设计取舍:
- 只用 std,不引 vergen/git2 等 build-dependencies(git 不可用时降级为
  "unknown",不 fail the build)。
- build.rs 存 Unix 秒,运行时用已有的 chrono 解析回 RFC3339。
- 声明 rerun-if-changed=.git/HEAD,确保切换提交后重新采集。
2026-07-09 11:50:39 +08:00
xfy
0ab3340133 fix(code-runner): allow exec on /tmp tmpfs for compiled languages
Docker tmpfs 挂载默认带 noexec,编译型语言(go/rust)把编译产物
落在 /tmp 后再 exec 会报 permission denied:
  - rust: /tmp/main (run-rust.sh 的 rustc 输出)
  - go:   /tmp/go-build*/b001/exe/main (GOTMPDIR=/tmp 的链接器输出)

解释型语言(python/node)执行根文件系统里的解释器,不在 tmpfs 上,不受影响。

给 /tmp tmpfs 显式加 exec 选项。这是容器执行的固有需求——只要
沙箱支持任何编译型语言,/tmp 就必须可执行。安全模型由只读根文件系统 +
cap_drop=ALL + no-new-privileges + pids/memory/cpu 限制兜底,/tmp 可执行
不引入额外攻击面(容器内本就允许执行自身进程)。
2026-07-09 11:04:27 +08:00
xfy
2f6f8e549d refactor(code-runner): default CODE_RUNNER_LANGUAGES to all-open
CODE_RUNNER_LANGUAGES 未设置时,白名单不再默认为 python,node,
而是放行 LANGUAGES 注册表里的全部语言。该环境变量变为「可选的收窄开关」:
新增语言到注册表即可默认启用,无需再同步运维白名单(避免两边脱节,
如本次 go/rust 就因 .env 未同步白名单导致 is_supported_lang 拒绝)。

- RunnerConfig.languages: Vec<String> → Option<Vec<String>>,
  None 表示不限制
- is_supported_lang: Option 为 None 时直接放行注册表语言
- 测试 is_supported_lang_default_whitelist → is_supported_lang_default_all_open,
  断言 go/rust 在默认(未设白名单)下可用
2026-07-09 11:02:04 +08:00
xfy
75767661ac feat(admin): surface Go and Rust on the runner page
SUPPORTED_LANGS 追加 go / rust,并为两者补 default_source 示例源码,
使新增语言在 /admin/runner 试运行沙箱的语言切换按钮中可见、可用。

前端语言集合此前是注册表的手动镜像副本(注释已声明需对齐),
本次保持该约定;runner.rs:15 的注释依然准确。
2026-07-09 10:52:03 +08:00
xfy
e48e992ca1 fix(system): add key to tab content div to fix skeleton delay
Without a key, Dioxus 0.7 VDOM diffing may reuse hook slots from
the previous tab component on tab switch. This caused DelayedSkeleton's
visible signal to retain the old true value, bypassing the 200ms delay.

Adding key based on active_tab forces full unmount/remount on tab switch.
2026-07-09 10:22:29 +08:00
xfy
c624997c04 feat(code-runner): add Go and Rust language support
为 Code Runner 新增 Go 和 Rust 两种编译型语言,沿用现有 base 镜像分层结构。

Go:
- run_cmd 直接用 go run(单条命令,内部编译+运行)
- 镜像把 GOCACHE/GOTMPDIR/GOPATH 重定向到 /tmp tmpfs
  (只读根文件系统下 /Users/issuser/.cache 不可写)
- default_limits: 1 核 / 256MB / 10s(编译冷启动比解释型慢)

Rust:
- rustc 编译 + 运行是两步,但 docker.rs 注入脚本用 exec 执行 run_cmd,
  exec 替换 shell 进程后 'A && B' 后半段不执行,
  因此镜像内置 /usr/local/bin/run-rust.sh wrapper 封装两步
- default_limits: 1 核 / 512MB / 15s(rustc 内存大、编译慢)

新增镜像与白名单后,默认 CODE_RUNNER_LANGUAGES=python,node,go,rust。
2026-07-09 09:40:32 +08:00
xfy
d690910efa fix(admin): 消除骨架屏→认证→正常页面的布局闪烁
合并 (true, None) 和 (false, _) 两个分支为统一的 fallback 骨架屏。
旧 (true, None) 分支渲染无侧边栏的全屏居中文字「正在验证身份...」,
与骨架屏 / 正常页面的侧边栏+卡片布局完全不同,在 checked.set(true)
同步触发 re-render 时产生明显的布局跳变。统一后三个状态的布局结构
一致,过渡平滑无闪烁。
2026-07-08 18:23:08 +08:00
xfy
53de550d7c fix(admin): 修复后台骨架屏不可见问题
- admin_layout: 移除 (false, _) 分支中的 DelayedSkeleton 包裹,直接渲染
  骨架屏并附加 animate-pulse。DelayedSkeleton 依赖 use_effect 延迟 200ms
  置 visible=true,但 SSR 不执行 effect,导致服务端 HTML 输出空节点;
  hydration 后 checked 又会立即置 true 退出该分支,骨架屏窗口趋近于零。
  去掉后 SSR HTML 直接包含骨架屏,用户在 WASM 加载 + 身份校验期间可见。

- comments: loading 初始值从 false 改为 true,与 use_paginated hook 保持
  一致。旧值导致首帧 loading()=false,骨架屏条件永远不满足。
2026-07-08 18:20:25 +08:00
xfy
3eaf330673 fix(admin): use flex split layout for write page to fix sticky footer jump
The sticky footer with -mt-12 negative margin caused a jump when
scrolling to bottom: sticky bottom-0 positions against the scroll
container's padding box, but the negative margin pulls the element up
by 48px, so at scroll-end the footer shifts up and clips the editor.

Replace sticky+neg-margin with a proper flex split layout:
- AdminLayout: write route now gets overflow-hidden on the card and a
  padding-free, non-scrolling flex main; other admin pages unchanged.
- write.rs: root becomes flex-col; content area is flex-1 overflow-y-auto
  with the px-10 py-12 padding moved here; footer is a flex-shrink-0
  sibling that sits at the card bottom permanently, never scrolls, never
  jumps.

min-h-0 added on flex children so overflow can shrink below content
height (required for flex + overflow to work).
2026-07-08 18:14:23 +08:00
xfy
7c98eee285 fix(admin): remove redundant pt-8 on write page top spacing
After the shell unification, main already provides py-12 (48px) top
padding via the shared admin shell. The write page's own pt-8 (32px)
was a leftover from when it had no outer card, so it stacked to 80px —
much larger than other admin pages. Remove it to match.
2026-07-08 17:46:50 +08:00
xfy
25c3172b7c fix(admin): unify write page shell with other admin pages + sticky footer
The write route had a separate shell in AdminLayout (main element acted
as its own rounded card + scroll container), while all other admin pages
used a dedicated rounded-card div wrapping a centered main. This caused
visible margin/spacing differences.

Changes:
- AdminLayout: remove is_write_route shell branching; all admin pages now
  share the same rounded-card div + centered main shell.
- write.rs: drop redundant max-w-7xl mx-auto on root div (main already
  provides it); make bottom action bar sticky bottom-0 with negative
  margins to bleed to card edges and a translucent backdrop so scrolling
  content doesn't bleed through.
2026-07-08 17:42:25 +08:00
xfy
5c37b17cb8 fix(admin): align runner page width with other admin pages
runner.rs was the only admin page using max-w-5xl (1024px) while all
others (system/comments/dashboard/posts/posts_trash/write) use
max-w-7xl (1280px). The page's own comment claimed to align with
dashboard/posts/system but the width class contradicted that.
2026-07-08 17:25:39 +08:00
xfy
d72495c002 refactor(admin): merge trash into /admin/posts as a URL-driven tab
回收站从独立路由 /admin/trash 合并为 /admin/posts 下的一个 tab,
消除「回收站」导航项,让文章管理(列表 + 回收站 + 自动清理配置)集中在
同一页面,符合「相关功能就近聚合」的组织原则。

路由(router.rs)
- 删除 Route::Trash / Route::TrashPage
- 新增 Route::PostsTrash (/posts/trash) 与 PostsTrashPage (/posts/trash/:page)
- 静态段声明在 :page 之前::page 为 i32 类型,天然排斥 'trash' 文本,
  路由匹配安全且遵循文件内 static-first 约定

导航(admin_layout.rs)
- 移除「回收站」导航项
- 「管理文章」高亮覆盖其下所有子路由(列表/分页/回收站 tab),
  顺带修掉原 PostsPage 分页不高亮的小 bug

页面(posts.rs / posts_trash.rs)
- 新增 PostsTabs:URL 驱动的 tab 栏(Link 切换路由,非本地 signal),
  回收站 tab 带 get_post_stats().trash 数量角标,>0 用主题强调色提醒
- trash.rs → posts_trash.rs:TrashPage 重命名为 PostsTrashPage,
  分页路由改指向 PostsTrash/PostsTrashPage,内容(列表/批量操作/
  清空回收站/AutoPurgeSettings)原样迁移;include_str 测试同步更新
- posts.rs 的 PostsPage 渲染 PostsTabs,列表逻辑不变

无后端契约变更:所有 server function(list/delete/restore/purge/
batch/empty_trash/get_trash_settings)签名不变,Pagination 组件
接收具体 Route 变体,给 trash tab 传 PostsTrash 即可,无需改组件。
2026-07-08 16:52:02 +08:00
xfy
9c3f2242ba feat(stats): add trash count to PostStats for posts page badge
为合并回收站到 /admin/posts 的 tab 设计铺路:PostStats 新增 trash 字段,
统计 deleted_at IS NOT NULL 的文章数,供文章列表页「回收站」tab 角标使用。

- stats.rs: 条件聚合查询增加 trash 列,server/非 server 构造同步补字段
- models/post.rs: PostStats 加 pub trash: i64
- cache.rs: post_stats_cache_roundtrip 测试 fixture 补 trash 字段
2026-07-08 16:40:32 +08:00
xfy
ebeec2a295 fix(comments): resolve reactivity dependency tracking in CommentSection hooks 2026-07-08 15:42:44 +08:00
xfy
a72a167a5f fix(comment): resolve potential SSR hydration mismatch in CommentSection 2026-07-08 15:38:29 +08:00
xfy
74a74e77a8 feat(comment): render form and header persistently to eliminate layout shift 2026-07-08 15:32:24 +08:00
xfy
42548d5c3a style(comment): redesign comment list skeleton to match real list layout 2026-07-08 15:30:32 +08:00
xfy
9e70fd9893 feat(runner): set Vim mode default to enabled in CodeRunner 2026-07-08 14:43:57 +08:00
xfy
cda5a92230 feat(runner): enable Vim mode toggle for CodeRunner sandbox 2026-07-08 14:37:52 +08:00
xfy
3bb67f6673 style(runner): optimize CodeMirror editor height auto-scaling and scrolling limit 2026-07-08 14:32:04 +08:00
xfy
f60bc4beaa fix(runner): fix CodeMirror editing reversion feedback loop 2026-07-08 14:28:45 +08:00
xfy
61c64841f9 refactor(skeletons): 统一骨架屏延迟机制,200ms 内加载不显示
- DelayedSkeleton 从「延迟 pulse 动画」改为「延迟渲染」:
  前 200ms 完全不渲染,超时后才显示并带 pulse 动画
- admin_layout 从 use_delayed_loading hook 改为 DelayedSkeleton 包裹
- CommentListSkeleton 的两处裸用(section.rs / post_detail.rs)
  补上 DelayedSkeleton 包裹
- 移除不再使用的 use_delayed_loading hook 模块
2026-07-08 14:18:08 +08:00
xfy
5b9e65bf72 fix(editor): 修复文章页折叠行被撑高 & 折叠图标垂直不居中
文章页 CodeRunner 嵌在 .md-content 内,CodeMirror 折叠后插入的
<img class="cm-widgetBuffer">(width:0、height:1em 的占位符,用于对齐折叠
widget 基线)被 .md-content img 的 margin:1rem 0 命中,上下各 16px margin
把折叠那行 .cm-line 撑到 47.5px(试运行页不在 .md-content 内,正常 19.6px)。
对比两页 .cm-line 的 children 锁定:文章页含 cm-widgetBuffer,试运行页没有。

input.css:.md-content img 选择器加 :where(:not(.cm-widgetBuffer)) 排除占位 img,
用 :where() 压低特异性避免影响其它规则。

themes.ts:core 对折叠列 .cm-foldGutter .cm-gutterElement 完全没设样式,格子
高度 ≈ font-size(14px) 比正文行(line-height ≈19.6px)矮,图标偏离中央。给格子
flex 居中 + line-height:1.4(复刻 CM 的字号×1.4 行高算法),图标落在正文行中央。
2026-07-08 14:03:14 +08:00
xfy
20540358c2 docs: remove Playwright from agents 2026-07-08 13:44:17 +08:00
xfy
533f12e851 fix(editor): 修复 CodeMirror 折叠图标垂直不居中
折叠三角 (▾/▸) 在每行行框里偏低,根因有二:

1. 图标字符本身基线不稳。codemirror 包的 basicSetup 调 foldGutter() 用默认
   openText "⌄" (U+2304「下花括号」),这是个基线/字形表现不稳定的符号字符,
   在多数 mono 字体里墨迹落在字符框底部,三角明显偏低。本地内联一份 basicSetup
   (CodeMirror 官方推荐的定制方式),改用几何形状块字符 ▾ (U+25BE) /
   ▸ (U+25B8),字形本身在字符框内居中;同时把 foldGutter() 展开后丢弃的
   @codemirror/{lint,search} 显式声明为依赖。

2. core 没给图标 <span> 设 vertical-align/display。baseTheme 只给
   .cm-foldGutter span 设了 padding/cursor,图标默认按基线贴在格子底部。
   themes.ts 加一条 flex 居中规则,把 .cm-foldGutter .cm-gutterElement 变成
   flex 容器,三角稳稳落在行框中央。

文章页 CodeRunner 与后台 SQL 控制台共用同一份 editor.js,一处修复两处生效。
2026-07-08 13:19:59 +08:00
xfy
7d0922c0f9 feat(editor): 可运行代码块在 CodeMirror 挂载前显示骨架屏
SSR 渲染时 CodeMirror 容器为空(JS 编辑器不在服务端拉起),hydration
完成前用户看到一块空白区域。新增 editor_ready signal(声明在 cfg 块外,
SSR/客户端双目标可见),CodeMirror 挂载后置 true、卸载时复位。

容器改为 relative,未就绪时叠加一层绝对定位覆盖骨架屏——5 行宽度递减
(90/70/55/85/40%) 的脉冲占位条,模拟代码缩进语境,配色沿用
paper-code-block / paper-tertiary 语义 token。容器本身始终在 DOM
(不与 CodeMirror 的 getElementById 挂载冲突),editor_ready 置 true
后骨架屏 if 分支消失即从 DOM 移除。

Playwright(release)验证:SSR 即渲染骨架屏(5 占位条,无闪烁),
hydration 后骨架屏消失、CodeMirror 可见。
2026-07-08 11:22:06 +08:00
xfy
b95777e58d fix(editor): 修复 SSR 直接访问时可运行代码块不挂载 CodeMirror
CodeRunner 原用 use_hook(|| format!("code-runner-{}", now_pseudo_unique()))
生成容器 id,后缀依赖 now_millis() 时间戳。Dioxus hydration 不传递
use_hook 状态——SSR 渲染与客户端 hydration 各执行一次 use_hook,时间戳
(以及顺带验证过的 ScopeId)两端不同,导致 CodeMirror create() 在 hydration
时用新 id 去 getElementById,找不到 SSR 渲染的容器(id 是旧值),返回 null
不挂载。路由跳转是纯客户端渲染,use_hook 只跑一次 id 一致,故正常。

改为由父组件传入确定性的 instance_id(PostContent 的片段索引 i,来自纯函数
split_content_fragments 对同一 content_html 的解析,SSR 与 hydration 一致),
container_id 直接派生自该 prop,不进 use_hook。admin 试运行页单实例固定 0。

Playwright(release 构建)验证:SSR 直接访问与路由跳转 .cm-editor 均为 1。
2026-07-08 11:04:40 +08:00
xfy
8f6c864f22 chore(tiptap): 移除未使用的 RunCodeOptsJs 重导出
RunCodeOptsJs 只在 mod wasm 内部用作 Closure 类型参数,无外部消费者,
从 pub use 重导出列表移除以消除 unused_imports warning。
2026-07-07 18:34:17 +08:00
xfy
a37b0ee811 docs: 修复 cargo doc 的两处 broken intra-doc links
- runner.rs: 把含函数调用表达式的 rustdoc 链接 `[crate::codemirror_bridge::get_module().create]`
  改为普通代码片段;get_module 是 WASM 专属符号,server target rustdoc 解析不到
- sql_result_table.rs: 模块级 doc 里裸用 `[SqlResult]` 但该类型来自 server-gated
  模块不在作用域,改为纯代码片段并补全路径
2026-07-07 18:29:54 +08:00
xfy
82315853a2 fix(tiptap): slash 命令创建可运行代码块时模态框被立即关闭
斜杠菜单中按 Enter 选择「可运行代码块」时,openRunnableModal 在
同一个 keydown 事件处理中同步调用。模态框的 document keydown 监听
立即注册后,该 Enter 事件继续冒泡到 document 触发模态框的 Enter
处理——insert() → close(),模态框在同一 tick 内创建又销毁,用户
看不到配置弹框。

将 document.addEventListener("keydown", ...) 延迟到 setTimeout(0)
注册,确保触发事件完成传播后才开始监听。
2026-07-07 17:51:06 +08:00
xfy
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
xfy
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
xfy
2a3a48af4e docs(agents): 记录 Tiptap 交互 bug 用 Playwright 调试的方法论
happy-dom 测不出 ProseMirror 真实交互 bug(键盘/selection/NodeView/
Suggestion range)。记录 Playwright 反馈环的标准搭建与诊断模式:
逐字符输入、调试写 DOM、二分定位 NodeView。附 /code 文本残留案例。

这类 bug 不进 git:repro.mjs/package.json/node_modules 用完即删。
2026-07-07 12:01:55 +08:00
xfy
df8f7397b2 fix(editor): 斜杠命令文本残留进新节点(/code 带入 codeBlock)
Suggestion 传给 command 的 range 在某些输入路径下过时——停在首次
输入 '/' 的位置 {from:1,to:2},不随后续字符更新。deleteRange 只删 '/',
命令文本(如 'code')残留,被 toggleCodeBlock 包进新节点。

该 bug 同时导致衍生症状:残留文本让 codeBlock 非空,Backspace 的
clearNodes 条件(!textContent.length)不成立,空块退格看似无效。

修复:command 转发处防御性重算 range——基于当前 selection 在同一段落
内往前找触发字符 '/',删到光标位置。对所有命令统一生效。

经 Playwright 真实浏览器复现验证(happy-dom 无法复现此 bug):
- /code 回车:codeBlock 现为空(原残留 'code' 文本)
- 空 codeBlock 退格:正常删除变段落(原无反应)
2026-07-07 11:59:26 +08:00
xfy
7fbaae7622 feat(editor): 斜杠命令空状态显示「无匹配命令」
搜索无结果时浮层显示居中提示(非空白卡片)。同步修两个空列表 bug:
- ArrowUp/Down 对 % 0 产生 NaN(除零)
- Enter 被吞(preventDefault 后无项可选,用户回车无反应)

空列表时方向键/回车放行(return false),仅 Escape 拦截关闭。
导出 createPopup 补 6 个 happy-dom 用例。
2026-07-07 10:24:54 +08:00
xfy
9a90514470 feat(editor): 斜杠命令支持英文别名搜索(中英文互通)
每条命令补 keywords 字段(空格分隔英文/常见词),搜索时 title/description/
keywords 任一命中即匹配。/code 现在能命中「代码块」,/link 命中「链接」。

提取 matchCommand 纯函数(原 inline filter),补 30 个用例覆盖中英文命中、
大小写不敏感、keywords 缺省回退、不命中场景。
2026-07-07 10:15:44 +08:00
xfy
d8036c6e70 fix(editor): 代码块内 Backspace 删整块(ignoreMutation 误忽略 contentDOM 编辑)
CodeBlockNodeView.ignoreMutation 无条件返回 true,导致 contentDOM(<code>)
内的 characterData/childList mutation 被忽略,ProseMirror 文档状态与 DOM
失同步——输入文字它不知道,Backspace 时基于错误状态重建,表现为删整块。

改为对齐 ProseMirror/Tiptap 默认 NodeView 逻辑:
- contentDOM 内的 mutation(characterData/childList)→ false(交给 PM)
- selection → false
- contentDOM 自身 attributes(高亮改 class)→ true(忽略)
- 工具栏/结果区装饰元素 → true(忽略)

补 2 个回归用例覆盖 contentDOM 内/外分支。参数类型改 ViewMutationRecord
(含 selection,ProseMirror 扩展类型)。
2026-07-07 10:03:36 +08:00
xfy
c8b2248066 fix(editor): runnable 块 classList.add 抛 InvalidCharacterError
CodeBlockNodeView 构造时把完整 info string 原样拼进 class
(`language-python runnable {...}`),classList.add 拒绝含空格 token,
导致编辑模式回填含 runnable 块的文章时崩溃(setMarkdown → addNode)。

改用 extractLang 只挂纯语言名 class。高亮靠 CodeBlockLowlight decoration,
本就不依赖此 class。补回归测试。
2026-07-07 09:41:05 +08:00
xfy
05460f1257 Merge branch 'feat/editor-runnable-codeblock'
编辑器三大增强:
- 斜杠命令插入可运行代码块(模态框配置语言+overrides)
- CodeBlockLowlight 语法高亮(Catppuccin Latte/Mocha,对齐读者侧)
- CodeBlockNodeView:语言标签 + 运行按钮(仅 runnable) + 内联运行结果

运行经 onRunCode 回调桥接到 Rust(start_exec + 轮询 get_exec_result)。
markdown 往返保真(language 承载完整 info string)。
2026-07-06 18:34:54 +08:00
xfy
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
xfy
0c1e8b7640 feat(bridge): 新增 make_run_code_closure 桥接编辑器内运行代码
tiptap_bridge.rs:
- EditorOptions extern 追加 set_on_run_code setter (js_name=onRunCode)
- 新增 RunCodeOptsJs 映射(language/source/overridesJson getter)
- 新增 format_run_result + make_run_code_closure
  · start_exec + 500ms 轮询 get_exec_result,30s 上限
  · overridesJson 空串视为 None,畸形 JSON 静默降级
  · 不依赖 server-only 的 languages 模块(前端 extractLang 已提取纯语言名)
- EditorHandle 加 _on_run_code 字段 + new 参数
- pub use 导出 make_run_code_closure + RunCodeOptsJs

write.rs: 跟进 EditorHandle::new 新签名(构造 on_run_code + set_on_run_code)。
2026-07-06 18:11:28 +08:00
xfy
6bdc48e84c feat(editor): CodeBlock NodeView 工具栏与结果区样式
语言标签 + 运行按钮 + 结果区,亮/暗双套 Catppuccin 配色。
runnable 绿条移到 .tiptap-codeblock 容器(替换旧 pre 绿条规则)。
2026-07-06 18:02:32 +08:00
xfy
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
xfy
82280e3d4f feat(editor): CodeBlockNodeView 显示语言标签与运行按钮
自定义 NodeView 包裹 <pre><code>,顶部工具栏显示语言(extractLang 提取),
runnable 块额外显示运行按钮。contentDOM 指向 <code>,保证 CodeBlockLowlight
decoration(高亮)正常生效。运行走 editor.storage.__onRunCode 回调。
2026-07-06 17:59:01 +08:00
xfy
0adc6d8382 fix(editor): 暗色 type 色值修正 + extractLang 小写化
- .dark .hljs-type/.hljs-title.class_ 由 #8839ef(紫) 改为 #f9e2af(黄),
  与 spec 表、官方 @catppuccin/highlightjs、读者侧 highlight.css 三处对齐
- extractLang 加 toLowerCase,与后端 parse_fence_info(languages.rs:85)对齐,
  避免大写语言名触发 lowlight Unknown language 抛错
2026-07-06 16:13:08 +08:00
xfy
4de48cd16c style(editor): biome 修正 import 排序(highlight/index)
TDD 阶段子代理未跑 biome check --write,补齐 import 字母序以过 make lint。
2026-07-06 15:53:16 +08:00
xfy
8493e4c4c4 feat(editor): 代码块语法高亮配色(Catppuccin Latte/Mocha)
色值取自 @catppuccin/highlightjs@1.0.1,与读者侧 highlight.css 同一 palette。
亮/暗双套,.dark 前缀切换,scope 到 .tiptap-editor 避免污染全站。
2026-07-06 15:50:35 +08:00
xfy
e86fe0767d feat(editor): 用 CodeBlockLowlight 替换 StarterKit 自带 CodeBlock
禁用 StarterKit codeBlock,引入 CodeBlockLowlight + lowlight 实例。
代码块现在有实时语法高亮(ProseMirror decoration),language 属性
仍承载完整 info string(markdown 往返不变)。
2026-07-06 15:48:02 +08:00
xfy
e79e0d9ee2 feat(editor): 新增 lowlight 实例与 extractLang 语言提取
common 集(~35 种语言)注册到 lowlight;extractLang 从完整 info string
(如 'python runnable {...}')提取首 token,使 runnable 块按正确语言高亮。
2026-07-06 15:45:42 +08:00