52b4f91622
fix(admin/write): restore scrollability by using overflow-y-auto and min-h-full
2026-07-03 16:50:53 +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
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
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
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
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
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
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
48a21564c4
refactor(assets): 背景图固定 opacity-10,移除动态透明度逻辑
...
动态判断不生效,统一固定为 10% 透明度,移除聚焦/有内容的条件类。
2026-07-02 11:17:41 +08:00
5fd883d7a1
feat(comments): 评论区有内容时自动调淡背景图透明度
...
与 tiptap 编辑器保持一致:无内容时 60%,有内容或聚焦时淡出到
10%。content_md 由 oninput 实时维护,输入即触发重渲染。
2026-07-02 11:14:58 +08:00
48107d8e18
refactor(assets): 评论区与后台编辑器背景图换用 xiantiaoxiaogou_input_bg
2026-07-02 10:58:52 +08:00
78f3ff4b2f
fix(admin): 登出按钮补 cursor-pointer
...
登出按钮缺少 cursor-pointer,鼠标悬停时仍显示文本光标而非手型,与
其他可点击元素不一致。
2026-07-01 17:00:58 +08:00
3faff98dc8
fix(layout): 后台导航栏与正文宽度对齐
...
Header 的导航宽度写死 max-w-3xl(前台阅读宽度),后台直接复用导致
导航栏(768px)比正文(max-w-5xl=1024px)窄 256px,左边缘错位。
给 Header 加 max_width prop(默认 max-w-3xl 保持前台行为不变),后台
两处调用点传 max-w-5xl,与 admin_layout 的 main 同宽对齐。
2026-07-01 17:00:58 +08:00
90734446b5
refactor(ui): remove redundant Tabs component
...
Tabs 现已无调用方(/admin/system 已改用 FilterTabs),删除以消除 DRY 违反。
全局只保留 FilterTabs 一个 tab 组件,动画/样式统一。
2026-06-30 18:12:03 +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
ff7d9e1e46
feat(ui): add Tabs component for page-level navigation
...
与 FilterTabs(列表筛选 + 滑动动画)并列,职责区分:
- FilterTabs:同质数据过滤(全部/待审/已通过)
- Tabs:切换到结构不同的面板(数据库/服务器/SQL 控制台)
选中态用按钮自身 border-b-2 下划线(无动画)。
API 与 FilterTabs 对齐(String value + EventHandler),便于调用方迁移。
2026-06-30 14:16:36 +08:00
81a4196e43
feat(admin): add /admin/system route shell with 5 tabs
...
新增系统管理入口页(数据库状态/服务器状态/SQL 控制台/导出/备份恢复),
顶部 tab 切换(用 use_signal 不深链)。路由注册 + 导航加「系统」项。
tab 内容待后续 task 填充。
2026-06-29 18:26:24 +08:00
45811df96e
fix(comments): add md-content class to comment item to fix syntax highlighting and blank line issues
2026-06-29 15:42:08 +08:00
656e35c79f
fix(comments): move decorative image properly inside textarea background layer
2026-06-29 15:20:48 +08:00
0b53e968c1
feat(comments): add decorative image to comment input with focus fade effect
2026-06-29 14:42:03 +08:00
d1b5b8ee4e
fix(ui): suppress unused variable warning for active param in server build
2026-06-29 14:29:45 +08:00
373498870a
style: apply cargo fmt to workspace
CI / check (push) Failing after 5m35s
CI / build (push) Has been skipped
2026-06-29 13:47:40 +08:00
c69a632e75
fix(ui): trigger FilterTabs indicator animation on click
2026-06-29 13:24:52 +08:00
3daa09efc2
fix(ui): fix WASM compilation error in FilterTabs indicator animation
2026-06-29 13:22:22 +08:00
ec5f933191
feat(ui): add smooth sliding animation to FilterTabs active indicator
2026-06-29 13:20:39 +08:00
d91a56f8b2
refactor(admin): extract comments filter tabs into FilterTabs component
2026-06-29 13:15:50 +08:00
178870427c
feat(ui): refactor EmptyState to accept dynamic string props and add empty state to archives page
2026-06-29 10:11:00 +08:00
ac1f92d816
refactor(core): 迁移 post-content 到 yggdrasil-core,删除 public/js
...
逐行 TypeScript 化(逻辑不变),改走 window.__initPostContent 全局入口。
post-content.js 已迁移进 libs/yggdrasil-core/,public/js/ 目录随之删除。
2026-06-26 13:57:48 +08:00
0398cc6c66
perf(render): 列表加显式 key + release 启用 panic=abort
...
依据 Dioxus 0.7 optimizing 指南做两项改进:
- 为数据驱动列表渲染补全显式 key(13 处,9 个文件):
home/archives/tags/search 文章与标签列表、post_card/post_footer
标签、header 桌面/移动导航、admin dashboard/posts/write 列表。
使用各类型稳定唯一字段(post.id / tag / tag.name / item.label /
err.id / year_group.year / month_group.month_en)作为 key,
让 Dioxus diff 正确识别元素身份。骨架屏 for _ in 0..N 静态占位
循环与已带 key 的评论树/admin 行不动。
- [profile.release] 加 panic = "abort":WASM 去掉 unwind 元数据减小
体积;server 端错误处理走 Result+?(见 error.rs),不依赖 panic
unwind,无副作用。
其余文件为本机格式化(单行折叠/多行展开),一并提交。
验证:dx check 通过、cargo test 405 passed。
2026-06-25 18:07:22 +08:00
d41eb4b3cd
refactor(write): 滚动条从内容区内部移到窗口边缘
...
将 /admin/write 从「锁一屏 + 内容区内部滚动」改为「整页自然滚动」,
滚动条出现在浏览器窗口右侧而非中间内容区边缘。
admin_layout: write 路由 root 由 h-dvh overflow-hidden 改为 min-h-dvh
自然文档流,main 去掉 overflow-hidden。
write.rs: 根 div 与内容区去掉 flex-1/min-h-0/overflow-y-auto 等滚动
约束;编辑器高度由 flex-1 改为 h-[60vh](min-h-[400px] 兜底);底部
操作栏去掉 flex-shrink-0,改为跟随页面滚动。
整页滚动时 Header 仍 sticky 吸顶(带毛玻璃),保存栏随内容滚走。
2026-06-25 16:24:26 +08:00
806b474599
feat(theme): 新增冷调玫瑰第二色用于次要按钮
...
在 input.css 的 @theme 新增 accent-2 / accent-2-soft 主题变量,
用于与鼠尾草绿主色成对的次要操作按钮。
颜色选择经 HSL 分析:色相 342°(冷调玫瑰,区别于暖砖红 9°),
饱和度 28%(低饱和从属于主色),保证视觉为浅色系且不浊。
对比度:亮色 #83495b vs 米白底 6.5:1、暗色 #cca4b0 vs entry 底 7.46:1,
均过 WCAG AA。
新增 BTN_SECONDARY 常量(ghost 描边风格)用于 dashboard「管理文章」
按钮,与「写文章」实心主按钮构成主次层级。两按钮统一用
inline-flex items-center justify-center 保证文字水平垂直居中、等高。
2026-06-25 15:06:45 +08:00
519c0ae3a9
feat(admin): 后台迁移至 paper-* 主题变量对齐前台
...
将 /admin 路由下硬编码的 Tailwind gray + hex 配色统一迁移到
input.css 定义的 paper-* 主题变量系统,使后台视觉完全对齐前台:
- 底色:bg-white → bg-paper-theme(米白,与前台一致)
- 卡片/表格:bg-white dark:bg-[#2e2e33] → bg-paper-entry
- 主操作按钮(写文章/保存/分页):bg-gray-900 黑 → bg-paper-accent 鼠尾草绿
- 文字/边框/hover:gray-* + dark:hex → text-paper-*/border-paper-*
- 清理 trash 页散落的 #5c7a5e/#7da97f/#e8f0e8 等 hex,路由到变量
- 骨架占位统一复用 ADMIN_* 常量与 SkeletonBox
保留 green/amber/red 状态语义色(通过/待审/删除)与 toggle 白色滑块。
统一采用 bg-paper-* 工具类语法,与 header/post_card 主流写法一致。
dx check + clippy + 402 tests 全通过。
2026-06-25 14:33:48 +08:00
df85df3d2e
style(empty-state): 配图加圆角,暗色模式降低亮度
...
- rounded-lg 圆角(= 项目的 --radius-paper 8px)
- dark:brightness-90 滤镜,让彩色配图在暗色主题下退后一些
2026-06-25 13:48:46 +08:00
cfd2af1fab
refactor(empty-state): 内联 SVG 换成 webp 配图
...
移除手绘的 LineDog 内联 SVG,改用 <img> 引用
public/images/xiaotiaoxiaogou_01.webp 原始插画。
2026-06-25 13:43:23 +08:00
8b581649a6
feat(home): 用「线条小狗」插画替换首页空状态
...
原空状态仅有一行「暂无文章」文案。新增 EmptyState 组件:
- 内联单色 SVG 配图(双手持相机,取景器内两只小狗),由 webp 重绘为线条画
- 描边用 currentColor 适配明暗主题,屏幕区填 accent-soft 作焦点
- 标题改「还没有文章」,副文案呼应站点定位
- 保留可选 action 字段供后台上下文复用
颜色、圆角、入场动画均沿用项目 Forest 调色板与既有视觉语言。
2026-06-25 13:37:07 +08:00
21322a4339
fix(card): 提升覆盖层 z-index 使封面图可点击跳转
...
封面完整图 .blur-img-full 在全局 CSS 有 z-index:1 (input.css:611),
盖在原 z-0 的覆盖层 Link 之上,导致 hover 封面命中 <img> 而非 <a>:
光标非 pointer 且点击不跳转。
将覆盖层提到 z-[2](>封面图 1,<标签 10),命中 <a> 后光标与点击一并解决,
标签 stop_propagation 与 hover 缩放不受影响。
2026-06-25 11:10:43 +08:00
71014aa0de
style: 封面图比例统一改为 21:9 超宽
...
卡片 16:9 仍偏高,统一改为 21:9(超宽荧幕比例),前后台一致:
- input.css: .blur-img.post-card-cover-blur aspect-ratio 16/9 → 21/9
- post_card.rs: 缩略图 thumb=400x225 → 420x180 匹配 21:9
- write.rs: 编辑器封面区 aspect-video → aspect-[21/9]
2026-06-24 15:53:55 +08:00
5fc8a9aeeb
style(card): 卡片封面图比例从 4:3 改为 16:9
...
- input.css: .blur-img.post-card-cover-blur 的 aspect-ratio 4/3 → 16/9
- post_card.rs: 缩略图请求 thumb=400x300 → 400x225 匹配 16:9
2026-06-24 15:49:53 +08:00
0301185a17
refactor(post-content): drop lightbox include_str!, use config-driven init
2026-06-24 11:07:24 +08:00
cb8c42e833
refactor: remove obsolete ImageViewer component
...
both call sites (PostCover, PostCard) now render raw .blur-img, so the
Dioxus ImageViewer component — with its leaky closure.forget() and dead
js_sys::eval delay — is no longer needed. remove the file and its mod
declaration.
2026-06-23 15:51:40 +08:00
8b1d55613e
refactor(post-card): use raw blur-img for cover, drop ImageViewer
...
card cover is display-only (click goes to the card link), so it uses
a bare .blur-img with ?w=20 placeholder + ?thumb=400x300 display, no
lightbox-single class. card pages are outside .post-content/.entry-cover
so lightbox.js never scans them.
2026-06-23 15:50:29 +08:00
75b9080df8
refactor(post-cover): use raw blur-img structure as single lightbox image
...
drop ImageViewer; render .blur-img with a lightbox-single class (the
class, not a data attribute, because Dioxus' typed span elements reject
arbitrary data-* attrs). lightbox.js now keys single-mode off the
lightbox-single class instead of data-single. cover uses ?w=20
placeholder + ?w=1200 display; SSR writes --ar from real dimensions.
2026-06-23 15:48:02 +08:00
f88d83b0ad
feat(post-content): load lightbox.js and init gallery
...
eval both post-content.js (copy) and lightbox.js (lightbox + lazy-load),
then call __initLightbox over ['.post-content', '.entry-cover'] so both
in-content images (gallery) and the cover (single) are wired up.
2026-06-23 15:45:30 +08:00