fix(ui): add async feedback and correct empty-state copy on dashboard #41

Merged
salmaelsoly merged 1 commit from development_dashboard_ux_fixes into development 2026-04-30 12:08:40 +00:00
Member

Closes #38.

Summary

Fixes four small dashboard UX defects: missing async feedback on Create Deck, wrong empty-state copy when a deck is selected with zero slides, black flash when opening the lightbox the first time, and a thumbnail flash to black after Create Slide. JS + HTML + CSS only — no Rust changes.

Changes

Issue Fix
#1 Create Deck OK no loading state showPrompt now disables the OK button, swaps its label with a Bootstrap spinner, disables the input + Cancel, and only closes the modal in a finally after the RPC resolves. Same fix incidentally improves Create Folder, Insert Slide, Move Slide, Rename Deck, Duplicate Deck.
#2 Wrong "Select a deck" copy on empty deck Split #slides-empty into #slides-empty-no-deck ("Select a deck to view slides.") and #slides-empty-no-slides ("No slides yet — click Create Slide to add one."). loadSlidesForDeck and renderSlides toggle the right one.
#3 Lightbox black flash New #preview-spinner overlay; showPreviewSlide adds a loading class to the image, shows the spinner, and clears both via onload/onerror. Cached-image short-circuit via img.complete && img.naturalWidth > 0.
#4 Thumbnail flash after Create Slide doCreateSlide now captures slide.insert response and calls appendSlideCard(inserted, slug) instead of loadSlidesForDeck(). Direct DOM append, no full reload. Guard rail: if inserted.new_name is missing, falls back to the full reload.

Files

 crates/hero_slides_ui/static/css/dashboard.css |  17 +++
 crates/hero_slides_ui/static/js/dashboard.js   | 196 +++++++++++++++++++------
 crates/hero_slides_ui/templates/index.html     |   9 +-
 3 files changed, 179 insertions(+), 43 deletions(-)

Test results

  • cargo test --workspace: 98 passed / 0 failed / 1 ignored (the AI-gated test). Same baseline as development.
  • cargo fmt --check: clean.
  • cargo clippy --workspace --no-deps: only the 2 pre-existing unnecessary_sort_by warnings in slide_ops.rs:219 and :448 (unchanged from development).

Test plan

  • Create Deck: spinner visible during the ~2-3s RPC, modal closes after.
  • Slides tab on a fresh deck (selected, 0 slides): empty state reads "No slides yet — click Create Slide to add one."
  • Slides tab with no deck selected: still reads "Select a deck to view slides."
  • Lightbox: open from a thumbnail → no black flash, spinner appears briefly then image. Navigate next/prev: no stale frame.
  • Create Slide on a deck with 2+ existing slides: existing thumbnails stay stable, new card appears with the Pending badge, then transitions through Generating to Generated.
  • Sanity: Insert Slide / Move Slide / Rename Deck / Duplicate Deck modals all complete and close after their RPC resolves.

Notes

  • The shared showPrompt change is a small contract shift: previously the modal closed before onConfirm; now it closes after. All 7 callers were audited and none rely on the old timing.
  • appendSlideCard writes directly to currentSlides, bypassing the server. If state ever drifts (e.g. concurrent edits), the next full reload reconciles. Acceptable for the single-user Hero context.
  • dashboard.js and dashboard.css are static assets embedded via rust_embed. After deploy users may need a hard refresh, and the hero_slides_ui binary needs rebuilding.
Closes #38. ## Summary Fixes four small dashboard UX defects: missing async feedback on Create Deck, wrong empty-state copy when a deck is selected with zero slides, black flash when opening the lightbox the first time, and a thumbnail flash to black after Create Slide. JS + HTML + CSS only — no Rust changes. ## Changes | Issue | Fix | |---|---| | #1 Create Deck OK no loading state | `showPrompt` now disables the OK button, swaps its label with a Bootstrap spinner, disables the input + Cancel, and only closes the modal in a `finally` after the RPC resolves. Same fix incidentally improves Create Folder, Insert Slide, Move Slide, Rename Deck, Duplicate Deck. | | #2 Wrong "Select a deck" copy on empty deck | Split `#slides-empty` into `#slides-empty-no-deck` ("Select a deck to view slides.") and `#slides-empty-no-slides` ("No slides yet — click Create Slide to add one."). `loadSlidesForDeck` and `renderSlides` toggle the right one. | | #3 Lightbox black flash | New `#preview-spinner` overlay; `showPreviewSlide` adds a `loading` class to the image, shows the spinner, and clears both via `onload`/`onerror`. Cached-image short-circuit via `img.complete && img.naturalWidth > 0`. | | #4 Thumbnail flash after Create Slide | `doCreateSlide` now captures `slide.insert` response and calls `appendSlideCard(inserted, slug)` instead of `loadSlidesForDeck()`. Direct DOM append, no full reload. Guard rail: if `inserted.new_name` is missing, falls back to the full reload. | ## Files ``` crates/hero_slides_ui/static/css/dashboard.css | 17 +++ crates/hero_slides_ui/static/js/dashboard.js | 196 +++++++++++++++++++------ crates/hero_slides_ui/templates/index.html | 9 +- 3 files changed, 179 insertions(+), 43 deletions(-) ``` ## Test results - `cargo test --workspace`: 98 passed / 0 failed / 1 ignored (the AI-gated test). Same baseline as `development`. - `cargo fmt --check`: clean. - `cargo clippy --workspace --no-deps`: only the 2 pre-existing `unnecessary_sort_by` warnings in `slide_ops.rs:219` and `:448` (unchanged from `development`). ## Test plan - [x] Create Deck: spinner visible during the ~2-3s RPC, modal closes after. - [x] Slides tab on a fresh deck (selected, 0 slides): empty state reads "No slides yet — click Create Slide to add one." - [x] Slides tab with no deck selected: still reads "Select a deck to view slides." - [x] Lightbox: open from a thumbnail → no black flash, spinner appears briefly then image. Navigate next/prev: no stale frame. - [x] Create Slide on a deck with 2+ existing slides: existing thumbnails stay stable, new card appears with the Pending badge, then transitions through Generating to Generated. - [x] Sanity: Insert Slide / Move Slide / Rename Deck / Duplicate Deck modals all complete and close after their RPC resolves. ## Notes - The shared `showPrompt` change is a small contract shift: previously the modal closed before `onConfirm`; now it closes after. All 7 callers were audited and none rely on the old timing. - `appendSlideCard` writes directly to `currentSlides`, bypassing the server. If state ever drifts (e.g. concurrent edits), the next full reload reconciles. Acceptable for the single-user Hero context. - `dashboard.js` and `dashboard.css` are static assets embedded via `rust_embed`. After deploy users may need a hard refresh, and the `hero_slides_ui` binary needs rebuilding.
fix(ui): add async feedback and correct empty-state copy on dashboard
All checks were successful
Test / test (push) Successful in 1m34s
Test / test (pull_request) Successful in 1m34s
6254c7e76a
salmaelsoly merged commit 7ac8b21106 into development 2026-04-30 12:08:40 +00:00
salmaelsoly deleted branch development_dashboard_ux_fixes 2026-04-30 12:08:45 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_slides!41
No description provided.