381 lines
27 KiB
Markdown
381 lines
27 KiB
Markdown
# Mix Detail — Hero + MetaContent overlay rework (mirror the Sessions hero) — Design Spec
|
||
|
||
Status: **shipped on dev** (2026-06-16). Author: product-designer. Date: 2026-06-16.
|
||
|
||
## 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 + eight-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 eight-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.
|