Add multi-select for slides with bulk actions and improved drag-drop #5

Closed
opened 2026-04-13 17:52:01 +00:00 by casper-stevens · 3 comments
Member

Context

Slide management currently only supports single-slide operations, making it tedious to manage large decks. Additionally, moving a slide to the end requires precise placement on the last slide edge rather than dropping onto empty space.

Goals

  • Add multi-select using standard patterns: click to select, shift-click for range, ctrl/cmd-click to toggle
  • Add visual indicator for selected slides and a select all / deselect all option
  • Extend existing actions (move, delete, duplicate) to work on multi-select
  • Ensure drag-and-drop reordering works with multiple selected slides
  • Make empty space after the last slide a valid drop target that moves slides to the end
## Context Slide management currently only supports single-slide operations, making it tedious to manage large decks. Additionally, moving a slide to the end requires precise placement on the last slide edge rather than dropping onto empty space. ## Goals - Add multi-select using standard patterns: click to select, shift-click for range, ctrl/cmd-click to toggle - Add visual indicator for selected slides and a select all / deselect all option - Extend existing actions (move, delete, duplicate) to work on multi-select - Ensure drag-and-drop reordering works with multiple selected slides - Make empty space after the last slide a valid drop target that moves slides to the end
Author
Member

Implementation Spec for Issue #5

Objective

Add multi-select capability to the slide grid in the HeroSlides dashboard, enabling users to select multiple slides and perform bulk actions (move, delete, duplicate), drag-and-drop multiple selected slides simultaneously, and drop slides onto empty space after the last card to move them to the end of the deck.

Requirements

  • Click a slide card to toggle its selected state
  • Shift+click to select a contiguous range from the last-clicked slide to the shift-clicked slide
  • Ctrl/Cmd+click to toggle individual slides without clearing the selection
  • Visual highlight (colored border/overlay) on selected slide cards
  • A toolbar area showing selection count with "Select All" and "Deselect All" buttons
  • Bulk delete: confirm dialog, then delete all selected slides (highest-numbered first to avoid renumbering conflicts)
  • Bulk move via drag-and-drop: dragging any selected slide drags the entire selection; drop indicator shows insertion point for the group
  • Bulk duplicate: duplicate all selected slides, inserting copies immediately after the last selected slide
  • Drop zone after the last slide card: dropping onto empty grid space moves slide(s) to the end position
  • All operations must refresh the slide list via loadSlidesForDeck() after completion
  • Keyboard shortcut: Ctrl/Cmd+A to select all slides when the slides tab is active

Files to Modify

File Action Description
crates/hero_slides_ui/static/js/dashboard.js Modify Add selection state, selection UI logic, bulk action functions, multi-drag, empty-space drop zone
crates/hero_slides_ui/static/css/dashboard.css Modify Add selected styles, drop zone styles, selection toolbar styles
crates/hero_slides_ui/templates/index.html Modify Add selection toolbar in the slides tab
crates/hero_slides_server/src/rpc.rs Modify Add slide.bulkDelete, slide.bulkMove, slide.duplicate RPC handlers
crates/hero_slides_lib/src/slide_ops.rs Modify Add duplicate_slide, bulk_delete_slides, bulk_move_slides functions
crates/hero_slides_lib/src/deck.rs Modify Add public wrapper functions
crates/hero_slides_lib/src/lib.rs Modify Re-export new public functions

Implementation Plan

Step 1: Add bulk slide operations to hero_slides_lib

Files: slide_ops.rs, deck.rs, lib.rs

  • Add duplicate_slide(dir, slide_name) function
  • Add bulk_delete_slides(dir, slide_names) function (deletes highest-numbered first)
  • Add bulk_move_slides(dir, slide_names, to_position) function (atomic multi-slide move)
  • Add public wrappers in deck.rs and re-export in lib.rs
  • Add unit tests
    Dependencies: none

Step 2: Add server RPC handlers for bulk operations

Files: rpc.rs

  • Add slide.duplicate, slide.bulkDelete, slide.bulkMove RPC handlers
  • Register in the method dispatch match block
    Dependencies: Step 1

Step 3: Add selection state and UI logic to dashboard.js

