feat: Phase 17.3 — Fixed embed queue panel with collapse/expand iframe resize (OQ1 Option A)
Read-only inline queue panel below the release embed's player bar; row-jump reuses PlayRelease. ForRelease mints a taller iframe plus a postMessage resize listener for the collapse toggle; ForTrack unchanged.
This commit is contained in:
@@ -3,19 +3,50 @@ namespace DeepDrftPublic.Client.Helpers;
|
||||
/// <summary>
|
||||
/// Builds the iframe embed snippet the share popover copies. Two targets: a single track
|
||||
/// (<see cref="ForTrack"/> → <c>FramePlayer?TrackEntryKey=...</c>) and a whole release
|
||||
/// (<see cref="ForRelease"/> → <c>FramePlayer?ReleaseEntryKey=...</c>). The iframe chrome
|
||||
/// (dimensions, border radius, autoplay permission) is identical across both, defined once here.
|
||||
/// (<see cref="ForRelease"/> → <c>FramePlayer?ReleaseEntryKey=...</c>).
|
||||
///
|
||||
/// <para>
|
||||
/// The two snippets diverge in height by design (Phase 17 §4.1, OQ6): a single-track embed has no
|
||||
/// queue, so <see cref="ForTrack"/> stays at the compact player height; a release embed renders the
|
||||
/// always-shown queue panel below the controls, so <see cref="ForRelease"/> is taller to show it
|
||||
/// without clipping. Other iframe chrome (width, border radius, autoplay permission) is identical and
|
||||
/// defined once in <see cref="Frame"/>.
|
||||
/// </para>
|
||||
///
|
||||
/// <para>
|
||||
/// OQ1 Option A — collapse/expand resize handshake. The release snippet carries a tiny host-side
|
||||
/// listener: the embedded player posts its desired height when the viewer collapses/expands the
|
||||
/// queue panel, and the listener sizes this specific iframe to match. It is scoped to the snippet's
|
||||
/// own iframe (matched by id) and ignores any message whose shape does not match, so it cannot be
|
||||
/// driven by foreign frames. It degrades to Option B's behaviour if the host strips the script: the
|
||||
/// panel still renders and toggles inside the iframe at its default (expanded) height — only the
|
||||
/// outer resize is lost. The track snippet needs no script (no panel, no toggle).
|
||||
/// </para>
|
||||
///
|
||||
/// Pure string composition so the snippet shape is unit-testable without rendering the component.
|
||||
/// </summary>
|
||||
public static class EmbedSnippetBuilder
|
||||
{
|
||||
// Compact single-track height (the historical embed height — must not change: UC6/AC6).
|
||||
private const int TrackHeight = 196;
|
||||
|
||||
// Release height: the compact player plus the queue panel (fixed, internally scrollable past N
|
||||
// rows per OQ6). The panel collapses to the track height via the resize handshake below.
|
||||
private const int ReleaseHeight = 384;
|
||||
|
||||
// baseUri carries a trailing slash (NavigationManager.BaseUri), so "FramePlayer" appends cleanly.
|
||||
public static string ForTrack(string baseUri, string trackEntryKey)
|
||||
=> Frame($"{baseUri}FramePlayer?TrackEntryKey={trackEntryKey}");
|
||||
=> Frame($"{baseUri}FramePlayer?TrackEntryKey={trackEntryKey}", TrackHeight);
|
||||
|
||||
public static string ForRelease(string baseUri, string releaseEntryKey)
|
||||
=> Frame($"{baseUri}FramePlayer?ReleaseEntryKey={releaseEntryKey}");
|
||||
=> Frame($"{baseUri}FramePlayer?ReleaseEntryKey={releaseEntryKey}", ReleaseHeight, ResizeScript);
|
||||
|
||||
private static string Frame(string src)
|
||||
=> $"""<iframe src="{src}" width="656" height="196" frameborder="0" style="border-radius:8px;" allow="autoplay"></iframe>""";
|
||||
private static string Frame(string src, int height, string trailingScript = "")
|
||||
=> $"""<iframe id="deepdrft-embed" src="{src}" width="656" height="{height}" frameborder="0" style="border-radius:8px;" allow="autoplay"></iframe>{trailingScript}""";
|
||||
|
||||
// Host-side listener: resize #deepdrft-embed when the embedded player posts its panel height. The
|
||||
// shape/origin-agnostic guard (ignores non-matching messages) keeps a foreign frame from driving
|
||||
// it; the height is clamped to a sane floor so a bad payload can't collapse the player away.
|
||||
private const string ResizeScript =
|
||||
"""<script>window.addEventListener("message",function(e){var d=e.data;if(!d||d.type!=="deepdrft-embed-resize")return;var f=document.getElementById("deepdrft-embed");var h=Number(d.height);if(f&&h>=150)f.style.height=h+"px";});</script>""";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user