120 lines
7.1 KiB
Markdown
120 lines
7.1 KiB
Markdown
---
|
|
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<string, string[]>` 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
|