Files: dashboard.js

  • Add selection state (Set of slide names, last-clicked tracking)
  • Add selection helper functions (toggle, select all, deselect, update UI)
  • Modify renderSlides() to support selection
  • Add click handlers with shift/ctrl support
  • Modify context menu for bulk actions
  • Add Ctrl/Cmd+A keyboard shortcut
    Dependencies: none

Step 4: Modify drag-and-drop for multi-slide support and empty-space drop zone

Files: dashboard.js

  • Modify dragstart to handle multiple selected slides
  • Modify drop handlers for bulk move
  • Add empty-space drop zone after last card
  • Add bulk action functions (bulkDeleteSlides, bulkDuplicateSlides, bulkMoveSlides)
    Dependencies: Step 2, Step 3

Step 5: Add CSS styles for selection and drop zone

Files: dashboard.css

  • Add .slide-card.selected styles (border, check icon overlay)
  • Add .slide-drop-end-zone styles
  • Add .slides-selection-bar toolbar styles
    Dependencies: none

Step 6: Add selection toolbar to the slides tab HTML template

Files: index.html

  • Add hidden selection bar with count, Select All, Deselect, Delete, Duplicate buttons
    Dependencies: none

Acceptance Criteria

  • Clicking a slide card selects it (blue border + check icon overlay)
  • Clicking another slide card deselects the first and selects the new one
  • Ctrl/Cmd+click toggles individual slides without clearing other selections
  • Shift+click selects a contiguous range
  • Ctrl/Cmd+A selects all slides when slides tab is active
  • Selection toolbar appears when 1+ slides are selected
  • Bulk delete prompts for confirmation, then deletes all selected slides
  • Bulk duplicate creates copies of all selected slides
  • Dragging a selected slide drags all selected slides together
  • Dropping multiple slides onto a card inserts them at the correct position
  • Dropping slides onto empty space moves them to the end
  • Right-clicking a selected slide (with multiple selected) shows bulk context menu
  • Existing single-slide operations continue to work
  • Unit tests pass for new lib functions

Notes

  • bulk_move must use temp-name approach with indexed temp names (tmp_moving_slide_0, tmp_moving_slide_1, etc.)
  • Bulk delete processes slides from highest number to lowest to avoid renumbering cascades
  • UI proxy architecture means no changes needed to routes.rs
  • Selection state survives in-place updates but clears on full rebuilds
  • Click handlers on .slide-card must not fire when clicking buttons inside the card
