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
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
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
9231e993e4
fix(clippy): 修复两处预存 clippy 错误
...
- execute.rs: ExecResult/ExecStatus 仅 server 端使用,加 cfg gate
消除 WASM 目标的 unused_imports
- system.rs: in_scope 外层闭包保留 || execute_for_editor() 包装
(Closure::new 要求 Fn 可重复调用,直接传闭包会 use-after-move),
加 #[allow(clippy::redundant_closure)] 并注释原因
cargo clippy 双目标 -- -D warnings 均通过。
2026-07-06 11:42:03 +08:00
1db641bca9
refactor(sql-console): SqlConsoleTab 改用 SqlResultTable 组件
...
删除调用方对 Vec<Vec<Value>> → Vec<Vec<String>> 的预处理(保留类型
信息),结果表格段替换为 <SqlResultTable>,空结果集分支保留。
2026-07-06 11:32:33 +08:00
d3c2e41fd8
fix(codemirror): 编辑器塌缩导致上下背景割裂(height:100% 失效)
...
上一提交(3c10f72)用 `& { height: 100% }` 让 .cm-editor 撑满容器,
但实测无效——headless chromium 抓取 computed style 显示:
容器#ed: h=280px (min-height)
.cm-editor: h=63px ← 塌缩!只有内容高度
.cm-gutters: h=63px
.cm-content: h=63px
根因:CSS 百分比高度要求父元素有「明确 height」(不是 min-height)。
容器只有 min-height: 280px,没有 height,`.cm-editor { height: 100% }`
解析为 auto,塌缩到内容高度(3 行 ≈ 63px)。剩余 217px 透出容器背景
(paper-entry/mantle),与 .cm-editor 的 base 色形成上下割裂。
修复:改用 flexbox 而非百分比高度——
- themes.ts:`& { flex: 1 1 0; minHeight: 0 }`(替换 height:100%)
- 容器(system.rs / runner.rs):`display: flex; flex-direction: column`
flex 子项的 `flex: 1` 不依赖父元素 height,能真正填满 min-height 撑开
的空间。headless 验证:.cm-editor 现为 280px,与容器一致,割裂消失。
诊断方法:构建自包含测试 HTML(内联 editor.js),chromium --headless
--dump-dom 抓 getComputedStyle。这是应有的反馈循环,避免了前几轮
凭代码猜测导致的反复误诊。
2026-07-06 00:20:55 +08:00
b207babdb6
refactor(admin): 统一按钮令牌,消除样式散落
...
将 7 个 admin 页面中复制粘贴/各自为政的按钮 class 收敛到 ui.rs 令牌:
主操作色系统一为主题绿(bg-paper-accent):
- dashboard/posts「发布文章」、write「发布/更新」+「确认」、runner 语言切换选中态
改用 BTN_PRIMARY / BTN_PRIMARY_SM(原为深色 bg-paper-primary,现统一为绿)
- system 4 处刷新/执行/创建备份、trash 保存设置、write 发布按钮改用 LoadingButton
统一 loading 态为 spinner 绝对居中叠加(按钮宽度不变,原 system 用文字切换、
write 用整体变灰,现全部一致)
描边/图标/行内按钮统一:
- posts 重建、system 刷新列表 → BTN_OUTLINE
- trash 清空回收站 → BTN_DANGER_OUTLINE
- trash 步进 ± 按钮(2 处重复字符串)→ BTN_ICON
- write 关闭 × 按钮(2 处重复)→ BTN_CLOSE_ICON
- system BackupRow 恢复/删除绕过令牌 → BTN_TEXT_AMBER / BTN_TEXT_RED
(删除色从 red-600 校正为令牌的 red-500,与其他行内删除一致)
消除约 15 处内联 class 字符串重复,system.rs 4 种主操作变体收敛为 1 种。
2026-07-06 00:17:25 +08:00
64907401a0
fix(codemirror): 行号区背景与代码区割裂(core base theme 覆盖 catppuccin)
...
现象:行号列(gutter)背景是 #f5f5f5 浅灰,代码区(content)是 catppuccin
base #eff1f5 浅蓝灰,两者不一致,有明显割裂。
误诊修正:上一提交(e1b312e)以为是容器背景与 CodeMirror 层次扁平,
改了容器为 code-block(crust)。但 CodeMirror 内部 .cm-editor 和
.cm-gutters 都有不透明背景,容器色根本透不出来——所以「没效果」。
本次回退该容器改动。
真因:CodeMirror core 的内置 base theme(@codemirror/view dist index.js:6916)
给 `&light .cm-gutters` 设了 backgroundColor: "#f5f5f5" / dark "#333338 ",
特异性为 .cm-editor.cm-light .cm-gutters,高于 @catppuccin/codemirror
的 .cm-gutters 覆盖,catppuccin 的 base 背景被 core 默认灰压制。
修复:themes.ts 在 catppuccin extension 之后追加一个 EditorView.theme,
用 backgroundColor: transparent !important 强制 .cm-gutters 透明,
继承 .cm-editor 的 base 色,行号区与代码区完全融合。light/dark 同理。
2026-07-05 23:58:18 +08:00
e1b312e651
fix(admin): SQL 编辑器 gutter 与 content 背景割裂
...
现象:行号区和代码输入区背景色看起来不一致,有割裂感。
根因:三层背景色各不相同——容器用 paper-entry(mantle #e6e9ef)、
标题栏用 paper-theme(base #eff1f5)、CodeMirror 自带 base 背景。
容器与编辑器同处 base/mantle 之间,层次扁平,CodeMirror 的 base
浮不出层次,gutter 与 content 的细微差异被放大。
修复:建立 crust > mantle > base 三层明确递进——
- 容器改 paper-code-block(crust #dce0e8,最深)
- 标题栏改 paper-entry(mantle,中)
- CodeMirror 保持自带 base(最浅)
编辑器作为「浅色岛」浮在深色容器上(VS Code / Sublime 的 IDE
经典范式),gutter 与 content 同为 base 完全融合,割裂消失。
2026-07-05 23:10:56 +08:00
2cfc64b319
fix(admin): SQL 控制台 Ctrl+Enter 触发 panic(无 dioxus scope)
...
现象:编辑器有焦点时点击执行(或按 Ctrl+Enter)会 panic:
called `Option::unwrap()` on a `None` value (runtime.rs:223)
RefCell already borrowed (runtime.rs:280)
根因:Ctrl+Enter 从 CodeMirror 的 JS 事件处理中触发 onRunShortcut
回调,此时 dioxus scope stack 为空。execute_for_editor 内部调
spawn(),而 spawn() 走 Runtime::with_current_scope →
current_scope_id().unwrap(),scope stack 空时直接 panic。
第二个 panic 是 unwind 期间再次 borrow scope_stack 触发的。
修复:用 dioxus 文档推荐的 web-sys 回调模式——在组件主体捕获
scope_id(此时 scope 活跃),JS 回调里用
Runtime::current().in_scope(scope_id, ...) 重建 scope 上下文
后再执行,spawn 即可找到 origin scope。
dioxus-core 源码(global_context.rs docstring)明示此模式,
dioxus-signals/src/global/mod.rs:201 也是这样用的。
注意:按钮 onclick 走 dioxus 事件系统(scope 已设),不受影响;
仅 CodeMirror JS 回调路径需要 in_scope 兜底。
2026-07-05 21:59:17 +08:00
fe6934ddd5
feat(admin): SQL 控制台接通 Ctrl+Enter 并重做视觉
...
接通上一提交打通的快捷键通道,同时重做编辑器/工具条/结果区视觉。
功能(接通 Ctrl+Enter):
- 把 run_sql 逻辑拆出 execute_for_editor 闭包(仅捕获 Copy 的 Signal),
注入 CodeMirror onRunShortcut,按钮 onclick 仍走 run_sql
- 两条路径共用同一套 4 道护栏 + 资源逻辑,行为完全等价
视觉(编辑器标题栏一体化):
- 编辑器加标题栏:左 accent 状态点 + SQL 标识,右 ⌘↵ 快捷键提示
- 容器升至 rounded-2xl + 280px 最小高度,留呼吸
- 执行按钮改胶囊式(rounded-full)+ active:scale 触觉反馈 +
SPINNER_SVG 替代纯文字「执行中...」
- 危险选项(我了解后果)用竖线分隔 + 红色语义,与普通选项分层
- 结果摘要从裸文本改徽章式(accent-soft 底 + 圆角胶囊)
- 加空结果友好态:SELECT 返回空集时显示「查询成功,无返回行」
- EXPLAIN 输出 pre 补 m-0,消除默认外边距
2026-07-05 21:31:16 +08:00
1dc02561a3
style(code-runner): 重做 admin/runner 视觉,对齐项目 token 体系
...
页面与 CodeRunner 组件此前用的是 daisyUI 类(base-100/btn-primary/
input-bordered/bg-neutral 等),但项目根本没装 daisyUI——这些类在
编译产物里 0 匹配,导致页面渲染成裸结构,是「半成品」观感的根因。
全部换成项目真实的 --color-paper-* 语义 token,视觉与 dashboard /
posts / system 等后台页面统一:
页面壳(runner.rs):
- h1 升至 text-4xl,与其它 admin 页一致;加底部分割线
- 外层对齐 max-w-5xl space-y-8
- 语言切换改为胶囊按钮组(选中态 accent 绿实心)
- overrides 输入框套 system.rs 的表单范式,加 focus 态
- 错误/提示用 red-500 dark: red-400,解析成功时显示字段说明
CodeRunner 组件(runner.rs):
- 容器改 rounded-2xl + paper-border + paper-entry
- 顶栏加状态点(accent)+ 胶囊运行按钮(active 缩放反馈)
- 运行中用 SPINNER_SVG 替代 daisyUI loading-spinner
- 输出区改 paper-code-block 底 + 语义色文字,随主题切
- 错误区改 red-50 dark: red-900/10 柔光块
2026-07-05 14:49:24 +08:00
575b6b533e
feat(code-runner): CodeRunner 挂载 CodeMirror 编辑器,支持双向绑定
...
兑现组件一直承诺但无人实现的「调用方挂载编辑器」契约——此前容器 div 只
输出 id,admin/runner 沙箱与文章正文 runnable 块都只能提交写死的初始源码,
作者/读者无法编辑。
- CodeRunner 在 WASM 端按自身 container_id 调 codemirror_bridge.create
挂载编辑器,onChange 回写内部 source_signal(编辑器内容 = 唯一真源)
- run_code 改读 source_signal 当前值,提交编辑后内容而非初始快照
- 主题切换经 use_resolved_theme 订阅,热切换编辑器主题
- use_drop 销毁 EditorHandle,释放 CodeMirror 实例与 closure 槽位
- source prop 外部变更(admin 切换语言重置示例)同步进 signal + 编辑器
- admin/runner 页面 overrides 解析挪进 use_memo,避免 render 体写状态
范式镜像 SQL 控制台(system.rs)与 Tiptap 编辑器(write.rs)。
2026-07-05 14:32:39 +08:00
16bd644783
fix(admin): 仪表盘空数据时显示空状态占位
...
空库下 get_post_stats / list_posts 正常返回,但 list_posts 返回
Some([]) 时走有数据分支、循环 0 次,渲染出一个空表格容器,视觉
上仪表盘近期文章区域一片空白,没有空状态引导。
复用项目既有的 empty_state::EmptyState 约定(与 posts.rs / trash.rs /
comments.rs 列表页一致):Some(posts) 且 posts.is_empty() 时渲染
暂无文章插画 + 写文章CTA。空状态放在 ADMIN_TABLE_CLASS 容器
之外,避免 overflow-hidden 裁掉插画的 py-20 内边距。
2026-07-04 22:49:25 +08:00
f3eb93f320
docs(agents): document code runner and fix clippy/biome lint
...
文档:
- AGENTS.md 新增「Code Runner」架构章节(三层架构 + WASM 可见性规则 +
governor 0.8 无 per_day 的处理 + runner 镜像契约)
- Environment 段补齐 CODE_RUNNER_* 与 RATE_LIMIT_CODE_EXEC_* 环境变量
Lint 修复(clippy --all-targets --all-features -D warnings 全绿):
- runner.rs/runner.rs: use_signal 冗余闭包 → 直接传 fn
- runner_config.rs: &*RUNNER_CONFIG 去 deref;assert_eq!(...false/true) → assert!
- markdown.rs: 局部变量 /// 改 //;Option.map().flatten() → and_then
- languages.rs: 删除从未读取的 LanguageDef.name 字段(语言名即 map key)
- docker.rs: start_container if let Err → ?;timeout match → is_err();
嵌套 if 合并(修 task 2 遗留 + clippy 1.96 新 lint)
- pages/admin/posts.rs: use_signal 冗余闭包(预存 lint,顺带修绿)
- codemirror editor.ts: biome format 重排 setSchema 单行
2026-07-03 18:57:25 +08:00
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
46860f7c41
fix(ui): apply mount animation inside each page component to avoid skeleton interception
2026-07-03 17:24:38 +08:00
197c08d258
style(ui): fix inconsistent padding on post card
2026-07-03 17:13:02 +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
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
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
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
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
eacc79ed83
feat(theme): 新增跟随系统主题模式与三态循环切换
...
Theme 枚举从 {Light, Dark} 扩展为 {Light, Dark, System},新增
ResolvedTheme 表示实际生效明暗。
- System 模式移除 localStorage 持久化,首屏防闪烁脚本因此自动回退到
prefers-color-scheme 分支,首屏零闪烁。
- use_theme_provider 提供 Theme + ResolvedTheme 双 context;resolved 是
theme 与 system_dark 的派生 memo。WASM 端注册 matchMedia change 监听,
系统偏好变化时实时同步 .dark class 与下游(CodeMirror 等)。
- ThemeToggle 由二态 toggle 改为三态循环(Light→Dark→System→Light),
图标按当前模式切换(太阳/月亮/显示器);仅当实际明暗翻转时才触发
圆形展开动画,避免 System 与同向 Light/Dark 间无意义动画。
- system.rs CodeMirror 传参改读 resolved,使 System 模式下系统偏好变化
时编辑器主题自动跟随。
2026-07-02 11:35:28 +08:00
9a218db478
refactor(assets): 编辑器背景图缩小至 w-24 并贴近右下角
...
原图无宽度约束,按原始尺寸渲染占满编辑器;现固定 w-24(与评论区
一致)并用 bottom-2 right-2 定位到右下角。一并提交新增的线条小狗
素材图与图标资源。
2026-07-02 11:22:34 +08:00
48a21564c4
refactor(assets): 背景图固定 opacity-10,移除动态透明度逻辑
...
动态判断不生效,统一固定为 10% 透明度,移除聚焦/有内容的条件类。
2026-07-02 11:17:41 +08:00
fe22d6dad8
feat(editor): tiptap 编辑器有内容时自动调淡背景图透明度
...
无内容时背景图保持 60% 透明度;当编辑器内有内容(非纯空白)时,
背景图淡出到 10%,与聚焦时行为一致。content signal 由 onUpdate
回调实时维护,输入即触发重渲染,无需额外状态。
2026-07-02 11:11:04 +08:00
48107d8e18
refactor(assets): 评论区与后台编辑器背景图换用 xiantiaoxiaogou_input_bg
2026-07-02 10:58:52 +08:00
9cf0e605d4
fix(admin): 修复服务器/数据库状态自动刷新失效 Bug
...
use_future 旧实现在同步闭包体内捕获 status/loading/error signal,
导致这些 signal 每次 .set() 后都触发 use_future 重建新 loop,
旧 loop 同时继续运行,造成并发 loop 指数增长(请求爆炸),
实际效果等同于自动刷新完全失效或行为异常。
修复:采用 Dioxus 0.7 官方推荐模式——
- use_future 闭包直接返回 async move {},不在同步层读任何 signal
- loop 内每次迭代读 refresh_interval/refresh_ms 的实时值
- 手动模式(interval = 0)改为 200ms yield + continue,
使切换到自动模式时最多延迟 200ms 生效,避免忙等
- sleep 结束后二次检查 interval,防止 sleep 期间用户切回手动时
仍然发起一次无意义请求
同时修复 DbStatusTab 和 ServerStatusTab 两处。
2026-07-01 17:09:39 +08:00
afa6bf892e
feat(register): 输入框支持回车键提交表单
...
注册页 4 个输入框(用户名/邮箱/密码/确认密码)原先 onkeydown 为 None,
无法用回车提交。改为监听 Enter 触发 on_submit,与登录页行为一致。
2026-07-01 17:00:58 +08:00
7de97d8222
fix(write): 编辑模式回显空白由 effect 竞态导致
...
编辑文章时编辑器空白。根因:edit_post 由 None→Some 时,回填 effect
(写 content signal)与初始化 effect(读 content signal)在同一 tick
触发,无保证先后顺序。初始化 effect 经常先跑,读到 content()= 跳过
setMarkdown,且 editor_content_set=true 永久阻止重试。
修复:初始化 effect 直接从 edit_post(真值源)取 content_md 回填,不再
依赖 content signal——后者是派生值,与回填 effect 存在竞态。两个 effect
都已在 edit_post 上订阅,回填时读取它没有竞态。
2026-07-01 17:00:58 +08:00
26d37f7271
refactor(admin): use FilterTabs in /admin/system
...
system.rs 的 tab 栏从 Tabs 改用既有 FilterTabs,视觉与评论页完全一致
(平滑滑动指示条 + 选中文字 text-paper-primary)。Props 形状相同,仅改组件名;
SystemTab::as_str/from_str 桥接与枚举 match 穷举逻辑不变。
2026-06-30 18:05:05 +08:00
bf91d18c4f
refactor(admin): use shared Tabs component in /admin/system
...
移除 System 组件内联的 tab 按钮,改调公共 Tabs 组件。
active_tab signal 经 SystemTab::as_str/from_str 与 Tabs 的 String API 桥接,
match 穷举面板选择逻辑不变。视觉/行为零变化,只消除重复。
同时移除 Task 1/2 加的临时 #[allow(dead_code)](as_str/from_str/Tabs 现已有调用方)。
2026-06-30 14:29:05 +08:00
ef75631889
feat(database): add SystemTab::as_str/from_str string bridge
...
为后续用基于 String 的 Tabs 公共组件替换内联 tab 做准备。
as_str/from_str 是纯函数双向映射,带 roundtrip/稳定 key/拒绝未知输入三类单测。
2026-06-30 14:13:54 +08:00
0b6a076d78
feat(database): use real COUNT(*) for small tables, fall back to estimate for large
...
row_estimate came from pg_class.reltuples, which is -1 for tables that
have never been ANALYZEd (the common case on a fresh/small DB), so the
admin table list showed -1 for every table — meaningless.
Replace row_estimate with row_count + row_count_estimated:
- total_size < 100MB: SELECT count(*) (real value, cost negligible on
small tables; identifier quoted via PG escaping to stay injection-safe)
- total_size >= 100MB: fall back to reltuples estimate, flagged so the UI
can prefix with ~
Frontend now shows real counts (1/2/14...) for small tables and ~N for
large ones; header copy updated to reflect the mixed source.
2026-06-30 13:57:37 +08:00
ecf3c73715
fix(database): make src/api/database compile under WASM (web-only) build
...
The /admin/system feature was never verified against the WASM frontend
target (dx serve builds src/main.rs with --features web and no server).
The entire src/api/database/ tree unconditionally pulled in server-only
crates (axum, sqlparser, dashmap, tokio, tokio_postgres, futures, regex)
and server-gated helpers (get_current_admin_user, parse_session_token,
get_user_by_token), so the frontend build failed with 43 errors.
Root cause + fixes (mirror the established settings.rs pattern):
- Gate server-only imports behind #[cfg(feature = server)] in
status/system_status/sql_console/schema/tasks/backup. The #[server] macro
strips call sites but NOT use statements, so unresolved imports remained.
- Ungate in main.rs: SystemSnapshot is a shared serde
type referenced by ServerStatus.host on both targets; only the sampler
task/SNAPSHOT static are internally server-gated.
- Gate (pure Axum handler, zero WASM consumers) and the
download_backup Axum handler in backup.rs.
- Move restore_backup's validation preamble (regex/backup_path/fs) inside
the #[cfg(feature = server)] block; gate std::path/chrono::Utc imports.
- Add [[bin]] required-features=[server] for generate_highlight_css so the
syntect-dependent build tool is skipped in web-only builds.
Genuine WASM bugs surfaced once the server bodies stopped masking them:
- system.rs: Closure import path (dioxus::prelude::wasm_bindgen ->
wasm_bindgen, matching write.rs); setTimeout expects i32 not u32;
editor_handle() -> editor_handle.read() (Signal is not Fn in 0.7).
- codemirror_bridge.rs: set_schema extern took &SqlSchema but SqlSchema is
a serde type with no IntoWasmAbi. Changed both set_schema signatures to
&JsValue; call site now serializes via serde-wasm-bindgen::to_value.
- system.rs: signals .set() inside spawn/use_future/onclick closures need
bindings (incl. the *_f rebinding copies); added cfg_attr
allow(unused_mut) on the 4 tab components, matching write.rs convention.
Verified: cargo check (default/server) clean; cargo check --features web
--target wasm32-unknown-unknown clean (0 errors); dx check clean; 411
cargo tests pass.
2026-06-30 13:41:23 +08:00