Top bar
canonThe application frame bar: workspace switch, global search (⌘K), utilities and account — never changes with the screen.
React implementation lives in the app (AppShell.tsx — TopBar). .as-ai-trigger is a reserved, unused variant — decision A4.
Used in no file in the app (main)
Default
export const Default = () => (
<Frame>
<header className="as-top">
<div className="as-brandzone">
<ModeButton />
</div>
<Search />
<Util />
</header>
</Frame>
);Variants
workspace switcher — the tile colour says which part of the system you are in (CRM, Datamart, Back office, Účetnictví, Dialer)
another workspace — same bar, different tile and name; nothing else about the bar changes
export const Variants = () => (
<div style={{ display: 'grid', gap: 'var(--sp-5)' }}>
<Labeled text="workspace switcher — the tile colour says which part of the system you are in (CRM, Datamart, Back office, Účetnictví, Dialer)">
<Frame>
<header className="as-top">
<div className="as-brandzone">
<ModeButton tile="crm" name="CRM" />
</div>
<Search />
<Util />
</header>
</Frame>
</Labeled>
<Labeled text="another workspace — same bar, different tile and name; nothing else about the bar changes">
<Frame>
<header className="as-top">
<div className="as-brandzone">
<ModeButton tile="accounting" name="Účetnictví" icon="report-money" />
</div>
<Search />
<Util />
</header>
</Frame>
</Labeled>
</div>
);States
quiet — nothing is waiting for the user
something is waiting — unread notifications show their count on the bell (from ten on „9+“), an unread assistant reply puts a dot on the assistant
assistant is working — the trigger pulses (.is-busy) so a run started in the panel stays visible after the panel is closed; the pulse stops under prefers-reduced-motion
export const States = () => (
<div style={{ display: 'grid', gap: 'var(--sp-5)' }}>
<Labeled text="quiet — nothing is waiting for the user">
<Frame>
<header className="as-top">
<div className="as-brandzone">
<ModeButton />
</div>
<Search />
<Util />
</header>
</Frame>
</Labeled>
<Labeled text="something is waiting — unread notifications show their count on the bell (from ten on „9+“), an unread assistant reply puts a dot on the assistant">
<Frame>
<header className="as-top">
<div className="as-brandzone">
<ModeButton />
</div>
<Search />
<Util unread={1} bell={3} />
</header>
</Frame>
</Labeled>
<Labeled text="assistant is working — the trigger pulses (.is-busy) so a run started in the panel stays visible after the panel is closed; the pulse stops under prefers-reduced-motion">
<Frame>
<header className="as-top">
<div className="as-brandzone">
<ModeButton />
</div>
<Search />
<Util busy />
</header>
</Frame>
</Labeled>
</div>
);With icon & kbd
the search carries the shortcut it answers to (⌘K) — the only shortcut chip in the shell; the assistant answers to ⌘J but says so through aria-keyshortcuts, not a chip
the search on its own — icon, placeholder, shortcut; it is a button, not an input (it opens the search palette)
export const WithIconAndKbd = () => (
<div style={{ display: 'grid', gap: 'var(--sp-5)' }}>
<Labeled text="the search carries the shortcut it answers to (⌘K) — the only shortcut chip in the shell; the assistant answers to ⌘J but says so through aria-keyshortcuts, not a chip">
<Frame>
<header className="as-top">
<div className="as-brandzone">
<ModeButton />
</div>
<Search />
<Util />
</header>
</Frame>
</Labeled>
<Labeled text="the search on its own — icon, placeholder, shortcut; it is a button, not an input (it opens the search palette)">
<div style={{ width: 420 }}>
<Search />
</div>
</Labeled>
</div>
);Composition
export const Composition = () => {
const [open, setOpen] = useState(false);
return (
<Frame>
<header className="as-top">
<div className="as-brandzone">
<ModeButton />
</div>
<Search onOpen={() => setOpen(true)} />
<Util unread={1} bell={3} />
</header>
<div style={{ display: 'flex', height: 220 }}>
<aside className="as-side" style={{ minHeight: 0 }}>
<nav className="as-nav">
<button type="button" className="as-row active" aria-current="page">
<Icon name="target" />
<span className="lbl">Obchody</span>
</button>
<button type="button" className="as-row">
<Icon name="users" />
<span className="lbl">Lidé</span>
</button>
</nav>
</aside>
<div
style={{
flex: 1,
padding: 'var(--sp-5)',
color: 'var(--fg-muted)',
font: 'var(--small)',
}}
>
{open
? 'Otevřel by se globální vyhledávač (⌘K).'
: 'Obsah stránky — the top bar never changes with the screen.'}
</div>
</div>
</Frame>
);
};