From ce437521ee97ff6b8e9029ae68db066a33d6e384 Mon Sep 17 00:00:00 2001 From: daniel-c-harvey Date: Tue, 16 Jun 2026 11:31:03 -0400 Subject: [PATCH] =?UTF-8?q?feat(share):=20add=20release-keyed=20copy-link?= =?UTF-8?q?=20mode=20to=20SharePopover;=20wire=20Cut=20header=20(=C2=A73b,?= =?UTF-8?q?=20P11=20W3=2011.E)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controls/SharePopover.razor | 52 ++++++++++--------- .../Controls/SharePopover.razor.cs | 30 +++++++++-- DeepDrftPublic.Client/Pages/CutDetail.razor | 6 +-- 3 files changed, 56 insertions(+), 32 deletions(-) diff --git a/DeepDrftPublic.Client/Controls/SharePopover.razor b/DeepDrftPublic.Client/Controls/SharePopover.razor index 73980bc..b1843af 100644 --- a/DeepDrftPublic.Client/Controls/SharePopover.razor +++ b/DeepDrftPublic.Client/Controls/SharePopover.razor @@ -6,7 +6,7 @@ Color="Color.Secondary" Disabled="@(!RendererInfo.IsInteractive)" OnClick="@Toggle" - aria-label="Share this track" /> + aria-label="@(IsReleaseMode ? "Share this release" : "Share this track")" /> @@ -31,31 +31,35 @@ } - - - - - @if (_embed) + @* Embed is a single-track affordance only; a release page is not a single-track embed (§3b.3). *@ + @if (!IsReleaseMode) { - - - - - @if (_embedCopied) - { - Copied! - } + + + + + @if (_embed) + { + + + + + @if (_embedCopied) + { + Copied! + } + - + } } diff --git a/DeepDrftPublic.Client/Controls/SharePopover.razor.cs b/DeepDrftPublic.Client/Controls/SharePopover.razor.cs index 111f766..a6217c3 100644 --- a/DeepDrftPublic.Client/Controls/SharePopover.razor.cs +++ b/DeepDrftPublic.Client/Controls/SharePopover.razor.cs @@ -1,20 +1,35 @@ +using DeepDrftModels.Enums; +using DeepDrftPublic.Client.Common; using Microsoft.AspNetCore.Components; using Microsoft.JSInterop; namespace DeepDrftPublic.Client.Controls; /// -/// Share affordance for the track detail page: a popover offering a canonical-link copy -/// and an optional iframe embed snippet. Clipboard writes go through navigator.clipboard; -/// each copy shows a transient "Copied!" confirmation that resets after a short delay. +/// Share affordance with two modes from one source of clipboard/popover-chrome logic +/// (Phase 11 §3b). Track mode ( set) offers a canonical-link copy plus an +/// optional iframe embed snippet. Release mode ( set) is copy-link-only — +/// it copies the absolute form of the release's canonical detail URL and hides the embed +/// affordance, since a release page is not a single-track embed. Clipboard writes go through +/// navigator.clipboard; each copy shows a transient "Copied!" confirmation that resets after a +/// short delay. /// public partial class SharePopover : ComponentBase, IDisposable { + /// Track mode: the vault entry key of the track to share. Mutually exclusive with the release target. [Parameter] public string? EntryKey { get; set; } + /// Release mode: the release id to share. When set (with ), the popover shares the release detail URL and omits the embed option. + [Parameter] public long? ReleaseId { get; set; } + + /// Release mode: the medium of the release, used to resolve its canonical detail route. + [Parameter] public ReleaseMedium ReleaseMedium { get; set; } + [Inject] public required NavigationManager Navigation { get; set; } [Inject] public required IJSRuntime JS { get; set; } + private bool IsReleaseMode => ReleaseId is not null; + private bool _open; private bool _embed; private bool _linkCopied; @@ -32,6 +47,13 @@ public partial class SharePopover : ComponentBase, IDisposable } } + // The URL "Copy link" places on the clipboard. Release mode resolves the canonical detail + // route (which carries a leading slash) and composes it against BaseUri (which carries a + // trailing slash) — trim one to avoid a doubled separator. + private string LinkUrl => IsReleaseMode + ? $"{Navigation.BaseUri.TrimEnd('/')}{ReleaseRoutes.DetailHref(ReleaseId!.Value, ReleaseMedium)}" + : TrackUrl; + private string TrackUrl => $"{Navigation.BaseUri}track/{EntryKey}"; private string EmbedSnippet => @@ -43,7 +65,7 @@ public partial class SharePopover : ComponentBase, IDisposable private async Task CopyLink() { - if (await CopyToClipboard(TrackUrl)) + if (await CopyToClipboard(LinkUrl)) { _linkCopied = true; await ResetAfterDelay(() => _linkCopied = false); diff --git a/DeepDrftPublic.Client/Pages/CutDetail.razor b/DeepDrftPublic.Client/Pages/CutDetail.razor index a08f561..2500049 100644 --- a/DeepDrftPublic.Client/Pages/CutDetail.razor +++ b/DeepDrftPublic.Client/Pages/CutDetail.razor @@ -79,10 +79,8 @@ else Play - @if (firstTrack is not null) - { - - } + @* Release-mode share: copies the canonical /cuts/{id} URL, not a single track (§3b). *@ +