Settings — Two-Pane Admin Pattern
/settings is a Shopify-admin-style two-pane settings shell, aligned to
Shopify's App Home / admin settings guidelines:
a left category nav + a right content pane per category, each category page owning its
own grouped cards, dirty-tracking Save Bar, and confirmation modals.
Structure
SettingsLayout(app/frontend/src/app/features/settings/settings-layout.ts) — the shell: a<nav>with a filterable category list (tip-inputfilter +RouterLinkActive-highlighted links, icon + label) on the left, and a<router-outlet>on the right. Categories: General, Notifications, Locations, Fleet, Users, Connected accounts (apps) — each a child route under/settingsmapping to a standalone page component infeatures/settings/pages/.- Category pages (
pages/{general,notifications,locations,fleet,users,apps}.ts) — each is a standalone routed component that composestip-cardgroups of related fields (tip-select,tip-input, toggle rows), owns its own dirty-tracking state, and renders its owntip-save-bar+tip-modalfor destructive confirmations.
The dirty-tracking contract (repeated per page)
Every settings page follows the same shape (see SettingsGeneral as the canonical
example):
private readonly baseline = signal<Values>(INITIAL); // last-saved snapshot
private readonly currentValues = computed<Values>(() => ({ /* live field signals */ }));
readonly dirty = computed(() => JSON.stringify(this.currentValues()) !== JSON.stringify(this.baseline()));
onSave(): void { this.baseline.set(this.currentValues()); this.toast.show('Settings saved', { tone: 'success' }); }
onDiscard(): void { this.applyValues(this.baseline()); }
tip-save-bar [visible]="dirty()" is the first element inside the page's scrollable
container (so its sticky; top: 0 pins correctly — see save-bar.md).
Destructive actions (Reset, in General) route through a tip-modal confirmation before
mutating baseline, and a tip-button variant="critical" inside [primary-action].
Shopify alignment
The category-nav + grouped-cards + inline row (label/sublabel + chevron or control) shape, the sticky contextual save bar, and confirmation modals for destructive settings mirror Shopify's admin settings template directly — this is a deliberate reference, not an accidental convergence; consult the linked Shopify doc before deviating from the category/card grouping when adding a new settings section.
Composing a new settings page
- Add a
SettingsCategoryentry toCATEGORIESinsettings-layout.ts(id, label, icon, path) and a matching child route under/settingsinapp.routes.ts. - Create
pages/<name>.ts+.html+.css, following the dirty-tracking contract above if the page has editable fields. - Group related fields into
tip-cards with a.stg-card-head(title + subtitle) — reusesettings-shared.cssclasses (stg-page,stg-card-head,stg-row,stg-field-grid, …) rather than inventing new layout classes per page.