Merge p11-w3-t2-release-share into dev (P11 11.E: release-keyed SharePopover mode, Cut header Share)

This commit is contained in:
daniel-c-harvey
2026-06-16 11:58:20 -04:00
3 changed files with 56 additions and 32 deletions
@@ -6,7 +6,7 @@
Color="Color.Secondary" Color="Color.Secondary"
Disabled="@(!RendererInfo.IsInteractive)" Disabled="@(!RendererInfo.IsInteractive)"
OnClick="@Toggle" OnClick="@Toggle"
aria-label="Share this track" /> aria-label="@(IsReleaseMode ? "Share this release" : "Share this track")" />
</MudTooltip> </MudTooltip>
<MudOverlay Visible="@_open" OnClick="@Close" AutoClose="true" /> <MudOverlay Visible="@_open" OnClick="@Close" AutoClose="true" />
@@ -31,6 +31,9 @@
} }
</MudStack> </MudStack>
@* Embed is a single-track affordance only; a release page is not a single-track embed (§3b.3). *@
@if (!IsReleaseMode)
{
<MudDivider /> <MudDivider />
<MudCheckBox @bind-Value="Embed" Color="Color.Primary" Label="Embed player" Dense="true" /> <MudCheckBox @bind-Value="Embed" Color="Color.Primary" Label="Embed player" Dense="true" />
@@ -57,6 +60,7 @@
</MudStack> </MudStack>
</MudStack> </MudStack>
} }
}
</MudStack> </MudStack>
</MudPopover> </MudPopover>
@@ -1,20 +1,35 @@
using DeepDrftModels.Enums;
using DeepDrftPublic.Client.Common;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop; using Microsoft.JSInterop;
namespace DeepDrftPublic.Client.Controls; namespace DeepDrftPublic.Client.Controls;
/// <summary> /// <summary>
/// Share affordance for the track detail page: a popover offering a canonical-link copy /// Share affordance with two modes from one source of clipboard/popover-chrome logic
/// and an optional iframe embed snippet. Clipboard writes go through navigator.clipboard; /// (Phase 11 §3b). Track mode (<see cref="EntryKey"/> set) offers a canonical-link copy plus an
/// each copy shows a transient "Copied!" confirmation that resets after a short delay. /// optional iframe embed snippet. Release mode (<see cref="ReleaseId"/> 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.
/// </summary> /// </summary>
public partial class SharePopover : ComponentBase, IDisposable public partial class SharePopover : ComponentBase, IDisposable
{ {
/// <summary>Track mode: the vault entry key of the track to share. Mutually exclusive with the release target.</summary>
[Parameter] public string? EntryKey { get; set; } [Parameter] public string? EntryKey { get; set; }
/// <summary>Release mode: the release id to share. When set (with <see cref="ReleaseMedium"/>), the popover shares the release detail URL and omits the embed option.</summary>
[Parameter] public long? ReleaseId { get; set; }
/// <summary>Release mode: the medium of the release, used to resolve its canonical detail route.</summary>
[Parameter] public ReleaseMedium ReleaseMedium { get; set; }
[Inject] public required NavigationManager Navigation { get; set; } [Inject] public required NavigationManager Navigation { get; set; }
[Inject] public required IJSRuntime JS { get; set; } [Inject] public required IJSRuntime JS { get; set; }
private bool IsReleaseMode => ReleaseId is not null;
private bool _open; private bool _open;
private bool _embed; private bool _embed;
private bool _linkCopied; 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 TrackUrl => $"{Navigation.BaseUri}track/{EntryKey}";
private string EmbedSnippet => private string EmbedSnippet =>
@@ -43,7 +65,7 @@ public partial class SharePopover : ComponentBase, IDisposable
private async Task CopyLink() private async Task CopyLink()
{ {
if (await CopyToClipboard(TrackUrl)) if (await CopyToClipboard(LinkUrl))
{ {
_linkCopied = true; _linkCopied = true;
await ResetAfterDelay(() => _linkCopied = false); await ResetAfterDelay(() => _linkCopied = false);
+2 -4
View File
@@ -79,10 +79,8 @@ else
Play Play
</MudButton> </MudButton>
@if (firstTrack is not null) @* Release-mode share: copies the canonical /cuts/{id} URL, not a single track (§3b). *@
{ <SharePopover ReleaseId="@release.Id" ReleaseMedium="@release.Medium" />
<SharePopover EntryKey="@firstTrack.EntryKey" />
}
</div> </div>
</div> </div>