- 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
- Reorder imports to group wasm32-gated items together
- Format struct pattern matches for readability
- Remove metadata/editor separator line for cleaner visual flow
- 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
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.
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
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.