|
|
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 |
|
|
|
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 |
|
|
|
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 |
|
|
|
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 |
|
|
|
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 |
|
|
|
3f3bbf284c
|
feat(api): add language registry and markdown fence info parser
|
2026-07-03 18:11:43 +08:00 |
|
|
|
9baa9da62f
|
feat(api): implement in-memory task registry with gc
|
2026-07-03 18:10:20 +08:00 |
|
|
|
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 |
|
|
|
5fdc88a48c
|
fix(runner): resolve task 2 container runner review findings
|
2026-07-03 18:02:56 +08:00 |
|
|
|
d8d30df80c
|
feat(infra): implement Docker execution layer using bollard client
|
2026-07-03 17:59:52 +08:00 |
|
|
|
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 |
|
|
|
60725053e4
|
feat(infra): implement runner config parsing and resource limits clamping
|
2026-07-03 17:50:42 +08:00 |
|
|
|
2fba43dc3f
|
chore(infra): add bollard dependency and modular structure
|
2026-07-03 17:49:08 +08:00 |
|
|
|
46860f7c41
|
fix(ui): apply mount animation inside each page component to avoid skeleton interception
|
2026-07-03 17:24:38 +08:00 |
|
|
|
d361bca220
|
feat(ui): add smooth mount animation for route transitions
|
2026-07-03 17:21:04 +08:00 |
|
|
|
197c08d258
|
style(ui): fix inconsistent padding on post card
|
2026-07-03 17:13:02 +08:00 |
|
|
|
e18fe18cc3
|
fix(admin/layout): move scrollbar to outer card edge for all admin pages
|
2026-07-03 16:53:10 +08:00 |
|
|
|
52b4f91622
|
fix(admin/write): restore scrollability by using overflow-y-auto and min-h-full
|
2026-07-03 16:50:53 +08:00 |
|
|
|
acfddb3e17
|
style(admin/write): overhaul write page to modern minimalist layout
|
2026-07-03 16:44:39 +08:00 |
|
|
|
d3a50728ed
|
style(admin): overhaul layout to modern minimalist sidebar design
|
2026-07-03 15:50:59 +08:00 |
|
|
|
38ba6692d3
|
style(admin): redesign admin UI with soft rounded corners and Catppuccin theme
|
2026-07-03 15:46:18 +08:00 |
|
|
|
9f69a132fa
|
refactor(admin): redesign write page for industrial aesthetic
|
2026-07-03 15:37:41 +08:00 |
|
|
|
cad0e3d83b
|
fix(admin): restrict write page width to match other pages
|
2026-07-03 15:35:06 +08:00 |
|
|
|
d1041a84dd
|
feat(admin): complete redesign of backend ui with industrial minimalist aesthetic
|
2026-07-03 15:32:02 +08:00 |
|
|
|
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 |
|
|
|
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 |
|
|
|
eb3087edf4
|
fix(theme): 跟随系统切换用主题按钮位置作为 VT 圆心
诊断发现跟随系统与手动点击的 JS 路径完全一致(__startViewTransition 全程
正常,无降级、无 reject),「看起来像淡入淡出」实为圆形展开动画在屏幕中心
圆心下的必然视觉效果:从中心向四周等距扩散,各方向同步推进,近似整体覆盖,
与手动点击(按钮在右上角,圆弧明显横扫)观感差异大。
改用 .theme-toggle 按钮的 getBoundingClientRect() 中心作为 VT 圆心,与手动
点击的动画起点一致;按钮不在 DOM 时回退到视口中心。同步更新注释说明。
|
2026-07-03 13:26:40 +08:00 |
|
|
|
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 |
|
|
|
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 |
|
|
|
64ad40ca61
|
fix(admin/posts): Tooltip 包裹后操作按钮恢复垂直居中
- Tooltip 外层 div 由块级改为 inline-flex,作为行内伸缩盒参与
flex 行对齐,不再撑高或破坏基线
- 操作列容器补 items-center,显式锁定所有子项垂直居中
|
2026-07-03 11:08:04 +08:00 |
|
|
|
73b9cad550
|
refactor(ui): 抽取 Tooltip 组件,行内重建按钮补 tooltip
新增可复用 Tooltip 组件(group-hover 显现,支持 top/bottom 朝向),
消除顶部重建按钮手写的内联 tooltip div 重复,并为表格行内重建
按钮补上 tooltip(朝上,避免被表格容器的 overflow-hidden 裁掉)。
|
2026-07-03 11:03:56 +08:00 |
|
|
|
b6fe0ae082
|
style(admin/posts): 删除按钮 loading 用 spinner 覆盖文字
- 删除改为非乐观:点击后保留行并显示 loading,服务端成功才移除行、
失败保留行并弹提示(顺带修掉原先「删除失败行却没了」的隐患)
- deleting 信号由 Option<i32> 改为 HashSet<i32>,支持并发删除
- 删除按钮 loading 样式与重建一致:文案恒为「删除」,spinner
居中覆盖、文字 opacity-40 衬底
|
2026-07-03 10:51:16 +08:00 |
|
|
|
1530d3a2f4
|
style(admin/posts): 顶部重建按钮 loading 用 spinner 覆盖文字
工具条「重建内容」「重建全部」按钮 loading 时由「重建中...」文案
改为 spinner 居中覆盖、文字 opacity-40 衬底,与行内重建按钮的
loading 样式统一。
|
2026-07-03 10:46:57 +08:00 |
|
|
|
db87d3c886
|
fix(admin/posts): 重建支持并发 loading,spinner 覆盖文字
- rebuilding 信号由 Option<i32> 改为 HashSet<i32>,连续点击多篇
文章的重建按钮可同时处于 loading 态(单值会被后点的覆盖)
- loading 样式调整:按钮文案恒为「重建」,spinner 绝对定位覆盖在
文字上方居中,文字 opacity 调至 40% 衬底,不再切换文案
|
2026-07-03 10:40:11 +08:00 |
|
|
|
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 |
|
|
|
e55f2e12bd
|
refactor(admin/posts): 重建按钮文案改「重建」并去掉完成弹窗
按钮态文案与原有一致(「重建中...」);on_rebuild 改为静默执行,
仅按行切换 rebuilding 按钮态,完成后不再弹浏览器 alert。
|
2026-07-03 10:16:13 +08:00 |
|
|
|
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 |
|
|
|
edee09596c
|
test(api/markdown): 解耦 wrap_images_with_blur 并脱离文件系统依赖
把 wrap_images_with_blur 拆成两部分:
- wrap_images_with_blur_with(html, dims_fn):纯函数核心,接受 dimensions
查询闭包,不碰文件系统
- wrap_images_with_blur(html):薄包装,注入真实 get_image_dimensions
测试改用纯函数核心,注入确定性 dimensions(如 Some((800,600)) 或 None),
彻底脱离 uploads/ 真实文件依赖。此前的 aspect-ratio 测试硬编码了
/uploads/2026/06/18/...webp 真实路径——文件不存在则静默走缺省分支,
断言虽能过但实际验证内容被削弱。
新增覆盖(共 8 个 wrap 相关测试):
- --ar 缺省/有值两种路径
- rel_path 去查询的验证(用 RefCell 捕获 Fn 闭包入参)
- alt 保留(双层)/空 alt 不生成属性
- 斜杠分隔的 --ar 格式 + sanitizer 管线不破坏斜杠
|
2026-07-02 17:39:15 +08:00 |
|
|
|
ab05c01f76
|
test(api/database): 备份恢复补单测 + 修复 backup_path 路径穿越漏洞
backup.rs 是恢复流程的安全关键路径,此前无任何单测。本次:
提取纯函数(便于单测,无行为变更):
- is_valid_backup_filename:文件名白名单校验,替换三处内联 Regex
- parse_backup_mode:从 -- mode: 行提取模式值
- has_valid_signature:首行签名头校验
新增 15 个单测,覆盖:
- 文件名白名单(正常/路径穿越/特殊字符三类边界)
- backup_path 路径穿越纵深防御
- 签名校验(精确/前导空白/非系统文件/空内容)
- 模式解析(pg_dump/sql-fallback/缺失/空值/多次)
修复一个真实的路径穿越漏洞(测试驱动发现):
backup_path("/etc/passwd") 之前返回 /etc/passwd 而非 backups/——
因为 [BACKUP_DIR, filename].collect::<PathBuf>() 在 filename 为绝对
路径时会丢弃 BACKUP_DIR 前缀(PathBuf 语义),随后的 components 检查
在错位的路径上运行而漏判。改为先校验 filename 自身的 components
(只允许 Normal 段),从根上杜绝穿越。
注:第一道白名单 is_valid_backup_filename 已拒绝含 / 的文件名,
故该漏洞实际不可达;但纵深防御必须健壮,本修复使其名副其实。
|
2026-07-02 17:37:07 +08:00 |
|
|
|
533cabb0b5
|
test(api/database): SQL 控制台护栏补表驱动单测 + 加固
sql_console.rs 是 SQL 控制台的安全关键路径,此前无任何单测。本次:
测试(新增 24 个,覆盖护栏 1+2 全分支):
- check_guards: DROP SCHEMA/CREATE DATABASE 绝禁、DROP/TRUNCATE/ALTER
需确认、UPDATE/DELETE 无 WHERE 绝禁(且 confirm 不能救)、多语句短路
- is_absolutely_forbidden: 大小写不敏感、误拦检查、报错名
- statement_type_name / is_read_only: AST 变体映射
- 两条安全不变量测试(见下)
加固(测试驱动发现的两个真实缺口):
1. 字符串预检 contains() 改为 token 序列匹配 is_absolutely_forbidden()——
防多空格/制表符/换行绕过 DROP/CREATE DATABASE。
2. check_guards 补 Statement::CreateDatabase 绝禁分支——此前 sqlparser
能解析 CREATE DATABASE(可绕过字符串预检进 AST),但 AST 层无对应分支,
字符串预检是其唯一防线。现在双重拦截。
并锁定两条安全不变量,防止 sqlparser 升级时悄悄回退:
- DROP DATABASE 不可解析 → 字符串预检是唯一防线
- CREATE DATABASE 可解析 → 双重防线都生效
|
2026-07-02 17:33:19 +08:00 |
|
|
|
65b15509a7
|
chore(wasm): 清理 wasm32 target 下残留的 clippy lint
这些 lint 在 server build(默认 --all-features)下被 cfg 剥离故未暴露,
仅 wasm32 web-only target 触发。逐项清理:
- footer.rs: 两处 redundant closure(web_sys::window 直接传函数引用、
sync_visible 直接传闭包)+ let _ = unit 绑定(scroll_to_*)。
- hooks/event_listener.rs: 复杂类型 Rc<RefCell<Option<(Closure,T)>>>
抽 type ListenerState<T> 别名。
- system.rs: 两处单模式 match { Ok=>.., _=>{} } 改 if let。
- write.rs: split(|c| matches!(c,...)) 改 split([char; N]) 数组模式。
- codemirror_bridge.rs: let _ = instance.destroy() 删 unit 绑定,
与 tiptap_bridge.rs 同处写法对齐。
wasm32 与 server 两 target clippy -D warnings 均通过。
|
2026-07-02 17:15:27 +08:00 |
|
|
|
fee5b7ba94
|
refactor(wasm): 消除 DOM 互操作中的 js_sys::eval 字符串求值
对照 Dioxus "Breaking Out" 文档审查后,将 3 处 js_sys::eval 改为
类型化调用,与 tiptap_bridge/codemirror_bridge 风格统一:
- utils/time.rs sleep_ms:eval("new Promise(r=>setTimeout(r,n))")
改为 js_sys::Promise + web_sys::Window::set_timeout_*,复用项目内
system.rs::wasm_sleep 同款写法。
- theme.rs 主题切换:format!-into-eval 拼 __startThemeTransition(x,y)
改为 Reflect::get 取函数 + Function::call2,消除字符串注入面
(原坐标虽为 f64 无实际风险,但属不必要 eval)。
- post_content.rs:__initPostContent / __initLightbox 两处 eval 字面量
改为 invoke_optional_global 辅助函数(Reflect::get + Function::apply),
消除旧版 "eval 字符串粘贴" 模式;__lightboxSelectors 直接复用 JsValue
传入,省去一次回读。
|
2026-07-02 17:15:18 +08:00 |
|
|
|
ba5b146dfa
|
fix(theme): 消除 detect_initial_theme 的 unreachable_code 警告
wasm 分支末尾的 return Theme::System 在 wasm target 下让尾部兜底
Theme::System 不可达(unreachable_code 警告)。把尾部兜底用
#[cfg(not(target_arch = "wasm32"))] 限定,使其只在 server 分支
(cookie 未命中)或边角构建时编译,wasm target 下函数以 wasm
分支的 return 自然结束,两端都零警告。
|
2026-07-02 16:49:31 +08:00 |
|
|
|
2b6b2ca9e4
|
fix(hooks): 修复 wasm32 target 编译失败
之前验证只跑了 server target(cargo build --all-features),漏掉 wasm32
前端 target,导致三类错误未被捕获:
1. event_listener.rs wasm 分支缺 use dioxus::prelude::*:
use_hook/use_effect/use_drop 来自 prelude,之前重写时误删。补回。
2. event_listener.rs use_effect 闭包 move 冲突(E0507/E0310):
use_effect 回调是 FnMut,但 acquire 是 FnOnce、handler 要 move 进事件
闭包。用 Option::take 模式包裹,首次运行消费,避免重复 move。同时给
A 加上 'static 约束。
3. query.rs items/total/footer.rs sync_visible 缺 mut:
wasm 分支的 .set() 调用需要 mut 绑定。之前为消 server target 的
unused_mut 警告误删,改用 cfg_attr 在非 wasm 时压制警告。
教训:fullstack 项目必须同时验证 wasm32 与 server 两个 target,单一
target 通过不代表整体可用。
|
2026-07-02 16:43:15 +08:00 |
|
|
|
291189fb77
|
fix(sanitizer): 折叠嵌套 if 修复 clippy::collapsible_if
865871f 引入的 checkbox type 白名单逻辑用了嵌套 if,触发 rust 1.96
的 clippy::collapsible_if,导致 make clippy 直接失败。按 clippy 建议
合并为单个 if 链,行为不变。
|
2026-07-02 16:36:05 +08:00 |
|
|
|
59359b18ce
|
refactor(hooks): 新增 use_paginated 并迁移 posts/trash 分页加载
按 Dioxus 0.7 custom hooks 范式,把后台分页列表页反复出现的
use_effect + spawn + (loading/items/total/error) 三件套收口到
use_paginated 组合式 hook。统一非 wasm cfg 处理(SSR 不发请求、
loading 立即置 false),调用方只关心 fetch 闭包与页码依赖。
迁移范围(按降级预案,只做最规整的两处):
- pages/admin/posts.rs:顺手补 error signal(原先吞掉 Err),向
trash 看齐,消除一致性债。
- pages/admin/trash.rs:直接替换,error 已有。
保留手写的形态(强行套 hook 反而更复杂):
- comments.rs:依赖 (page, status) 双 signal,status 是额外维度,
套不进 (page, per_page) 模型;改 hook 会为单一调用点变复杂。
- system.rs 三个 tab:load_once + use_future 轮询形态,与 hook 的
单次加载模型不契合。
- dashboard.rs:多源聚合(3 个并发 spawn 分别 set 不同 signal)。
list_posts / list_deleted_posts 是 server function,两端都生成
(wasm 端 client stub、server 端真实实现),故去掉原 cfg import。
|
2026-07-02 16:30:47 +08:00 |
|
|
|
759bbab7ee
|
refactor(utils): comment_storage 从 hooks/ 迁至 utils/
该文件全是普通函数(save_author / load_pending_comments 等),没有任何
use_ 开头的 Hook,放在 hooks/ 下名不副实。内部只剩结构体与 localStorage
读写(时间/HTML 工具已在上一 commit 拆出),迁到 utils/ 后文件名与内容
自洽,hooks/ 目录回归只放真正的渲染期 Hook。
机械替换 4 个组件文件的 use 路径(hooks::comment_storage → utils::comment_storage)。
|
2026-07-02 16:18:52 +08:00 |
|
|
|
dcdd72a8c2
|
refactor(utils): 拆分 comment_storage 的时间/HTML 工具函数
消除 server 端对 hooks 模块的跨层引用:
- escape_html(+ 两份重复实现:comment_storage 用 '、helpers 用 ')
统一到 utils/html.rs,单引号采用 HTML5 标准 '。
- now_millis / relative_label_from_millis / format_relative_time_iso 及其
单元测试迁到 utils/time.rs,与既有 sleep_ms 同构(wasm32/非 wasm 双版本)。
调用方迁移:
- api/comments/helpers.rs:删掉本地 escape_html,format_relative_time 改引
utils::time;其 escape_html 测试随之删除(utils/html.rs 已覆盖)。
- api/comments/create.rs:两处 helpers::escape_html 改 utils::html。
- api/markdown.rs:escape_heading_text 改 utils::html。
- components/comments/pending_item.rs:format_relative_time_iso 改从
utils::time 引入;render_pending_content 留在 comment_storage(语义紧贴
待审核评论)。
- hooks/comment_storage.rs:is_expired 的 now_millis 改引 utils::time。
comment_storage.rs 现在只剩结构体与 localStorage 读写,文件名即将自洽。
|
2026-07-02 16:15:23 +08:00 |
|
|
|
f00c2bf963
|
refactor(hooks): 新增 use_event_listener 通用事件监听 hook
把 theme.rs 与 footer.rs 两处手写的 "use_hook 持有 Closure+target、
use_effect 注册 add_event_listener、use_drop 移除" 样板收口到一个
通用 hook,按 Dioxus 0.7 custom hooks 范式封装。
hook 设计:
- target 通过 acquire 闭包在 use_effect 首次运行时获取(此时 DOM 一定
可用),调用方无需再自己包 use_effect。
- 泛型 AsRef<EventTarget> 统一 Window / Element / MediaQueryList。
- 非 wasm32 整体编译为 noop,调用方用 #[cfg] 隔离 web_sys 调用即可。
footer 的 "注册后首次同步" 业务逻辑保留在 hook 之外(语义不属于
事件监听)。theme 的 handler 改为重新 match_media 读取 matches,
功能等价(低频事件,开销可忽略)。
|
2026-07-02 16:02:51 +08:00 |
|
|
|
62bd281684
|
fix(admin/posts): 重建结果消息改为独立行,修复悬浮溢出表格的错位
RebuildCacheBar 的「已重建 X 篇文章」结果消息原用 absolute top-full mt-2
悬挂在按钮行下方,但 mt-2(8px) + text-sm(20px) = 28px 大于外层 space-y-6
的 24px 间距,消息底边向下溢出 4px 侵入表格容器上沿;横向 left-0 又使消息
落在右上角按钮组正下方、覆盖状态/日期/操作列,语义位置错位。
将 rebuilding / rebuild_result 状态上提到 PostsPage:
- 结果消息在 header 与表格之间独立成行,进入文档流,吃 space-y-6 正常间距,
既不撑高 header 触发 items-center 重排(曾用 absolute 规避的旧问题),
也不脱离流溢进表格(absolute 引入的新问题)。
- RebuildCacheBar 改为接收父级 Signal props,只渲染按钮行本身。
|
2026-07-02 14:19:06 +08:00 |
|