fix(redesign): a11y, mobile, perf polish for production push

Comprehensive pre-production sweep across the Aurora redesign — drives
svelte-check to 0 errors / 0 warnings (was 61) without changing visual
intent. Highlights:

- Mobile: hero title shrinks at 480px, signal-list stacks timestamp
  under sentence below 640px, sidebar icon buttons bumped to 40x40
- Light theme: muted-foreground darkened to #3a3560 to clear WCAG AA
  on glass surfaces and the modal close button
- Perf: topbar backdrop-filter 28→14px, mobile-more sheet 28→12px to
  cut concurrent blur layers on mid-tier mobile
- a11y: prefers-reduced-motion mute for aurora drift / pulses /
  shimmer / stagger; aria-label on every icon-only button;
  aria-describedby on Hint; combobox/listbox/aria-activedescendant on
  SearchPalette; modal dialog tabindex; 47 label-without-control
  warnings across 14 form pages cleaned up via for=/id= or label→div
- Dashboard derived state split into topology- vs status-bound layers
  so polling no longer re-runs the full provider/wires computation
- Mobile bottom nav derived from baseNavEntries by key lookup so
  adding a top-level nav entry keeps the two trees in sync
- Bug: template-configs page now respects the global provider filter
  for both the count meter and the type pill (was reading the
  unfiltered cache)
- Misc: portal EventChart tooltip and switch its swatches to Aurora
  tokens; CollapsibleSlot warning state uses warning-fg/-bg tokens
  instead of #d97706; Hint z-index 99999→9999; element refs across
  Modal/EntitySelect/MultiEntitySelect/SearchPalette/IconGridSelect/
  Hint/targets converted to \$state for reactivity; 4 dead
  .topbar-cta selectors removed
