--- task: Implement 7 humor-units admin improvements slug: 20260317-000000_humor-units-7-improvements effort: comprehensive phase: execute progress: 0/64 mode: interactive started: 2026-03-17T00:00:00Z updated: 2026-03-17T00:01:00Z --- ## Context Implementing 7 ordered features for the humor-units SvelteKit admin page. Files: src/lib/types.ts, src/routes/admin/+page.svelte, src/routes/+page.svelte, src/components/ConversionResult.svelte, new src/routes/admin/api/order/+server.ts. Each feature must pass `npm run build` before committing and proceeding. ### Risks - TypeScript strict mode may reject certain Svelte 5 patterns (e.g., action typing) - Drag-and-drop with Svelte 5 runes requires careful state management - Form dirty-check needs accurate initial-value tracking - Auto-ID edge cases: user clears field, then types again - The `description` field must be passed through all API layers (POST/PUT) without breaking existing validation - CSS override of Pico hover must handle both light and dark mode correctly ### Plan 1. Feature 1: Add `description?: string` to Unit type; add textarea in admin unit form; add `use:tooltip` action in ConversionResult.svelte 2. Feature 2: Track form initial values; dirty detection; auto-save on "+ Add" when dirty; highlight invalid fields with `field-error` class 3. Feature 3: HTML5 DnD on group rows and unit rows; new PUT /admin/api/order endpoint 4. Feature 4: Add `sortOrder?` to Group type; select in group form; sort logic in orderedResults derived 5. Feature 5: Auto-ID from label (kebab) in create forms; ID field with manual-edit tracking 6. Feature 6: Add `text-decoration: underline` to `.bulk-clear:hover` and ensure color override 7. Feature 7: Add "delete" to bulkAction dropdown; confirmation UI; DELETE each checked unit ## Criteria ### Feature 1: Unit descriptions / tooltips - [ ] ISC-1: `description?: string` optional field added to Unit interface in types.ts - [ ] ISC-2: Unit form has textarea labeled "Description" below existing fields - [ ] ISC-3: Description value saved via POST /admin/api/units (new unit) - [ ] ISC-4: Description value saved via PUT /admin/api/units/:id (edit unit) - [ ] ISC-5: Description value loaded into form when unit is selected for editing - [ ] ISC-6: `use:tooltip` Svelte action defined in frontend converter page - [ ] ISC-7: Tooltip action sets `title` attribute after 500ms mouseenter delay - [ ] ISC-8: Tooltip action clears timeout and removes `title` on mouseleave - [ ] ISC-9: Tooltip applied to unit label/symbol span in ConversionResult - [ ] ISC-10: Tooltip NOT set when description is empty or undefined ### Feature 2: Auto-save partial forms + error blocking - [ ] ISC-11: `isDirty()` function detects changes from initial form values - [ ] ISC-12: Initial form snapshot captured when form is opened (select/new) - [ ] ISC-13: Clicking "+ Add Unit" while dirty unit form open attempts auto-save - [ ] ISC-14: Clicking "+ Add Group" while dirty group form open attempts auto-save - [ ] ISC-15: Successful auto-save opens new form as intended - [ ] ISC-16: Failed auto-save displays error inline; does NOT open new form - [ ] ISC-17: `field-error` CSS class defined with invalid border-color var - [ ] ISC-18: First invalid/empty required field highlighted with `field-error` on save failure - [ ] ISC-19: Required unit fields validated: label, labelPlural, symbol, toBase>0, id (kebab) - [ ] ISC-20: Required group fields validated: label, id (kebab) - [ ] ISC-21: Form not dirty if user clicked "+ Add" but typed nothing yet ### Feature 3: Drag-to-reorder groups and units - [ ] ISC-22: Group header rows have `draggable="true"` attribute - [ ] ISC-23: Group drag cursor is `grab` (CSS) - [ ] ISC-24: Drag handle `⠿` icon added to unit rows (left side, cursor grab) - [ ] ISC-25: Groups can be reordered by drag-and-drop within the list - [ ] ISC-26: Units can be reordered within their group by drag-and-drop - [ ] ISC-27: Units cannot be dragged between groups via DnD - [ ] ISC-28: After drop, PUT /admin/api/order called with new order arrays - [ ] ISC-29: New endpoint `src/routes/admin/api/order/+server.ts` created - [ ] ISC-30: Order endpoint is auth-gated via authRequest - [ ] ISC-31: Order endpoint accepts `groups?: string[]` and reorders data.groups - [ ] ISC-32: Order endpoint accepts `units?: Record` and reorders units within groups - [ ] ISC-33: Order endpoint saves data and returns `{ ok: true }` ### Feature 4: Per-group sort order setting - [ ] ISC-34: `sortOrder?: 'defined' | 'alpha'` added to Group interface in types.ts - [ ] ISC-35: Group edit form has select for "Display order" (Defined order / Alphabetical) - [ ] ISC-36: sortOrder value saved via PUT /admin/api/groups/:id - [ ] ISC-37: sortOrder value loaded into form when group is selected for editing - [ ] ISC-38: Frontend orderedResults sorts by `label` when group.sortOrder === 'alpha' - [ ] ISC-39: Frontend uses defined order when sortOrder is undefined or 'defined' ### Feature 5: Auto-ID generation from label - [ ] ISC-40: `toKebab(s)` helper function defined - [ ] ISC-41: `idWasManuallyEdited` boolean state tracked for unit create form - [ ] ISC-42: `idWasManuallyEdited` boolean state tracked for group create form - [ ] ISC-43: Unit create form ID field live-updates from label while not manually edited - [ ] ISC-44: Group create form ID field live-updates from label while not manually edited - [ ] ISC-45: Typing in ID field sets `idWasManuallyEdited = true`, stops auto-update - [ ] ISC-46: Clearing ID field sets `idWasManuallyEdited = false`, resumes auto-generation - [ ] ISC-47: On form blur or save attempt: ID generated from label if ID empty and label non-empty ### Feature 6: Clear button hover highlight - [ ] ISC-48: `.bulk-clear:not(:disabled):hover` CSS has `text-decoration: underline` - [ ] ISC-49: Hover color uses `--pico-contrast` for dark text in light/Dan mode - [ ] ISC-50: Background stays transparent on hover - [ ] ISC-51: Dark mode hover effect not broken (text lightens appropriately) - [ ] ISC-52: All three Pico vars overridden: `--pico-color`, `--pico-background-color`, `--pico-border-color` ### Feature 7: Bulk delete action - [ ] ISC-53: "Delete" option added to bulkAction select (value: `'delete'`) - [ ] ISC-54: Group target row hidden when bulkAction is 'delete' - [ ] ISC-55: Confirmation section shown: "Delete N units? [Confirm] [Cancel]" - [ ] ISC-56: N in confirmation reflects current checkedUnitIds.size - [ ] ISC-57: Confirm calls DELETE /admin/api/units/:id for each checked unit - [ ] ISC-58: After all deletions, selection cleared and data reloaded - [ ] ISC-59: Failed deletions shown as formError with count of failures - [ ] ISC-60: "Cancel" resets bulkAction to '' and clears confirmation state - [ ] ISC-61: Apply button disabled when bulkAction is 'delete' (confirm/cancel separate UI) ### Anti-criteria - [ ] ISC-A1: data/units.json and data/config.json not directly modified by feature code - [ ] ISC-A2: Auth system, session handling unchanged - [ ] ISC-A3: No global CSS added outside scoped style blocks - [ ] ISC-A4: No bare :root var overrides for Pico - [ ] ISC-A5: npm run build passes after each feature implementation ## Decisions ## Verification