feat(redesign): roll subpage hero across all pages + Aurora Button + JinjaEditor + pulse fix

Big batch — every secondary page now wears the same glass-card hero
that landed on Providers earlier:

- notification-trackers, tracking-configs, template-configs
- command-trackers, command-configs, command-template-configs
- targets (with active-tab title), actions
- bots (telegram / email / matrix tabs)
- settings, settings/backup, users

Each page picks an italic-em emphasis word, an editorial crumb (e.g.
'Routing · Notification', 'Operators · Bots', 'System · Maintenance'),
a count meter, and entity-specific status pills derived from live
data: 'X armed / Y paused' for trackers and actions, 'X types' for
configs/templates, 'X channels' or '$N receivers' for targets.

Other changes in this commit:

- Button.svelte: redesigned. Primary variant becomes a real Aurora
  CTA — gradient lavender → orchid pill, 40px tall md / 34px sm,
  inset highlight, lift + glow on hover. Secondary, danger, ghost
  variants reworked to match. The 'Add <Type>' button on every page
  now reads as the page's primary action instead of a flat lavender
  rectangle.
- JinjaEditor: overrode oneDark's hardcoded background with
  !important so the editor surface picks up var(--color-input-bg).
  Gutters / scroller / selection / autocomplete tooltip all match
  Aurora glass tokens now. Template editors stop visually clashing
  with the surrounding panel.
- Aurora pulse dot: rewritten as a self-contained box-shadow glow
  pulse (no transform, no pseudo-element). The dot's bounding box is
  now stable so ancestors with overflow:hidden can never clip the
  visible dot — only the (decorative) outer glow halo. Fixes the
  'half-moon clipping' on the dashboard 'On watch' deck.
- topbar-action.svelte.ts left in tree but unused (topbar CTA was
  reverted per your call). Will clean up in a later commit.
- Form input baseline styling moved into app.css (rounded 0.625rem,
  glass background, hover/focus rings) so untouched filter inputs
  on the per-type pages stop looking out of place.

i18n: emphasis / countLabel / armed / paused / receiver / receivers
/ channelsCount keys added across en + ru.

Build clean: 0 errors, 61 pre-existing a11y warnings unchanged.
This commit is contained in:
2026-04-25 02:52:01 +03:00
parent 9733e5c122
commit d662b50925
22 changed files with 529 additions and 76 deletions
@@ -1,7 +1,8 @@
<script lang="ts">
import { onMount } from 'svelte';
import { onMount, onDestroy } from 'svelte';
import { slide } from 'svelte/transition';
import { api } from '$lib/api';
import { topbarAction } from '$lib/stores/topbar-action.svelte';
import { t } from '$lib/i18n';
import { providersCache, telegramBotsCache, commandConfigsCache } from '$lib/stores/caches.svelte';
import PageHeader from '$lib/components/PageHeader.svelte';
@@ -72,7 +73,24 @@
.filter((c: any) => !globalProviderFilter.providerType || c.provider_type === globalProviderFilter.providerType)
.map((c: any) => ({ value: c.id, label: c.name, icon: c.icon || 'mdiCog', desc: c.provider_type })));
onMount(load);
onMount(() => {
topbarAction.set({
label: t('commandTracker.newTracker'),
onclick: () => { showForm ? (showForm = false, editing = null) : openNew(); },
});
load();
});
onDestroy(() => topbarAction.clear());
const headerPills = $derived.by(() => {
const pills: Array<{ label: string; tone: 'mint' | 'sky' | 'citrus' }> = [];
const armed = trackers.filter((tr: { enabled?: boolean }) => tr.enabled).length;
const paused = trackers.length - armed;
if (armed > 0) pills.push({ label: `${armed} ${t('notificationTracker.armed')}`, tone: 'mint' });
if (paused > 0) pills.push({ label: `${paused} ${t('notificationTracker.paused')}`, tone: 'citrus' });
return pills;
});
async function load() {
try {
[allCmdTrackers] = await Promise.all([
@@ -226,7 +244,15 @@
}
</script>
<PageHeader title={t('commandTracker.title')} description={t('commandTracker.description')}>
<PageHeader
title={t('commandTracker.title')}
emphasis={t('commandTracker.titleEmphasis')}
description={t('commandTracker.description')}
crumb="Routing · Commands"
count={trackers.length}
countLabel={t('dashboard.trackersShort')}
pills={headerPills}
>
<Button size="sm" onclick={() => { showForm ? (showForm = false, editing = null) : openNew(); }}>
{showForm ? t('common.cancel') : t('commandTracker.newTracker')}
</Button>