103 Commits

Author SHA1 Message Date
xfy
79cb809010 perf(posts): add optional pagination to get_posts_by_tag, fix total count
- get_posts_by_tag 现接受 page/per_page 可选参数;两者均 None 时返回全部
  (上限 200,用于无翻页 UI 的标签详情页),均提供时走标准分页。
- 修正 total:不再用 posts.len(),改为真实 COUNT(*),即使被 LIMIT 截断
  也返回完整计数。
- 新增 CacheKey::PostsByTagPage 分页缓存键,与不分页键 PostsByTag 共存。
- 前端 tags.rs 传 (None, None) 保持原全部展示行为。
2026-06-18 11:14:56 +08:00
xfy
170c021b37 feat(cache): add PostListItem DTO and use it in list/tag/search caches 2026-06-17 15:51:19 +08:00
xfy
449a545886 security: fix critical issues from repository review
Some checks failed
CI / build (push) Has been cancelled
CI / check (push) Has been cancelled
P0 blockers:
- Fix migration numbering conflict and duplicate indexes
- Change comments.post_id FK to ON DELETE CASCADE
- Restrict public post detail endpoint to published posts only
- Fix rate-limiting IP extraction and fallback to ConnectInfo
- Harden HTML sanitizer: deny unknown URL schemes, restrict data URIs
- Remove session token from login response body
- Enforce image pixel/dimension limits on upload and serving

P1 high-risk:
- Validate uploads by magic bytes and decode GIF/WebP
- Add pagination/rate-limiting to search, tag posts, and comments
- Make first-admin registration and slug uniqueness check atomic
- HTML-escape comment author fields
- Improve HTML minify cache key and skip admin/error responses
- Add mobile navigation menu

P2 accessibility/quality:
- Associate form labels with inputs
- Key PostDetail article by slug to re-init scripts on navigation
- Improve image viewer keyboard accessibility
- Make theme toggle SSR-friendly and add aria-label
- Invalidate slug 404 cache on create and pending count on new comment
- Deduplicate tags case-insensitively

P3 cleanup:
- Remove unused tower-http dependency, expand make clean
- Configure DB pool timeouts and verified recycling
- Run background cleanup tasks immediately on startup
- Use SHA-256 for stable disk cache keys
- Log DB errors with Display instead of Debug
- Update README migration instructions

All tests pass (321), clippy clean, dx check clean.
2026-06-17 10:34:14 +08:00
xfy
a9f0e8d16b docs(development): 补充代码高亮开发文档
- DEVELOPMENT.md 增加代码高亮系统的详细开发指南,
  涵盖添加/修复语法、刷新文章、调试流程等
- admin/posts.rs 重构重建逻辑:提取 do_rebuild 闭包消除重复,
  新增「重建全部」按钮用于批量刷新已有文章渲染缓存
2026-06-16 15:19:45 +08:00
xfy
603a7f68cb refactor(ui): 提取共享 UI 组件,消除跨页面重复
新增 src/components/ui.rs 作为通用 UI 原子层,封装:

组件:
- <Pagination variant="admin"|"frontend">:合并 posts/comments/trash/home
  四个重复的分页实现,用 variant 区分配色(admin 灰黑 / 前台主题绿)
- <StatusBadge>:统一文章状态、评论状态、回收站剩余天数的徽章外层
- <EmptyState variant="default"|"error">:统一列表空态与加载失败占位

类名常量:
- ADMIN_CARD_CLASS / ADMIN_TABLE_CLASS / ADMIN_ROW_HOVER / CHECKBOX_CLASS
- BTN_SOLID_{GREEN,AMBER,RED}:批量操作实心按钮
- BTN_TEXT_{GREEN,AMBER,RED,ACCENT}:行内文字按钮

清理:
- 删除 input.css 中零引用的 .btn-primary 死代码(22 行)
- 删除 4 个重复的分页组件函数

注意:
- 前台空状态(home/search/archives/tags)保持 text-paper-secondary 配色,
  未强行统一到 admin 的灰色 token,避免改变视觉
