826 Commits

Author SHA1 Message Date
xfy
9851f98dc0 chore(docker): setup sandboxed runtime containers and build script
- runner-base: alpine 3.18 + 非 root 用户 1000:1000 + /code 工作目录
- runner-python: 基于 base, apk add python3 + python 符号链接(对齐 run_cmd 'python')
- runner-node: 基于 base, apk add nodejs
- runner.toml: 镜像自描述(运行时实际配置由 Rust LANGUAGES 注册表 + 环境变量决定)
- build-runners.sh: 按 base→python→node 顺序构建, tag 与 languages.rs 严格对齐
2026-07-03 18:48:03 +08:00
xfy
bbd4553467 feat(admin): add dedicated code-runner sandbox page at /admin/runner
不改动 852 行的 write.rs 编辑器布局,改为独立 admin 页面(与 posts/system 同款):
- runner.rs: Runner 页面(语言切换 join 按钮 + overrides JSON 输入 + CodeRunner 沙箱)
  切换语言自动填充示例源码;overrides JSON 实时校验,畸形时提示并忽略
- mod.rs: 注册 runner 模块并导出 Runner
- router.rs: 新增 #[route("/runner")] Runner {} 嵌套在 /admin 下
- admin_layout.rs: 导航新增「试运行」入口
2026-07-03 18:41:05 +08:00
xfy
0e8b5fd7b7 feat(ui): scan and mount code-runner component client-side in reader
采用 Dioxus vdom 友好的片段拆分(避免篡改 dangerous_inner_html 产物导致 hydration 冲突):
- post_content.rs: split_content_fragments 把 content_html 拆成 Html/Runnable 片段,
  Runnable 作为 <CodeRunner> 组件穿插渲染;HTML 实体解码还原源码;6 个单测
- markdown.rs: 可运行 pre 增加 data-source(转义后的原始源码), 供阅读器无损提取
- sanitizer.rs: 放行 pre 的 data-source 属性

(任务 7 的 data-source 增量一并在此提交)
2026-07-03 18:35:57 +08:00
xfy
6b875e6ba5 feat(ui): create CodeRunner Dioxus UI component with async polling
- runner.rs: CodeRunner 组件(源码展示 + Run 按钮 + 阶段/输出/错误区)
  spawn 提交 StartExec 后用 sleep_ms(WASM 友好) 轮询 GetExecResult,MAX_POLLS 兜底
  mut 信号加 cfg_attr 放行 server 的 unused_mut(AGENTS.md 约定)
  提前克隆 source/language 给 move 闭包,避免 rsx! 二次借用 (E0382)
- execute.rs: 修正双目标可见性——server fn 模块不能 cfg-gate
  共享类型 use 双目标可见,server-only 辅助 use 单独 gate(对齐 posts 模块约定)
- mod.rs: execute 不再 gate,languages/progress 仍 gate
2026-07-03 18:28:52 +08:00
xfy
576803302d refactor(editor): support dynamic languages python/javascript in codemirror
- editor.ts: 新增 languageCompartment + buildLanguageExtension(lang, schema)
  python → lang-python, node/javascript → lang-javascript, sql/缺省 → lang-sql
  新增 setLanguage(lang) 热切换; setSchema 保留当前语言不被强制切回 sql
- package.json: +@codemirror/lang-python +lang-javascript
- codemirror_bridge.rs: EditorInstance 新增 set_language wasm-bindgen extern

(产物 public/codemirror/ 被 gitignore,本地已重建)
2026-07-03 18:22:21 +08:00
xfy
a77a2e3502 feat(markdown): support rendering and sanitizing runnable pre code-blocks
- markdown.rs: CodeBlock 处理识别 `runnable` 标记 + 受支持语言,在 <pre> 上
  挂 data-runnable/data-lang/data-overrides;overrides JSON 经 escape_html 转义
  防属性注入;非可运行围栏的 language-xxx 改取纯语言 token(首个空白前)