This commit is contained in:
2026-04-25 14:41:12 +03:00
parent 9eb76c1407
commit 711f218622
25 changed files with 233 additions and 153 deletions
+3 -3
View File
@@ -214,14 +214,14 @@
{#if error}<ErrorBanner message={error} />{/if}
<form onsubmit={save} class="space-y-3">
<div>
<label class="block text-sm font-medium mb-1">{t('actions.provider')}</label>
<div class="block text-sm font-medium mb-1">{t('actions.provider')}</div>
<EntitySelect items={providerItems} bind:value={form.provider_id}
placeholder={t('actions.selectProvider')} disabled={!!editing} />
</div>
{#if actionTypes.length > 0}
<div>
<label class="block text-sm font-medium mb-1">{t('actions.actionType')}</label>
<div class="block text-sm font-medium mb-1">{t('actions.actionType')}</div>
{#if !editing}
<div class="space-y-1">
{#each actionTypes as at}
@@ -251,7 +251,7 @@
</div>
<div>
<label class="block text-sm font-medium mb-1">{t('actions.schedule')}</label>
<div class="block text-sm font-medium mb-1">{t('actions.schedule')}</div>
<div class="flex gap-2 items-center mb-2">
<label class="flex items-center gap-1 text-sm">
<input type="radio" name="schedule_type" value="interval" bind:group={form.schedule_type} class="accent-[var(--color-primary)]" />
+13 -13
View File
@@ -153,8 +153,8 @@
{#if showAddForm}
<div class="border border-[var(--color-border)] rounded-md p-3 space-y-2 bg-[var(--color-muted)]/30">
<div>
<label class="block text-xs font-medium mb-1">{t('actions.ruleName')}</label>
<input bind:value={newRule.name} placeholder={t('actions.ruleNamePlaceholder')}
<label for="rule-name-new" class="block text-xs font-medium mb-1">{t('actions.ruleName')}</label>
<input id="rule-name-new" bind:value={newRule.name} placeholder={t('actions.ruleNamePlaceholder')}
class="w-full px-2 py-1.5 border border-[var(--color-border)] rounded text-sm bg-[var(--color-background)]" />
</div>
@@ -189,8 +189,8 @@
{#if expandedRule === rule.id}
<div class="mt-2 pt-2 border-t border-[var(--color-border)] space-y-2">
<div>
<label class="block text-xs font-medium mb-1">{t('actions.ruleName')}</label>
<input bind:value={rule.name}
<label for="rule-name-{rule.id}" class="block text-xs font-medium mb-1">{t('actions.ruleName')}</label>
<input id="rule-name-{rule.id}" bind:value={rule.name}
class="w-full px-2 py-1.5 border border-[var(--color-border)] rounded text-sm bg-[var(--color-background)]" />
</div>
@@ -219,7 +219,7 @@
<!-- Person selector -->
{#if personItems.length > 0}
<div>
<label class="block text-xs font-medium mb-1">{t('actions.persons')}</label>
<div class="block text-xs font-medium mb-1">{t('actions.persons')}</div>
<MultiEntitySelect items={personItems}
bind:values={ruleConfig.criteria.person_ids}
placeholder={t('actions.addPerson')}
@@ -231,7 +231,7 @@
<!-- Person excludes -->
<div>
<label class="block text-xs font-medium mb-1">{t('actions.excludePersons')}</label>
<div class="block text-xs font-medium mb-1">{t('actions.excludePersons')}</div>
<MultiEntitySelect items={personItems}
bind:values={ruleConfig.criteria.exclude_person_ids}
placeholder={t('actions.addExcludePerson')}
@@ -244,14 +244,14 @@
<!-- Smart search query -->
<div>
<label class="block text-xs font-medium mb-1">{t('actions.searchQuery')}</label>
<div class="block text-xs font-medium mb-1">{t('actions.searchQuery')}</div>
<input bind:value={ruleConfig.criteria.query} placeholder={t('actions.searchQueryPlaceholder')}
class="w-full px-2 py-1.5 border border-[var(--color-border)] rounded text-sm bg-[var(--color-background)]" />
</div>
<!-- Asset type -->
<div class="flex items-center gap-3">
<label class="text-xs font-medium">{t('actions.assetType')}:</label>
<span class="text-xs font-medium">{t('actions.assetType')}:</span>
{#each ['all', 'image', 'video'] as at}
<label class="flex items-center gap-1 text-xs">
<input type="radio"
@@ -266,12 +266,12 @@
<!-- Date range -->
<div class="flex gap-2">
<div class="flex-1">
<label class="block text-xs font-medium mb-1">{t('actions.dateFrom')}</label>
<div class="block text-xs font-medium mb-1">{t('actions.dateFrom')}</div>
<input type="date" bind:value={ruleConfig.criteria.date_from}
class="w-full px-2 py-1.5 border border-[var(--color-border)] rounded text-sm bg-[var(--color-background)]" />
</div>
<div class="flex-1">
<label class="block text-xs font-medium mb-1">{t('actions.dateTo')}</label>
<div class="block text-xs font-medium mb-1">{t('actions.dateTo')}</div>
<input type="date" bind:value={ruleConfig.criteria.date_to}
class="w-full px-2 py-1.5 border border-[var(--color-border)] rounded text-sm bg-[var(--color-background)]" />
</div>
@@ -290,7 +290,7 @@
{#if albumItems.length > 0}
<div>
<label class="block text-xs font-medium mb-1">{t('actions.selectAlbum')}</label>
<div class="block text-xs font-medium mb-1">{t('actions.selectAlbum')}</div>
<MultiEntitySelect items={albumItems}
bind:values={ruleConfig.target_album_ids}
placeholder={t('actions.selectAlbumPlaceholder')}
@@ -301,7 +301,7 @@
</div>
{:else}
<div>
<label class="block text-xs font-medium mb-1">{t('actions.albumId')}</label>
<div class="block text-xs font-medium mb-1">{t('actions.albumId')}</div>
<input bind:value={ruleConfig.target_album_id}
class="w-full px-2 py-1.5 border border-[var(--color-border)] rounded text-sm bg-[var(--color-background)] font-mono" />
</div>
@@ -314,7 +314,7 @@
{#if ruleConfig.create_album_if_missing}
<div>
<label class="block text-xs font-medium mb-1">{t('actions.newAlbumName')}</label>
<div class="block text-xs font-medium mb-1">{t('actions.newAlbumName')}</div>
<input bind:value={ruleConfig.create_album_name}
class="w-full px-2 py-1.5 border border-[var(--color-border)] rounded text-sm bg-[var(--color-background)]" />
</div>