230 Commits

Author SHA1 Message Date
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
xfy
5321b8cf97 refactor: reorganize admin write page layout with card-based sections 2026-06-05 09:58:26 +08:00
xfy
c26c62558e fix: add status_badge_class for badge styling, restore posts table backgrounds 2026-06-04 16:17:41 +08:00
xfy
58e9dbc5b7 refactor: add status_label/status_class/formatted_date helpers to Post model 2026-06-04 16:13:49 +08:00
xfy
58f972aa17 fix: restore register success alert layout with login link 2026-06-04 15:59:17 +08:00
xfy
4e33bd3ee6 refactor: extract form atoms (FormInput, FormLabel, AlertBox) and replace repeated input/button styles 2026-06-04 15:55:40 +08:00
xfy
ce14c476b5 refactor: replace string-based navigation with typed Route and Link components 2026-06-04 14:55:18 +08:00
xfy
5d018864c2 refactor: remove PageLayout from all frontend pages, delegate to FrontendLayout
- Remove PageLayout wrapper from Home, HomePage, Archives, Tags,
  TagDetail, PostDetail, Search, and About components
- Remove unused imports: use_nav_items, use_route, PageLayout, Route
- Pages now render only their content; Header/Footer are provided by
  FrontendLayout via the router's #[layout] attribute
- Skeleton screens (DelayedSkeleton) remain in data-loading branches
- This eliminates redundant Header/Footer re-mounting on every route
  change, which was the primary source of page transition flicker

Files changed:
- src/pages/home.rs: remove PageLayout, keep HomeInfo + HomePosts
- src/pages/about.rs: remove PageLayout, render content directly
- src/pages/archives.rs: remove PageLayout, keep header + ArchivesContent
- src/pages/post_detail.rs: remove PageLayout, keep PostDetailContent
- src/pages/search.rs: remove PageLayout, keep search form + results
- src/pages/tags.rs: remove PageLayout from Tags and TagDetail
2026-06-03 18:38:11 +08:00
xfy
778726251a fix: remove SuspenseBoundary, render skeleton screens directly in loading branch 2026-06-03 17:59:38 +08:00
xfy
754c1f5b86 feat: wrap all skeleton screens with DelayedSkeleton to prevent flicker 2026-06-03 17:43:34 +08:00
xfy
62519d620d feat: add SearchSkeleton component and replace inline skeleton on search page 2026-06-03 17:30:47 +08:00
xfy
c2e1fbe3ac feat: add TagsSkeleton/TagDetailSkeleton and replace generic fallback on tags pages 2026-06-03 17:25:47 +08:00
xfy
5becd73ebc feat: add ArchiveSkeleton and replace generic fallback on archives page 2026-06-03 17:19:29 +08:00
xfy
372c701b07 feat: add PostDetailSkeleton and replace generic fallback on post detail page 2026-06-03 17:13:39 +08:00
xfy
076448d6ed feat: add HomeSkeleton and replace generic fallback on home page 2026-06-03 17:09:20 +08:00
xfy
ccffab851a fix: admin pages use client-only fetching; fix theme cookie parsing; restore custom skeletons 2026-06-03 14:55:50 +08:00
xfy
6cfe664085 feat: SSR for home and tags pages 2026-06-03 14:40:15 +08:00
xfy
34e70f6c57 feat: SSR for admin pages 2026-06-03 14:33:49 +08:00
xfy
1afb477829 feat: SSR for archives page 2026-06-03 14:23:44 +08:00
xfy
fe30d0495f feat: SSR for post detail page 2026-06-03 14:17:52 +08:00
xfy
c6ced73bac fix(admin): resolve compilation errors in posts and write pages 2026-06-03 10:57:22 +08:00
xfy
09060e12c0 fix(admin): cap tiptap editor ready-polling at 100 attempts
Replace infinite loop with bounded for-loop (100 × 100ms = 10s max).
On timeout the skeleton overlay is dismissed so the user can still
interact with the form instead of being stuck forever.
2026-06-03 10:34:06 +08:00
xfy
e6c3cacf12 chore: format with cargo fix 2026-06-03 10:12:04 +08:00
xfy
5544ea0c18 feat(admin): add cover_image input field in write form 2026-06-02 18:22:22 +08:00