From 4b0f537508a9282ff387fff9f45abfbfc595dceb Mon Sep 17 00:00:00 2001 From: Mikhail Yenuchenko Date: Thu, 6 Aug 2026 16:57:05 +0300 Subject: [PATCH] =?UTF-8?q?style:=20GUI=20polish=20=E2=80=94=20visibility-?= =?UTF-8?q?aware=20polling,=20CSS=20vars=20for=20dark=20mode=20(code-revie?= =?UTF-8?q?w.md=20=C2=A7=20Phase=202)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - panel.js: skip HTMX polling requests while the tab is hidden, via htmx:beforeRequest rather than htmx's eval-based trigger filter (the panel's CSP allows no unsafe-eval). - panel.css: replace all dark-mode !important overrides with CSS custom properties reassigned once under prefers-color-scheme: dark. - panel.css: consolidate the duplicate main{max-width} rule. Co-Authored-By: Claude Sonnet 5 --- internal/web/static/panel.css | 150 ++++++++++++++++++---------------- internal/web/static/panel.js | 16 ++++ 2 files changed, 94 insertions(+), 72 deletions(-) diff --git a/internal/web/static/panel.css b/internal/web/static/panel.css index faf651d..206d15b 100644 --- a/internal/web/static/panel.css +++ b/internal/web/static/panel.css @@ -4,18 +4,57 @@ added here must therefore stay here: an inline style="..." attribute in a template is blocked by that policy and silently does nothing. */ -:root { color-scheme: light dark; } +/* Colour tokens. Light values live on :root; the dark media query below + reassigns the same names rather than re-declaring every rule that uses + them, so a rule needs !important nowhere in this file — the custom + property already carries the right value for the active scheme. */ +:root { + color-scheme: light dark; + --bg: #f6f7f9; --fg: #1b1f24; + --card-bg: #fff; + --border: #e2e5e9; /* dividers: card, table, app, nav, code, encrypt-fields */ + --control-border: #cfd4da; /* input, select, textarea, action buttons */ + --input-bg: #fff; + --code-bg: #f0f2f4; + --surface-bg: #eef1f5; --surface-bg-hover: #e2e7ee; --surface-open-bg: #dde3ec; + --nav-active-bg: #e6ebf5; + --flash-bg: #ecfdf3; --flash-border: #abefc6; --flash-fg: #067647; + --credential-bg: #fffbeb; --credential-border: #f5c518; + --danger-bg: #fef3f2; --danger-border: #fecdca; --danger-fg: #b42318; --danger-bg-hover: #fee4e2; + --st-ok-bg: #ecfdf3; --st-ok-fg: #067647; --st-ok-border: #abefc6; + --st-warn-bg: #fffaeb; --st-warn-fg: #b54708; --st-warn-border: #fedf89; + --st-error-bg: #fef3f2; --st-error-fg: #b42318; --st-error-border: #fecdca; + --st-unknown-bg: #f0f2f4; --st-unknown-fg: #6b7280; --st-unknown-border: #e2e5e9; +} +@media (prefers-color-scheme: dark) { + :root { + --bg: #14171a; --fg: #e6e8eb; + --card-bg: #1d2125; + --border: #2b3138; + --control-border: #2b3138; + --input-bg: #14171a; + --code-bg: #14171a; + --surface-bg: #22262b; --surface-bg-hover: #2b3138; --surface-open-bg: #313841; + --nav-active-bg: #22303f; + --flash-bg: #0d2818; --flash-border: #1a5336; --flash-fg: #75d99b; + --credential-bg: #2a2408; --credential-border: #6b5a10; + --danger-bg: #2d1211; --danger-border: #6b201a; --danger-fg: #f5a29b; --danger-bg-hover: #3d1a18; + --st-ok-bg: #0d2818; --st-ok-fg: #75d99b; --st-ok-border: #1a5336; + --st-warn-bg: #2e2308; --st-warn-fg: #f5c86b; --st-warn-border: #6b5210; + --st-error-bg: #2d1211; --st-error-fg: #f5a29b; --st-error-border: #6b201a; + --st-unknown-bg: #22262b; --st-unknown-fg: #9aa3ad; --st-unknown-border: #2b3138; + } +} * { box-sizing: border-box; } body { font: 15px/1.5 system-ui, -apple-system, Segoe UI, Roboto, sans-serif; - margin: 0; padding: 2rem 1rem; background: #f6f7f9; color: #1b1f24; + margin: 0; padding: 2rem 1rem; background: var(--bg); color: var(--fg); } -@media (prefers-color-scheme: dark) { - body { background: #14171a; color: #e6e8eb; } - .card { background: #1d2125 !important; border-color: #2b3138 !important; } - input { background: #14171a !important; color: inherit !important; border-color: #2b3138 !important; } -} -main { max-width: 42rem; margin: 0 auto; } +/* 48rem is a reading measure: right for the forms and prose that make up most + of the panel, and the width the navigation bar's two rows were sized for. + Page-specific overrides below widen or narrow it for the pages that need + something else. */ +main { max-width: 48rem; margin: 0 auto; } h1 { font-size: 1.4rem; margin: 0 0 1rem; } /* The full mark, on the two pages that have no navigation bar to carry the compact one. It takes the column's width so its edges line up with the card @@ -25,14 +64,14 @@ h1 { font-size: 1.4rem; margin: 0 0 1rem; } once the body's padding is taken off. */ .mark { display: block; width: 100%; max-width: 24rem; height: auto; margin-bottom: 1.4rem; } .card { - background: #fff; border: 1px solid #e2e5e9; border-radius: 10px; + background: var(--card-bg); border: 1px solid var(--border); border-radius: 10px; padding: 1.5rem; margin: 0 auto; } .card.narrow { max-width: 24rem; } label { display: block; font-weight: 600; margin: 0.9rem 0 0.3rem; } input { width: 100%; padding: 0.55rem 0.7rem; font-size: 1rem; - border: 1px solid #cfd4da; border-radius: 6px; background: #fff; + border: 1px solid var(--control-border); border-radius: 6px; background: var(--input-bg); color: inherit; } /* One vocabulary for actions. Anything that performs an action looks like a button: a