style: unify workbench typography and prepare isolated visual review
This commit is contained in:
@@ -371,20 +371,20 @@ export function CatalogSyncDrawer({
|
||||
key={phase}
|
||||
aria-current={current ? "step" : undefined}
|
||||
aria-label={`${label}, ${status}`}
|
||||
className={`flex items-center gap-2 text-xs ${failedOutcome ? "font-semibold text-destructive" : interruptedOutcome ? "font-semibold text-amber-600" : terminalOutcome || current ? "font-semibold text-foreground" : "text-muted-foreground"}`}
|
||||
className={`flex items-center gap-2 text-xs ${failedOutcome ? "font-semibold text-destructive" : interruptedOutcome ? "font-semibold text-warning" : terminalOutcome || current ? "font-semibold text-foreground" : "text-muted-foreground"}`}
|
||||
>
|
||||
{confirmationSkipped ? (
|
||||
<Minus aria-hidden="true" className="size-3.5 text-muted-foreground" />
|
||||
) : failedOutcome ? (
|
||||
<X aria-hidden="true" className="size-3.5 text-destructive" />
|
||||
) : interruptedOutcome ? (
|
||||
<AlertTriangle aria-hidden="true" className="size-3.5 text-amber-600" />
|
||||
<AlertTriangle aria-hidden="true" className="size-3.5 text-warning" />
|
||||
) : terminalOutcome ? (
|
||||
<Minus aria-hidden="true" className="size-3.5 text-muted-foreground" />
|
||||
) : complete ? (
|
||||
<CheckCircle2 aria-hidden="true" className="size-3.5 text-[oklch(var(--success))]" />
|
||||
) : current ? (
|
||||
<LoaderCircle aria-hidden="true" className="size-3.5 animate-spin text-amber-600" />
|
||||
<LoaderCircle aria-hidden="true" className="size-3.5 animate-spin text-warning" />
|
||||
) : (
|
||||
<Circle aria-hidden="true" className="size-3.5" />
|
||||
)}
|
||||
@@ -398,16 +398,16 @@ export function CatalogSyncDrawer({
|
||||
<div className="mt-5 grid grid-cols-3 gap-2">
|
||||
{(["tables", "columns", "relationships"] as const).map((name) => (
|
||||
<div key={name} className="rounded-md border border-border bg-muted/25 px-3 py-2">
|
||||
<p className="text-[11px] font-semibold uppercase tracking-wide text-muted-foreground">{name}</p>
|
||||
<p className="text-xs font-semibold text-muted-foreground">{name}</p>
|
||||
<p className="mt-1 text-lg font-semibold tabular-nums">{run.counts[name] ?? ""}</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{run.state === "awaiting_confirmation" && run.plannedDiff ? (
|
||||
<section className="mt-5 rounded-md border border-amber-500/50 bg-amber-500/8 p-4" aria-label="Destructive changes">
|
||||
<section className="mt-5 rounded-md border border-warning/50 bg-warning/8 p-4" aria-label="Destructive changes">
|
||||
<div className="flex gap-3">
|
||||
<AlertTriangle className="mt-0.5 size-5 shrink-0 text-amber-600" />
|
||||
<AlertTriangle className="mt-0.5 size-5 shrink-0 text-warning" />
|
||||
<div>
|
||||
<h3 className="font-semibold">Confirm {deletionCount} removals</h3>
|
||||
<p className="mt-1 text-sm text-muted-foreground">The database will be scanned again before anything is removed.</p>
|
||||
@@ -453,7 +453,7 @@ export function CatalogSyncDrawer({
|
||||
className="thot-catalog-drawer__event-log max-h-64 overflow-y-auto rounded-md bg-zinc-950 p-3 font-mono text-xs leading-5 text-zinc-200"
|
||||
>
|
||||
{events.length === 0 ? <p className="text-zinc-500">Waiting for events…</p> : events.map((event) => (
|
||||
<p key={event.sequence} className={event.level === "error" ? "text-red-300" : event.level === "warning" ? "text-amber-300" : undefined}>
|
||||
<p key={event.sequence} className={event.level === "error" ? "text-red-300" : event.level === "warning" ? "text-warning" : undefined}>
|
||||
<span className="mr-2 text-zinc-500">{new Date(event.createdAt).toLocaleTimeString()}</span>{event.message}
|
||||
</p>
|
||||
))}
|
||||
|
||||
@@ -516,8 +516,8 @@ export function DatabaseColumns({
|
||||
<h3 className="mt-1 font-heading text-2xl font-semibold">{active.name}</h3>
|
||||
<p className="mt-1 text-sm text-muted-foreground">Physical schema fields are read-only. Review fields can be edited.</p>
|
||||
{stale ? (
|
||||
staleBannerOpen ? <div className="mt-4 rounded-md border border-amber-500/50 bg-amber-500/8 p-4 text-sm"><p className="font-semibold">Newer column metadata is available.</p><p className="mt-1 text-muted-foreground">Your draft is preserved until you reload.</p><div className="mt-3 flex gap-2"><Button type="button" variant="outline" onClick={() => void reloadColumn()}>Reload latest</Button><Button type="button" variant="ghost" onClick={() => setStaleBannerOpen(false)}>Keep editing</Button></div></div>
|
||||
: <div className="mt-4 flex items-center justify-between gap-3 rounded-md border border-amber-500/40 bg-amber-500/8 px-4 py-3 text-sm"><span>Reload the latest value before this metadata can be saved.</span><Button type="button" variant="outline" onClick={() => void reloadColumn()}>Reload latest</Button></div>
|
||||
staleBannerOpen ? <div className="mt-4 rounded-md border border-warning/50 bg-warning/8 p-4 text-sm"><p className="font-semibold">Newer column metadata is available.</p><p className="mt-1 text-muted-foreground">Your draft is preserved until you reload.</p><div className="mt-3 flex gap-2"><Button type="button" variant="outline" onClick={() => void reloadColumn()}>Reload latest</Button><Button type="button" variant="ghost" onClick={() => setStaleBannerOpen(false)}>Keep editing</Button></div></div>
|
||||
: <div className="mt-4 flex items-center justify-between gap-3 rounded-md border border-warning/40 bg-warning/8 px-4 py-3 text-sm"><span>Reload the latest value before this metadata can be saved.</span><Button type="button" variant="outline" onClick={() => void reloadColumn()}>Reload latest</Button></div>
|
||||
) : null}
|
||||
<ColumnMetadataFieldMatrix
|
||||
column={active}
|
||||
@@ -652,8 +652,8 @@ export function DatabaseColumns({
|
||||
<p className="thot-label">{table.name} · column</p>
|
||||
<h3 className="mt-1 break-words font-heading text-xl font-semibold">{active.name}</h3>
|
||||
{stale ? (
|
||||
staleBannerOpen ? <div className="mt-4 rounded-md border border-amber-500/50 bg-amber-500/8 p-4 text-sm"><p className="font-semibold">Newer column metadata is available.</p><p className="mt-1 text-muted-foreground">Your draft is preserved until you reload.</p><div className="mt-3 flex gap-2"><Button type="button" variant="outline" onClick={() => void reloadColumn()}>Reload latest</Button><Button type="button" variant="ghost" onClick={() => setStaleBannerOpen(false)}>Keep editing</Button></div></div>
|
||||
: <div className="mt-4 flex items-center justify-between gap-3 rounded-md border border-amber-500/40 bg-amber-500/8 px-4 py-3 text-sm"><span>Reload the latest value before this metadata can be saved.</span><Button type="button" variant="outline" onClick={() => void reloadColumn()}>Reload latest</Button></div>
|
||||
staleBannerOpen ? <div className="mt-4 rounded-md border border-warning/50 bg-warning/8 p-4 text-sm"><p className="font-semibold">Newer column metadata is available.</p><p className="mt-1 text-muted-foreground">Your draft is preserved until you reload.</p><div className="mt-3 flex gap-2"><Button type="button" variant="outline" onClick={() => void reloadColumn()}>Reload latest</Button><Button type="button" variant="ghost" onClick={() => setStaleBannerOpen(false)}>Keep editing</Button></div></div>
|
||||
: <div className="mt-4 flex items-center justify-between gap-3 rounded-md border border-warning/40 bg-warning/8 px-4 py-3 text-sm"><span>Reload the latest value before this metadata can be saved.</span><Button type="button" variant="outline" onClick={() => void reloadColumn()}>Reload latest</Button></div>
|
||||
) : null}
|
||||
<ColumnMetadataFieldMatrix
|
||||
column={active}
|
||||
|
||||
@@ -220,7 +220,7 @@ export function DatabaseForm({
|
||||
|
||||
{stale ? (
|
||||
staleBannerOpen ? (
|
||||
<div className="rounded-md border border-amber-300/70 bg-amber-50 p-4 text-sm text-amber-950 dark:border-amber-700 dark:bg-amber-950/30 dark:text-amber-100" role="alert">
|
||||
<div className="rounded-md border border-warning/70 bg-warning p-4 text-sm text-warning dark:border-warning dark:bg-warning/30 text-warning" role="alert">
|
||||
<p className="font-semibold">A newer database configuration is available.</p>
|
||||
<p className="mt-1 leading-5">Reload the latest values before saving, testing, or deleting. Your draft is still intact.</p>
|
||||
<div className="mt-3 flex flex-wrap gap-2">
|
||||
@@ -233,14 +233,14 @@ export function DatabaseForm({
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="rounded-md border border-amber-300/70 bg-amber-50 px-4 py-3 text-sm text-amber-950 dark:border-amber-700 dark:bg-amber-950/30 dark:text-amber-100" role="status">
|
||||
<div className="rounded-md border border-warning/70 bg-warning px-4 py-3 text-sm text-warning dark:border-warning dark:bg-warning/30 text-warning" role="status">
|
||||
Reload the latest values before this configuration can be changed.
|
||||
</div>
|
||||
)
|
||||
) : null}
|
||||
|
||||
{partialSecretFailure ? (
|
||||
<div className="rounded-md border border-amber-300/70 bg-amber-50 p-4 text-sm text-amber-950 dark:border-amber-700 dark:bg-amber-950/30 dark:text-amber-100" role="alert">
|
||||
<div className="rounded-md border border-warning/70 bg-warning p-4 text-sm text-warning dark:border-warning dark:bg-warning/30 text-warning" role="alert">
|
||||
<p className="font-semibold">Database configuration saved; secret update could not be confirmed.</p>
|
||||
<p className="mt-1 leading-5">{partialSecretFailure} The values you entered are retained in this form.</p>
|
||||
<Button type="button" size="sm" variant="outline" className="mt-3" disabled={busy || stale} onClick={onRetrySecrets}>
|
||||
|
||||
@@ -102,9 +102,9 @@ type StateTone = "neutral" | "info" | "success" | "warning" | "danger";
|
||||
|
||||
const stateToneClass: Record<StateTone, string> = {
|
||||
neutral: "bg-muted-foreground/55",
|
||||
info: "bg-sky-500",
|
||||
success: "bg-emerald-500",
|
||||
warning: "bg-amber-500",
|
||||
info: "bg-muted-foreground/55",
|
||||
success: "bg-success",
|
||||
warning: "bg-warning",
|
||||
danger: "bg-destructive",
|
||||
};
|
||||
|
||||
@@ -125,7 +125,7 @@ function StateCell({
|
||||
<span className={`size-1.5 shrink-0 rounded-full ${stateToneClass[tone]}`} aria-hidden="true" />
|
||||
<span className="truncate">{label}</span>
|
||||
</span>
|
||||
<span className={`truncate pl-3 text-[11px] ${detailClassName}`}>{detail}</span>
|
||||
<span className={`truncate pl-3 text-xs ${detailClassName}`}>{detail}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -621,7 +621,7 @@ export function DatabaseGrid({
|
||||
<p
|
||||
role="note"
|
||||
aria-label="Metadata generation source data disclosure"
|
||||
className="mt-1 text-xs font-medium text-amber-800 dark:text-amber-300"
|
||||
className="mt-1 text-xs font-medium text-warning"
|
||||
>
|
||||
When available, up to five real source rows and five representative values from
|
||||
columns not marked sensitive are sent to the selected provider.
|
||||
|
||||
@@ -586,7 +586,7 @@ export function DatabaseRelationships({
|
||||
<dt className="thot-label">Column mapping</dt>
|
||||
<dd className="mt-2 overflow-hidden rounded-md border border-border">
|
||||
<table className="w-full text-left text-xs">
|
||||
<thead className="bg-muted/60 font-mono uppercase tracking-wide text-muted-foreground"><tr><th className="px-3 py-2">Source</th><th className="px-3 py-2">Target</th></tr></thead>
|
||||
<thead className="bg-muted/60 font-sans text-muted-foreground"><tr><th className="px-3 py-2">Source</th><th className="px-3 py-2">Target</th></tr></thead>
|
||||
<tbody>{activeRelationship.columns.map((pair) => <tr key={`${pair.sourceColumnName}:${pair.targetColumnName}`} className="border-t border-border"><td className="px-3 py-2 font-mono">{pair.sourceColumnName}</td><td className="px-3 py-2 font-mono">{pair.targetColumnName}</td></tr>)}</tbody>
|
||||
</table>
|
||||
</dd>
|
||||
|
||||
@@ -599,12 +599,12 @@ export function DatabaseTables({
|
||||
<h3 className="mt-1 break-words font-heading text-xl font-semibold">{activeTable.name}</h3>
|
||||
{stale ? (
|
||||
staleBannerOpen ? (
|
||||
<div className="mt-4 rounded-md border border-amber-500/50 bg-amber-500/8 p-4 text-sm">
|
||||
<div className="mt-4 rounded-md border border-warning/50 bg-warning/8 p-4 text-sm">
|
||||
<p className="font-semibold">A newer table description is available.</p>
|
||||
<p className="mt-1 text-muted-foreground">Your draft is preserved until you reload the current metadata.</p>
|
||||
<div className="mt-3 flex gap-2"><Button type="button" variant="outline" onClick={() => void reloadTable()}>Reload latest</Button><Button type="button" variant="ghost" onClick={() => setStaleBannerOpen(false)}>Keep editing</Button></div>
|
||||
</div>
|
||||
) : <div className="mt-4 flex items-center justify-between gap-3 rounded-md border border-amber-500/40 bg-amber-500/8 px-4 py-3 text-sm"><span>Reload the latest value before this description can be saved.</span><Button type="button" variant="outline" onClick={() => void reloadTable()}>Reload latest</Button></div>
|
||||
) : <div className="mt-4 flex items-center justify-between gap-3 rounded-md border border-warning/40 bg-warning/8 px-4 py-3 text-sm"><span>Reload the latest value before this description can be saved.</span><Button type="button" variant="outline" onClick={() => void reloadTable()}>Reload latest</Button></div>
|
||||
) : null}
|
||||
<div className="mt-5 grid gap-4">
|
||||
<label className="grid gap-1.5 text-sm font-semibold">Physical table name<input className="h-9 rounded-md border border-input bg-muted/35 px-3 font-mono text-xs" value={activeTable.name} readOnly /></label>
|
||||
@@ -650,12 +650,12 @@ export function DatabaseTables({
|
||||
<p className="text-sm text-muted-foreground">Only review metadata can be changed.</p>
|
||||
{stale ? (
|
||||
staleBannerOpen ? (
|
||||
<div className="mt-4 rounded-md border border-amber-500/50 bg-amber-500/8 p-4 text-sm">
|
||||
<div className="mt-4 rounded-md border border-warning/50 bg-warning/8 p-4 text-sm">
|
||||
<p className="font-semibold">A newer table description is available.</p>
|
||||
<p className="mt-1 text-muted-foreground">Your draft is preserved until you reload the current metadata.</p>
|
||||
<div className="mt-3 flex gap-2"><Button type="button" variant="outline" onClick={() => void reloadTable()}>Reload latest</Button><Button type="button" variant="ghost" onClick={() => setStaleBannerOpen(false)}>Keep editing</Button></div>
|
||||
</div>
|
||||
) : <div className="mt-4 flex items-center justify-between gap-3 rounded-md border border-amber-500/40 bg-amber-500/8 px-4 py-3 text-sm"><span>Reload the latest value before this description can be saved.</span><Button type="button" variant="outline" onClick={() => void reloadTable()}>Reload latest</Button></div>
|
||||
) : <div className="mt-4 flex items-center justify-between gap-3 rounded-md border border-warning/40 bg-warning/8 px-4 py-3 text-sm"><span>Reload the latest value before this description can be saved.</span><Button type="button" variant="outline" onClick={() => void reloadTable()}>Reload latest</Button></div>
|
||||
) : null}
|
||||
<div className="mt-5 grid gap-4">
|
||||
<label className="grid gap-1.5 text-sm font-semibold">Physical table name<input className="h-9 rounded-md border border-input bg-muted/35 px-3 font-mono text-xs" value={activeTable.name} readOnly /></label>
|
||||
|
||||
@@ -327,7 +327,7 @@ export function DescriptionGenerationDrawer({
|
||||
{apparentlyStale ? (
|
||||
<p
|
||||
id="description-generation-unlock-help"
|
||||
className="mb-3 rounded-md border border-amber-500/35 bg-amber-500/8 px-3 py-2 text-xs leading-5 text-muted-foreground"
|
||||
className="mb-3 rounded-md border border-warning/35 bg-warning/8 px-3 py-2 text-xs leading-5 text-muted-foreground"
|
||||
>
|
||||
Unlock interrupts apparently stale work and marks the run interrupted. A live worker will prevent it.
|
||||
</p>
|
||||
@@ -411,7 +411,7 @@ export function DescriptionGenerationDrawer({
|
||||
<thead>
|
||||
<tr className="border-b border-border bg-muted/45">
|
||||
{progressCounters.map(([name, label]) => (
|
||||
<th key={name} scope="col" className="border-l border-border px-2 py-1.5 text-left text-[10px] font-semibold uppercase tracking-wide text-muted-foreground first:border-l-0">
|
||||
<th key={name} scope="col" className="border-l border-border px-2 py-1.5 text-left text-xs font-semibold text-muted-foreground first:border-l-0">
|
||||
{label}
|
||||
</th>
|
||||
))}
|
||||
@@ -458,7 +458,7 @@ export function DescriptionGenerationDrawer({
|
||||
className="thot-catalog-drawer__event-log overflow-y-auto rounded-md bg-zinc-950 p-3 font-mono text-xs leading-5 text-zinc-200"
|
||||
>
|
||||
{events.length === 0 ? <p className="text-zinc-500">Waiting for events…</p> : events.map((event) => (
|
||||
<p key={event.sequence} className={event.level === "error" ? "text-red-300" : event.level === "warning" ? "text-amber-300" : undefined}>
|
||||
<p key={event.sequence} className={event.level === "error" ? "text-red-300" : event.level === "warning" ? "text-warning" : undefined}>
|
||||
<span className="mr-2 text-zinc-500">{new Date(event.createdAt).toLocaleTimeString()}</span>{event.message}
|
||||
</p>
|
||||
))}
|
||||
|
||||
@@ -25,7 +25,7 @@ test("uses operational body text for every available-command list", () => {
|
||||
}
|
||||
|
||||
expect(styles).toMatch(
|
||||
/\.thot-fleet-action-selector__select\s*\{[^}]*font-size:\s*0\.9375rem;/s,
|
||||
/\.thot-fleet-action-selector__select\s*\{[^}]*font-size:\s*var\(--text-control\);/s,
|
||||
);
|
||||
expect(styles).toMatch(
|
||||
/\.thot-fleet-action-selector\s*\{[^}]*flex:\s*0 0 auto;/s,
|
||||
|
||||
@@ -54,12 +54,12 @@
|
||||
.thot-fleet-ledger__kpi-label {
|
||||
margin: 0;
|
||||
color: oklch(var(--muted-foreground));
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
font-family: var(--font-sans);
|
||||
font-size: var(--text-meta);
|
||||
font-weight: 600;
|
||||
letter-spacing: normal;
|
||||
line-height: 1.35;
|
||||
text-transform: uppercase;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.thot-fleet-ledger__title,
|
||||
@@ -75,7 +75,7 @@
|
||||
margin: 0;
|
||||
font-family: var(--font-sans);
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.0125em;
|
||||
line-height: 1.25;
|
||||
white-space: nowrap;
|
||||
@@ -85,7 +85,7 @@
|
||||
max-width: 68ch;
|
||||
margin: 0.45rem 0 0;
|
||||
color: oklch(var(--muted-foreground));
|
||||
font-size: 0.875rem;
|
||||
font-size: var(--text-control);
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
@@ -191,15 +191,15 @@
|
||||
|
||||
.thot-fleet-ledger__status-label {
|
||||
grid-column: 1 / -1;
|
||||
font-size: 0.625rem;
|
||||
font-size: var(--text-meta);
|
||||
}
|
||||
|
||||
.thot-fleet-ledger__status-value {
|
||||
overflow: hidden;
|
||||
color: oklch(var(--foreground));
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
font-family: var(--font-sans);
|
||||
font-size: var(--text-meta);
|
||||
font-weight: 600;
|
||||
line-height: 1.45;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
@@ -208,7 +208,7 @@
|
||||
.thot-fleet-ledger__status-detail {
|
||||
overflow: hidden;
|
||||
color: oklch(var(--muted-foreground));
|
||||
font-size: 0.75rem;
|
||||
font-size: var(--text-meta);
|
||||
line-height: 1.45;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
@@ -224,18 +224,17 @@
|
||||
|
||||
.thot-fleet-ledger__kpi-strip {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(100%, 8.5rem), 1fr));
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(100%, 6rem), 1fr));
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.thot-fleet-ledger__kpi {
|
||||
min-width: 0;
|
||||
padding: 0 1rem 0.75rem 0;
|
||||
padding: 0 0.75rem 0.75rem 0;
|
||||
}
|
||||
|
||||
.thot-fleet-ledger__kpi + .thot-fleet-ledger__kpi {
|
||||
padding-left: 1rem;
|
||||
border-left: 1px solid oklch(var(--border));
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.thot-fleet-ledger__kpi-value,
|
||||
@@ -246,18 +245,18 @@
|
||||
.thot-fleet-ledger__kpi-value {
|
||||
margin-top: 0.2rem;
|
||||
color: oklch(var(--foreground));
|
||||
font-family: var(--font-mono);
|
||||
font-size: clamp(1.25rem, 2vw, 1.625rem);
|
||||
font-family: var(--font-sans);
|
||||
font-size: var(--text-body);
|
||||
font-variant-numeric: tabular-nums;
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.035em;
|
||||
font-weight: 600;
|
||||
letter-spacing: normal;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.thot-fleet-ledger__kpi-detail {
|
||||
margin-top: 0.15rem;
|
||||
color: oklch(var(--muted-foreground));
|
||||
font-size: 0.75rem;
|
||||
font-size: var(--text-meta);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
@@ -280,7 +279,7 @@
|
||||
color: oklch(var(--primary));
|
||||
background: oklch(var(--primary) / 0.08);
|
||||
box-shadow: 0 1px 2px oklch(var(--primary) / 0.1);
|
||||
font-weight: 700;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.thot-fleet-back-action:not(:disabled):hover {
|
||||
@@ -326,7 +325,7 @@
|
||||
color: oklch(var(--muted-foreground));
|
||||
background: transparent;
|
||||
font: inherit;
|
||||
font-size: 0.8125rem;
|
||||
font-size: var(--text-control);
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
@@ -346,8 +345,8 @@
|
||||
max-width: 18rem;
|
||||
overflow: hidden;
|
||||
color: oklch(var(--foreground));
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 650;
|
||||
font-size: var(--text-control);
|
||||
font-weight: 600;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -392,14 +391,14 @@
|
||||
display: grid;
|
||||
min-width: 7.5rem;
|
||||
color: oklch(var(--foreground));
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.6875rem;
|
||||
font-family: var(--font-sans);
|
||||
font-size: var(--text-meta);
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.thot-fleet-action-selector__scope span {
|
||||
color: oklch(var(--muted-foreground));
|
||||
font-size: 0.625rem;
|
||||
font-size: var(--text-meta);
|
||||
}
|
||||
|
||||
.thot-fleet-action-selector__select {
|
||||
@@ -413,7 +412,7 @@
|
||||
border-radius: var(--radius);
|
||||
color: oklch(var(--foreground));
|
||||
background: oklch(var(--background));
|
||||
font-size: 0.9375rem;
|
||||
font-size: var(--text-control);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
@@ -430,7 +429,7 @@
|
||||
.thot-fleet-action-selector__reason {
|
||||
flex-basis: 100%;
|
||||
color: oklch(var(--muted-foreground));
|
||||
font-size: 0.75rem;
|
||||
font-size: var(--text-meta);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
@@ -438,9 +437,9 @@
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
color: oklch(var(--muted-foreground));
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.6875rem;
|
||||
letter-spacing: 0.025em;
|
||||
font-family: var(--font-sans);
|
||||
font-size: var(--text-meta);
|
||||
letter-spacing: normal;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -628,10 +627,10 @@
|
||||
}
|
||||
|
||||
.thot-fleet-ledger-grid .ag-header-cell-text {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.6875rem;
|
||||
letter-spacing: 0.055em;
|
||||
text-transform: uppercase;
|
||||
font-family: var(--font-sans);
|
||||
font-size: var(--text-meta);
|
||||
letter-spacing: normal;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.thot-fleet-ledger-grid .ag-row {
|
||||
@@ -647,7 +646,8 @@
|
||||
.thot-fleet-ledger-grid .ag-row.ag-row-selected .ag-cell,
|
||||
.thot-fleet-ledger-grid .ag-row.ag-row-selected .ag-grid-pinned-left-cells,
|
||||
.thot-fleet-ledger-grid .ag-row.ag-row-selected .ag-grid-pinned-right-cells {
|
||||
background-color: oklch(93% 0.002 17.2) !important;
|
||||
background-color: oklch(var(--nav-active)) !important;
|
||||
color: oklch(var(--nav-active-foreground));
|
||||
}
|
||||
|
||||
.thot-fleet-icon-action {
|
||||
@@ -672,7 +672,7 @@
|
||||
background: oklch(24% 0.014 258);
|
||||
box-shadow: 0 8px 20px -10px oklch(12% 0.02 258 / 0.72);
|
||||
content: attr(data-tooltip);
|
||||
font-size: 0.6875rem;
|
||||
font-size: var(--text-meta);
|
||||
font-weight: 600;
|
||||
line-height: 1.25;
|
||||
text-align: center;
|
||||
@@ -701,8 +701,8 @@
|
||||
background: oklch(var(--popover));
|
||||
box-shadow: var(--shadow-sm);
|
||||
content: attr(data-tooltip);
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 650;
|
||||
font-size: var(--text-meta);
|
||||
font-weight: 600;
|
||||
line-height: 1.2;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
@@ -765,7 +765,7 @@
|
||||
}
|
||||
|
||||
.thot-fleet-ledger__drawer-title {
|
||||
font-size: 1.35rem;
|
||||
font-size: var(--text-section);
|
||||
line-height: 1.18;
|
||||
}
|
||||
|
||||
@@ -949,19 +949,6 @@
|
||||
min-height: 28rem;
|
||||
}
|
||||
|
||||
.thot-fleet-ledger__kpi-strip {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.thot-fleet-ledger__kpi:nth-child(odd) {
|
||||
padding-left: 0;
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
.thot-fleet-ledger__kpi:nth-child(n + 3) {
|
||||
padding-top: 0.75rem;
|
||||
border-top: 1px solid oklch(var(--border));
|
||||
}
|
||||
|
||||
.thot-fleet-ledger__navigation {
|
||||
flex-wrap: wrap;
|
||||
|
||||
@@ -180,7 +180,7 @@ export interface FleetLedgerKpiStripProps extends WithClassName {
|
||||
}
|
||||
|
||||
export function FleetLedgerKpiStrip({
|
||||
title = "Fleet summary",
|
||||
title = "Catalog summary",
|
||||
items,
|
||||
className,
|
||||
}: FleetLedgerKpiStripProps) {
|
||||
|
||||
@@ -211,7 +211,7 @@ export function SensitiveDataReviewDrawer({
|
||||
: "no sensitive match"}. Coverage: {suggestion.coverage.replace("_", " ")}. Observed values: {suggestion.observedValues}.
|
||||
</p>
|
||||
</div>
|
||||
<span className={`rounded px-2 py-0.5 text-[11px] font-semibold ${changedFromCurrent ? "bg-amber-500/12 text-amber-800 dark:text-amber-300" : "bg-muted text-muted-foreground"}`}>
|
||||
<span className={`rounded px-2 py-0.5 text-xs font-semibold ${changedFromCurrent ? "bg-warning/12 text-warning" : "bg-muted text-muted-foreground"}`}>
|
||||
{changedFromCurrent ? "Change" : "No change"}
|
||||
</span>
|
||||
</li>
|
||||
|
||||
@@ -268,7 +268,7 @@ export function SensitivityAnalysisHistoryDrawer({
|
||||
<thead>
|
||||
<tr className="border-b border-border bg-muted/45">
|
||||
{progressCounters.map(([name, label]) => (
|
||||
<th key={name} scope="col" className="border-l border-border px-2 py-1.5 text-left text-[10px] font-semibold uppercase tracking-wide text-muted-foreground first:border-l-0">
|
||||
<th key={name} scope="col" className="border-l border-border px-2 py-1.5 text-left text-xs font-semibold text-muted-foreground first:border-l-0">
|
||||
{label}
|
||||
</th>
|
||||
))}
|
||||
@@ -320,7 +320,7 @@ export function SensitivityAnalysisHistoryDrawer({
|
||||
className="thot-catalog-drawer__event-log overflow-y-auto rounded-md bg-zinc-950 p-3 font-mono text-xs leading-5 text-zinc-200"
|
||||
>
|
||||
{events.length === 0 ? <p className="text-zinc-500">Waiting for events…</p> : events.map((event) => (
|
||||
<p key={event.sequence} className={event.level === "error" ? "text-red-300" : event.level === "warning" ? "text-amber-300" : undefined}>
|
||||
<p key={event.sequence} className={event.level === "error" ? "text-red-300" : event.level === "warning" ? "text-warning" : undefined}>
|
||||
<span className="mr-2 text-zinc-500">{new Date(event.createdAt).toLocaleTimeString()}</span>{event.message}
|
||||
</p>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user