feat(settings): tabbed redesign + per-action HTMX feedback (LC-426) #435

Merged
longjacksonle merged 1 commit from feat/settings-redesign-feedback into main 2026-06-21 23:44:03 +02:00

Reworks the Settings page (ref data/ref-settings.jpg) from a mile-long scroll with fake anchor-jump tabs and silent saves into a tabbed, two-column layout where every action confirms its result. Askama + HTMX + Tailwind, no client framework; reuses the existing .btn / .input / .card / .toast vocabulary. Closes LC-426 (sub-tasks LC-427..LC-431).

Decision on tabs

Went with option (a): real tabs, client-side. All section data is already server-rendered, so settings.js just shows one panel at a time (hash + sessionStorage synced, ARIA tablist, arrow-key nav) - no new per-tab routes, instant switching, every form keeps its htmx wiring. A <noscript> rule reveals all panels and hides the tab rail when JS is off.

Layout + structure (LC-427 / LC-428)

  • Centered, max-width two-column shell: sticky vertical section nav + content; collapses to a scrollable top strip on mobile.
  • Each settings group is a bordered card (title + description) with a clear type scale.
  • Notification checkboxes -> styled toggle switches with aligned descriptions.
  • Quiet-hours time inputs -> labelled, aligned grid.
  • One button system (primary / secondary / danger / ghost); Revoke and Remove avatar share the destructive styling.

Feedback system (LC-429 / LC-430 / LC-431)

  • Global #lc-toast-region + toast.js: auto-dismiss, hover-hold, manual close, aria-live, plus a window.__lcToast helper for non-form actions.
  • A reusable SettingsFeedback fragment returns the inline per-form status AND an out-of-band toast in one response. An HX-aware helper returns it for htmx requests and keeps the full-page redirect otherwise (no-JS still works).
  • Every save form posts via hx-post into its own status slot, with an in-button spinner (hx-indicator) and hx-disabled-elt to block double-submit; success and validation-error both render a status.
  • Avatar: live preview on select + a "not applied until you Save profile" hint that clears on save; save confirms ("Profile saved" / "Profile picture updated"); Remove avatar confirms and reverts the preview via an OOB swap.
  • Revoke session removes its row + toast; Add highlight word toasts; Download my data shows a "preparing" toast; Delete my account shows a disabled "Deleting..." state.

Handlers / tests

post_language / appearance / settings / dnd-schedule / profile / avatar-delete / session-revoke / keyword-add gained an HX branch; their non-htmx redirect paths and the existing settings tests are unchanged. New routes_settings_feedback asserts the HX path returns the inline status + OOB toast and the non-HX path still redirects.

New i18n: settings-fb-*, settings-avatar-pending, settings-remove-avatar-confirm, settings-data-preparing, settings-deleting, action-dismiss (en + es). Frontend + response-shape only; no schema/route change.

just check, just test, just test-saas pass; toast.js + settings.js syntax-checked; Tailwind rebuilt. The dev server is Bunyip-SSO-gated, so an in-browser pass on the PR build (light + dark) is worthwhile.

🤖 Generated with Claude Code

