docs(phase-10): spec Mix detail hero+meta overlay mirroring Sessions (shared ReleaseHeroOverlay recommended)
This commit is contained in:
@@ -0,0 +1,381 @@
|
||||
# Mix Detail — Hero + MetaContent overlay rework (mirror the Sessions hero) — Design Spec
|
||||
|
||||
Status: **design-complete, implementation-ready.** Author: product-designer. Date: 2026-06-16.
|
||||
**No code has been written by this doc.**
|
||||
|
||||
## 0. Goal
|
||||
|
||||
Rework the **Mix detail** Hero + MetaContent so the **cover art becomes a background image** with **all
|
||||
metadata laid out on top of it**, inside a **max-medium square cover-art region** — mirroring the
|
||||
already-shipped **Session detail** hero-overlay composition. This consolidates the masthead + cover +
|
||||
meta into one overlaid block, frees vertical room for the lava-lamp visualizer behind the content, and
|
||||
cleans up the aesthetic so the Mix page reads as a member of the same design family as Sessions.
|
||||
|
||||
The Mix visualizer + seven-knob controls layout landed in the Phase 10 reframe (`TopRowCenter` slot,
|
||||
in-flow controls container between the back link and the lava-lamp) **must be preserved unchanged** —
|
||||
this rework touches only what sits *below* that top row.
|
||||
|
||||
---
|
||||
|
||||
## 1. What is actually shipped today (confirmed from live source, not spec)
|
||||
|
||||
Read of the live tree on 2026-06-16:
|
||||
|
||||
**Session detail** (`Pages/SessionDetail.razor` + `.razor.css`) — the target aesthetic, **already shipped**:
|
||||
|
||||
- **Does NOT use `ReleaseDetailScaffold`.** It composes its own hero overlay directly inside a
|
||||
`MudContainer MaxWidth="Large"`, and wires `PlayTrack` in its own `@code` block (the scaffold's
|
||||
play-toggle logic is duplicated here deliberately — see `SessionDetail.razor` lines 131–145).
|
||||
- Structure: a `.session-hero` positioning context (`position: relative; aspect-ratio: 16/10;
|
||||
max-height: 70vh; min-height: 420px; overflow: hidden; border-radius: 8px`) holding:
|
||||
- `.session-hero-img` — a `MudPaper` whose `background-image` is the hero/cover image
|
||||
(`background-size: cover`), or a `.session-hero-placeholder` when none.
|
||||
- `.session-hero-shim` — a plain `<div>` darkening gradient (stronger top + bottom) for overlay legibility.
|
||||
- `.session-hero-top` — absolutely-positioned overlay row: genre chip + release-date + `SharePopover`.
|
||||
- `.session-hero-bottom` — absolutely-positioned overlay row: optional cover thumbnail + title/artist +
|
||||
`PlayStateIcon`.
|
||||
- The back link (`.deepdrft-track-detail-back`) sits **above** the hero, in normal flow.
|
||||
- CSS uses `::deep` on every class that lands on a MudBlazor child component's native output
|
||||
(`.session-hero-img` on `MudPaper`, `.session-overlay-chip.mud-chip` on `MudChip`,
|
||||
`.session-hero-bottom-row` on `MudStack`, the play/share icon-color overrides on `MudIconButton`).
|
||||
|
||||
**Mix detail** (`Pages/MixDetail.razor` + `.razor.css`) — the page to rework, **uses the scaffold**:
|
||||
|
||||
- `<MixWaveformVisualizer>` paints a fixed full-viewport backdrop (`z-index: 0`); a
|
||||
`.mix-detail-foreground` wrapper (`z-index: 1`) lifts the content above it; inside a
|
||||
`MudContainer MaxWidth="Large"` (class `mix-detail-container`) sits a `<ReleaseDetailScaffold>`.
|
||||
- The scaffold's **`TopRowCenter`** slot holds `<MixVisualizerControls>`; **`TopRightAction`** holds the
|
||||
lava-lamp `MudIconButton` (the Phase 10 reframe layout — **do not touch**).
|
||||
- The scaffold's **`Hero`** slot today is a `.mix-detail-cover` (square, `max-width: 220px`, centered)
|
||||
holding a `MudPaper` cover-art / placeholder. The **`MetaContent`** slot holds genre chip + release
|
||||
date. The masthead (title + artist) is rendered by the scaffold's **default header region** above the
|
||||
hero. The `BodyContent` slot holds the share row.
|
||||
|
||||
**The scaffold** (`Controls/ReleaseDetailScaffold.razor` + `.razor.cs`) — the shared chrome:
|
||||
|
||||
- Vertical order: top row (back | `TopRowCenter` | `TopRightAction`) → `TopContent` → header
|
||||
(masthead + play, or a custom `Header`) → `Hero` → divider + `MetaContent` (gated by `ShowMeta`) →
|
||||
`BodyContent` → default track-keyed share row (gated by `ShowShareRow`).
|
||||
- Owns the back link and the play-toggle wiring. Cut and Track also consume it; Session does **not**.
|
||||
|
||||
**Render boundary (both detail pages are identical here — confirmed):** both `SessionDetail` and
|
||||
`MixDetail` derive from `ReleaseDetailBase`, run under `InteractiveAuto`, and bridge the prerendered
|
||||
release+track across the prerender→WASM seam via `PersistentComponentState` (keyed `session-detail` /
|
||||
`mix-detail`). The release DTO (title, artist, genre, release date, `ImagePath`) is **available at first
|
||||
render in both passes** — there is no render-mode divergence to design around. The image is served from
|
||||
`api/image/{EscapeDataString(key)}` in both pages. **Conclusion: the data read at render time is the
|
||||
same shape and same timing for both; the overlay rework is purely presentational.**
|
||||
|
||||
---
|
||||
|
||||
## 2. The DRY/SOLID question — where is the source of truth?
|
||||
|
||||
This is the load-bearing decision. The brief asks: extract a shared hero-overlay shell that both Sessions
|
||||
and Mixes consume, or per-page duplication?
|
||||
|
||||
### The honest finding: the two pages are structurally divergent *by design today*
|
||||
|
||||
Sessions **deliberately does not use the scaffold** — it forks the whole chrome to get the overlay
|
||||
composition. Mixes **does use the scaffold**, and the scaffold's `Hero`/`MetaContent`/masthead are
|
||||
*separate stacked regions*, which is the opposite of "everything overlaid on the cover." So the two
|
||||
pages do not share a hero today, and the scaffold's stacked-region model is not the overlay model.
|
||||
|
||||
Three meaningfully different directions, in shape:
|
||||
|
||||
**Direction A — Per-page copy.** Inline the `.session-hero` overlay structure into `MixDetail.razor`,
|
||||
copy the `.session-*` CSS into `MixDetail.razor.css` (renamed `.mix-hero-*`), tune the square/medium
|
||||
sizing. No shared component.
|
||||
- *Pro:* fastest; zero risk to Sessions; Mix can diverge freely (it has a visualizer behind it that
|
||||
Sessions does not).
|
||||
- *Con:* **two copies of the overlay cascade to keep in sync** — exactly the drift the `track-view-css-
|
||||
consolidation` note spent a pass undoing. The shim gradient, the overlay-label typography, the
|
||||
`::deep` icon-color overrides, the responsive wrap rules all get duplicated. A future overlay tweak
|
||||
has to land twice. Violates the "one source, multiple views" instinct (Daniel's standing preference).
|
||||
|
||||
**Direction B — Extract a shared `ReleaseHeroOverlay` component, both pages consume it.** Pull the
|
||||
`.session-hero` overlay (image/placeholder + shim + top overlay + bottom overlay) into a new
|
||||
`Controls/ReleaseHeroOverlay.razor` that takes the release data (+ optional play affordance + optional
|
||||
share slot + optional cover-thumb) and renders the overlaid hero. Sessions swaps its inline hero for the
|
||||
component; Mix renders the component inside its `.mix-detail-foreground`, **bypassing the scaffold's
|
||||
`Hero`/`MetaContent`/masthead regions** (Mix stops using the scaffold for the hero, same as Sessions
|
||||
already does).
|
||||
- *Pro:* **one source of truth for the overlay** — the headline DRY win. Honors "same data shape,
|
||||
different rendering": both pages feed the same release DTO into one overlay VM/parameter set, the
|
||||
divergence (visualizer backdrop, square-vs-wide aspect) rides parameters/CSS, not a second copy.
|
||||
SOLID: the overlay is a single-responsibility presentational component; the pages compose it.
|
||||
- *Con:* touches the **already-shipped Sessions page** (regression surface on a working view) and means
|
||||
Mix no longer routes its hero through the scaffold — Mix keeps the scaffold only for the back/controls
|
||||
top row, or drops the scaffold entirely (see §4 sub-decision). More upfront work; a real refactor.
|
||||
|
||||
**Direction C — Teach the scaffold an overlay mode.** Add an overlay-hero capability to
|
||||
`ReleaseDetailScaffold` so it can render its `Hero`/masthead/`MetaContent` as one overlaid block when a
|
||||
flag/slot says so; migrate Sessions onto the scaffold in overlay mode and switch Mix to overlay mode.
|
||||
- *Pro:* one component owns *all* detail chrome including the overlay; Sessions finally joins the scaffold.
|
||||
- *Con:* **largest blast radius and worst SOLID.** It bloats the scaffold with a second layout
|
||||
personality (stacked-regions *and* overlaid-hero) gated by a flag — exactly the "variance rides a
|
||||
flag" anti-pattern the scaffold's own convention forbids (Phase 9 §5.3: "layout variance rides a
|
||||
slot, never a boolean"). It also drags the working Sessions page through a chrome migration for no
|
||||
user-visible gain. Over-engineered for a two-consumer overlay.
|
||||
|
||||
### Recommendation: **Direction B — extract `ReleaseHeroOverlay`, both pages consume it.**
|
||||
|
||||
Rationale, with the trade-off stated plainly:
|
||||
|
||||
- **The source of truth should be one overlay component, not the scaffold and not a copy.** Sessions
|
||||
already proved the overlay wants to live *outside* the scaffold's stacked-region model — forcing it
|
||||
back into the scaffold (Direction C) fights that and bloats shared chrome. Copying it (Direction A)
|
||||
reintroduces the exact cascade-duplication this codebase already paid down once.
|
||||
- **It satisfies "one source, multiple views" directly:** one overlay fed the same release DTO,
|
||||
rendering differences (Mix's visualizer backdrop, the square medium cover vs. Sessions' wide hero)
|
||||
expressed as component parameters + a CSS class, never as a forked structure.
|
||||
- **The cost is real and must be owned:** Direction B edits the shipped Sessions page. That is a
|
||||
regression surface on a working view. Mitigation: extract by *moving* Sessions' exact current markup +
|
||||
CSS into the component first (a behavior-preserving lift — Sessions should look pixel-identical after),
|
||||
then point Mix at it. The Sessions migration is the risky step; treat it as its own wave with a
|
||||
before/after visual check (§7 acceptance).
|
||||
|
||||
**If Daniel wants to minimize risk to Sessions and ship Mix fast, Direction A is the acceptable
|
||||
fallback** — but it takes on the duplication debt knowingly, and a later consolidation pass (like the
|
||||
track-card one) becomes likely. Recommended only if the Sessions page is considered too load-bearing to
|
||||
touch right now. **Flagging this as the one open decision for Daniel (§8, Q1).**
|
||||
|
||||
---
|
||||
|
||||
## 3. The shared component — `ReleaseHeroOverlay` (Direction B shape)
|
||||
|
||||
A new plain-shell presentational component: `DeepDrftPublic.Client/Controls/ReleaseHeroOverlay.razor`
|
||||
(+ `.razor.css` carrying the overlay cascade, moved from `SessionDetail.razor.css`).
|
||||
|
||||
**Responsibility (single):** given a release's display data, render the background-image hero with the
|
||||
metadata overlaid (top row: genre/date + share slot; bottom row: optional cover thumb + title/artist +
|
||||
optional play affordance). It owns no data fetch, no player wiring beyond invoking a passed-in callback,
|
||||
no JS interop.
|
||||
|
||||
**Parameters (the "same data shape" contract):**
|
||||
|
||||
| Parameter | Type | Purpose |
|
||||
|-----------|------|---------|
|
||||
| `HeroImageKey` | `string?` | The background image entry key (Sessions: hero-then-cover precedence; Mix: cover). Null → placeholder. |
|
||||
| `PlaceholderIcon` | `string` | Material icon for the no-image placeholder (Sessions: `Piano`; Mix: `Album`). |
|
||||
| `CoverThumbKey` | `string?` | Optional small cover thumbnail shown in the bottom row (Sessions shows it only when it differs from the hero image; Mix likely null — see §4). |
|
||||
| `Title` / `Artist` | `string` / `string?` | Overlaid title + artist. |
|
||||
| `Genre` | `string?` | Genre chip (top overlay) when present. |
|
||||
| `ReleaseDate` | `DateOnly?` | Release date (top overlay) when present. |
|
||||
| `ShareContent` | `RenderFragment?` | The share affordance (each page passes its `SharePopover` with the right release params). |
|
||||
| `PlayContent` | `RenderFragment?` | The play affordance (each page passes its `PlayStateIcon` wired to its own toggle). |
|
||||
| `Class` | `string?` | Extra class for per-page aspect/sizing variance (`mix-hero` vs default wide). |
|
||||
|
||||
Play/share ride as **slots**, not as wired-in player logic, so the component stays presentational and
|
||||
each page keeps owning its own play-toggle (Sessions already does; the scaffold does for Mix today —
|
||||
this preserves that ownership without the component reaching for the cascaded player).
|
||||
|
||||
**House constraint — plain-div shell.** The overlay shell (`.release-hero`, `.release-hero-shim`,
|
||||
`.release-hero-top`, `.release-hero-bottom`) is **plain `<div>`s with project CSS classes**, exactly as
|
||||
Sessions does today. The **background-image surface stays a `MudPaper`** *only because Sessions already
|
||||
uses one there* — but note it carries no card affordances; if staff-engineer prefers, it can become a
|
||||
plain `<div class="release-hero-img">` with the same `background-image` style, which is *more* aligned
|
||||
with the plain-shell rule. **Recommendation: make it a plain `<div>`** and drop the `MudPaper` — there
|
||||
is no MudPaper behavior being used (Elevation=0, Square=true), so the Mud wrapper is dead weight. This is
|
||||
a small improvement over the shipped Sessions code; flag it to Daniel as an incidental cleanup
|
||||
(§8, Q2). Chips/icons remain Mud components (they carry real behavior) and keep their `::deep` overrides.
|
||||
|
||||
---
|
||||
|
||||
## 4. Mix-specific composition + the square medium cover
|
||||
|
||||
Daniel's ask: "metadata laid out on top of a **max-medium square cover-art region**." Two design notes
|
||||
specific to Mix that differ from Sessions:
|
||||
|
||||
### 4a. Aspect ratio — square medium, not Sessions' wide hero
|
||||
|
||||
Sessions uses `aspect-ratio: 16/10; max-height: 70vh; min-height: 420px` (a wide, tall hero). Daniel
|
||||
wants Mix to use a **square** region at a **max-medium** size. The current Mix cover is `max-width:
|
||||
220px` (small). "Max-medium square" reads as: a centered `aspect-ratio: 1/1` block, capped at a medium
|
||||
width — recommend **`max-width: 420–480px`** (medium: bigger than the 360px track cover, smaller than
|
||||
the Large container) — so the overlaid metadata has room to sit on the cover without crowding, while the
|
||||
lava-lamp visualizer keeps the surrounding canvas. This rides the `Class` parameter (`mix-hero`) + a Mix
|
||||
CSS rule, not a forked component.
|
||||
|
||||
- *Why square, not wide:* the Mix cover art is square album art; a 16/10 crop would letterbox or
|
||||
distort it, and the point is to free room for the visualizer, which a smaller square does better than a
|
||||
full-bleed wide hero.
|
||||
- *Open sub-question (§8, Q3):* on a square overlay, the **top overlay row (genre/date/share) + bottom
|
||||
overlay row (title/artist/play) over a 480px square** may feel cramped versus Sessions' tall hero.
|
||||
Acceptable mitigation: keep the same two-overlay structure but let the shim carry more darkening, or
|
||||
drop the cover thumbnail (4b). Daniel tunes on screen per his standing preference.
|
||||
|
||||
### 4b. No cover thumbnail in the bottom row (recommended)
|
||||
|
||||
Sessions shows a small cover thumb in the bottom overlay *only when the hero image differs from the
|
||||
cover* (it has a dedicated hero image distinct from the cover). **Mix has no separate hero image — the
|
||||
cover art *is* the background.** So a cover thumbnail would duplicate the background. **Recommend Mix
|
||||
passes `CoverThumbKey = null`** — the bottom overlay is just title/artist + play. This falls out of the
|
||||
shared component's existing `showCover` logic for free.
|
||||
|
||||
### 4c. Mix keeps the scaffold for the top row only — or drops it
|
||||
|
||||
With the hero now a self-composed overlay (not the scaffold's `Hero`/`MetaContent`/masthead regions),
|
||||
Mix has a sub-decision:
|
||||
|
||||
- **Option (i) — keep `ReleaseDetailScaffold` for the back/controls top row only.** Mix keeps supplying
|
||||
`TopRowCenter` (controls) + `TopRightAction` (lava-lamp) to the scaffold, but stops supplying `Hero` /
|
||||
`MetaContent` / the default masthead, and instead renders `<ReleaseHeroOverlay>` in `BodyContent` (or a
|
||||
new slot). **Problem:** the scaffold's default header region renders the masthead (title+artist) *and*
|
||||
a second `PlayStateIcon` — which would now duplicate the overlay's title/artist/play. Suppressing the
|
||||
scaffold's masthead requires the `Header` slot to render *nothing*, which is awkward (the slot exists to
|
||||
*replace* the masthead, and an empty `Header` is a smell).
|
||||
- **Option (ii) — Mix drops the scaffold, composes directly like Sessions does.** Mix renders the back
|
||||
link + the controls top row + the lava-lamp + `<ReleaseHeroOverlay>` itself inside
|
||||
`.mix-detail-foreground`, mirroring how Sessions composes directly. **But** this loses the scaffold's
|
||||
ownership of the back link and the three-zone top-row structure that the Phase 10 reframe specifically
|
||||
built into the scaffold (`TopRowCenter`), and would duplicate that row.
|
||||
|
||||
**Recommendation: Option (i), with the scaffold's masthead suppressed by passing an empty-but-present
|
||||
`Header` fragment** — *or*, cleaner, **the overlay renders inside the scaffold's existing `Hero` slot and
|
||||
Mix passes a `Header` fragment that renders nothing** so the scaffold contributes only the top row +
|
||||
hero. The least-smelly realization: **keep the scaffold (it owns the Phase 10 top row — the constraint we
|
||||
must preserve), put `<ReleaseHeroOverlay>` in the `Hero` slot, leave `MetaContent` null (metadata now
|
||||
lives in the overlay), and pass a no-op `Header` fragment to suppress the duplicate masthead/play.**
|
||||
This preserves the visualizer/controls layout exactly (§5) while moving the hero+meta into the overlay.
|
||||
|
||||
> **Flag for staff-engineer:** an empty `Header` fragment to suppress the masthead is slightly awkward
|
||||
> but is the lowest-risk way to keep the Phase 10 top row intact. If it reads badly in code, the
|
||||
> alternative is a small scaffold change (a `ShowHeader` gate mirroring `ShowMeta`/`ShowShareRow`) — that
|
||||
> is a *minimal, slot-consistent* scaffold edit (a gate, not a layout flag), acceptable under the Phase 9
|
||||
> §5.3 convention because it suppresses an optional region rather than switching layouts. **Recommend the
|
||||
> `ShowHeader` gate over the empty-fragment hack** if staff-engineer touches the scaffold anyway. Noted
|
||||
> as §8 Q4.
|
||||
|
||||
---
|
||||
|
||||
## 5. Preserving the Phase 10 visualizer + controls layout (hard constraint)
|
||||
|
||||
The Phase 10 reframe put the controls in the scaffold's **`TopRowCenter`** slot and the lava-lamp in
|
||||
**`TopRightAction`**, with the in-flow grow/collapse behavior and the `flex-wrap` responsive drop. This
|
||||
rework **must not disturb any of that.** Concretely:
|
||||
|
||||
- **Keep the scaffold and its three-zone top row.** Mix continues supplying `TopRowCenter`
|
||||
(`<MixVisualizerControls>`) and `TopRightAction` (the lava-lamp `MudIconButton`) unchanged. The
|
||||
`_controlsExpanded` flag, `ToggleSettings`, and the filled/outline lamp glyph are untouched.
|
||||
- **The overlay goes *below* the top row**, in the `Hero` slot — it occupies the space the old
|
||||
`.mix-detail-cover` + masthead + `MetaContent` occupied. Net effect: the region below the controls row
|
||||
gets *shorter* (one overlaid block instead of masthead + 220px cover + meta divider + meta row),
|
||||
which **frees more canvas for the lava-lamp visualizer** — exactly Daniel's stated goal.
|
||||
- **`MixWaveformVisualizer` is unchanged.** It is a fixed full-viewport backdrop at `z-index: 0`; the
|
||||
overlay rides inside `.mix-detail-foreground` (`z-index: 1`) like the current cover does. The footer
|
||||
clip / lava-rest-line work (Phase 10 §2c) is independent of this and unaffected.
|
||||
- **`MetaContent` becomes null** (metadata moves into the overlay), so the scaffold's divider +
|
||||
`.deepdrft-track-detail-meta` row no longer renders for Mix. The share row moves into the overlay's
|
||||
`ShareContent` slot (matching Sessions, which overlays share top-right).
|
||||
|
||||
**Acceptance tie-in:** after the rework, expanding the controls still grows the in-flow container between
|
||||
back and lamp, still wraps on narrow widths, and the lava-lamp still toggles it — no change to that
|
||||
interaction (§7).
|
||||
|
||||
---
|
||||
|
||||
## 6. CSS approach
|
||||
|
||||
- **The overlay cascade moves into `ReleaseHeroOverlay.razor.css`** (Direction B), renamed from
|
||||
`.session-*` to neutral `.release-hero-*`. Sessions' `SessionDetail.razor.css` keeps only what is
|
||||
page-specific (the `.session-detail-page` padding, the per-page aspect overrides if any); Mix's
|
||||
`MixDetail.razor.css` keeps only the `.mix-detail-foreground` z-index lift + the `mix-hero` square/
|
||||
medium sizing override.
|
||||
- **`::deep` is required** wherever a class lands on a MudBlazor child component's native output — this
|
||||
is unchanged from Sessions today and must carry into the shared component's scoped CSS:
|
||||
- the background-image surface **if it stays `MudPaper`** (`::deep .release-hero-img`) — *avoidable by
|
||||
making it a plain `<div>`, §3, which removes the `::deep` need for that element entirely*;
|
||||
- the genre chip on `MudChip` (`::deep .release-overlay-chip.mud-chip`);
|
||||
- the bottom-row `MudStack` wrap (`::deep .release-hero-bottom-row`);
|
||||
- the play/share icon-color overrides on `MudIconButton`/`MudProgressCircular`
|
||||
(`::deep .release-hero-play .mud-icon-button`, etc.).
|
||||
- **The square/medium aspect for Mix** is a single override scoped to the `mix-hero` class
|
||||
(`aspect-ratio: 1/1; max-width: ~480px; margin-inline: auto`) — it overrides the component's default
|
||||
wide aspect. This is the "divergence rides CSS, not structure" realization of the one-source rule.
|
||||
- **No `MudCard`/`MudPaper` shell for the overlay container** (house rule). The `.release-hero`
|
||||
positioning context, the shim, and both overlay rows are plain `<div>`s — as Sessions already does.
|
||||
The only Mud wrappers that remain are the chip, the icon buttons, and (optionally) the image surface —
|
||||
each carrying real component behavior, none acting as a layout shell. **If staff-engineer reaches for a
|
||||
Mud wrapper as a layout shell, stop and flag it** (per the standing constraint).
|
||||
|
||||
---
|
||||
|
||||
## 7. Acceptance criteria (observable)
|
||||
|
||||
1. **Cover-as-background.** On a Mix detail page with a cover image, the cover renders as a
|
||||
background-image hero (`background-size: cover`), not as a bordered thumbnail; metadata sits overlaid
|
||||
on top of it.
|
||||
2. **Square medium region.** The hero is a centered square (`aspect-ratio: 1/1`) capped at a medium
|
||||
width (~480px), visibly larger than the old 220px cover, with the surrounding canvas left to the
|
||||
visualizer.
|
||||
3. **All metadata overlaid.** Title, artist, genre (when present), release date (when present), and the
|
||||
share affordance all render *over* the cover image — no separate masthead block, no separate meta
|
||||
divider/row below the cover.
|
||||
4. **Placeholder path.** A Mix with no cover image shows the placeholder treatment (Album icon over the
|
||||
soft-secondary gradient) with metadata still legibly overlaid.
|
||||
5. **Legibility.** The darkening shim keeps overlaid text readable over light and dark cover art, in both
|
||||
light and dark theme.
|
||||
6. **Visualizer/controls preserved.** The lava-lamp toggle still opens the in-flow seven-knob controls
|
||||
container between the back link and the lamp; it still grows in place, still wraps on narrow widths,
|
||||
and the lava-lamp glyph still swaps filled/outline. No regression to the Phase 10 layout.
|
||||
7. **More canvas for the visualizer.** The content block below the controls row is shorter than before
|
||||
(one overlaid hero vs. masthead + cover + meta), leaving more visible visualizer area.
|
||||
8. **Sessions unchanged (Direction B).** After the shared-component extraction, the Session detail page
|
||||
renders pixel-identically to before (before/after visual check on a session with a dedicated hero
|
||||
image, a session with cover-only, and a session with no image).
|
||||
9. **One source of truth (Direction B).** The overlay markup + cascade exists in exactly one component;
|
||||
grepping for `.session-hero` / `.release-hero` finds no duplicate structure across the two pages.
|
||||
10. **No Mud layout shell.** The overlay container, shim, and overlay rows are plain `<div>`s; no
|
||||
`MudCard`/`MudPaper` acts as a layout wrapper (image surface excepted only if kept as `MudPaper`).
|
||||
|
||||
---
|
||||
|
||||
## 8. Open questions for Daniel
|
||||
|
||||
1. **DRY decision (the load-bearing one).** Recommended **Direction B** — extract a shared
|
||||
`ReleaseHeroOverlay` both pages consume (one source of truth; edits the shipped Sessions page).
|
||||
Fallback **Direction A** — per-page copy in Mix (fast, zero Sessions risk, takes on duplication debt).
|
||||
**Which do you want?** (B is the "one source, multiple views" call; A is the play-it-safe-on-Sessions
|
||||
call.)
|
||||
2. **Drop the `MudPaper` on the image surface** for a plain `<div class="release-hero-img">` while we're
|
||||
in here? It carries no Mud behavior (Elevation=0/Square=true), so it is dead weight and a plain div is
|
||||
more on-spec with the plain-shell rule. Incidental cleanup — yes/no?
|
||||
3. **Square hero size.** Recommended ~**480px max-width** square. Crowded vs. roomy is a feel call you'll
|
||||
tune on screen — is ~480px the right starting point, or do you want it bigger (closer to the Sessions
|
||||
hero scale) / smaller (more visualizer room)?
|
||||
4. **Suppressing the duplicate masthead.** Mix's hero now carries title/artist/play, so the scaffold's
|
||||
default masthead must be suppressed. Recommended: add a small **`ShowHeader` gate** to the scaffold
|
||||
(slot-consistent with `ShowMeta`/`ShowShareRow`), vs. the hackier empty-`Header`-fragment. OK to add
|
||||
the `ShowHeader` gate?
|
||||
5. **Square overlay crowding (deferrable).** If the genre/date/share top row + title/artist/play bottom
|
||||
row feel cramped on a 480px square, are you fine tuning shim/spacing on screen, or do you want a
|
||||
different overlay arrangement for the square (e.g. a single bottom-stacked overlay) speced now?
|
||||
|
||||
---
|
||||
|
||||
## 9. File-change inventory (for staff-engineer, Direction B)
|
||||
|
||||
**New:**
|
||||
- `DeepDrftPublic.Client/Controls/ReleaseHeroOverlay.razor` (+ `.razor.css`) — the shared overlay,
|
||||
lifted from Sessions' current hero markup + CSS, parameterized per §3.
|
||||
|
||||
**Edited:**
|
||||
- `DeepDrftPublic.Client/Pages/SessionDetail.razor` — replace the inline `.session-hero` block with
|
||||
`<ReleaseHeroOverlay ... />`, passing its hero/cover precedence, share, and play slots. Behavior-
|
||||
preserving (must render identically).
|
||||
- `DeepDrftPublic.Client/Pages/SessionDetail.razor.css` — remove the overlay cascade now living in the
|
||||
component; keep only page-specific rules.
|
||||
- `DeepDrftPublic.Client/Pages/MixDetail.razor` — replace the `.mix-detail-cover` `Hero` slot with
|
||||
`<ReleaseHeroOverlay Class="mix-hero" ... CoverThumbKey="null" />`; drop `MetaContent`; move the share
|
||||
row into the overlay's `ShareContent` slot; suppress the scaffold masthead (per Q4). **`TopRowCenter` /
|
||||
`TopRightAction` / the visualizer / `_controlsExpanded` wiring untouched.**
|
||||
- `DeepDrftPublic.Client/Pages/MixDetail.razor.css` — keep `.mix-detail-foreground`; add the `mix-hero`
|
||||
square/medium sizing override; remove `.mix-detail-cover`.
|
||||
- `DeepDrftPublic.Client/Controls/ReleaseDetailScaffold.razor[.cs]` — **only if Q4 = ShowHeader gate:**
|
||||
add a `bool ShowHeader = true` gate around the default header region.
|
||||
- `DeepDrftPublic/wwwroot/styles/deepdrft-styles.css` — no change required; `.deepdrft-track-detail-
|
||||
cover*` stays (Track detail still uses it). The `.mix-detail-container .deepdrft-track-detail-
|
||||
container` width override stays (the scaffold still hosts the top row).
|
||||
|
||||
**For Direction A (fallback):** no new component; the overlay markup is inlined into `MixDetail.razor`
|
||||
and the `.session-*` cascade is copied + renamed into `MixDetail.razor.css`. Sessions untouched.
|
||||
Reference in New Issue
Block a user