From 12f1e93c4ab0d192481b05ab88660856837272eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Sun, 16 Aug 2026 23:22:41 +0000 Subject: [PATCH] panels are a themed surface, not three literal rgba pairs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cornerstone of the layout was the least themeable thing in it. Measured before touching anything, which is the only reason this is the right fix: duck-dark radius=8px bg=rgba(255,255,255,0.12) border=rgba(0,0,0,0.25) blur=24px plain radius=0px bg=rgba(255,255,255,0.12) border=rgba(0,0,0,0.25) blur=24px So the RADIUS was already following `--radius` and I had been telling the owner otherwise — the rounding in the Plain screenshot was something else. What did not follow anything was the surface: three literal rgba pairs and a fixed `backdrop-blur-xl` in the component. Now: plain radius=0px bg=rgb(255,255,255) border=rgb(0,0,0) blur=0px Two distinctions the old code drew in literals are kept as tokens rather than flattened, because both are real and a theme should be able to revisit them. `--panel-raised-*` is the fullscreen surface: DENSER glass, not darker, because panel chrome is dark text and a heavy dark fill hid every icon. `--panel-border-bare` is for a panel with no header, which has nothing else separating it from what it sits on. `--panel-blur` earns its place beyond theming: a flat theme was paying for a 24px backdrop blur it did not want, and on a solid panel the compositor does that work for nothing. ── A near miss worth recording ── The first attempt silently changed nothing. The patch matched on four spaces of indentation where the file has two, `str.replace` reported no error, the build succeeded, and `panel-blur` DID apply — so the class landed while the surface did not. It looked like a partial success and would have shipped as one. Caught by measuring computed styles again rather than trusting the edit; the fix now asserts the replacement changed the file. 950 pass / 7 fail unchanged. Co-Authored-By: Claude Opus 5 --- .../src/components/Workspace/PanelSlot.tsx | 13 ++++++++----- src/workspaces/theme/css/chrome.css | 6 ++++++ src/workspaces/theme/css/themes/duck-dark.css | 8 ++++++-- src/workspaces/theme/css/themes/duck-light.css | 8 +++++++- src/workspaces/theme/css/themes/plain.css | 4 ++++ 5 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/workspaces/officerdev/src/components/Workspace/PanelSlot.tsx b/src/workspaces/officerdev/src/components/Workspace/PanelSlot.tsx index c45cd433..79bce366 100644 --- a/src/workspaces/officerdev/src/components/Workspace/PanelSlot.tsx +++ b/src/workspaces/officerdev/src/components/Workspace/PanelSlot.tsx @@ -546,10 +546,13 @@ export const PanelSlot = ({ // control — is black throughout, so the old near-opaque dark fill left every one of them unreadable. // This is the nav Header's exact recipe (`rgba(255,255,255,0.25)` over a 0.35 border), which is the // app's established "raised above the rest" surface and is already proven to carry black text. - const fullscreenStyle = { backgroundColor: 'rgba(255, 255, 255, 0.25)', borderColor: 'rgba(255, 255, 255, 0.35)' }; + // Fullscreen is DENSER glass, not darker: panel chrome is dark text throughout, and a heavy dark fill + // made every icon unreadable. A panel with no header takes a harder edge, having nothing else to + // separate it from what it sits on. Both were literal rgba pairs and are now the theme's to decide. + const fullscreenStyle = { backgroundColor: 'var(--panel-raised-bg)', borderColor: 'var(--panel-raised-border)' }; const normalStyle = noHeader - ? { backgroundColor: 'rgba(255, 255, 255, 0.12)', borderColor: 'rgba(0, 0, 0, 0.25)' } - : { backgroundColor: 'rgba(255, 255, 255, 0.12)', borderColor: 'rgba(255, 255, 255, 0.2)' }; + ? { backgroundColor: 'var(--panel-bg)', borderColor: 'var(--panel-border-bare)' } + : { backgroundColor: 'var(--panel-bg)', borderColor: 'var(--panel-border)' }; const panelStyle = { ...(isFullscreen ? fullscreenStyle : normalStyle), ...(transitioningPanelId === panel.id ? { viewTransitionName: `panel-${panel.id}` } : {}), @@ -560,8 +563,8 @@ export const PanelSlot = ({
diff --git a/src/workspaces/theme/css/chrome.css b/src/workspaces/theme/css/chrome.css index 2948a0b8..9dee830f 100644 --- a/src/workspaces/theme/css/chrome.css +++ b/src/workspaces/theme/css/chrome.css @@ -83,3 +83,9 @@ .header-ink-border { border-color: color-mix(in srgb, var(--header-fg) 40%, transparent); } + +/* Panel glass. `backdrop-blur-xl` was a fixed 24px, so a flat theme still paid for a blur it did not want — + and on a solid panel the browser composites it for nothing. */ +.panel-blur { + backdrop-filter: blur(var(--panel-blur)); +} diff --git a/src/workspaces/theme/css/themes/duck-dark.css b/src/workspaces/theme/css/themes/duck-dark.css index 31626edf..30d59d75 100644 --- a/src/workspaces/theme/css/themes/duck-dark.css +++ b/src/workspaces/theme/css/themes/duck-dark.css @@ -67,8 +67,12 @@ --glass-bg: rgba(0, 0, 0, 0.2); --glass-border: rgba(255, 255, 255, 0.1); - --panel-bg: rgba(0, 0, 0, 0.2); - --panel-border: rgba(255, 255, 255, 0.1); + --panel-bg: rgba(255, 255, 255, 0.12); + --panel-border: rgba(255, 255, 255, 0.2); + --panel-border-bare: rgba(0, 0, 0, 0.25); + --panel-raised-bg: rgba(255, 255, 255, 0.25); + --panel-raised-border: rgba(255, 255, 255, 0.35); + --panel-blur: 24px; --panel-radius: 0.75rem; --panel-header-bg: rgba(0, 0, 0, 0.15); --panel-header-fg: hsl(var(--foreground)); diff --git a/src/workspaces/theme/css/themes/duck-light.css b/src/workspaces/theme/css/themes/duck-light.css index 4577d0b1..3cf8b288 100644 --- a/src/workspaces/theme/css/themes/duck-light.css +++ b/src/workspaces/theme/css/themes/duck-light.css @@ -72,8 +72,14 @@ --glass-bg: rgba(255, 255, 255, 0.1); --glass-border: rgba(255, 255, 255, 0.2); - --panel-bg: rgba(255, 255, 255, 0.1); + --panel-bg: rgba(255, 255, 255, 0.12); --panel-border: rgba(255, 255, 255, 0.2); + /* A panel with no header has nothing to separate it from what it sits on, so it takes a harder edge. */ + --panel-border-bare: rgba(0, 0, 0, 0.25); + /* Fullscreen is DENSER glass, not darker: panel chrome is dark text, and a heavy dark fill hid it. */ + --panel-raised-bg: rgba(255, 255, 255, 0.25); + --panel-raised-border: rgba(255, 255, 255, 0.35); + --panel-blur: 24px; --panel-radius: 0.75rem; --panel-header-bg: rgba(0, 0, 0, 0.05); --panel-header-fg: hsl(var(--foreground)); diff --git a/src/workspaces/theme/css/themes/plain.css b/src/workspaces/theme/css/themes/plain.css index 680ae117..4232848b 100644 --- a/src/workspaces/theme/css/themes/plain.css +++ b/src/workspaces/theme/css/themes/plain.css @@ -72,6 +72,10 @@ --panel-bg: #ffffff; --panel-border: #000000; + --panel-border-bare: #000000; + --panel-raised-bg: #ffffff; + --panel-raised-border: #000000; + --panel-blur: 0px; --panel-radius: 0; --panel-header-bg: #f2f2f2; --panel-header-fg: #000000;