The live UI did not follow the canvas because its base layer differed: dark palette in hex (now the canvas oklch values), 13 px body text, flat Frame panels. - Tokens: canvas palette, 14 px body, 1.4 line height; Frame without `dense` gets the 3 px ring; Panel takes a description line. - Shell: 56 px brand button with version, 11 px group headings, user card at the foot, versions moved into the header status popover, Home / group / section crumbs, amber "Attention" status when blocking is off or paused. - New KpiStrip and PageTabs; Dashboard KPIs in three frames and a Refresh button. - Zones: KPI strip, tab with count, views, framed table with the canvas columns. - Apps: Installed / App Store tabs and a grid instead of cards (store inline). - Blocking: state banner and tab counts; one "Blocking" title. - Settings: actions in the header, label-and-help rows with the control on the right. - DHCP, Administration, DNS Client, Logs, Cache, About: subtitles, framed tables, KPI strips where the data exists; Login cover with the three-point list. - docs/compose.shnt.example.yaml: production compose with the console image. Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
37 lines
872 B
TypeScript
37 lines
872 B
TypeScript
import styles from './PageTabs.module.css'
|
|
|
|
/*
|
|
The canvas's page tabs: an underline under the active one and a small count after
|
|
its name. They switch a panel on the same screen (an ARIA tablist), unlike
|
|
`SubTabs`, whose entries are routes.
|
|
*/
|
|
export function PageTabs<T extends string>({
|
|
label,
|
|
tabs,
|
|
active,
|
|
onChoose,
|
|
}: {
|
|
label: string
|
|
tabs: { id: T; label: string; count?: number }[]
|
|
active: T
|
|
onChoose: (id: T) => void
|
|
}) {
|
|
return (
|
|
<div className={styles.tabs} role="tablist" aria-label={label}>
|
|
{tabs.map((t) => (
|
|
<button
|
|
key={t.id}
|
|
type="button"
|
|
role="tab"
|
|
aria-selected={t.id === active}
|
|
className={styles.tab}
|
|
onClick={() => onChoose(t.id)}
|
|
>
|
|
{t.label}
|
|
{t.count != null && <em>{t.count}</em>}
|
|
</button>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|