- sanitizer.rs: clean_html 放行 <pre> 的 data-runnable/data-lang/data-overrides
- 新增 4 个 markdown 测试 + 2 个 sanitizer 测试覆盖转义/白名单/字段顺序
2026-07-03 18:19:26 +08:00
xfy
9fe128d44d feat(api): implement StartExec and GetExecResult server functions
- rate_limit.rs: 新增 CODE_EXEC 双层限流(per-second burst + 每日总额)
  governor 0.8 无 per_day,用 with_period(24h)+allow_burst 模拟
- execute.rs: StartExec(IP 提取/语言白名单/源码大小/入队/并发信号量/clamp/容器执行)
  + GetExecResult(轮询读取 DashMap);系统异常脱敏,日志记详情
- .env.example: RATE_LIMIT_CODE_EXEC_PER_SEC 改为整数(governor 不支持小数)
2026-07-03 18:15:59 +08:00
xfy
3f3bbf284c feat(api): add language registry and markdown fence info parser 2026-07-03 18:11:43 +08:00
xfy
9baa9da62f feat(api): implement in-memory task registry with gc 2026-07-03 18:10:20 +08:00
xfy
60fd6378b6 feat(api): define shared serialized structs for code runner
Co-authored-by: plan docs/superpowers/plans/2026-07-03-code-runner.md Task 3
2026-07-03 18:09:27 +08:00
xfy
5fdc88a48c fix(runner): resolve task 2 container runner review findings 2026-07-03 18:02:56 +08:00
xfy
f6042d23f6 chore(skill): add matt-pocock engineering skills
Add 20 engineering/productivity skills from mattpocock/skills:
ask-matt, code-review, codebase-design, diagnosing-bugs,
domain-modeling, grill-me, grill-with-docs, grilling, handoff,
implement, improve-codebase-architecture, prototype, research,
setup-matt-pocock-skills, tdd, teach, to-issues, to-prd, triage,
writing-great-skills.