## Implementation Spec for Issue #5 ### Objective Add multi-select capability to the slide grid in the HeroSlides dashboard, enabling users to select multiple slides and perform bulk actions (move, delete, duplicate), drag-and-drop multiple selected slides simultaneously, and drop slides onto empty space after the last card to move them to the end of the deck. ### Requirements - Click a slide card to toggle its selected state - Shift+click to select a contiguous range from the last-clicked slide to the shift-clicked slide - Ctrl/Cmd+click to toggle individual slides without clearing the selection - Visual highlight (colored border/overlay) on selected slide cards - A toolbar area showing selection count with "Select All" and "Deselect All" buttons - Bulk delete: confirm dialog, then delete all selected slides (highest-numbered first to avoid renumbering conflicts) - Bulk move via drag-and-drop: dragging any selected slide drags the entire selection; drop indicator shows insertion point for the group - Bulk duplicate: duplicate all selected slides, inserting copies immediately after the last selected slide - Drop zone after the last slide card: dropping onto empty grid space moves slide(s) to the end position - All operations must refresh the slide list via loadSlidesForDeck() after completion - Keyboard shortcut: Ctrl/Cmd+A to select all slides when the slides tab is active ### Files to Modify | File | Action | Description | |------|--------|-------------| | `crates/hero_slides_ui/static/js/dashboard.js` | Modify | Add selection state, selection UI logic, bulk action functions, multi-drag, empty-space drop zone | | `crates/hero_slides_ui/static/css/dashboard.css` | Modify | Add selected styles, drop zone styles, selection toolbar styles | | `crates/hero_slides_ui/templates/index.html` | Modify | Add selection toolbar in the slides tab | | `crates/hero_slides_server/src/rpc.rs` | Modify | Add slide.bulkDelete, slide.bulkMove, slide.duplicate RPC handlers | | `crates/hero_slides_lib/src/slide_ops.rs` | Modify | Add duplicate_slide, bulk_delete_slides, bulk_move_slides functions | | `crates/hero_slides_lib/src/deck.rs` | Modify | Add public wrapper functions | | `crates/hero_slides_lib/src/lib.rs` | Modify | Re-export new public functions | ### Implementation Plan #### Step 1: Add bulk slide operations to hero_slides_lib Files: `slide_ops.rs`, `deck.rs`, `lib.rs` - Add `duplicate_slide(dir, slide_name)` function - Add `bulk_delete_slides(dir, slide_names)` function (deletes highest-numbered first) - Add `bulk_move_slides(dir, slide_names, to_position)` function (atomic multi-slide move) - Add public wrappers in deck.rs and re-export in lib.rs - Add unit tests Dependencies: none #### Step 2: Add server RPC handlers for bulk operations Files: `rpc.rs` - Add `slide.duplicate`, `slide.bulkDelete`, `slide.bulkMove` RPC handlers - Register in the method dispatch match block Dependencies: Step 1 #### Step 3: Add selection state and UI logic to dashboard.js Files: `dashboard.js` - Add selection state (Set of slide names, last-clicked tracking) - Add selection helper functions (toggle, select all, deselect, update UI) - Modify renderSlides() to support selection - Add click handlers with shift/ctrl support - Modify context menu for bulk actions - Add Ctrl/Cmd+A keyboard shortcut Dependencies: none #### Step 4: Modify drag-and-drop for multi-slide support and empty-space drop zone Files: `dashboard.js` - Modify dragstart to handle multiple selected slides - Modify drop handlers for bulk move - Add empty-space drop zone after last card - Add bulk action functions (bulkDeleteSlides, bulkDuplicateSlides, bulkMoveSlides) Dependencies: Step 2, Step 3 #### Step 5: Add CSS styles for selection and drop zone Files: `dashboard.css` - Add .slide-card.selected styles (border, check icon overlay) - Add .slide-drop-end-zone styles - Add .slides-selection-bar toolbar styles Dependencies: none #### Step 6: Add selection toolbar to the slides tab HTML template Files: `index.html` - Add hidden selection bar with count, Select All, Deselect, Delete, Duplicate buttons Dependencies: none ### Acceptance Criteria - [ ] Clicking a slide card selects it (blue border + check icon overlay) - [ ] Clicking another slide card deselects the first and selects the new one - [ ] Ctrl/Cmd+click toggles individual slides without clearing other selections - [ ] Shift+click selects a contiguous range - [ ] Ctrl/Cmd+A selects all slides when slides tab is active - [ ] Selection toolbar appears when 1+ slides are selected - [ ] Bulk delete prompts for confirmation, then deletes all selected slides - [ ] Bulk duplicate creates copies of all selected slides - [ ] Dragging a selected slide drags all selected slides together - [ ] Dropping multiple slides onto a card inserts them at the correct position - [ ] Dropping slides onto empty space moves them to the end - [ ] Right-clicking a selected slide (with multiple selected) shows bulk context menu - [ ] Existing single-slide operations continue to work - [ ] Unit tests pass for new lib functions ### Notes - bulk_move must use temp-name approach with indexed temp names (tmp_moving_slide_0, tmp_moving_slide_1, etc.) - Bulk delete processes slides from highest number to lowest to avoid renumbering cascades - UI proxy architecture means no changes needed to routes.rs - Selection state survives in-place updates but clears on full rebuilds - Click handlers on .slide-card must not fire when clicking buttons inside the card
Author
Member

Test Results

  • Total: 49
  • Passed: 49
  • Failed: 0

All tests passed.

## Test Results - Total: 49 - Passed: 49 - Failed: 0 All tests passed.
Author
Member

Pull request opened: #13

This PR implements the changes described in the spec above.

Pull request opened: https://forge.ourworld.tf/lhumina_code/hero_slides/pulls/13 This PR implements the changes described in the spec above.
Sign in to join this conversation.
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#5
No description provided.