using AIStudio.Tools.PluginSystem; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Rendering; using Microsoft.AspNetCore.Components.Web; namespace AIStudio.Components; /// /// The copy button of a code block which AI Studio highlights itself, made like the one of /// MudBlazor.Markdown, which is internal: the same classes, so that it appears at the same place while /// the pointer is on the block, and the same confirmation for a moment after a click. /// /// /// It copies through the clipboard service of the app, the native clipboard of the runtime, which the /// button of the library falls back to as well. /// public sealed class CodeBlockCopyButton : ComponentBase { private const string CSS_CLASS = "ma-2 mud-markdown-code-highlight-copybtn"; private static readonly TimeSpan CONFIRMATION_DURATION = TimeSpan.FromSeconds(1.25); private static string TB(string fallbackEN) => I18N.I.T(fallbackEN, typeof(CodeBlockCopyButton).Namespace, nameof(CodeBlockCopyButton)); /// /// The code to copy. /// [Parameter] public string Text { get; set; } = string.Empty; [Inject] private IMudMarkdownClipboardService ClipboardService { get; init; } = null!; private bool isCopied; /// /// What a copy button of a code block confirms with, those of MudBlazor.Markdown included. /// internal static string ConfirmationText => TB("Copied!"); #region Overrides of ComponentBase protected override void BuildRenderTree(RenderTreeBuilder builder) { if (!this.isCopied) { builder.OpenComponent(0); builder.AddComponentParameter(1, nameof(MudIconButton.OnClick), EventCallback.Factory.Create(this, this.CopyAsync)); builder.AddComponentParameter(2, nameof(MudIconButton.Class), CSS_CLASS); builder.AddComponentParameter(3, nameof(MudIconButton.Icon), Icons.Material.Rounded.ContentCopy); builder.AddComponentParameter(4, nameof(MudIconButton.Color), Color.Primary); builder.AddComponentParameter(5, nameof(MudIconButton.Variant), Variant.Filled); builder.AddComponentParameter(6, nameof(MudIconButton.Size), Size.Medium); builder.CloseComponent(); return; } builder.OpenComponent(10); builder.AddComponentParameter(11, nameof(MudTooltip.Text), ConfirmationText); builder.AddComponentParameter(12, nameof(MudTooltip.Arrow), true); builder.AddComponentParameter(13, nameof(MudTooltip.Placement), Placement.Left); builder.AddComponentParameter(14, nameof(MudTooltip.Visible), true); builder.AddComponentParameter(15, nameof(MudTooltip.ShowOnClick), false); builder.AddComponentParameter(16, nameof(MudTooltip.ShowOnFocus), false); builder.AddComponentParameter(17, nameof(MudTooltip.ShowOnHover), false); builder.AddComponentParameter(18, nameof(MudTooltip.RootClass), CSS_CLASS); builder.AddComponentParameter(19, nameof(MudTooltip.ChildContent), (RenderFragment)(content => { content.OpenComponent(0); content.AddComponentParameter(1, nameof(MudIconButton.Icon), Icons.Material.Rounded.DoneAll); content.AddComponentParameter(2, nameof(MudIconButton.Color), Color.Success); content.AddComponentParameter(3, nameof(MudIconButton.Variant), Variant.Filled); content.AddComponentParameter(4, nameof(MudIconButton.Size), Size.Medium); content.CloseComponent(); })); builder.CloseComponent(); } #endregion private async Task CopyAsync() { if (string.IsNullOrEmpty(this.Text)) return; await this.ClipboardService.CopyToClipboardAsync(this.Text); this.isCopied = true; this.StateHasChanged(); await Task.Delay(CONFIRMATION_DURATION); this.isCopied = false; this.StateHasChanged(); } }