Paint the backgrounds the dead bg-base class dropped

Tailwind 4 emits nothing for a colour it does not know, and the `base`
colour alias was removed on purpose because it also coloured the
`text-base` font-size utility. Every remaining `bg-base` (about 85 uses)
therefore rendered transparent. On the page background that looked the
same, but command blocks, previews and status pills inside surface cards
lost their wells, the segmented filter track hid its selected option, and
the alert bulk-selection bar showed white text on a see-through pill.

Each use now gets what it was meant to have, checked live in light and
dark:
- a new `bg-page` utility (the page backdrop, not a theme colour) for
  wells inside a surface card: command and JSON blocks, the branding
  header preview, setup wizard wells, the segmented track;
- `bg-surface` where the block sits on a surface-alt body (resource drawer
  JSON, correlation and policy cards) or floats (the bulk-selection bar),
  `bg-surface-alt` for the muted Card tone, and `hover:bg-surface-hover`
  for drawer buttons whose hover did nothing;
- no class at all on page shells that sit directly on body.

Terminal-coloured command text that assumed a dark well gets light-mode
shades so it stays readable on the restored light well. An architecture
guard fails if a runtime class uses `bg-base` again or a theme colour
named `base` returns.

Contract-Neutral: Restores intended backgrounds for a Tailwind class that generated no CSS; no API, data or behaviour contract changes beyond the frontend-primitives note on the new bg-page utility.
This commit is contained in:
rcourtman
2026-10-05 23:55:22 +01:00
parent 8d77c0e277
commit bf7f53d8b0
40 changed files with 290 additions and 112 deletions
@@ -2427,6 +2427,17 @@ not a replacement status card, CTA band, or page-local nested card.
shared owner must also cap concurrent numeric animations and snap overflow
readouts to their current target so a realtime estate update cannot make
animation cost grow with the number of visible resources.
Background colours come from the `@theme inline` surface tokens in
`frontend-modern/src/index.css` and the `bg-page` utility beside them.
`bg-page` paints the page backdrop (`--color-bg-base`) for a well that
should read as the page behind a surface card: command and JSON blocks,
the branding header preview, and the segmented filter track. A block that
sits directly on a `bg-surface-alt` body, such as resource drawer content,
uses `bg-surface` instead. No theme colour may be named `base`: it also
colours the `text-base` font-size utility, and without it Tailwind 4
renders `bg-base` as nothing, which left those wells and the alert
selection bar transparent. `src/__tests__/App.architecture.test.ts` fails
if either comes back.
Shared primitives must not reintroduce app-shell monitored-system capacity
banners. Monitored-system grouping and ledger presentation belongs in the
owned settings surfaces, while commercial plan explanation belongs in
@@ -0,0 +1,134 @@
{
"version": 1,
"base_sha": "8d77c0e2772fe7c023f4be963721c4c7709c57e0",
"verified_at": "2026-10-05T22:54:59Z",
"result": "passed",
"changed_paths": [
"frontend-modern/src/App.tsx",
"frontend-modern/src/AppLayout.tsx",
"frontend-modern/src/components/Alerts/ResourceTable.tsx",
"frontend-modern/src/components/AppBootstrapStatus.tsx",
"frontend-modern/src/components/ErrorBoundary.tsx",
"frontend-modern/src/components/Infrastructure/ResourceChangeSummary.tsx",
"frontend-modern/src/components/Infrastructure/ResourceCorrelationSummary.tsx",
"frontend-modern/src/components/Infrastructure/ResourceDetailDrawerDebugTab.tsx",
"frontend-modern/src/components/Infrastructure/ResourceDetailDrawerOverviewTab.tsx",
"frontend-modern/src/components/Infrastructure/ResourceDetailDrawerSupportDisclosure.tsx",
"frontend-modern/src/components/Infrastructure/ResourcePolicySummary.tsx",
"frontend-modern/src/components/Login.tsx",
"frontend-modern/src/components/Settings/AIProviderConfigurationSection.tsx",
"frontend-modern/src/components/Settings/AgentIntegrationsPanel.tsx",
"frontend-modern/src/components/Settings/BackupTransferDialogs.tsx",
"frontend-modern/src/components/Settings/BrandingSettingsCard.tsx",
"frontend-modern/src/components/Settings/CopyCommandBlock.tsx",
"frontend-modern/src/components/Settings/InfrastructureAgentDoctorPage.tsx",
"frontend-modern/src/components/Settings/InfrastructureInstallerSection.tsx",
"frontend-modern/src/components/Settings/NodeModalSetupGuideSection.tsx",
"frontend-modern/src/components/Settings/QuickSecuritySetup.tsx",
"frontend-modern/src/components/Settings/SSOProvidersPanel.tsx",
"frontend-modern/src/components/Settings/SuggestProfileModal.tsx",
"frontend-modern/src/components/Settings/UpdateInstallGuide.tsx",
"frontend-modern/src/components/Settings/updatesSettingsModel.ts",
"frontend-modern/src/components/SetupWizard/SetupWizard.tsx",
"frontend-modern/src/components/SetupWizard/steps/SecurityStep.tsx",
"frontend-modern/src/components/SetupWizard/steps/WelcomeStep.tsx",
"frontend-modern/src/components/patrol/RunToolCallTrace.tsx",
"frontend-modern/src/components/shared/Card.tsx",
"frontend-modern/src/components/shared/CommandPaletteModal.tsx",
"frontend-modern/src/components/shared/EmptyState.tsx",
"frontend-modern/src/components/shared/filterButtonGroupModel.ts",
"frontend-modern/src/features/alerts/AlertDeadManDestinationSection.tsx",
"frontend-modern/src/index.css"
],
"content_sha256": {
"frontend-modern/src/App.tsx": "00a405e01fc87c3f738fb744876e16f13e68d50cb8f31d469f040c637a6f59f0",
"frontend-modern/src/AppLayout.tsx": "3cb3f11a0f39adcd33cef84e7e99451395909313f1898383aa9fcc221dcb0f49",
"frontend-modern/src/components/Alerts/ResourceTable.tsx": "760ff1b760ac8c910582c5b81900a15788fa1ec5a08edd989c54cfafd0a55f49",
"frontend-modern/src/components/AppBootstrapStatus.tsx": "f33978b847c89626e24698dbe5c27db587425a4968573eb75a92f2f75b35f726",
"frontend-modern/src/components/ErrorBoundary.tsx": "ac334eb9bd8aebdb8d8c5fe62e82c399d393a1c670f30f600457278bf98ca45e",
"frontend-modern/src/components/Infrastructure/ResourceChangeSummary.tsx": "4f3f035d2c87e562680dcf61c88cfbc0bb4f2daced31c0bda8427194fe25d992",
"frontend-modern/src/components/Infrastructure/ResourceCorrelationSummary.tsx": "cf77b97ce7bfce0aa642668f4f0123a9e592196e7b5e83a9791ef8e95dca33e5",
"frontend-modern/src/components/Infrastructure/ResourceDetailDrawerDebugTab.tsx": "77ebc85ed5b7de3624c87846288dadc887b5555bac325b98f347246222d7b4c4",
"frontend-modern/src/components/Infrastructure/ResourceDetailDrawerOverviewTab.tsx": "63192be4ab8de0e2aa920207cec14d593571f282d8bde1c8951a2d1413c00fc8",
"frontend-modern/src/components/Infrastructure/ResourceDetailDrawerSupportDisclosure.tsx": "c0f3aaac14865c0944969b2fbfc898bd311def49f25db6938ccbadac9bc822e3",
"frontend-modern/src/components/Infrastructure/ResourcePolicySummary.tsx": "7d87ab5e6ea2948160bf275b6d9fec7ff4ee38ce457f75b85d24c1dbb2c95203",
"frontend-modern/src/components/Login.tsx": "0790413c0199b2bd0e0fcb9dc53cfa0fc6ac84717acbfa4f5140e725cf3d2ff2",
"frontend-modern/src/components/Settings/AIProviderConfigurationSection.tsx": "686708cbbddce209b141e1f9b4c60b0ad57079432be77e384c0d0c4e88dbf7e4",
"frontend-modern/src/components/Settings/AgentIntegrationsPanel.tsx": "45b3473d4a67cf505651c483616a0724085bbaa2f3f1e53c2021c5cfda2d6d0c",
"frontend-modern/src/components/Settings/BackupTransferDialogs.tsx": "a873e334d4eaf5b25bc31ba8922b07119fe16da169b91966c591b8f3a60cf06b",
"frontend-modern/src/components/Settings/BrandingSettingsCard.tsx": "c36f0f518c9674eb05c5050e2e23b9598673a5adf00d039c143cf180a8f21f7f",
"frontend-modern/src/components/Settings/CopyCommandBlock.tsx": "084835c7beb84d0800f9b5590fcb899f7e6088513fc1251b2a74f15e2225b411",
"frontend-modern/src/components/Settings/InfrastructureAgentDoctorPage.tsx": "6064372d8a07257b222888e47c075e5428a6a9392ffbd257963855d0fbe31d38",
"frontend-modern/src/components/Settings/InfrastructureInstallerSection.tsx": "9787d5c0615787f6e0a3fc1caefc3ebef93f4618f6f74b4b2470a0fa0c40e37f",
"frontend-modern/src/components/Settings/NodeModalSetupGuideSection.tsx": "0b8b4600e20bcbd5235a5a7fecffd99c9752d8417955b23c8ce7be473f18042c",
"frontend-modern/src/components/Settings/QuickSecuritySetup.tsx": "8884d86ac12281a5805c33ef608fb0f86f6a61166a6eb72edcc2412b477781b5",
"frontend-modern/src/components/Settings/SSOProvidersPanel.tsx": "2f56e9f1635b34581457c00a60a49166caceeeed2209a187d032704b3d2ca716",
"frontend-modern/src/components/Settings/SuggestProfileModal.tsx": "b54c5c7449fe824f1ba13676bd3bac151bc0b6a880d831b211480dc41f6806d1",
"frontend-modern/src/components/Settings/UpdateInstallGuide.tsx": "65877c2b8a4706721881545dd4f769a41485d3c8df2ede5f9022c337c77d6e92",
"frontend-modern/src/components/Settings/updatesSettingsModel.ts": "7c8cbb83097f65bb1e17fbab859fd0711f870bb0aaa1e9c91fcc71cfd165bb49",
"frontend-modern/src/components/SetupWizard/SetupWizard.tsx": "c96e980aec912bfae0976132168121d45fe2ba8b8e92af9c998e6cf7d69edf56",
"frontend-modern/src/components/SetupWizard/steps/SecurityStep.tsx": "2ae173c4fc65b7aa528d1ca4196d085547081c9742e4f504d00a0baeccbc20b1",
"frontend-modern/src/components/SetupWizard/steps/WelcomeStep.tsx": "4849c5fe13442131a5c6427d81f3c366c94e48a9701f41d1c927476b7af17dbc",
"frontend-modern/src/components/patrol/RunToolCallTrace.tsx": "88b4bedf474d2fa23f56d59db0c746c83e004b920489c86bb6827d50133a7366",
"frontend-modern/src/components/shared/Card.tsx": "03e4ff8a482b6dd086eb4b2765fa517edc229c02ff27105b0e572523c07a7d5f",
"frontend-modern/src/components/shared/CommandPaletteModal.tsx": "8e0a8aaa1bbd2151ddb578e65c1230ef710b2666647cec3ab55a27fc23ac28c3",
"frontend-modern/src/components/shared/EmptyState.tsx": "ee47b2b011fd67fc79913be1c86d8526ffaea8b49716965e0b8f358ebbc2dd74",
"frontend-modern/src/components/shared/filterButtonGroupModel.ts": "a180ecf16e3bb84dadbd6f59a036190960082a527272551648fa9a6e9dd168ab",
"frontend-modern/src/features/alerts/AlertDeadManDestinationSection.tsx": "57b1d0468a61a3e382a72649cb3fd5764e7d00e25f529fa156706bb54121e099",
"frontend-modern/src/index.css": "8ee3a5cfffdf960243238f037147d817a950c65cadb5d36fdc59d58d3837572b"
},
"routes": [
"/settings/pulse-intelligence/assistant",
"/settings/infrastructure/agent-doctor",
"/settings/system-recovery",
"/standalone/machines",
"/proxmox/overview",
"/alerts/notifications",
"/alerts/thresholds",
"/alerts/schedule",
"/settings/system-updates",
"/settings",
"/machines",
"/settings/security/api",
"/patrol",
"/settings/system-general",
"/settings/pulse-intelligence/provider",
"/settings/infrastructure",
"/settings/security-sso"
],
"viewports": [
{
"width": 1440,
"height": 1000
},
{
"width": 390,
"height": 844
}
],
"states": [
"Private mock stack (backend 7781, Vite 5281). Every capture was taken on main and on the change in the same session by swapping the files under Vite, in light and dark",
"External agents connector setup with every details panel open: install and client-config command blocks, the capability chip, the access-model panels and their lists were transparent on the white card; they now read as slate-100 wells in light and slate-900 wells in dark",
"Agent Doctor command blocks, the export-configuration options box, the Ollama pull command, the agent installer commands, the Proxmox node setup-guide command and the SAML metadata XML preview: transparent before, page-coloured wells after",
"Update install guide for systemd and Docker (version response set to that deployment type): the wells now paint, and the green and blue command text gained light-mode shades, because green-400 on a light well measured about 1.6:1",
"Dead Man's Switch: the \"Not configured\" pill had no fill and read as plain text; it is now a white chip with a border ring in light and a ringed chip in dark. The detail grid is a recessed well",
"Alert threshold bulk-selection bar after ticking two storage rows: before, light mode showed white count text on a see-through pill (the count was invisible) and dark mode showed the table through it; after, it is an opaque bg-surface pill with readable text in both themes",
"Command palette shortcut chips read as keycaps; the palette input already painted bg-surface, so its redundant class was removed",
"Patrol mode segmented control (ai_autofix capability supplied): the selected option was a white chip on a white track; the track is now page-coloured and the selection stands out in both themes",
"Branding header preview (white_label capability supplied): the preview header bar now sits on a page-coloured backdrop instead of disappearing into the card",
"Muted Card tone (API token hint, alert configuration summary): slate-100 in light, unchanged in dark. The unused glass tone was removed",
"Machine drawer Debug tab: JSON blocks sit on the drawer's bg-surface-alt body, so they use bg-surface like the drawer's other cards (white on slate-100 in light, flat in dark as before)",
"Setup wizard (security status set to no authentication, bootstrap validation fulfilled with a dummy value): Welcome command wells with legible text and copy buttons, and the Security step wells and footer band, in both themes",
"Login, wizard root, app scroll shell and the framed 404 empty state dropped a class that generated no CSS: the Login page and the empty-state element are pixel-identical before and after, and the shells sit directly on body, which already paints the page colour",
"Hover-only drawer buttons, measured with their exact classes in the live drawer: hover:bg-base never changed the colour; hover:bg-surface-hover goes to rgb(248,250,252) in light and rgb(51,65,85) in dark",
"Not reachable on the mock stack and judged from their containers: the drawer change-history filters, change reason and metadata, the correlation and change summary cards and the coloured drawer buttons (the compact drawer fetches no history in mock), Quick Security Setup (unauthenticated sessions go to the wizard), the agent-profile suggestion JSON, the Patrol tool-call trace, other node-modal tabs, the needs-setup nav tab, the bootstrap/error/init shells, and ResourcePolicySummary, which has no production caller",
"Phone at 390: Dead Man's Switch grid, External agents command block, update steps and wizard command wells render the same wells in both themes"
],
"interactions": [
"Opened connector setup and expanded every details panel; opened the machine drawer and its Debug tab; opened the command palette with Cmd/Ctrl+K",
"Expanded all threshold groups and ticked two storage rows to raise the bulk-edit bar",
"Opened Create Backup, Add infrastructure > Install Pulse Agent > Generate token, Add infrastructure > Proxmox VE with an endpoint entered, Add SAML > Preview metadata, and the Ollama provider section",
"Advanced the setup wizard to the Security step; showed the Login page via the logged-out flag",
"Hovered the old and new drawer button classes in light and dark; repeated the key surfaces at 390px"
]
}
+3 -3
View File
@@ -527,7 +527,7 @@ function App() {
<Show
when={runtime.enhancedStore()}
fallback={
<div class="min-h-screen flex items-center justify-center bg-base">
<div class="min-h-screen flex items-center justify-center">
<div class="text-muted">Initializing...</div>
</div>
}
@@ -559,7 +559,7 @@ function App() {
{/* Main content area - shrinks when AI panel is open, scrolls independently */}
<div
ref={setAppScrollShellRef}
class={`app-scroll-shell isolate flex-1 min-w-0 overflow-y-scroll bg-base text-base-content font-sans py-1 sm:py-6 transition-all duration-300`}
class={`app-scroll-shell isolate flex-1 min-w-0 overflow-y-scroll text-base-content font-sans py-1 sm:py-6 transition-all duration-300`}
>
<AppLayout
connectionStatus={runtime.connectionStatus}
@@ -615,7 +615,7 @@ function App() {
</Show>
}
>
<div class="min-h-screen bg-base text-base-content font-sans">
<div class="min-h-screen text-base-content font-sans">
<div class="mx-auto w-full max-w-6xl px-4 py-6 sm:px-6">{props.children}</div>
</div>
</Show>
+1 -1
View File
@@ -694,7 +694,7 @@ export function AppLayout(props: AppLayoutProps) {
return `${baseClasses} bg-surface text-blue-600 dark:text-blue-400 border-border border-b border-b-surface shadow-xs font-semibold`;
}
if (needsSetup()) {
return `${baseClasses} text-muted opacity-70 bg-base hover:bg-surface-hover`;
return `${baseClasses} text-muted opacity-70 hover:bg-surface-hover`;
}
return `${baseClasses} text-muted hover:text-base-content hover:bg-surface-hover`;
};
@@ -1007,30 +1007,30 @@ describe('App architecture', () => {
});
});
function collectFrontendSources(dir: string): Array<{ path: string; source: string }> {
return readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
const entryPath = join(dir, entry.name);
if (entry.isDirectory()) {
return collectFrontendSources(entryPath);
}
// Only runtime sources matter; a test may quote an old shape in order to
// assert against it, as the guards below do.
if (!/\.(css|ts|tsx)$/.test(entry.name)) {
return [];
}
if (entryPath.includes('__tests__') || /\.(test|spec)\./.test(entry.name)) {
return [];
}
return [{ path: entryPath, source: readFileSync(entryPath, 'utf8') }];
});
}
describe('mobile bottom navigation clearance', () => {
const NAV_HEIGHT_VARIABLE = '--pulse-mobile-nav-height';
// Matches the shape every drifted copy used, spaced or not. The lookbehind
// keeps the declared 2.5rem fallback from matching its own guard.
const HARDCODED_BAR_HEIGHT = /(?<![\d.])5rem\s*\+\s*env\(\s*safe-area-inset-bottom/;
function collectFrontendSources(dir: string): Array<{ path: string; source: string }> {
return readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
const entryPath = join(dir, entry.name);
if (entry.isDirectory()) {
return collectFrontendSources(entryPath);
}
// Only runtime sources matter; a test may quote the old shape in order
// to assert against it, as this one does.
if (!/\.(css|ts|tsx)$/.test(entry.name)) {
return [];
}
if (entryPath.includes('__tests__') || /\.(test|spec)\./.test(entry.name)) {
return [];
}
return [{ path: entryPath, source: readFileSync(entryPath, 'utf8') }];
});
}
it('declares the bar height as a single custom property', () => {
expect(appStylesSource).toContain(NAV_HEIGHT_VARIABLE);
});
@@ -1050,6 +1050,33 @@ describe('mobile bottom navigation clearance', () => {
});
});
describe('page background utility', () => {
// Tailwind 4 emits nothing for a colour it does not know, so `bg-base`
// rendered transparent without any error: command blocks, the alert
// selection bar and segmented-control tracks all lost their backgrounds.
// A theme colour named `base` is not the fix either, because it also gives
// the `text-base` font-size utility a colour and paints text in the page
// colour. The page backdrop is the bg-page utility.
const DEAD_BASE_BACKGROUND = /(?<![\w-])bg-base(?![\w-])/;
// A comment may name the old class to explain a fix, as toggleModel does.
const COMMENTS = /\/\*[\s\S]*?\*\/|(^|[^:])\/\/.*$/gm;
it('declares the page backdrop as a utility, never as a colour named base', () => {
expect(appStylesSource).toMatch(
/@utility bg-page \{\s*background-color: var\(--color-bg-base\);\s*\}/,
);
expect(appStylesSource).not.toMatch(/--color-base\s*:/);
});
it('keeps every runtime class off the bg-base utility that renders nothing', () => {
const offenders = collectFrontendSources(join(process.cwd(), 'src'))
.filter(({ source }) => DEAD_BASE_BACKGROUND.test(source.replace(COMMENTS, '$1')))
.map(({ path }) => path.slice(process.cwd().length + 1));
expect(offenders).toEqual([]);
});
});
describe('Docker phone update reflow boundary', () => {
it('scopes label wrapping to narrow Docker cells without restoring a nested scrollport', () => {
const phoneStyles = appStylesSource.slice(appStylesSource.indexOf('/* Phone update states'));
@@ -145,9 +145,9 @@ export function ResourceTable(props: ResourceTableProps) {
</Show>
<Show when={selectedIds().size > 0 && props.onBulkEdit}>
<div class="fixed bottom-8 left-1/2 -translate-x-1/2 bg-base border border-border shadow-2xl rounded-full px-5 py-3 flex items-center gap-6 z-100 animate-in slide-in-from-bottom-5">
<span class="text-sm font-medium text-white">
{selectedIds().size} <span class="text-slate-400">selected</span>
<div class="fixed bottom-8 left-1/2 -translate-x-1/2 bg-surface border border-border shadow-2xl rounded-full px-5 py-3 flex items-center gap-6 z-100 animate-in slide-in-from-bottom-5">
<span class="text-sm font-medium text-base-content">
{selectedIds().size} <span class="text-muted">selected</span>
</span>
<div class="flex items-center gap-2">
<button
@@ -163,7 +163,7 @@ export function ResourceTable(props: ResourceTableProps) {
{getAlertBulkEditOpenLabel()}
</button>
<ActionIconButton
class="rounded-full bg-surface text-slate-400 hover:bg-slate-700 hover:text-white focus-visible:ring-offset-0"
class="rounded-full focus-visible:ring-offset-0"
onClick={clearSelectedIds}
label={ALERT_BULK_EDIT_CLEAR_LABEL}
size="sm"
@@ -30,7 +30,7 @@ export const AppBootstrapStatus: Component<AppBootstrapStatusProps> = (props) =>
return (
<main
class="flex min-h-screen items-center justify-center bg-base px-4 py-8 text-base-content"
class="flex min-h-screen items-center justify-center px-4 py-8 text-base-content"
aria-labelledby="app-bootstrap-title"
>
<div class="w-full max-w-md rounded-md border border-border bg-surface p-6 text-center shadow-xs sm:p-8">
@@ -14,7 +14,7 @@ interface ErrorBoundaryProps {
const DefaultErrorFallback: Component<{ error: Error; reset: () => void }> = (props) => {
return (
<div class="min-h-screen flex items-center justify-center bg-base p-4">
<div class="min-h-screen flex items-center justify-center p-4">
<div class="max-w-md w-full bg-surface rounded-md shadow-xs p-6">
<div class="flex items-center mb-4">
<AlertTriangleIcon class="mr-3 h-12 w-12 text-red-500" aria-hidden="true" />
@@ -92,7 +92,7 @@ export const ResourceChangeSummary: Component<ResourceChangeSummaryProps> = (pro
: null;
return (
<li class={`rounded-md border border-border-subtle bg-base ${itemPadding()}`}>
<li class={`rounded-md border border-border-subtle bg-page ${itemPadding()}`}>
<div class={`flex flex-wrap items-start justify-between ${gapSize()}`}>
<div class="min-w-0">
<p class={headlineText()}>{headline}</p>
@@ -56,7 +56,7 @@ export const ResourceCorrelationSummary: Component<ResourceCorrelationSummaryPro
<Show when={hasContent()}>
<div
data-testid={props.dataTestId}
class={`rounded-md border border-border-subtle bg-base p-4 ${className()}`.trim()}
class={`rounded-md border border-border-subtle bg-surface p-4 ${className()}`.trim()}
>
<div class="flex flex-wrap items-start justify-between gap-2">
<div>
@@ -37,7 +37,7 @@ export const ResourceDetailDrawerDebugTab: Component<ResourceDetailDrawerDebugTa
<div class="text-[11px] font-medium uppercase tracking-wide text-base-content mb-2">
Unified Resource
</div>
<pre class="max-h-[280px] overflow-auto rounded-md bg-base p-3 text-[11px] text-base-content">
<pre class="max-h-[280px] overflow-auto rounded-md bg-surface p-3 text-[11px] text-base-content">
{JSON.stringify(props.resource, null, 2)}
</pre>
</div>
@@ -46,7 +46,7 @@ export const ResourceDetailDrawerDebugTab: Component<ResourceDetailDrawerDebugTa
<div class="text-[11px] font-medium uppercase tracking-wide text-base-content mb-2">
Identity Matching
</div>
<pre class="max-h-[220px] overflow-auto rounded-md bg-base p-3 text-[11px] text-base-content">
<pre class="max-h-[220px] overflow-auto rounded-md bg-surface p-3 text-[11px] text-base-content">
{JSON.stringify(
{
identity: props.resource.identity,
@@ -81,7 +81,7 @@ export const ResourceDetailDrawerDebugTab: Component<ResourceDetailDrawerDebugTa
{status?.error}
</div>
</Show>
<pre class="mt-3 max-h-[220px] overflow-auto rounded-md bg-base p-3 text-[11px] text-base-content">
<pre class="mt-3 max-h-[220px] overflow-auto rounded-md bg-surface p-3 text-[11px] text-base-content">
{JSON.stringify(section.payload ?? {}, null, 2)}
</pre>
</details>
@@ -322,7 +322,7 @@ export const ResourceAccessDisclosure: Component<{
<button
type="button"
onClick={() => props.drawer.setShowDiscoveryContext((value) => !value)}
class="inline-flex items-center rounded-md border border-border bg-surface px-2.5 py-1 text-[10px] font-medium text-base-content transition-colors hover:bg-base"
class="inline-flex items-center rounded-md border border-border bg-surface px-2.5 py-1 text-[10px] font-medium text-base-content transition-colors hover:bg-surface-hover"
>
{props.drawer.showDiscoveryContext() ? 'Hide analysis' : 'Open analysis'}
</button>
@@ -473,7 +473,7 @@ export const ResourceDetailDrawerOverviewTab: Component<ResourceDetailDrawerOver
label="Change kind"
fieldBaseClass="space-y-1 text-[10px]"
labelClass="text-muted"
selectBaseClass="w-full rounded-sm border border-border bg-base px-2 py-1 text-[11px] text-base-content"
selectBaseClass="w-full rounded-sm border border-border bg-surface px-2 py-1 text-[11px] text-base-content"
value={drawer.timelineKindFilter()}
onChange={(event) =>
drawer.setTimelineKindFilter(
@@ -489,7 +489,7 @@ export const ResourceDetailDrawerOverviewTab: Component<ResourceDetailDrawerOver
label="Source type"
fieldBaseClass="space-y-1 text-[10px]"
labelClass="text-muted"
selectBaseClass="w-full rounded-sm border border-border bg-base px-2 py-1 text-[11px] text-base-content"
selectBaseClass="w-full rounded-sm border border-border bg-surface px-2 py-1 text-[11px] text-base-content"
value={drawer.timelineSourceTypeFilter()}
onChange={(event) =>
drawer.setTimelineSourceTypeFilter(
@@ -505,7 +505,7 @@ export const ResourceDetailDrawerOverviewTab: Component<ResourceDetailDrawerOver
label="Source adapter"
fieldBaseClass="space-y-1 text-[10px]"
labelClass="text-muted"
selectBaseClass="w-full rounded-sm border border-border bg-base px-2 py-1 text-[11px] text-base-content"
selectBaseClass="w-full rounded-sm border border-border bg-surface px-2 py-1 text-[11px] text-base-content"
value={drawer.timelineSourceAdapterFilter()}
onChange={(event) =>
drawer.setTimelineSourceAdapterFilter(
@@ -618,12 +618,12 @@ export const ResourceDetailDrawerOverviewTab: Component<ResourceDetailDrawerOver
</Show>
</div>
<Show when={change.reason}>
<div class="mt-1 rounded-sm border border-border bg-base px-2 py-1 text-[10px] text-base-content">
<div class="mt-1 rounded-sm border border-border bg-page px-2 py-1 text-[10px] text-base-content">
{change.reason}
</div>
</Show>
<Show when={hasMetadataEntries(change.metadata)}>
<details class="mt-1 rounded-sm border border-border bg-base px-2 py-1">
<details class="mt-1 rounded-sm border border-border bg-page px-2 py-1">
<summary class="cursor-pointer list-none text-[10px] font-medium text-muted">
Metadata
</summary>
@@ -867,7 +867,7 @@ export const ResourceDetailDrawerOverviewTab: Component<ResourceDetailDrawerOver
<button
type="button"
onClick={drawer.toggleDockerUpdateControls}
class="inline-flex items-center rounded-md border border-sky-200 bg-surface px-2.5 py-1 text-[10px] font-medium text-sky-700 transition-colors hover:bg-base dark:border-sky-700 dark:text-sky-300"
class="inline-flex items-center rounded-md border border-sky-200 bg-surface px-2.5 py-1 text-[10px] font-medium text-sky-700 transition-colors hover:bg-surface-hover dark:border-sky-700 dark:text-sky-300"
>
{drawer.showDockerUpdateControls() ? 'Hide actions' : 'Show actions'}
</button>
@@ -1114,7 +1114,7 @@ export const ResourceDetailDrawerOverviewTab: Component<ResourceDetailDrawerOver
<button
type="button"
onClick={() => drawer.setShowPbsJobDetail((value) => !value)}
class="inline-flex items-center rounded-md border border-indigo-200 bg-surface px-2.5 py-1 text-[10px] font-medium text-indigo-700 transition-colors hover:bg-base dark:border-indigo-700 dark:text-indigo-300"
class="inline-flex items-center rounded-md border border-indigo-200 bg-surface px-2.5 py-1 text-[10px] font-medium text-indigo-700 transition-colors hover:bg-surface-hover dark:border-indigo-700 dark:text-indigo-300"
>
{drawer.showPbsJobDetail() ? 'Hide jobs' : 'Show jobs'}
</button>
@@ -1242,7 +1242,7 @@ export const ResourceDetailDrawerOverviewTab: Component<ResourceDetailDrawerOver
<button
type="button"
onClick={() => drawer.setShowPmgMailFlowDetail((value) => !value)}
class="inline-flex items-center rounded-md border border-rose-200 bg-surface px-2.5 py-1 text-[10px] font-medium text-rose-700 transition-colors hover:bg-base dark:border-rose-700 dark:text-rose-300"
class="inline-flex items-center rounded-md border border-rose-200 bg-surface px-2.5 py-1 text-[10px] font-medium text-rose-700 transition-colors hover:bg-surface-hover dark:border-rose-700 dark:text-rose-300"
>
{drawer.showPmgMailFlowDetail() ? 'Hide mail flow' : 'Show mail flow'}
</button>
@@ -48,7 +48,7 @@ export const ResourceDetailDrawerSupportDisclosure: Component<
onClick={props.onToggle}
class={
props.buttonClass ??
'inline-flex min-h-11 shrink-0 items-center rounded-md border border-border bg-surface px-2.5 py-1 text-[10px] font-medium text-base-content transition-colors hover:bg-base sm:min-h-0'
'inline-flex min-h-11 shrink-0 items-center rounded-md border border-border bg-surface px-2.5 py-1 text-[10px] font-medium text-base-content transition-colors hover:bg-surface-hover sm:min-h-0'
}
>
{props.expanded ? props.hideLabel : props.showLabel}
@@ -24,7 +24,7 @@ export const ResourcePolicySummary: Component<ResourcePolicySummaryProps> = (pro
return (
<Show when={posture()}>
{(value) => (
<div class={`rounded-md border border-border-subtle bg-base p-4 ${className()}`.trim()}>
<div class={`rounded-md border border-border-subtle bg-surface p-4 ${className()}`.trim()}>
<div class="flex flex-wrap items-start justify-between gap-2">
<div>
<h3 class="text-sm font-semibold text-base-content">
+3 -3
View File
@@ -344,7 +344,7 @@ export const Login: Component<LoginProps> = (props) => {
<Show
when={!loadingAuth()}
fallback={
<div class="min-h-screen flex items-center justify-center bg-base">
<div class="min-h-screen flex items-center justify-center">
<div class="text-center">
<LoadingSpinner size="lg" tone="info" label="Checking authentication" class="mb-4" />
<p class="text-muted">Checking authentication...</p>
@@ -379,7 +379,7 @@ export const Login: Component<LoginProps> = (props) => {
>
<Suspense
fallback={
<div class="min-h-screen flex items-center justify-center bg-base">
<div class="min-h-screen flex items-center justify-center">
<div class="text-center">
<LoadingSpinner size="lg" tone="info" label="Loading setup" class="mb-4" />
<p class="text-muted">Loading setup...</p>
@@ -438,7 +438,7 @@ const LoginForm: Component<{
} = props;
return (
<div class="min-h-screen flex items-center justify-center bg-base py-12 px-4 sm:px-6 lg:px-8">
<div class="min-h-screen flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
<div class="max-w-md w-full space-y-8">
{/* Demo Credentials Banner */}
<Show when={demoModeEnabled}>
@@ -297,7 +297,7 @@ export const AIProviderConfigurationSection: Component<AIProviderConfigurationSe
</p>
<CopyCommandBlock
command={`ollama pull ${suggestedModel()}`}
codeClass="block whitespace-pre overflow-x-auto rounded-md border border-border bg-base p-3 pr-10 font-mono text-xs text-base-content"
codeClass="block whitespace-pre overflow-x-auto rounded-md border border-border bg-page p-3 pr-10 font-mono text-xs text-base-content"
/>
<Show when={suggestedModelNote()}>
<p class="text-xs text-muted">{suggestedModelNote()}</p>
@@ -309,7 +309,7 @@ export const AgentIntegrationsPanel: Component = () => {
<CopyCommandBlock
command={mcpInstallShellCommand}
onCopy={handleCopySnippet}
codeClass="block whitespace-pre overflow-x-auto rounded-md border border-border bg-base p-3 font-mono text-xs text-base-content"
codeClass="block whitespace-pre overflow-x-auto rounded-md border border-border bg-page p-3 font-mono text-xs text-base-content"
/>
</div>
<div class="space-y-2">
@@ -319,7 +319,7 @@ export const AgentIntegrationsPanel: Component = () => {
<CopyCommandBlock
command={mcpInstallPowerShellCommand}
onCopy={handleCopySnippet}
codeClass="block whitespace-pre overflow-x-auto rounded-md border border-border bg-base p-3 font-mono text-xs text-base-content"
codeClass="block whitespace-pre overflow-x-auto rounded-md border border-border bg-page p-3 font-mono text-xs text-base-content"
/>
</div>
</div>
@@ -353,7 +353,7 @@ export const AgentIntegrationsPanel: Component = () => {
<CopyCommandBlock
command={openCodeMcpConfig()}
onCopy={handleCopySnippet}
codeClass="block whitespace-pre overflow-x-auto rounded-md border border-border bg-base p-3 font-mono text-xs text-base-content"
codeClass="block whitespace-pre overflow-x-auto rounded-md border border-border bg-page p-3 font-mono text-xs text-base-content"
/>
</div>
<div class="space-y-2">
@@ -371,7 +371,7 @@ export const AgentIntegrationsPanel: Component = () => {
<CopyCommandBlock
command={claudeMcpConfig()}
onCopy={handleCopySnippet}
codeClass="block whitespace-pre overflow-x-auto rounded-md border border-border bg-base p-3 font-mono text-xs text-base-content"
codeClass="block whitespace-pre overflow-x-auto rounded-md border border-border bg-page p-3 font-mono text-xs text-base-content"
/>
</div>
</div>
@@ -395,7 +395,7 @@ export const AgentIntegrationsPanel: Component = () => {
<Show when={mcpSurfaceToolPosture()}>
{(posture) => (
<div
class="flex w-fit flex-wrap items-center gap-1.5 rounded-md border border-border bg-base px-2 py-1 text-[11px] font-medium text-muted"
class="flex w-fit flex-wrap items-center gap-1.5 rounded-md border border-border bg-page px-2 py-1 text-[11px] font-medium text-muted"
title={posture().title}
data-testid="agent-mcp-tool-posture"
>
@@ -411,7 +411,7 @@ export const AgentIntegrationsPanel: Component = () => {
)}
</Show>
<Show when={surfaceContractEntries().length > 0}>
<details class="rounded-md border border-border bg-base p-3">
<details class="rounded-md border border-border bg-page p-3">
<summary class="cursor-pointer text-sm font-semibold text-base-content">
Patrol access model
</summary>
@@ -432,7 +432,7 @@ export const AgentIntegrationsPanel: Component = () => {
</span>
<For each={entry.badges}>
{(badge) => (
<span class="rounded-full border border-border bg-base px-2 py-0.5 text-[10px] uppercase tracking-wide text-muted">
<span class="rounded-full border border-border bg-page px-2 py-0.5 text-[10px] uppercase tracking-wide text-muted">
{badge}
</span>
)}
@@ -449,7 +449,7 @@ export const AgentIntegrationsPanel: Component = () => {
</details>
</Show>
<Show when={hasManifestInventory()}>
<details class="rounded-md border border-border bg-base p-3">
<details class="rounded-md border border-border bg-page p-3">
<summary class="cursor-pointer text-sm font-semibold text-base-content">
Live manifest details
</summary>
@@ -468,7 +468,7 @@ export const AgentIntegrationsPanel: Component = () => {
</span>
</summary>
<div class="mt-3 space-y-2">
<ul class="divide-y divide-border rounded-md border border-border bg-base">
<ul class="divide-y divide-border rounded-md border border-border bg-page">
<For each={workflowPrompts()}>
{(prompt) => (
<li class="space-y-1 p-3">
@@ -548,7 +548,7 @@ export const AgentIntegrationsPanel: Component = () => {
<For each={errorCodeSummaries()}>
{(summary) => (
<span
class="rounded-md border border-border bg-base px-2 py-1"
class="rounded-md border border-border bg-page px-2 py-1"
title={`Declared by ${summary.capabilityNames.join(', ')}`}
>
<code class="font-mono">{summary.code}</code>
@@ -591,7 +591,7 @@ export const AgentIntegrationsPanel: Component = () => {
<p class="text-xs text-muted">{section.description}</p>
</Show>
</div>
<ul class="divide-y divide-border rounded-md border border-border bg-base">
<ul class="divide-y divide-border rounded-md border border-border bg-page">
<For each={section.entries}>
{(cap) => (
<li class="space-y-1 p-3">
@@ -45,7 +45,7 @@ export const BackupTransferDialogs: Component<BackupTransferDialogsProps> = (pro
<div class="space-y-4">
<Show when={props.securityStatus()?.hasAuthentication}>
<div class="bg-base rounded-md p-4 border border-border">
<div class="bg-page rounded-md p-4 border border-border">
<div class="space-y-3">
<label class="flex items-start gap-3 cursor-pointer">
<input
@@ -152,7 +152,7 @@ export const BrandingSettingsCard: Component<BrandingSettingsCardProps> = (props
</div>
</div>
<div class="flex min-h-28 flex-col justify-between gap-4 rounded-md border border-border bg-base p-4">
<div class="flex min-h-28 flex-col justify-between gap-4 rounded-md border border-border bg-page p-4">
<div>
<p class="text-xs font-medium uppercase tracking-wide text-muted">Header preview</p>
<div class="mt-3 flex min-h-10 items-center justify-center gap-2 overflow-hidden rounded-sm bg-surface px-3 py-2">
@@ -11,7 +11,7 @@ interface CopyCommandBlockProps {
const DEFAULT_CONTAINER_CLASS = 'relative group';
const DEFAULT_CODE_CLASS =
'block rounded-md border border-border bg-base p-3 font-mono text-sm text-base-content';
'block rounded-md border border-border bg-page p-3 font-mono text-sm text-base-content';
export function CopyCommandBlock(props: CopyCommandBlockProps) {
const handleCopy = () => {
@@ -654,7 +654,7 @@ export const InfrastructureAgentDoctorPage: Component<InfrastructureAgentDoctorP
}
label="Copy safe-profile inspection command"
/>
<pre class="overflow-x-auto rounded-md bg-base p-3 pr-12 text-xs text-base-content">
<pre class="overflow-x-auto rounded-md bg-page p-3 pr-12 text-xs text-base-content">
<code>
{buildSafeCollectorInspectCommand({
pulseUrl: operations.selectedAgentUrl(),
@@ -682,7 +682,7 @@ export const InfrastructureAgentDoctorPage: Component<InfrastructureAgentDoctorP
}
label="Copy safe-profile apply command"
/>
<pre class="overflow-x-auto rounded-md bg-base p-3 pr-12 text-xs text-base-content">
<pre class="overflow-x-auto rounded-md bg-page p-3 pr-12 text-xs text-base-content">
<code>
{buildSafeCollectorApplyCommand({
pulseUrl: operations.selectedAgentUrl(),
@@ -767,7 +767,7 @@ export const InfrastructureAgentDoctorPage: Component<InfrastructureAgentDoctorP
onClick={() => void copyCommand(tokenFileCommand())}
label="Copy private token-file command"
/>
<pre class="overflow-x-auto rounded-md bg-base p-3 pr-12 text-xs text-base-content">
<pre class="overflow-x-auto rounded-md bg-page p-3 pr-12 text-xs text-base-content">
<code>{tokenFileCommand()}</code>
</pre>
</div>
@@ -782,7 +782,7 @@ export const InfrastructureAgentDoctorPage: Component<InfrastructureAgentDoctorP
title="Copy one-time action-runner credential"
label={`Copy action-runner credential for ${target.displayName}`}
/>
<pre class="overflow-x-auto rounded-md bg-base p-3 pr-12 text-xs text-base-content">
<pre class="overflow-x-auto rounded-md bg-page p-3 pr-12 text-xs text-base-content">
<code>{reveal().token}</code>
</pre>
</div>
@@ -796,7 +796,7 @@ export const InfrastructureAgentDoctorPage: Component<InfrastructureAgentDoctorP
onClick={() => void copyCommand(installCommand())}
label="Copy action-runner installer command"
/>
<pre class="overflow-x-auto rounded-md bg-base p-3 pr-12 text-xs text-base-content">
<pre class="overflow-x-auto rounded-md bg-page p-3 pr-12 text-xs text-base-content">
<code>{installCommand()}</code>
</pre>
</div>
@@ -914,7 +914,7 @@ export const InfrastructureAgentDoctorPage: Component<InfrastructureAgentDoctorP
title="Copy host-local agent repair command"
label={`Copy ${target.needsCredentialRepair ? 'authentication repair' : 'update'} command for ${target.displayName}`}
/>
<pre class="overflow-x-auto rounded-md bg-base p-3 pr-12 text-xs text-base-content">
<pre class="overflow-x-auto rounded-md bg-page p-3 pr-12 text-xs text-base-content">
<code>{command()}</code>
</pre>
<Show
@@ -964,7 +964,7 @@ export const InfrastructureAgentDoctorPage: Component<InfrastructureAgentDoctorP
title="Copy host-local agent uninstall command"
label={`Copy ${entry.label} uninstall command for ${target.displayName}`}
/>
<pre class="overflow-x-auto rounded-md bg-base p-3 pr-12 text-xs text-base-content">
<pre class="overflow-x-auto rounded-md bg-page p-3 pr-12 text-xs text-base-content">
<code>
{operations.getPlatformUninstallCommand(
entry.platform,
@@ -715,7 +715,7 @@ export const InfrastructureInstallerSection: Component<InfrastructureInstallerSe
title="Copy command"
label={`Copy ${snippet.label} command`}
/>
<pre class="overflow-x-auto rounded-md bg-base p-3 pr-12 text-xs text-base-content">
<pre class="overflow-x-auto rounded-md bg-page p-3 pr-12 text-xs text-base-content">
<code>{copyCommand()}</code>
</pre>
</div>
@@ -165,7 +165,7 @@ export const NodeModalSetupGuideSection: Component<NodeModalSetupGuideSectionPro
<p class="text-blue-800 dark:text-blue-200 font-medium">
Run this command on your Proxmox VE node:
</p>
<div class="relative bg-base rounded-md p-3 font-mono text-xs overflow-x-auto">
<div class="relative bg-page rounded-md p-3 font-mono text-xs overflow-x-auto">
<button
type="button"
disabled={state.loadingAgentCommand() || setupHandoffDisabled()}
@@ -279,7 +279,7 @@ export const NodeModalSetupGuideSection: Component<NodeModalSetupGuideSectionPro
</p>
<div class="space-y-3">
<div class="relative bg-base rounded-md p-3 font-mono text-xs overflow-x-auto">
<div class="relative bg-page rounded-md p-3 font-mono text-xs overflow-x-auto">
<button
type="button"
onClick={async () => {
@@ -653,7 +653,7 @@ export const NodeModalSetupGuideSection: Component<NodeModalSetupGuideSectionPro
<p class="text-blue-800 dark:text-blue-200 text-xs mt-3">
Run this command on your PBS node:
</p>
<div class="relative bg-base rounded-md p-3 font-mono text-xs overflow-x-auto">
<div class="relative bg-page rounded-md p-3 font-mono text-xs overflow-x-auto">
<button
type="button"
onClick={() =>
@@ -750,7 +750,7 @@ export const NodeModalSetupGuideSection: Component<NodeModalSetupGuideSectionPro
</p>
<div class="space-y-3">
<div class="relative bg-base rounded-md p-3 font-mono text-xs overflow-x-auto">
<div class="relative bg-page rounded-md p-3 font-mono text-xs overflow-x-auto">
<Show when={state.formData().host && state.formData().host.trim() !== ''}>
<button
type="button"
@@ -217,7 +217,7 @@ Important:
</div>
</div>
<div class="bg-base rounded-md p-3 space-y-3">
<div class="bg-page rounded-md p-3 space-y-3">
<div class="flex items-center justify-between">
<span class={labelClass()}>Password Setup</span>
<div class="flex items-center space-x-2">
@@ -390,7 +390,7 @@ Important:
</div>
<div class="space-y-3">
<div class="bg-base rounded-md p-3">
<div class="bg-page rounded-md p-3">
<span class={labelClass('text-xs')}>Username</span>
<div class="mt-1 flex items-center gap-2">
<code class="flex-1 font-mono text-sm bg-surface px-3 py-2 rounded-sm border border-border">
@@ -406,7 +406,7 @@ Important:
</div>
</div>
<div class="bg-base rounded-md p-3">
<div class="bg-page rounded-md p-3">
<span class={labelClass('text-xs')}>Password</span>
<div class="mt-1 flex items-center gap-2">
<code class="flex-1 font-mono text-sm bg-surface px-3 py-2 rounded-sm border border-border break-all">
@@ -422,7 +422,7 @@ Important:
</div>
</div>
<div class="bg-base rounded-md p-3">
<div class="bg-page rounded-md p-3">
<span class={labelClass('text-xs')}>API token</span>
<div class="mt-1 flex items-center gap-2">
<code class="flex-1 font-mono text-sm bg-surface px-3 py-2 rounded-sm border border-border break-all">
@@ -940,7 +940,7 @@ export const SSOProvidersPanel: Component<SSOProvidersPanelProps> = (props) => {
<span>Copy</span>
</CopyValueButton>
</div>
<pre class="text-xs bg-base text-base-content p-4 rounded-md overflow-x-auto whitespace-pre-wrap break-all font-mono">
<pre class="text-xs bg-page text-base-content p-4 rounded-md overflow-x-auto whitespace-pre-wrap break-all font-mono">
{metadataPreview()?.xml}
</pre>
</div>
@@ -525,8 +525,8 @@ export const SuggestProfileModal: Component<SuggestProfileModalProps> = (props)
</div>
<div class="space-y-3">
<h5 class="text-sm font-medium text-base-content">Raw JSON</h5>
<div class="bg-base rounded-md p-3 overflow-x-auto">
<pre class="text-xs text-slate-300 font-mono">
<div class="bg-page rounded-md p-3 overflow-x-auto">
<pre class="text-xs text-base-content font-mono">
{JSON.stringify(sugg().config, null, 2)}
</pre>
</div>
@@ -57,7 +57,7 @@ function InstallStep(props: { step: UpdateInstallStep; index: number }) {
containerClass="ml-0 sm:ml-8 relative group"
codeClass={
props.step.commandCodeClass ??
'block rounded-md border border-border bg-base p-3 font-mono text-sm text-green-400'
'block rounded-md border border-border bg-page p-3 font-mono text-sm text-green-700 dark:text-green-400'
}
/>
</Show>
@@ -181,7 +181,7 @@ export const UpdateInstallGuide: Component<UpdateInstallGuideProps> = (props) =>
<div class="space-y-2">
<CopyCommandBlock
command={buildIdleDockerComposeCommand()}
codeClass="block rounded-md border border-border bg-base p-2.5 font-mono text-xs text-blue-400"
codeClass="block rounded-md border border-border bg-page p-2.5 font-mono text-xs text-blue-700 dark:text-blue-400"
/>
<p class="text-[10px] text-blue-600 dark:text-blue-400">
Not using Compose?{' '}
@@ -54,9 +54,9 @@ const makeDockerUpdate = (overrides: Partial<DockerUpdateCommands> = {}): Docker
});
const PRO_STEP_CODE_CLASS =
'block rounded-md border border-border bg-base p-3 font-mono text-sm text-green-400 whitespace-pre-wrap break-all';
'block rounded-md border border-border bg-page p-3 font-mono text-sm text-green-700 dark:text-green-400 whitespace-pre-wrap break-all';
const SYSTEMD_DOWNLOAD_CODE_CLASS =
'block rounded-md border border-border bg-base p-3 font-mono text-sm text-base-content whitespace-pre-wrap break-all';
'block rounded-md border border-border bg-page p-3 font-mono text-sm text-base-content whitespace-pre-wrap break-all';
// ---- buildIdleDockerComposeCommand -----------------------------------------
// Single return path; assert the exact constant.
@@ -52,7 +52,7 @@ const makeDockerUpdate = (overrides: Partial<DockerUpdateCommands> = {}): Docker
});
const PRO_STEP_CODE_CLASS =
'block rounded-md border border-border bg-base p-3 font-mono text-sm text-green-400 whitespace-pre-wrap break-all';
'block rounded-md border border-border bg-page p-3 font-mono text-sm text-green-700 dark:text-green-400 whitespace-pre-wrap break-all';
// ---- buildUpdateInstallGuide (complementary branch-coverage) ----------------
@@ -70,14 +70,14 @@ function buildProDockerUpdateSteps(dockerUpdate: DockerUpdateCommands): UpdateIn
title: 'Pull the new Pulse Pro image (pinned to this release’s digest)',
command: dockerUpdate.composePullCommand,
commandCodeClass:
'block rounded-md border border-border bg-base p-3 font-mono text-sm text-green-400 whitespace-pre-wrap break-all',
'block rounded-md border border-border bg-page p-3 font-mono text-sm text-green-700 dark:text-green-400 whitespace-pre-wrap break-all',
},
{
id: 'docker-pro-up',
title: 'Recreate the container on the new image',
command: dockerUpdate.composeUpCommand,
commandCodeClass:
'block rounded-md border border-border bg-base p-3 font-mono text-sm text-green-400 whitespace-pre-wrap break-all',
'block rounded-md border border-border bg-page p-3 font-mono text-sm text-green-700 dark:text-green-400 whitespace-pre-wrap break-all',
},
];
if (dockerUpdate.loginCommand) {
@@ -192,7 +192,7 @@ export function buildUpdateInstallGuide(
title: 'Download and extract the new version',
command: systemdDownloadCommand,
commandCodeClass:
'block rounded-md border border-border bg-base p-3 font-mono text-sm text-base-content whitespace-pre-wrap break-all',
'block rounded-md border border-border bg-page p-3 font-mono text-sm text-base-content whitespace-pre-wrap break-all',
},
{ id: 'systemd-start', title: 'Start the service', command: 'sudo systemctl start pulse' },
],
@@ -67,11 +67,7 @@ export const SetupWizard: Component<SetupWizardProps> = (props) => {
]);
return (
<div
class="min-h-screen bg-base flex flex-col"
role="main"
aria-label={t('setup.wizard.ariaLabel')}
>
<div class="min-h-screen flex flex-col" role="main" aria-label={t('setup.wizard.ariaLabel')}>
{/* Background decoration */}
<div class="fixed inset-0 overflow-hidden pointer-events-none" aria-hidden="true"></div>
@@ -229,7 +229,7 @@ export const SecurityStep: Component<SecurityStepProps> = (props) => {
</Show>
</div>
<div class="bg-base rounded-md p-4 border border-border text-left">
<div class="bg-page rounded-md p-4 border border-border text-left">
<Toggle
checked={shareUsageStatistics()}
onChange={() => setShareUsageStatistics(!shareUsageStatistics())}
@@ -238,7 +238,7 @@ export const SecurityStep: Component<SecurityStepProps> = (props) => {
/>
</div>
<div class="bg-base rounded-md p-4 border border-border text-left">
<div class="bg-page rounded-md p-4 border border-border text-left">
<div class="text-[11px] font-semibold uppercase tracking-wide text-muted mb-2">
{t('setup.security.nextScreen.title')}
</div>
@@ -250,7 +250,7 @@ export const SecurityStep: Component<SecurityStepProps> = (props) => {
</div>
</div>
{/* Actions */}
<div class="p-8 bg-base flex gap-4 border-t border-border relative z-10">
<div class="p-8 bg-page flex gap-4 border-t border-border relative z-10">
<button
onClick={props.onBack}
class="px-6 py-3.5 bg-surface border border-border hover:bg-surface-hover text-base-content font-medium rounded-md transition-colors"
@@ -176,20 +176,20 @@ export const WelcomeStep: Component<WelcomeStepProps> = (props) => {
<div class="mb-5 space-y-2">
<For each={bootstrapCommands()}>
{(item) => (
<div class="bg-base rounded-md border border-border-subtle px-3 py-2.5">
<div class="bg-page rounded-md border border-border-subtle px-3 py-2.5">
<div class="mb-1.5 text-[11px] font-semibold text-muted">{item.label}</div>
<div class="flex items-center justify-between gap-3 font-mono text-sm text-emerald-400">
<div class="flex items-center justify-between gap-3 font-mono text-sm text-emerald-700 dark:text-emerald-400">
<div class="flex min-w-0 items-center space-x-3 overflow-x-auto scrollbar-hide">
<Terminal class="h-4 w-4 shrink-0" />
<code class="whitespace-nowrap select-all">{item.command}</code>
</div>
<button
onClick={() => void copyCommand(item.id, item.command)}
class="shrink-0 rounded-md bg-surface p-2 text-slate-300 transition-colors hover:bg-slate-700 hover:text-white focus:outline-hidden focus:ring-0"
class="shrink-0 rounded-md bg-surface p-2 text-muted transition-colors hover:bg-surface-hover hover:text-base-content focus:outline-hidden focus:ring-0"
title={`${t('setup.welcome.copyCommandTitle')}: ${item.label}`}
>
<Show when={copiedCommand() === item.id} fallback={<Copy class="h-4 w-4" />}>
<Check class="h-4 w-4 text-emerald-400" />
<Check class="h-4 w-4 text-emerald-600 dark:text-emerald-400" />
</Show>
</button>
</div>
@@ -200,7 +200,7 @@ export const RunToolCallTrace: Component<RunToolCallTraceProps> = (props) => {
<Show when={call.input}>
<div>
<div class="text-[10px] font-medium text-muted mb-1">Input</div>
<pre class="text-[11px] font-mono bg-base rounded-sm p-2 max-h-32 overflow-auto whitespace-pre-wrap text-base-content">
<pre class="text-[11px] font-mono bg-page rounded-sm p-2 max-h-32 overflow-auto whitespace-pre-wrap text-base-content">
{truncate(call.input, 500)}
</pre>
</div>
@@ -208,7 +208,7 @@ export const RunToolCallTrace: Component<RunToolCallTraceProps> = (props) => {
<Show when={call.output}>
<div>
<div class="text-[10px] font-medium text-muted mb-1">Output</div>
<pre class="text-[11px] font-mono bg-base rounded-sm p-2 max-h-32 overflow-auto whitespace-pre-wrap text-base-content">
<pre class="text-[11px] font-mono bg-page rounded-sm p-2 max-h-32 overflow-auto whitespace-pre-wrap text-base-content">
{truncate(call.output, 500)}
</pre>
</div>
@@ -1,6 +1,6 @@
import { JSX, splitProps, mergeProps } from 'solid-js';
type Tone = 'default' | 'muted' | 'info' | 'success' | 'warning' | 'danger' | 'card' | 'glass';
type Tone = 'default' | 'muted' | 'info' | 'success' | 'warning' | 'danger' | 'card';
type Padding = 'none' | 'sm' | 'md' | 'lg';
export type CardProps = {
@@ -12,13 +12,12 @@ export type CardProps = {
const toneClassMap: Record<Tone, string> = {
default: 'bg-surface',
muted: 'bg-base',
muted: 'bg-surface-alt',
info: 'bg-blue-50 dark:bg-blue-900/25',
success: 'bg-emerald-50 dark:bg-emerald-900/25',
warning: 'bg-amber-50 dark:bg-amber-900/25',
danger: 'bg-red-50 dark:bg-red-900/25',
card: 'bg-surface',
glass: 'bg-base',
};
const paddingClassMap: Record<Padding, string> = {
@@ -39,7 +39,6 @@ export function CommandPaletteModal(props: CommandPaletteModalProps) {
onKeyDown={commandPalette.handleInputKeyDown}
placeholder="Type a command or search..."
class="w-full"
inputClass="bg-base"
clearOnFocusedEscape={false}
shortcutHint="Cmd+K"
role="combobox"
@@ -84,7 +83,7 @@ export function CommandPaletteModal(props: CommandPaletteModalProps) {
</Show>
</div>
<Show when={command.shortcut}>
<span class="rounded-sm border border-border-subtle bg-base px-2 py-1 text-[10px] font-medium text-base-content">
<span class="rounded-sm border border-border-subtle bg-page px-2 py-1 text-[10px] font-medium text-base-content">
{command.shortcut}
</span>
</Show>
@@ -34,7 +34,7 @@ export function EmptyState(props: EmptyStateProps) {
const containerClass = [
'flex w-full animate-fade-in flex-col',
variant === 'framed'
? 'rounded-md border border-dashed border-border bg-base px-6 py-10 sm:px-8 sm:py-16'
? 'rounded-md border border-dashed border-border px-6 py-10 sm:px-8 sm:py-16'
: 'px-4 py-8',
alignment === 'center' ? 'items-center text-center' : 'items-start text-left',
local.class ?? '',
@@ -39,7 +39,7 @@ const groupClassByVariant: Record<FilterButtonGroupVariant, string> = {
'inline-flex items-center gap-1 bg-surface-hover rounded-md p-0.5 ring-1 ring-border-subtle overflow-x-auto scrollbar-hide',
prominent: 'grid grid-cols-1 gap-2',
segmented:
'flex items-center gap-1 rounded-md border border-border bg-base p-1 shadow-inner overflow-x-auto scrollbar-hide',
'flex items-center gap-1 rounded-md border border-border bg-page p-1 shadow-inner overflow-x-auto scrollbar-hide',
};
const labelClassByVariant: Partial<Record<FilterButtonGroupVariant, string>> = {
@@ -15,7 +15,10 @@ interface AlertDeadManDestinationSectionProps {
const REDACTED_PING_URL = '***REDACTED***';
const statusPresentation: Record<DeadManStatus['state'], { label: string; class: string }> = {
disabled: { label: 'Not configured', class: 'bg-base text-muted' },
disabled: {
label: 'Not configured',
class: 'bg-surface text-muted ring-1 ring-inset ring-border',
},
starting: {
label: 'Starting',
class: 'bg-blue-100 text-blue-800 dark:bg-blue-900/25 dark:text-blue-100',
@@ -153,7 +156,7 @@ export function AlertDeadManDestinationSection(props: AlertDeadManDestinationSec
<Show when={status()}>
{(current) => (
<div class="grid gap-3 rounded-md border border-border bg-base p-3 text-xs sm:grid-cols-2 lg:grid-cols-4">
<div class="grid gap-3 rounded-md border border-border bg-page p-3 text-xs sm:grid-cols-2 lg:grid-cols-4">
<div>
<div class="font-medium text-muted">Last success</div>
<div class="mt-1 text-base-content">
+9
View File
@@ -97,6 +97,15 @@
}
}
/* The page backdrop as a background, for wells inside a surface card (code
blocks, previews, segmented-control tracks) that should read as the page
behind the card. It is a utility rather than a theme colour on purpose: a
colour named `base` also gave `text-base` a colour and painted text in the
page colour, and without that colour the old class rendered nothing. */
@utility bg-page {
background-color: var(--color-bg-base);
}
@utility animate-slideDown {
animation: slideDown 0.3s ease-out;
}