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. /// public partial class SharePopover : ComponentBase, IDisposable { [Parameter] public string? EntryKey { get; set; } [Inject] public required NavigationManager Navigation { get; set; } [Inject] public required IJSRuntime JS { get; set; } private bool _open; private bool _embed; private bool _linkCopied; private bool _embedCopied; private readonly CancellationTokenSource _cts = new(); private bool Embed { get => _embed; set { _embed = value; if (!value) _embedCopied = false; } } private string TrackUrl => $"{Navigation.BaseUri}track/{EntryKey}"; private string EmbedSnippet => $""""""; private void Toggle() => _open = !_open; private void Close() => _open = false; private async Task CopyLink() { if (await CopyToClipboard(TrackUrl)) { _linkCopied = true; await ResetAfterDelay(() => _linkCopied = false); } } private async Task CopyEmbed() { if (await CopyToClipboard(EmbedSnippet)) { _embedCopied = true; await ResetAfterDelay(() => _embedCopied = false); } } private async Task CopyToClipboard(string text) { try { await JS.InvokeVoidAsync("navigator.clipboard.writeText", text); return true; } catch (Exception) { return false; } } private async Task ResetAfterDelay(Action reset) { try { await Task.Delay(1500, _cts.Token); } catch (TaskCanceledException) { return; } reset(); StateHasChanged(); } public void Dispose() => _cts.Cancel(); }