Update skills-lock.json with corresponding source/hash entries.
2026-07-03 18:00:16 +08:00
xfy
d8d30df80c feat(infra): implement Docker execution layer using bollard client 2026-07-03 17:59:52 +08:00
xfy
b0ebba3475 fix(runner_config): remove server gate on runner_config, safeguard clamp logic, and parse allow_network case-insensitively 2026-07-03 17:52:50 +08:00
xfy
60725053e4 feat(infra): implement runner config parsing and resource limits clamping 2026-07-03 17:50:42 +08:00
xfy
2fba43dc3f chore(infra): add bollard dependency and modular structure 2026-07-03 17:49:08 +08:00
xfy
c85a898fbd docs(skill): add yggdrasil-ui-design-taste skill 2026-07-03 17:43:19 +08:00
xfy
922d1d0755 fix(ui): apply border-radius to table corner cells to prevent background bleed 2026-07-03 17:31:05 +08:00
xfy
0dbbc9d813 fix(ui): remove display block from table to fix horizontal fill rendering 2026-07-03 17:29:52 +08:00
xfy
c7b11b7f04 style(ui): redesign markdown tables to match modern aesthetic 2026-07-03 17:27:54 +08:00
xfy
46860f7c41 fix(ui): apply mount animation inside each page component to avoid skeleton interception 2026-07-03 17:24:38 +08:00
xfy
d361bca220 feat(ui): add smooth mount animation for route transitions 2026-07-03 17:21:04 +08:00
xfy
197c08d258 style(ui): fix inconsistent padding on post card 2026-07-03 17:13:02 +08:00
xfy
34d1d65823 style(css): apply minimalist transparent scrollbar globally 2026-07-03 17:05:06 +08:00
xfy
e18fe18cc3 fix(admin/layout): move scrollbar to outer card edge for all admin pages 2026-07-03 16:53:10 +08:00
xfy
52b4f91622 fix(admin/write): restore scrollability by using overflow-y-auto and min-h-full 2026-07-03 16:50:53 +08:00
xfy
acfddb3e17 style(admin/write): overhaul write page to modern minimalist layout 2026-07-03 16:44:39 +08:00
xfy
d3a50728ed style(admin): overhaul layout to modern minimalist sidebar design 2026-07-03 15:50:59 +08:00
xfy
38ba6692d3 style(admin): redesign admin UI with soft rounded corners and Catppuccin theme 2026-07-03 15:46:18 +08:00
xfy
9f69a132fa refactor(admin): redesign write page for industrial aesthetic 2026-07-03 15:37:41 +08:00
xfy
cad0e3d83b fix(admin): restrict write page width to match other pages 2026-07-03 15:35:06 +08:00
xfy
d1041a84dd feat(admin): complete redesign of backend ui with industrial minimalist aesthetic 2026-07-03 15:32:02 +08:00
xfy
45f4e9cde0 refactor(ui): 去除 Rust 中硬编码颜色,统一语义色阶
跟随 Catppuccin 配色迁移,清理 src/ 中绕过 paper-* 语义 token 的
硬编码 dark:[#hex] 任意值,改用 Tailwind 默认灰阶(gray-700/800),
它们随主题切换自然适配。

- post.rs 状态徽章:dark:bg-[#333]/dark:text-[#9b9c9d] → gray-800/gray-400/500
  (同步更新测试断言)
- comments/* 与 skeletons/* 的 dark:[#2a2a2a]/[#2e2e33]/[#333]/[#5a5a62]
  → 对应 gray-600/700/800
- trash.rs 状态灯发光圈 rgba 由旧鼠尾草绿(92,122,94) 改 Latte green(64,160,43)
- ui.rs BTN_SECONDARY 注释更新为新 Teal 强调色值

注:src/pages/admin/posts.rs 的 clippy redundant_closure 报错为既有问题,
与本次配色迁移无关,不在范围内。
2026-07-03 14:25:40 +08:00
xfy
90fc6977b0 feat(editor): Tiptap 编辑器配色迁移到 Catppuccin(Latte/Mocha)
编辑器 CSS 此前用硬编码 GitHub 风格色(#0366d6/#d73a49/#24292e 等),
独立于 paper-* 语义 token。逐元素重映射到 Catppuccin 调色板:

亮色 Latte:正文 text、标题 text、placeholder overlay0、
  行内 code surface0/red、pre crust、blockquote surface1/subtext0、
  hr surface1、链接 blue、selection surface0、表格 surface1/crust、
  slash 弹层 mantle/surface0、checkbox/选中态 green(主强调)
暗色 Mocha:对应角色映射(text/cdd6f4 等)

上传遮罩的 rgba(255,255,255,*) 白字与 rgba(239,68,68,*) 红删除按钮
属中性覆盖层,保留不动。
2026-07-03 14:18:03 +08:00
xfy
385fb43516 feat(theme): 全站配色迁移到 Catppuccin(Latte/Mocha)
亮色 Latte、暗色 Mocha。语义 token 重新映射:
- theme/entry 背景用 base/mantle
- primary/secondary/content 文字用 text/subtext1/subtext0
- tertiary 占位符用 overlay0
- code-block/code-bg 用 crust/surface0
- border 用 surface1
- 主强调 accent 改 Green(#40a02b / #a6e3a1)
- 次强调 accent-2 改 Teal(#179299 / #94e2d5)

同步修正组件层硬编码字面量:
- md-content 链接 hover 改用 accent-2(Teal)
- copy-code 按钮用 paper-tertiary/paper-theme/accent 语义色
- blur-img 灰底去掉 fallback,直接用 paper-code-bg 变量

破坏性变更,不兼容旧色。
2026-07-03 14:11:07 +08:00
xfy
cb77d28a68 fix(theme): 跟随系统切换改为瞬切,放弃 VT 动画
诊断确认:跟随系统与手动点击的 VT 流程在 JS/CSS 层完全等价(animationName、
--tt-r、bg 翻转、clip-path 全部正确),但视觉上跟随系统场景下圆形展开动画
不显示,仅瞬切。系统偏好变化是后台事件,VT 在此上下文下动画不可靠。

改用设置语义的瞬切:JS 侧新增 applyResolvedTheme(isDark) 入口(非翻转语义,
直接 add/remove dark class),Rust effect 改调 __applyResolvedTheme 传实际
明暗值,移除圆心计算逻辑。职责清晰:
- 手动点击 → __startThemeTransition → VT 圆形展开(用户手势,动画可靠)
- 跟随系统 → __applyResolvedTheme → 瞬切(后台同步语义)
2026-07-03 13:42:17 +08:00
xfy
eb3087edf4 fix(theme): 跟随系统切换用主题按钮位置作为 VT 圆心
诊断发现跟随系统与手动点击的 JS 路径完全一致(__startViewTransition 全程
正常,无降级、无 reject),「看起来像淡入淡出」实为圆形展开动画在屏幕中心
圆心下的必然视觉效果:从中心向四周等距扩散,各方向同步推进,近似整体覆盖,
与手动点击(按钮在右上角,圆弧明显横扫)观感差异大。

改用 .theme-toggle 按钮的 getBoundingClientRect() 中心作为 VT 圆心,与手动
点击的动画起点一致;按钮不在 DOM 时回退到视口中心。同步更新注释说明。
2026-07-03 13:26:40 +08:00
xfy
740afca05a chore: 在 lint 中添加类型检查并新增加载图标
- 在 Makefile 的 lint 目标中增加 `pnpm typecheck`
- 添加带渐变效果的旋转加载 SVG 图标
2026-07-03 11:36:24 +08:00
xfy
188fc464e2 fix(theme): System 模式下系统偏好变化时同步 dark class
原实现存在缺口:<html> 的 dark class 运行时写入点只有「首屏预加载脚本」与
「手动点击 ThemeToggle」两处,System 模式下系统颜色偏好自动变化时无人同步——
尽管 system_dark signal 与 resolved memo 都会更新,下游(CodeMirror 等)也
能跟随,但页面配色纹丝不动,与文件头注释承诺的「实时同步 .dark class」不符。

新增 use_effect 兜底:仅 System 模式下 resolved 实际翻转时,以视口中心为圆心
复用 __startThemeTransition 触发 VT 圆形展开动画。Light/Dark 显式模式由
ThemeToggle::onclick 全权负责,effect 不介入,避免重复触发;首次挂载通过
prev_resolved 信号记录基线,自然跳过(DOM 已由 ThemePreload 设好)。
2026-07-03 11:35:10 +08:00
xfy
c79c390482 fix(ui): ADMIN_TABLE_CLASS 去掉 overflow-hidden,修复 tooltip 被裁
overflow-hidden 用于圆角裁剪表格,但会硬裁掉行内按钮的 tooltip
(无论朝上朝下)。去掉后:表格行 hover 背景 (bg-paper-entry) 与
容器背景同色,圆角处无视觉差异,tooltip 可正常溢出表格边界。
全局生效,所有 admin 表格的 tooltip 不再被裁。
2026-07-03 11:15:48 +08:00
xfy
64ad40ca61 fix(admin/posts): Tooltip 包裹后操作按钮恢复垂直居中
- Tooltip 外层 div 由块级改为 inline-flex,作为行内伸缩盒参与
  flex 行对齐,不再撑高或破坏基线
- 操作列容器补 items-center,显式锁定所有子项垂直居中
2026-07-03 11:08:04 +08:00
xfy
73b9cad550 refactor(ui): 抽取 Tooltip 组件,行内重建按钮补 tooltip
新增可复用 Tooltip 组件(group-hover 显现,支持 top/bottom 朝向),
消除顶部重建按钮手写的内联 tooltip div 重复,并为表格行内重建
按钮补上 tooltip(朝上,避免被表格容器的 overflow-hidden 裁掉)。
2026-07-03 11:03:56 +08:00
xfy
b6fe0ae082 style(admin/posts): 删除按钮 loading 用 spinner 覆盖文字
- 删除改为非乐观:点击后保留行并显示 loading,服务端成功才移除行、
  失败保留行并弹提示(顺带修掉原先「删除失败行却没了」的隐患)
- deleting 信号由 Option<i32> 改为 HashSet<i32>,支持并发删除
- 删除按钮 loading 样式与重建一致:文案恒为「删除」,spinner
  居中覆盖、文字 opacity-40 衬底
2026-07-03 10:51:16 +08:00
xfy
1530d3a2f4 style(admin/posts): 顶部重建按钮 loading 用 spinner 覆盖文字
工具条「重建内容」「重建全部」按钮 loading 时由「重建中...」文案
改为 spinner 居中覆盖、文字 opacity-40 衬底,与行内重建按钮的
loading 样式统一。
2026-07-03 10:46:57 +08:00
xfy
db87d3c886 fix(admin/posts): 重建支持并发 loading,spinner 覆盖文字
- rebuilding 信号由 Option<i32> 改为 HashSet<i32>,连续点击多篇
  文章的重建按钮可同时处于 loading 态(单值会被后点的覆盖)
- loading 样式调整:按钮文案恒为「重建」,spinner 绝对定位覆盖在
  文字上方居中,文字 opacity 调至 40% 衬底,不再切换文案
2026-07-03 10:40:11 +08:00
xfy
a5c00caa80 style(admin/posts): 操作列加宽横排,重建按钮 loading 用 spinner 图标
- 操作列宽 w-24 → w-44,三个按钮一行排开不换行
- 重建按钮 loading 态由「重建中...」文案改为 spinner 图标 + 「重建中」
- spinner 复用 public/icons/90-ring-with-gradient.svg,作为 SPINNER_SVG
  常量收入 ui.rs(修正原 SVG 损坏的孤立 ':' 选择器,重命名 id/类名
  避免多处内联时冲突),用 currentColor 继承按钮文字色
2026-07-03 10:26:14 +08:00
xfy
e55f2e12bd refactor(admin/posts): 重建按钮文案改「重建」并去掉完成弹窗
按钮态文案与原有一致(「重建中...」);on_rebuild 改为静默执行,
仅按行切换 rebuilding 按钮态,完成后不再弹浏览器 alert。
2026-07-03 10:16:13 +08:00
xfy
0fe0387ea3 feat(admin/posts): 文章列表操作列新增「重建内容」按钮
新增 rebuild_post_content_html(post_id) server function,从 DB 读取
content_md(事务内 FOR UPDATE 锁行)重新渲染 content_html/toc_html
并更新 word_count/reading_time,按影响范围精准失效列表、slug 单篇
与搜索缓存。

PostRow 操作列在「编辑」「删除」之间插入「重建内容」按钮(鼠尾草绿
文字样式),按行禁用并切换「重建中...」文案,成功/失败弹出浏览器
提示,与删除按钮的反馈模式一致。

为避免与单篇 rebuilding 信号冲突,将原批量重建工具条信号 renaming
为 batch_rebuilding。
2026-07-03 10:13:15 +08:00
xfy
687c56af19 fix(post): 恢复文章正文列表的 marker
Tailwind Preflight 全局把 ol/ul 的 list-style 清成 none,
而 .md-content 下的列表规则只恢复了缩进,没有恢复 list-style-type,
导致有序列表不显示数字、无序列表不显示项目符号。

拆分 ol/ul 规则,分别恢复 list-style-type: decimal/disc。
任务列表项(含 checkbox 的 li)已有 list-style: none 覆盖,不受影响。
2026-07-03 09:44:37 +08:00
xfy
0e110cdcbd chore: update rust analayzer 2026-07-02 18:16:16 +08:00