Reworks the Settings page (ref data/ref-settings.jpg) from a mile-long scroll with fake anchor-jump tabs and silent saves into a tabbed, two-column layout where every action confirms its result. Askama + HTMX + Tailwind, no client framework; reuses the existing .btn / .input / .card / .toast vocabulary. Closes LC-426 (sub-tasks LC-427..LC-431). ## Decision on tabs Went with option (a): real tabs, client-side. All section data is already server-rendered, so settings.js just shows one panel at a time (hash + sessionStorage synced, ARIA tablist, arrow-key nav) - no new per-tab routes, instant switching, every form keeps its htmx wiring. A `<noscript>` rule reveals all panels and hides the tab rail when JS is off. ## Layout + structure (LC-427 / LC-428) - Centered, max-width two-column shell: sticky vertical section nav + content; collapses to a scrollable top strip on mobile. - Each settings group is a bordered card (title + description) with a clear type scale. - Notification checkboxes -> styled toggle switches with aligned descriptions. - Quiet-hours time inputs -> labelled, aligned grid. - One button system (primary / secondary / danger / ghost); Revoke and Remove avatar share the destructive styling. ## Feedback system (LC-429 / LC-430 / LC-431) - Global `#lc-toast-region` + toast.js: auto-dismiss, hover-hold, manual close, aria-live, plus a `window.__lcToast` helper for non-form actions. - A reusable `SettingsFeedback` fragment returns the inline per-form status AND an out-of-band toast in one response. An HX-aware helper returns it for htmx requests and keeps the full-page redirect otherwise (no-JS still works). - Every save form posts via hx-post into its own status slot, with an in-button spinner (`hx-indicator`) and `hx-disabled-elt` to block double-submit; success and validation-error both render a status. - Avatar: live preview on select + a "not applied until you Save profile" hint that clears on save; save confirms ("Profile saved" / "Profile picture updated"); Remove avatar confirms and reverts the preview via an OOB swap. - Revoke session removes its row + toast; Add highlight word toasts; Download my data shows a "preparing" toast; Delete my account shows a disabled "Deleting..." state. ## Handlers / tests `post_language` / `appearance` / `settings` / `dnd-schedule` / `profile` / `avatar-delete` / `session-revoke` / `keyword-add` gained an HX branch; their non-htmx redirect paths and the existing settings tests are unchanged. New `routes_settings_feedback` asserts the HX path returns the inline status + OOB toast and the non-HX path still redirects. New i18n: `settings-fb-*`, `settings-avatar-pending`, `settings-remove-avatar-confirm`, `settings-data-preparing`, `settings-deleting`, `action-dismiss` (en + es). Frontend + response-shape only; no schema/route change. `just check`, `just test`, `just test-saas` pass; toast.js + settings.js syntax-checked; Tailwind rebuilt. The dev server is Bunyip-SSO-gated, so an in-browser pass on the PR build (light + dark) is worthwhile. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(settings): tabbed redesign + per-action HTMX feedback (LC-426)
All checks were successful
check-secrets / Nosey parker (push) Successful in 6s
check-secrets / TruffleHog (push) Successful in 8s
check-secrets / Kingfisher (push) Successful in 10s
check-secrets / TruffleHog (pull_request) Successful in 8s
check-secrets / Nosey parker (pull_request) Successful in 8s
check-secrets / Kingfisher (pull_request) Successful in 10s
Check / clippy + fmt + tests (pull_request) Successful in 5m35s
Create release / Create release from merged PR (pull_request) Has been skipped
fb0ca33d48
Reworks the Settings page from one mile-long scroll with fake (anchor-jump) tabs and silent saves into a tabbed, two-column layout where every action confirms its result. Keeps the Askama + HTMX + Tailwind, server-rendered, no-client-framework stack and reuses the existing .btn / .input / .card / .toast component vocabulary.

Layout + structure (LC-427/428): real tabs - settings.js shows one panel at a time (hash + sessionStorage synced, ARIA tablist, arrow-key nav), with a centered max-width two-column shell (sticky vertical section nav + content) that collapses to a scrollable top strip on mobile. Each settings group is a bordered card with a title + description and a clear type scale. The notification checkboxes become styled toggle switches with aligned descriptions; the quiet-hours time inputs get a labelled, aligned grid; Revoke / Remove avatar use the shared destructive styling. Progressive enhancement: a <noscript> rule reveals every panel and drops the tab rail when JS is off.

Feedback system (LC-429/430/431): a global #lc-toast-region + toast.js (auto-dismiss, hover-hold, manual close, aria-live, plus a window.__lcToast helper). A reusable SettingsFeedback fragment returns the inline per-form status AND an out-of-band toast in one response; an HX-aware helper returns it for htmx requests and keeps the full-page redirect otherwise (no-JS still works). Every save form posts via hx-post into its own status slot with an in-button spinner (hx-indicator) and hx-disabled-elt to prevent double-submit; success and validation-error both render a status. Profile save confirms ("Profile saved" / "Profile picture updated"); the avatar gets a live preview on select with a "not applied until you Save profile" hint that clears on save; Remove avatar confirms and reverts the preview via an OOB swap; session Revoke removes its row + toast; Add highlight word toasts; Download my data shows a "preparing" toast; Delete my account shows a disabled "Deleting..." state.

Handlers gained an HX branch (post_language/appearance/settings/dnd-schedule/profile/avatar-delete/session-revoke/keyword-add); their non-htmx redirect paths and the existing settings tests are unchanged. New regression test routes_settings_feedback asserts the HX path returns the inline status + OOB toast and the non-HX path still redirects.

New i18n: settings-fb-* / settings-avatar-pending / settings-remove-avatar-confirm / settings-data-preparing / settings-deleting / action-dismiss (en + es). Frontend + response-shape only, no schema/route change. just check, just test, just test-saas pass; toast.js + settings.js syntax-checked; Tailwind rebuilt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
longjacksonle deleted branch feat/settings-redesign-feedback 2026-06-21 23:44:04 +02: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
psa-systems/lets-chat!435
No description provided.