- 回收站分页计数单位从"条"修正为"篇"(回收站里是文章)
2026-06-16 14:20:05 +08:00
xfy
6986a62bb5 style(ui): 重新设计回收站自动清理设置界面
- 合并为单一折叠卡片,顶部摘要条始终显示当前清理状态
- 用主题绿 toggle 开关取代原生 checkbox
- 保留天数改为数字步进器(−/输入框/+)
- 保存按钮改用鼠尾草绿强调色,与项目设计系统一致
- 新增 dirty/已保存 草稿状态反馈
- 补齐 hover/active/focus-visible 交互细节
2026-06-16 13:38:57 +08:00
xfy
4ba4fedb23 feat(ui): 新增 /admin/trash 回收站管理页面与导航 2026-06-16 12:38:41 +08:00
xfy
0242534274 style(tags): 修复文档注释列表缩进以消除 clippy 警告
Some checks failed
CI / check (push) Failing after 4m52s
CI / build (push) Has been skipped
2026-06-12 19:48:10 +08:00
xfy
c5d1eb117c docs(auth-pages, router, main): 补充中文注释 2026-06-12 19:31:21 +08:00
xfy
18500c9496 docs(pages-admin): 补充中文注释 2026-06-12 19:24:22 +08:00
xfy
abfab19839 docs(pages-frontend): 补充中文注释 2026-06-12 19:16:59 +08:00
xfy
294d60afab style: format rust code
Some checks failed
CI / build (push) Has been cancelled
CI / check (push) Has been cancelled
2026-06-12 17:14:31 +08:00
xfy
ee6aaf179c feat(posts): add batch limit and error handling to rebuild_content_html 2026-06-12 11:44:53 +08:00
xfy
835d71972c fix(admin): add missing dark mode background colors to skeleton components 2026-06-12 11:15:46 +08:00
xfy
f8fb35f8c2 fix(admin): use arbitrary value for tooltip dark text color 2026-06-12 10:55:32 +08:00
xfy
1c3f1aac34 fix(admin): flip tooltip to bottom to avoid navbar overlap
Changed from bottom-full/mb-2 to top-full/mt-2, added z-50.
2026-06-12 10:54:02 +08:00
xfy
8840faa830 fix(admin): use arbitrary dark mode values for tooltip bg
Matches project pattern of dark:text-[#dadadb] / dark:bg-[#dadadb]
for reliable Tailwind v4 class-based dark mode.
2026-06-12 10:52:05 +08:00
xfy
c62cf5a239 feat(admin): add tooltip to rebuild content button
Pure CSS tooltip appears on hover, inverted color scheme
(white-on-dark / dark-on-light) matching admin aesthetic.
2026-06-12 10:50:18 +08:00
xfy
67e23d672c feat(admin): add rebuild content button to posts management page
Outline-style button next to '写文章', calls rebuild_content_html(false)
to rebuild posts with NULL content_html. Shows result message below header.
2026-06-12 10:43:49 +08:00
xfy
75e0659cb2 fix(admin): 后台管理页改为 CSR 避免闪烁
- dashboard: use_resource → use_signal + wasm32-only 加载
- posts: use_server_future → use_signal + wasm32-only 加载 + 乐观删除
- write: use_resource → use_signal + wasm32-only 加载
- 移除 use_server_future/use_resource 导致的骨架屏闪烁
- 操作按钮使用乐观更新,不调用 restart()
2026-06-11 18:04:07 +08:00
xfy
ea440cd61c fix(admin): 评论管理页改为 CSR 避免按钮点击闪烁 2026-06-11 17:34:39 +08:00
xfy
569eec5bf8 fix(admin): 评论管理页多项修复
- 修复默认头像无法显示:AdminComment 添加 avatar_url 字段
- 修复状态标签换行:移除 w-20 固定宽度,添加 whitespace-nowrap
- 操作按钮添加 cursor-pointer
- 已处于该状态的评论隐藏对应操作按钮
- 修复操作后页面不自动刷新:将 restart() 移到异步块内
2026-06-11 16:10:42 +08:00
xfy
c10134c32e fix(comments): convert confirm_with_message Result to Option for WASM compatibility 2026-06-11 13:15:17 +08:00
xfy
04737300e6 feat(comments): add complete comment system with guest commenting, moderation, and admin UI
Implements a fully self-built comment system for the blog:

Data layer:
- comments table with BIGSERIAL PK, parent_id self-reference (ON DELETE SET NULL),
  depth tracking (max 20), status workflow (pending/approved/spam/trash),
  content hashing for dedup, GDPR consent tracking, IP/UA storage with auto-purge
- 5 partial indexes optimized for read patterns
- updated_at auto-trigger

API (9 Dioxus server functions):
- Public: get_comments, get_comment_count, create_comment
- Admin: get_pending_comments, get_pending_count, get_all_comments,
  approve_comment (with ancestor auto-approval), spam_comment, trash_comment,
  batch_update_comment_status

Security:
- Function-level rate limiting (1/sec, burst 5) via FullstackContext IP extraction
- Input validation (name, email, URL scheme, content length, consent)
- Parent chain validation (must be approved, same post)
- Strict comment Markdown renderer (headings→strong, no img/id/data URIs, nofollow links)
- Honeypot anti-spam field
- 5-minute dedup window via SHA-256 content hash

Frontend:
- CommentSection with SuspenseBoundary isolation
- Flat-list rendering with depth-based CSS indentation (responsive)
- Gravatar via cravatar.cn (server-computed, email never exposed)
- Inline reply forms (one-at-a-time via Signal)
- Admin action buttons (approve/spam/delete) visible per-comment
- CommentForm with privacy consent, Markdown hint, loading states

Admin:
- /admin/comments page with status tabs, batch operations, pagination
- Pending count badge on admin dashboard

Infrastructure:
- Shared get_current_admin_user moved from posts/helpers to auth module
- COMMENT_LIMITER rate limiter tier
- Moka caches (60s TTL for comments, 10s for pending count)
- IP/UA purge background task (daily, 90-day retention)
2026-06-11 12:34:26 +08:00
xfy
efa41b42c2 feat(auth): add loading state to login/register forms and update AGENTS.md 2026-06-11 10:44:27 +08:00
xfy
f9d23d1eed refactor(ui): redesign with warm palette, sage accent, and consistent theme vars
- Warm editorial color palette (#faf9f6 light / #141416 dark)
- Sage green accent (#5c7a5e) for nav, links, buttons, tags
- Replace all hardcoded hex colors with CSS theme utilities
- Serif font (system Georgia) only on header logo
- Better hover states: scale, brightness, color transitions
- Accent-colored focus rings on inputs
- Fix language mixing: Back to Home → 返回首页
- No external font dependencies
2026-06-11 10:29:11 +08:00
xfy
9cf6a7e4e6 fix(admin): replace use_delayed_loading with DelayedSkeleton for posts page
Use the same skeleton pattern as Home/Archives/Search pages.
Skeleton shows immediately (static gray blocks) instead of opacity-0 blank,
eliminating white flash during fast loads.
2026-06-10 18:15:46 +08:00
xfy
265eb15887 feat(admin): add pagination to posts management page
- list_posts API now accepts page/per_page params with LIMIT/OFFSET
- Add /admin/posts/:page route with PostsPage component
- Pagination component with prev/next navigation (20 posts/page)
- Update dashboard to use new list_posts(1, 5) signature
2026-06-10 18:03:36 +08:00
xfy
373d4f09ed refactor: clean up write page formatting and remove separator line
- Reorder imports to group wasm32-gated items together
- Format struct pattern matches for readability
- Remove metadata/editor separator line for cleaner visual flow
2026-06-10 17:50:07 +08:00
xfy
d3c5653808 feat: redesign admin write page with fixed-height editor layout
- Redesign write page UI with cleaner, more immersive editing experience
- Use CSS variables for theme-aware styling (paper-theme colors)
- Make editor fill remaining viewport height with internal scrolling
- Move action bar below editor (left-aligned, non-floating)
- Fix layout: page no longer scrolls, only editor content scrolls
- Update write skeleton to match new layout
- Update admin layout to use h-dvh for write routes to prevent page scroll
- Fix Dioxus.toml dev resource loading to include style.css

Fixes from review:
- Add missing relative positioning for loading overlay
- Use consistent root_class in unauthenticated state
- Use h-dvh instead of h-screen for mobile viewport compatibility
- Ensure skeleton matches actual component layout classes
2026-06-10 17:41:31 +08:00
xfy
2f433e8f11 feat: add 404 Not Found page
- Add NotFound component with elegant design
- Register catch-all route in router
- Add skeleton placeholder for NotFound route
- Remove unused design-taste-frontend skill
2026-06-10 15:43:05 +08:00
xfy
bd9053132b refactor(admin): use explicit field ignores and separate error/loading arms 2026-06-10 14:38:52 +08:00
xfy
31b83cd449 chore: adapt admin pages to new PostListResponse shape 2026-06-10 14:35:51 +08:00
xfy
a2ec043c59 chore: adapt search page to new PostListResponse shape 2026-06-10 14:30:57 +08:00
xfy
4015412b41 feat: display accurate total in tag detail page 2026-06-10 14:25:54 +08:00
xfy
2ade51bd0f feat: display accurate total in archives page 2026-06-10 14:22:18 +08:00
xfy
a2b0c759af feat: use total count for accurate home page pagination 2026-06-10 14:18:22 +08:00
xfy
a3fa602df2 refactor(api): unify error handling with AppError enum
Replace scattered ServerFnError::new("...") inline calls and utils.rs
helper functions with a single AppError enum that provides:
- Automatic tracing::error logging for system errors
- Safe generic messages to frontend (no SQL/connection detail leaks)
- Typed error variants (Unauthorized, Forbidden, NotFound, etc.)
- 5 unit tests for message passthrough and detail hiding

Removes src/api/utils.rs entirely; all error creation now goes through
src/api/error.rs.
2026-06-10 13:16:06 +08:00
xfy
717266db1e fix: resolve conditional compilation and dead code warnings 2026-06-08 16:11:24 +08:00
xfy
3fc91db515 fix(posts): replace space-x-3 with flex gap-3 for edit/delete button spacing 2026-06-05 18:22:59 +08:00
xfy
f6db477a88 fix(write): reset tiptap editor state on unmount to prevent blank editor on re-navigation 2026-06-05 18:16:46 +08:00
xfy
72b932c21b fix(write): add allow lint for unused vars in write_editor 2026-06-05 17:58:05 +08:00
xfy
4805f915c7 fix(write): address review feedback - backfill race, load errors, nav delay 2026-06-05 17:51:46 +08:00
xfy
2ecdc09138 feat(write): support edit mode with data backfill 2026-06-05 17:45:54 +08:00
xfy
0c3a084c9b feat(admin): add edit button to post list 2026-06-05 17:37:37 +08:00
xfy
026a331dcd feat(router): add /admin/write/:id route for post editing 2026-06-05 17:34:26 +08:00
xfy
08bd69d64b feat(write): add onImageUpload callback to tiptap editor 2026-06-05 15:23:36 +08:00
xfy
dd7022ec75 fix: replace select element with overlay pattern to fix dropdown arrow alignment in write page 2026-06-05 11:09:02 +08:00
xfy
28d1ee0d52 fix: reset UserContext on login/logout to prevent admin page stuck on re-login
Root cause: UserContext.checked was never reset on logout, causing AdminLayout's use_effect to skip get_current_user() on subsequent mounts, leaving the page in (checked=true, user=None) limbo.

- Reset ctx.user and ctx.checked on logout in admin_layout.rs
- Reset ctx.checked on login success in login.rs so AdminLayout re-validates session on mount
2026-06-05 10:42:20 +08:00
xfy
58cfcc31bf fix: improve label and button text contrast in write page light mode 2026-06-05 10:33:41 +08:00