Merge light-glass-panels into dev
Queue, waveform-visualizer control deck, and privacy overlays now render as light translucent glass with legible dark text in light theme via a new theme-aware --deepdrft-panel-* token family; dark-glass charcoal unchanged in dark theme. Lifts the prior dark-glass exemption for these three panels.
This commit is contained in:
@@ -80,7 +80,7 @@ Keep this seam clean — it is the most architecturally load-bearing part of the
|
||||
- Dark mode toggles via cookie (`darkMode`, 365 days). Client-side via JS interop.
|
||||
- During server prerender, `DarkModeService` (in `DeepDrftPublic`) reads the cookie and seeds `DarkModeSettings.IsDarkMode`, which carries into WASM render via `PersistentComponentState`. Avoids "wrong theme flash" on initial paint.
|
||||
- `DarkModeSettings` lives in `DeepDrftPublic.Client.Common` (consumed by both server prerender and client components).
|
||||
- **Theme-aware token layer:** `DeepDrftShared.Client/wwwroot/styles/deepdrft-tokens.css` defines two kinds of CSS custom properties. *Source tokens* (`--deepdrft-navy`, `--deepdrft-white`, `--deepdrft-green-accent`, etc.) are brand constants — identical in `:root` and `.deepdrft-theme-dark`. *Theme-aware aliases* are defined in both blocks and flip when the theme wrapper class changes. Component and page CSS must bind the **alias**, not the source token, so neutral surfaces invert for free. Current alias families: `--deepdrft-page-surface`/`-text`/`-text-muted` (neutral page backgrounds and text), `--deepdrft-play-chip`/`-glyph`/`-chip-soft` (play-state icon chip and glyph), `--deepdrft-popover-surface` (default MudBlazor popover background — light: `color-mix(navy 4%, white)`, a near-page-background surface; dark: references source token `--deepdrft-popover-surface-dark`, a `color-mix(navy-mid 80%, green-accent 20%)` bluer navy defined once in `:root` and referenced by both the `.deepdrft-theme-dark` wrapper block and `body.deepdrft-theme-dark` so portaled popovers are reached). Bespoke dark-glass panels (visualizer/queue/privacy) bind `--deepdrft-panel-ground` directly and are intentionally exempt from the neutral-surface alias.
|
||||
- **Theme-aware token layer:** `DeepDrftShared.Client/wwwroot/styles/deepdrft-tokens.css` defines two kinds of CSS custom properties. *Source tokens* (`--deepdrft-navy`, `--deepdrft-white`, `--deepdrft-green-accent`, etc.) are brand constants — identical in `:root` and `.deepdrft-theme-dark`. *Theme-aware aliases* are defined in both blocks and flip when the theme wrapper class changes. Component and page CSS must bind the **alias**, not the source token, so neutral surfaces invert for free. Current alias families: `--deepdrft-page-surface`/`-text`/`-text-muted` (neutral page backgrounds and text), `--deepdrft-play-chip`/`-glyph`/`-chip-soft` (play-state icon chip and glyph), `--deepdrft-popover-surface` (default MudBlazor popover background — light: `color-mix(navy 4%, white)`, a near-page-background surface; dark: references source token `--deepdrft-popover-surface-dark`, a `color-mix(navy-mid 80%, green-accent 20%)` bluer navy defined once in `:root` and referenced by both the `.deepdrft-theme-dark` wrapper block and `body.deepdrft-theme-dark` so portaled popovers are reached). The bespoke glass panels (visualizer/queue/privacy) now bind their own theme-aware `--deepdrft-panel-surface`/`-text`/`-text-muted`/`-border`/`-row-hover` family: dark-glass charcoal (sourced from the `--deepdrft-panel-ground` constant) with light text in dark theme, and a light translucent glass with dark text in light theme. These tokens are re-declared in `body.deepdrft-theme-dark` because the panels are MudOverlay panels that portal to `<body>` (same portal scope as popovers); the `--deepdrft-panel-ground` source token is now consumed only via the dark `--deepdrft-panel-surface` value.
|
||||
- **Portaled-popover body-class bridge:** MudBlazor popovers portal to `<body>`, outside the `.deepdrft-theme-dark` wrapper `<div>`, so the dark popover token never reached them. Fix: `MainLayout.razor` stamps `deepdrft-theme-dark` on `<body>` via the `setBodyThemeClass(isDark)` helper in `DeepDrftShared.Client/Interop/theme/theme.ts` (lazy-imported as `_content/DeepDrftShared.Client/js/theme/theme.js`). The call fires only on first render or when `_isDarkMode` actually changes (gated by `_lastAppliedDarkMode` comparison) to avoid redundant JS calls on unrelated re-renders. The `body.deepdrft-theme-dark` selector in `deepdrft-tokens.css` resolves `--deepdrft-popover-surface` from `--deepdrft-popover-surface-dark` for these portaled elements.
|
||||
- Typography: Google Fonts (Bodoni Moda, Cormorant, DM Sans). Hand-rolled gas-lamp icon (lit/unlit) lives in `DeepDrftShared.Client/Common/DDIcons.cs`.
|
||||
|
||||
|
||||
@@ -424,11 +424,11 @@ h2, h3, h4, h5, h6,
|
||||
section labels are LIGHT (static). The slider track/thumb and the lamp toggles are green.
|
||||
============================================================================= */
|
||||
.waveform-visualizer-control-panel.mix-visualizer-controls-bar {
|
||||
/* Greyed panel ground — desaturated charcoal so the blue slider reads against it (defect #1).
|
||||
Token is tunable in deepdrft-tokens.css without touching this rule. */
|
||||
background: var(--deepdrft-panel-ground);
|
||||
/* Square corners + thin light border — NowPlayingCard chrome (§5). */
|
||||
border: 1px solid var(--deepdrft-border-light);
|
||||
/* Theme-aware glass ground — dark charcoal in dark theme, light translucent glass in light
|
||||
(so the deck reads against the light page). Tunable in deepdrft-tokens.css. */
|
||||
background: var(--deepdrft-panel-surface);
|
||||
/* Square corners + thin theme-aware border — NowPlayingCard chrome (§5). */
|
||||
border: 1px solid var(--deepdrft-panel-border);
|
||||
border-radius: 0;
|
||||
/* Optional backdrop blur — cheap on a small modal panel, nice over the visualizer (§5). */
|
||||
backdrop-filter: blur(8px);
|
||||
@@ -445,7 +445,7 @@ h2, h3, h4, h5, h6,
|
||||
--mud-palette-primary: var(--deepdrft-green-accent); /* knob arc/pointer + slider track/thumb (interactive) */
|
||||
--mud-palette-surface: var(--deepdrft-navy); /* knob center fill — darkest navy reads against the panel */
|
||||
--mud-palette-surface-variant: var(--deepdrft-muted); /* knob background track — muted-navy filler */
|
||||
--mud-palette-text-primary: var(--deepdrft-white); /* knob value label — light */
|
||||
--mud-palette-text-primary: var(--deepdrft-panel-text); /* knob value label — flips dark on light glass */
|
||||
}
|
||||
|
||||
/* ── Row layout (§3). Each row is a horizontal band. Row 1 (MODE) and row 3 (WAVE) use
|
||||
@@ -486,13 +486,13 @@ h2, h3, h4, h5, h6,
|
||||
}
|
||||
|
||||
/* ── Section label "LAVA:" / "WAVE:" (§3, §5). NowPlayingCard .np-label TYPOGRAPHY (mono, uppercase,
|
||||
tracked), recoloured LIGHT — labels are static, so light by the colour principle (§5, §10.3). ── */
|
||||
tracked), coloured via --deepdrft-panel-text — theme-aware (navy in light, off-white in dark). ── */
|
||||
.waveform-visualizer-control-panel .wvc-section-label {
|
||||
font-family: var(--deepdrft-font-mono);
|
||||
font-size: 0.6rem;
|
||||
letter-spacing: 0.25em;
|
||||
text-transform: uppercase;
|
||||
color: var(--deepdrft-white);
|
||||
color: var(--deepdrft-panel-text);
|
||||
align-self: center;
|
||||
flex: 0 0 auto;
|
||||
opacity: 0.85;
|
||||
@@ -520,10 +520,11 @@ h2, h3, h4, h5, h6,
|
||||
opacity: 0.38;
|
||||
}
|
||||
|
||||
/* Caption icons render LIGHT (§5/§9: static/decorative = light). !important beats the scoped
|
||||
.mix-visualizer-control ::deep .mix-visualizer-control-icon rule (which sets green for the legacy
|
||||
inline mount) when the icon also carries mix-visualizer-control-icon. Lamp toggles are MudIconButton
|
||||
not MudIcon so they are unaffected — they stay green (interactive, Color.Primary). (defect #3) */
|
||||
/* Caption icons inherit the portaled panel's body text — theme-aware (dark text on light glass,
|
||||
off-white on dark glass). !important beats the scoped .mix-visualizer-control ::deep
|
||||
.mix-visualizer-control-icon rule (which sets green for the legacy inline mount) when the icon also
|
||||
carries mix-visualizer-control-icon. Lamp toggles are MudIconButton not MudIcon so they are
|
||||
unaffected — they stay green (interactive, Color.Primary). (defect #3) */
|
||||
.waveform-visualizer-control-panel .waveform-visualizer-control-icon {
|
||||
opacity: 0.85;
|
||||
translate: 0 -1rem;
|
||||
@@ -838,8 +839,8 @@ body:has(.deepdrft-queue-overlay) {
|
||||
width: min(90vw, 520px);
|
||||
height: min(90vw, 520px);
|
||||
max-height: 90vh;
|
||||
background: var(--deepdrft-panel-ground);
|
||||
border: 1px solid var(--deepdrft-border-light);
|
||||
background: var(--deepdrft-panel-surface);
|
||||
border: 1px solid var(--deepdrft-panel-border);
|
||||
border-radius: 0;
|
||||
backdrop-filter: blur(8px);
|
||||
overflow: hidden;
|
||||
@@ -850,16 +851,16 @@ body:has(.deepdrft-queue-overlay) {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.85rem 1rem;
|
||||
border-bottom: 1px solid var(--deepdrft-border-light);
|
||||
border-bottom: 1px solid var(--deepdrft-panel-border);
|
||||
}
|
||||
|
||||
/* Mono uppercase eyebrow — the NowPlayingCard .np-label typography, recoloured light (static). */
|
||||
/* Mono uppercase eyebrow — the NowPlayingCard .np-label typography, theme-aware (static). */
|
||||
.deepdrft-queue-modal-title {
|
||||
font-family: var(--deepdrft-font-mono);
|
||||
font-size: 0.72rem;
|
||||
letter-spacing: 0.2em;
|
||||
text-transform: uppercase;
|
||||
color: var(--deepdrft-white);
|
||||
color: var(--deepdrft-panel-text);
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
@@ -887,12 +888,12 @@ body:has(.deepdrft-queue-overlay) {
|
||||
gap: 0.6rem;
|
||||
padding: 0.45rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
color: var(--deepdrft-white);
|
||||
color: var(--deepdrft-panel-text);
|
||||
transition: background 0.15s ease;
|
||||
}
|
||||
|
||||
.deepdrft-queue-row:hover {
|
||||
background: color-mix(in srgb, var(--deepdrft-white) 6%, transparent);
|
||||
background: var(--deepdrft-panel-row-hover);
|
||||
}
|
||||
|
||||
/* Current track: a subtle green wash + left accent, matching the green = active principle. */
|
||||
@@ -910,7 +911,7 @@ body:has(.deepdrft-queue-overlay) {
|
||||
.deepdrft-queue-position {
|
||||
font-family: var(--deepdrft-font-mono);
|
||||
font-size: 0.72rem;
|
||||
opacity: 0.6;
|
||||
color: var(--deepdrft-panel-text-muted);
|
||||
min-width: 1.4rem;
|
||||
text-align: right;
|
||||
flex: 0 0 auto;
|
||||
@@ -935,7 +936,7 @@ body:has(.deepdrft-queue-overlay) {
|
||||
|
||||
.deepdrft-queue-artist {
|
||||
font-size: 0.74rem;
|
||||
opacity: 0.6;
|
||||
color: var(--deepdrft-panel-text-muted);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@@ -997,8 +998,8 @@ body:has(.deepdrft-privacy-overlay) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: min(90vw, 480px);
|
||||
background: var(--deepdrft-panel-ground);
|
||||
border: 1px solid var(--deepdrft-border-light);
|
||||
background: var(--deepdrft-panel-surface);
|
||||
border: 1px solid var(--deepdrft-panel-border);
|
||||
border-radius: 0;
|
||||
backdrop-filter: blur(8px);
|
||||
overflow: hidden;
|
||||
@@ -1009,7 +1010,7 @@ body:has(.deepdrft-privacy-overlay) {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.85rem 0.85rem 0.85rem 1rem;
|
||||
border-bottom: 1px solid var(--deepdrft-border-light);
|
||||
border-bottom: 1px solid var(--deepdrft-panel-border);
|
||||
}
|
||||
|
||||
/* Mono uppercase eyebrow — matches queue modal title. */
|
||||
@@ -1018,27 +1019,28 @@ body:has(.deepdrft-privacy-overlay) {
|
||||
font-size: 0.72rem;
|
||||
letter-spacing: 0.2em;
|
||||
text-transform: uppercase;
|
||||
color: var(--deepdrft-white);
|
||||
color: var(--deepdrft-panel-text);
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
/* Tuck the close icon flush with the panel edge; keep it subtle. */
|
||||
.deepdrft-privacy-modal-close {
|
||||
opacity: 0.6;
|
||||
color: var(--deepdrft-white) !important;
|
||||
color: var(--deepdrft-panel-text) !important;
|
||||
}
|
||||
|
||||
.deepdrft-privacy-modal-close:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Privacy copy: same mono treatment as the former inline paragraph, but readable on dark ground. */
|
||||
/* Privacy copy: same mono treatment as the former inline paragraph; theme-aware text colour
|
||||
so it stays legible on both the dark-glass (dark) and light-glass (light) panel surfaces. */
|
||||
.deepdrft-privacy-modal-body {
|
||||
font-family: var(--deepdrft-font-mono);
|
||||
font-size: 0.72rem;
|
||||
letter-spacing: 0.06em;
|
||||
line-height: 1.7;
|
||||
color: var(--deepdrft-white);
|
||||
color: var(--deepdrft-panel-text);
|
||||
opacity: 0.8;
|
||||
margin: 0;
|
||||
padding: 1rem 1rem 1.25rem;
|
||||
|
||||
@@ -28,9 +28,24 @@
|
||||
(Phase 15 §4/§10.5). Mild so the panel reads as modal without a blackout. Change here once. */
|
||||
--deepdrft-modal-scrim-alpha: 0.15;
|
||||
/* Panel ground — muted, desaturated charcoal beneath the controls panel.
|
||||
Tunable: increase blue channel (e.g. #1e2235) to recover warmth, lower (e.g. #191b20) to go darker. */
|
||||
Tunable: increase blue channel (e.g. #1e2235) to recover warmth, lower (e.g. #191b20) to go darker.
|
||||
Source token; consumed by the theme-aware --deepdrft-panel-surface dark value below. */
|
||||
--deepdrft-panel-ground: #1a1c22;
|
||||
|
||||
/* Glass-panel family — the bespoke overlay panels (queue / visualizer control deck / privacy).
|
||||
Light values here make these panels a light translucent glass with dark text so they read
|
||||
coherently against the light page; the .deepdrft-theme-dark block below reproduces today's
|
||||
dark-glass charcoal exactly so dark mode is visually unchanged. Surface keeps the glassmorphic
|
||||
translucency (paired with backdrop-blur in the consuming rules).
|
||||
Light surface: near-page-surface white at 82% so the backdrop blur still shows through;
|
||||
text/border are navy-based for legibility on the light glass. */
|
||||
--deepdrft-panel-surface: rgba(250, 250, 248, 0.82);
|
||||
--deepdrft-panel-text: var(--deepdrft-navy);
|
||||
--deepdrft-panel-text-muted: var(--deepdrft-muted);
|
||||
--deepdrft-panel-border: var(--deepdrft-border);
|
||||
/* Row/hover wash on the panel surface — a navy tint on light, a white tint on dark (below). */
|
||||
--deepdrft-panel-row-hover: color-mix(in srgb, var(--deepdrft-navy) 8%, transparent);
|
||||
|
||||
/* Wireframe font stack */
|
||||
--deepdrft-font-display: "Cormorant Garamond", Georgia, serif;
|
||||
--deepdrft-font-mono: "Geist Mono", monospace;
|
||||
@@ -90,8 +105,9 @@
|
||||
bluer navy (colour-mix of navy-mid + green-accent at 20%), defined once in
|
||||
--deepdrft-popover-surface-dark below and referenced by both the .deepdrft-theme-dark
|
||||
wrapper block and the body.deepdrft-theme-dark block so portaled popover content (which
|
||||
portals to <body>, outside the wrapper div) is also reached. Bespoke dark-glass panels
|
||||
(visualizer/queue/privacy) do NOT bind this — they keep --deepdrft-panel-ground. */
|
||||
portals to <body>, outside the wrapper div) is also reached. The bespoke glass panels
|
||||
(visualizer/queue/privacy) do NOT bind this — they have their own theme-aware
|
||||
--deepdrft-panel-* family (dark glass in dark theme, light glass in light). */
|
||||
--deepdrft-popover-surface-dark: color-mix(in srgb, var(--deepdrft-navy-mid) 80%, var(--deepdrft-green-accent) 20%);
|
||||
--deepdrft-popover-surface: color-mix(in srgb, var(--deepdrft-navy) 4%, var(--deepdrft-white));
|
||||
|
||||
@@ -172,6 +188,16 @@
|
||||
non-portaled elements only (drawers, inline menus). Portaled MudBlazor popovers live at
|
||||
<body> level; the body.deepdrft-theme-dark block below uses the same source token. */
|
||||
--deepdrft-popover-surface: var(--deepdrft-popover-surface-dark);
|
||||
|
||||
/* Glass-panel family (dark) — reproduces today's dark-glass chrome EXACTLY. Surface is the
|
||||
opaque charcoal ground the panels used directly before tokenisation; text is off-white;
|
||||
border is the thin light-on-dark hairline (NowPlayingCard spirit); row hover is the prior
|
||||
white 6% wash. Dark mode must look unchanged. */
|
||||
--deepdrft-panel-surface: var(--deepdrft-panel-ground);
|
||||
--deepdrft-panel-text: var(--deepdrft-white);
|
||||
--deepdrft-panel-text-muted: color-mix(in srgb, var(--deepdrft-white) 60%, transparent);
|
||||
--deepdrft-panel-border: var(--deepdrft-border-light);
|
||||
--deepdrft-panel-row-hover: color-mix(in srgb, var(--deepdrft-white) 6%, transparent);
|
||||
}
|
||||
|
||||
/* Portal-scope dark popover surface. MudBlazor popovers (selects, menus, share body) portal
|
||||
@@ -181,4 +207,14 @@
|
||||
(navy-mid + 20% green-accent tint) rather than the pure charcoal #162437. */
|
||||
body.deepdrft-theme-dark {
|
||||
--deepdrft-popover-surface: var(--deepdrft-popover-surface-dark);
|
||||
|
||||
/* The bespoke glass panels (queue / visualizer / privacy) are MudOverlay panels that portal to
|
||||
<body>, outside the .deepdrft-theme-dark wrapper div — same portal scope as popovers. Re-declare
|
||||
the dark glass-panel family here so the panels resolve the dark (charcoal) values; without this
|
||||
they would fall through to the light :root values while the page is in dark mode. */
|
||||
--deepdrft-panel-surface: var(--deepdrft-panel-ground);
|
||||
--deepdrft-panel-text: var(--deepdrft-white);
|
||||
--deepdrft-panel-text-muted: color-mix(in srgb, var(--deepdrft-white) 60%, transparent);
|
||||
--deepdrft-panel-border: var(--deepdrft-border-light);
|
||||
--deepdrft-panel-row-hover: color-mix(in srgb, var(--deepdrft-white) 6%, transparent);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user