Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
69d0c7d
Upgrade Hex1b and improve dashboard terminal navigation and metadata
mitchdenny Sep 19, 2026
d032bfd
Make terminal titles copyable like working directories
mitchdenny Sep 19, 2026
1a01805
Right-align terminal paths beside copy indicators
mitchdenny Sep 19, 2026
a807ee2
Use Fluent font sizing and fit icons in terminal footer
mitchdenny Sep 19, 2026
bd46143
Match terminal footer buttons to console toolbar styling
mitchdenny Sep 19, 2026
5372636
Align compact terminal footer buttons with dimensions selector
mitchdenny Sep 19, 2026
581c0de
Add Minecraft terminal example to playground AppHost
mitchdenny Sep 20, 2026
f3b44f0
Upgrade Hex1b packages and local tool to 0.169.0
mitchdenny Sep 20, 2026
71ef21f
Cover terminal header clipboard and focus behavior in Playwright
mitchdenny Sep 20, 2026
61288f5
Force WebGL2 for Firefox dashboard terminals
mitchdenny Sep 20, 2026
5c3557c
Link Firefox renderer workaround to Mozilla bug
mitchdenny Sep 20, 2026
d1af6fc
Merge main and terminal ApplicationModel namespace migration
mitchdenny Sep 21, 2026
eab0469
Update Hex1b packages and terminal assets to 0.169.1
mitchdenny Sep 21, 2026
81ec494
Soften terminal focus outline
mitchdenny Sep 21, 2026
c89b3ec
Mute terminal focus purple with neutral stroke
mitchdenny Sep 21, 2026
05c15f1
Use muted neutral tones for terminal focus
mitchdenny Sep 21, 2026
d4f739a
Tint muted terminal focus with purple
mitchdenny Sep 21, 2026
0781fd9
Upgrade Hex1b to 0.170.0 and follow Dashboard terminal palettes
mitchdenny Sep 21, 2026
095587f
Update Hex1b packages and tools to 0.171.0
mitchdenny Sep 22, 2026
a611e40
Add terminal palette review chart to playground
mitchdenny Sep 22, 2026
b4f6c01
Tint terminal palette backgrounds purple
mitchdenny Sep 22, 2026
d4713a0
Enrich Aspire terminal ANSI colors with contrast-aware tuning
mitchdenny Sep 22, 2026
3f1f4d7
Add independent terminal palette preference to Dashboard settings
mitchdenny Sep 22, 2026
a3a1255
Move terminal palette selection into the terminal footer
mitchdenny Sep 23, 2026
ae42d58
Offer only explicit terminal palettes
mitchdenny Sep 23, 2026
3504b2c
Hatch unused terminal viewport space with palette colors
mitchdenny Sep 23, 2026
a06cd91
Distinguish terminal surface with a pinstripe and darker surround
mitchdenny Sep 23, 2026
de460a9
Enable terminal URL detection and soften the surface pinstripe
mitchdenny Sep 23, 2026
778740a
Name terminal palettes Aspire light and Aspire dark
mitchdenny Sep 23, 2026
f32366b
Merge main and adapt terminal integration to the AOT Dashboard
mitchdenny Sep 23, 2026
db78c01
Use dashed underlines for detected terminal links
mitchdenny Sep 23, 2026
9b87e20
Merge main into terminal scrollbar integration
mitchdenny Sep 24, 2026
2fdfd35
Merge main into terminal scrollbar integration
mitchdenny Sep 24, 2026
4e5c472
Configure explicit per-workload Windows PTY socket paths
mitchdenny Sep 24, 2026
b664d2d
Use Dashboard typography for terminal headers
mitchdenny Sep 24, 2026
3850606
Use Aspire purple for pressed terminal header buttons
mitchdenny Sep 24, 2026
23f2809
Update Hex1b packages to 0.172.0-alpha.1654.1.f826137
mitchdenny Sep 25, 2026
68312f0
Update Hex1b alpha with expanding scrollbar markers
mitchdenny Sep 25, 2026
96e2e85
Update Hex1b to alpha 1787 with refined scrollbar marks
mitchdenny Sep 26, 2026
c252b1f
Use Hex1b default palette-derived scrollbar track color
mitchdenny Sep 26, 2026
c112d14
Keep scrollbar marks contrasting with the terminal palette
mitchdenny Sep 27, 2026
289cdf9
Update Hex1b packages and browser assets to stable 0.172.0
mitchdenny Sep 27, 2026
f3eade3
Support reordering and scrolling terminal dock tabs
mitchdenny Sep 28, 2026
3ac625d
Refine dock insertion marker and align persistent scroll controls
mitchdenny Sep 28, 2026
e600abd
Let terminal dock tabs use available header width
mitchdenny Sep 28, 2026
211cf67
Fade overflowing dock tabs into the scroll control background
mitchdenny Sep 28, 2026
3f58a59
Balance terminal dock tab padding around the close icon
mitchdenny Sep 28, 2026
566f28b
Merge main into terminal scrollbar integration
mitchdenny Sep 28, 2026
cc194eb
Keep terminal header icons persistent and move progress values to too…
mitchdenny Sep 29, 2026
d09d36b
Use theme purple for terminal header icons
mitchdenny Sep 29, 2026
4ab1a0d
Keep dock terminal titles static within their tabs
mitchdenny Sep 29, 2026
7e926ae
Preserve UNC authority when compacting terminal paths
mitchdenny Sep 29, 2026
663faf0
Correct terminal palette playground guidance
mitchdenny Sep 29, 2026
0b65f15
Address terminal review feedback and CI coverage
mitchdenny Sep 29, 2026
8854669
Downgrade Hex1b terminal integration to 0.171.0
mitchdenny Sep 30, 2026
40128a6
Polish terminal frame and labeled footer controls
mitchdenny Sep 30, 2026
90aac1b
Reset terminal clipboard feedback after copy completes
mitchdenny Sep 30, 2026
5f96c12
Polish terminal control sizing
JamesNK Oct 1, 2026
2756fc1
Polish terminal header styling and fix review feedback
JamesNK Oct 1, 2026
d333d52
Refine terminal dock tab sizing
JamesNK Oct 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .config/dotnet-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
]
},
"hex1b.tool": {
"version": "0.165.0",
"version": "0.171.0",
"commands": [
"hex1b"
]
Expand Down
2 changes: 1 addition & 1 deletion .mcp.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"type": "stdio",
"command": "dnx",
"args": [
"Hex1b.McpServer@0.133.0",
"Hex1b.McpServer@0.171.0",
"--yes"
]
},
Expand Down
6 changes: 3 additions & 3 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,9 @@
<PackageVersion Include="Grpc.Tools" Version="2.83.0" />
<!-- Keep compatible with @hex1b/web-terminal in src/Aspire.Dashboard/package.json.
Native-only Hex1b builds can differ without changing the web terminal package. -->
<PackageVersion Include="Hex1b" Version="0.168.0" />
<PackageVersion Include="Hex1b.McpServer" Version="0.165.0" />
<PackageVersion Include="Hex1b.Tool" Version="0.165.0" />
<PackageVersion Include="Hex1b" Version="0.171.0" />
<PackageVersion Include="Hex1b.McpServer" Version="0.171.0" />
<PackageVersion Include="Hex1b.Tool" Version="0.171.0" />
<PackageVersion Include="Humanizer.Core" Version="3.0.10" />
<PackageVersion Include="KubernetesClient" Version="19.0.2" />
<PackageVersion Include="Markdig" Version="1.3.2" />
Expand Down
16 changes: 10 additions & 6 deletions docs/specs/cli-backchannel.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,17 @@ privileged administrators.

Process-backed AppHost terminals (both docked and interaction prompts) also configure
Hex1b's Windows PTY helper socket directory before creating the deferred workload. Aspire
secures `%USERPROFILE%\.aspire\pty` and sets `HEX1B_PTY_SHIM_SOCKET_DIR` in the AppHost's
process environment. An existing override is preserved, normalized to an absolute path,
secures `%USERPROFILE%\.aspire\pty` and supplies a unique explicit
`WindowsPtyProxySocketPath` to each workload. An existing `HEX1B_PTY_SHIM_SOCKET_DIR`
override is read without changing the process environment, normalized to an absolute path,
and validated with the same override policy; unsafe directories or permission failures prevent
terminal creation. Hex1b may additionally grant Windows SYSTEM access to this directory.
The override remains set for the process lifetime because Hex1b reads it at PTY startup,
not when the process-options callback runs. Setting only the child process environment
would not control this socket. Linux and macOS use direct PTYs and need no such override.
terminal creation. Socket paths are checked against the native endpoint length limit
before creating directories. Sockets live in an Aspire-owned `proxy` subdirectory
so Hex1b's startup ACL enforcement does not rewrite the override directory's permissions.
The shorter unique filenames keep paths within the previous allocation's length budget.
Hex1b snapshots the explicit path before deferred startup,
so later parent or child environment changes cannot redirect it. Hex1b owns socket cleanup.
Linux and macOS use direct PTYs and need no socket path.

## Philosophy

Expand Down
41 changes: 36 additions & 5 deletions docs/specs/with-terminal.md
Original file line number Diff line number Diff line change
Expand Up @@ -336,10 +336,14 @@ it does not lock the terminal, its creator's automation, or other viewers.
### Browser requirements and package pairing

The dashboard uses `@hex1b/web-terminal` and the `Hex1b` NuGet package at
exactly `0.168.0`. HWT1 is experimental state transfer
exactly `0.171.0`. HWT1 is experimental state transfer
between these paired packages, not a stable wire contract implemented by
Aspire. Upgrade both together. The full npm `dist` tree is vendored, including
module workers, relative imports, fonts and licenses.
Aspire. Upgrade both together. The vendored runtime consists of one bundled
JavaScript file for the client and both workers, a font, and two licenses.
Worker roles use fragments on the bundled file URL rather than separate worker
modules; the dashboard references the standalone vendored bundle for both.
The 0.171 producer retains at most 200 command marks even when older backing
text is still present; scrollback text is retained independently.

The dashboard uses the package's automatic renderer selection: WebGPU is
preferred, with WebGL2 used when WebGPU capabilities or device acquisition are
Expand Down Expand Up @@ -376,7 +380,10 @@ The package handles Ctrl/Cmd+click on authoritative OSC 8 hyperlinks in live
output and history. HMP state replay preserves link destinations across late
attachment and reconnect. It only opens absolute HTTP, HTTPS and mailto destinations
with `noopener,noreferrer`; plain clicks and drags retain selection/application
behavior. Aspire adds no custom opener or plain-text URL detection. See the
behavior. Aspire also enables Hex1b's per-view plain-text HTTP/HTTPS URL detector
with dashed underlines and a Ctrl/Cmd-click action that opens a new tab with
`noopener,noreferrer`. Remote file paths and custom URI schemes are not enabled.
See the
[hyperlink PR](https://github.com/mitchdenny/hex1b/pull/489),
[renderer PR](https://github.com/mitchdenny/hex1b/pull/491), and
[hyperlink replay fix](https://github.com/mitchdenny/hex1b/pull/493).
Expand Down Expand Up @@ -450,7 +457,31 @@ input to the footer controls; <kbd>Shift+F6</kbd> moves focus to the preceding
dashboard control. Hiding the hint preserves its space so focus changes do not
resize the terminal or move the footer controls.

Dock tabs share the Resources/Parameters tab styling. The dock resize handle
Outside the dock, terminal headers keep a fixed icon slot before the workload title. Active progress
uses a ring with the percentage in its tooltip, not inline text; otherwise the
resource page shows its resource icon, and other surfaces use a terminal icon.
Error and warning progress retain their accessible labels and theme colors.
Working directories shorten in the middle when space is limited; UNC paths keep
their server and share together or show no path if even the root cannot fit.
The terminal's Light/Dark palette is an explicit browser preference, independent
of the Dashboard theme. It defaults to Dark and can be changed in the terminal
footer; Dashboard chrome still follows Settings theme changes.

Dock tabs use the titles supplied when the terminals are created, not live workload
titles. The dock does not show a separate workload title, icon, progress, or working
directory alongside the tabs.

Dock tabs share the Resources/Parameters tab styling. Drag a tab to reorder it,
or focus its title and press Alt+Shift+Left/Right. Reordering keeps the active
terminal and mounted viewers unchanged. The order is local to the dashboard
session and survives recovery snapshots; newly discovered terminals append.
Tabs stay on one row, with horizontal scrolling. Left/right buttons remain
visible beside **Open in window**, disabled when there are no more tabs in
that direction. A thin line between tabs indicates the drop position.
Activating a tab brings its title and close button into view,
and dragging near either edge scrolls the strip to reach off-screen tabs.

The dock resize handle
uses the dashboard's Fluent splitter styling, including neutral gray hover,
drag and keyboard-focus feedback.

Expand Down
1 change: 1 addition & 0 deletions eng/github-ci/test-trigger-map.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ path_rules:

- paths:
- src/Aspire.Dashboard/Components/Controls/TerminalView.razor.js
- src/Aspire.Dashboard/Components/Controls/TerminalTitle.razor.js
- src/Aspire.Dashboard/Components/Layout/TerminalDock.razor.js
- src/Aspire.Dashboard/wwwroot/js/app.js
- src/Aspire.Dashboard/wwwroot/js/app-terminalwindow.js
Expand Down
21 changes: 18 additions & 3 deletions playground/Terminals/Terminals.AppHost/AppHost.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,29 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

// WithTerminal() is currently experimental (ASPIRETERMINAL001). Suppressed here
// because this playground project intentionally exercises the experimental API.
#pragma warning disable ASPIRETERMINAL001
// This playground intentionally exercises the experimental terminal and file-based app APIs.
#pragma warning disable ASPIRETERMINAL001, ASPIRECSHARPAPPS001

using Terminals.AppHost;

var builder = DistributedApplication.CreateBuilder(args);

builder.AddCSharpApp("palette-test", "Scripts/palette-test.cs")
.WithTerminal(options =>
{
options.Columns = 120;
options.Rows = 50;
options.ShowTerminalHost = true;
});

builder.AddCSharpApp("terminal-features", "Scripts/terminal-features.cs")
.WithTerminal(options =>
{
options.Columns = 120;
options.Rows = 32;
options.ShowTerminalHost = true;
});

builder.AddPostgres("postgres").WithRepl();
builder.AddRedis("redis").WithRepl();
builder.AddValkey("valkey").WithRepl();
Expand Down
110 changes: 110 additions & 0 deletions playground/Terminals/Terminals.AppHost/Scripts/palette-test.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

// Open palette-test in the Terminals playground, then use the terminal footer's
// Terminal palette selector to compare Aspire Light and Aspire Dark.
// Run directly: dotnet run --file palette-test.cs (add -- --once to emit the chart and exit).
// Original chart inspired by the block/foreground views in https://github.com/eikenb/terminal-colors.
// SGR reference: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html

using System.Text;

const string Reset = "\u001b[0m";
string[] names = ["Black", "Red", "Green", "Yellow", "Blue", "Magenta", "Cyan", "White"];
var chart = new StringBuilder();

// Keep default and indexed colors as SGR references (e.g. ESC[31;44m), not resolved RGB.
// This lets the browser recolor existing content and selection without rerunning the script.
string Foreground(int index) => index < 8 ? $"{30 + index}" : $"{90 + index - 8}";
string Background(int index) => index < 8 ? $"{40 + index}" : $"{100 + index - 8}";
string Label(int index) => $"{index:00} {(index < 8 ? "" : "Bright ")}{names[index % 8]}";

void Cell(string text, string foreground, string background, int width)
{
chart.Append("\u001b[").Append(foreground).Append(';').Append(background).Append('m');
chart.Append(text.PadRight(width));
chart.Append(Reset);
}

chart.AppendLine("ASPIRE TERMINAL PALETTE REVIEW");
chart.AppendLine("Switch Aspire Light / Dark using the Terminal palette selector in the footer. Select text to compare selection colors.");
chart.AppendLine("ANSI names identify slots, not fixed RGB values. Low-contrast matrix cells are intentional.");
chart.AppendLine();
chart.AppendLine("DEFAULT SURFACE (uncolored cells use the palette background)");
chart.AppendLine("+--------------------------------------------------------------------------------------------------+");
chart.AppendLine("| |");
chart.AppendLine("| Default foreground: The quick brown fox jumps over the lazy dog. 0123456789 !? [] {} |");
chart.AppendLine("+--------------------------------------------------------------------------------------------------+");
chart.AppendLine();
chart.AppendLine("ANSI SWATCHES: blank fill, default text, black text (00), bright-white text (15)");

for (var start = 0; start < 16; start += 8)
{
chart.AppendLine(start == 0 ? "Normal 00-07" : "Bright 08-15 (explicit bright slots, not bold)");
for (var index = start; index < start + 8; index++)
{
chart.Append($"{index:00} {names[index % 8]}".PadRight(12));
}
chart.AppendLine();

foreach (var (text, foreground) in new[] { ("", "39"), (" Default", "39"), (" Black", "30"), (" White", "97") })
{
for (var index = start; index < start + 8; index++)
{
Cell(text, foreground, Background(index), 11);
chart.Append(' ');
}
chart.AppendLine();
}
chart.AppendLine();
}

chart.AppendLine("TEXT MATRIX: rows = foreground; columns = background; D = palette default");
chart.Append("Foreground".PadRight(18));
foreach (var column in new[] { "D", "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "10", "11", "12", "13", "14", "15" })
{
chart.Append(column.PadRight(5));
}
chart.AppendLine();

for (var foreground = -1; foreground < 16; foreground++)
{
chart.Append((foreground < 0 ? "D Default" : Label(foreground)).PadRight(18));
for (var background = -1; background < 16; background++)
{
Cell(" Aa0 ", foreground < 0 ? "39" : Foreground(foreground), background < 0 ? "49" : Background(background), 5);
}
chart.AppendLine();
}

chart.AppendLine();
chart.AppendLine($"ATTRIBUTES: Normal Aa0 \u001b[1mBold Aa0{Reset} \u001b[2mDim Aa0{Reset} \u001b[4mUnderline Aa0{Reset} \u001b[7mReverse Aa0{Reset}");
chart.AppendLine($"ANSI TEXT: \u001b[31mRed{Reset} \u001b[32mGreen{Reset} \u001b[33mYellow{Reset} \u001b[34mBlue{Reset} \u001b[35mMagenta{Reset} \u001b[36mCyan{Reset}");
chart.AppendLine($"TRUE RGB CONTROL (does not follow palette): \u001b[38;2;255;128;64mOrange #FF8040{Reset}");
chart.Append("Chart stays still for selection and screenshots. Resize or scroll as needed. Ctrl+C exits.");

using var stopping = new CancellationTokenSource();
Console.CancelKeyPress += (_, e) =>
{
e.Cancel = true;
stopping.Cancel();
};

try
{
Console.Write("\u001b]2;Aspire palette review\u0007");
Console.Write(Reset);
Console.Write(chart);
if (!args.Contains("--once"))
{
await Task.Delay(Timeout.Infinite, stopping.Token);
}
}
catch (OperationCanceledException) when (stopping.IsCancellationRequested)
{
// Leave the chart available until the user stops the resource or presses Ctrl+C.
}
finally
{
Console.Write($"{Reset}\u001b]2;\u0007");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

// Run directly with `dotnet run --file terminal-features.cs`, or open the terminal-features
// resource in the Terminals playground. No terminal library is needed: these are ordinary OSC
// escape sequences terminated by BEL (\u0007).
// Title/directory: https://iterm2.com/documentation-escape-codes.html
// Progress: https://learn.microsoft.com/windows/terminal/tutorials/progress-bar-sequences
// Command marks: https://iterm2.com/documentation-shell-integration.html

using var stopping = new CancellationTokenSource();
Console.CancelKeyPress += (_, e) =>
{
e.Cancel = true;
stopping.Cancel();
};

// Report illustrative paths (including a space to exercise URI decoding) without touching the filesystem.
var sourceDirectory = new Uri(Path.Combine(Environment.CurrentDirectory, "demo source") + Path.DirectorySeparatorChar).AbsoluteUri;
var outputDirectory = new Uri(Path.Combine(Environment.CurrentDirectory, "demo output") + Path.DirectorySeparatorChar).AbsoluteUri;

Console.WriteLine("Terminal feature driver. Watch the title bar and scrollbar. Press Ctrl+C to stop.");

try
{
for (var cycle = 1; ; cycle++)
{
Console.WriteLine($"\u001b]2;Terminal demo - cycle {cycle}\u0007");
Console.WriteLine($"\u001b]7;{sourceDirectory}\u0007");
Console.WriteLine("\u001b]133;A\u0007$ \u001b]133;B\u0007terminal-feature-demo");
Console.WriteLine("\u001b]133;C\u0007");

Console.WriteLine("\u001b]9;4;3\u0007Indeterminate progress: preparing work...");
await Task.Delay(2000, stopping.Token);

Console.WriteLine($"\u001b]2;Building - cycle {cycle}\u0007");
for (var percentage = 0; percentage <= 100; percentage += 10)
{
Console.WriteLine($"\u001b]9;4;1;{percentage}\u0007Determinate progress: {percentage}%");
Console.WriteLine($" Cycle {cycle}: processing item {percentage + 1}");
Console.WriteLine(" More output for scrollback, selection and command-marker navigation.");
await Task.Delay(400, stopping.Token);
}

Console.WriteLine($"\u001b]7;{outputDirectory}\u0007");
Console.WriteLine("\u001b]2;Warning - retrying\u0007");
Console.WriteLine("\u001b]9;4;4;60\u0007Warning progress at 60% (simulated).");
await Task.Delay(2000, stopping.Token);

Console.WriteLine("\u001b]2;Error - demonstration only\u0007");
Console.WriteLine("\u001b]9;4;2;75\u0007Error progress at 75% (simulated).");
await Task.Delay(2000, stopping.Token);

Console.WriteLine("\u001b]2;Complete\u0007");
Console.WriteLine("\u001b]9;4;1;100\u0007Complete at 100%.");
// Alternate completion status so retained command markers include successful and failed commands.
Console.WriteLine($"\u001b]133;D;{cycle % 2}\u0007");
await Task.Delay(2000, stopping.Token);

Console.WriteLine("\u001b]9;4;0\u0007Progress cleared.");
Console.WriteLine("\u001b]2;\u0007Title cleared: the title bar should show its fallback name.");
await Task.Delay(2000, stopping.Token);
}
}
catch (OperationCanceledException) when (stopping.IsCancellationRequested)
{
// Ctrl+C stops the continuous demo without reporting a failed workload.
}
finally
{
Console.WriteLine("\u001b]9;4;0\u0007\u001b]2;\u0007Driver stopped.");
}
53 changes: 53 additions & 0 deletions src/Aspire.Dashboard/Components/Controls/TerminalTitle.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
@namespace Aspire.Dashboard.Components.Controls

<div class="terminal-metadata" data-directory="@State?.WorkingDirectory" @ref="_metadataElement">
<div class="terminal-icon" data-state="@(HasProgress ? State!.ProgressState : "none")" title="@(HasProgress ? ProgressTooltip : null)">
@if (HasProgress)
{
<AspireProgressRing Width="16px" Value="@ProgressValue" AriaLabel="@ProgressLabel" />
}
else
{
<FluentIcon Class="terminal-idle-icon" Value="@(IdleIcon ?? s_terminalIcon)" Width="16px" Color="Color.Primary" aria-hidden="true" />
}
</div>
@if (!string.IsNullOrEmpty(DisplayTitle))
{
<div class="terminal-title-container">
<FluentButton Id="@_titleButtonId"
Class="terminal-title-button aspire-button"
Appearance="ButtonAppearance.Transparent"
AdditionalAttributes="@TitleCopyAttributes">
<span class="terminal-title-content">
<span class="terminal-title">@DisplayTitle</span>
<span class="terminal-title-copy-icons" aria-hidden="true">
<FluentIcon Class="copy-icon" Icon="Icons.Regular.Size16.Copy" Color="Color.Primary" />
<FluentIcon Class="checkmark-icon" Icon="Icons.Regular.Size16.Checkmark" Color="Color.Primary" Style="display:none" />
</span>
</span>
</FluentButton>
<span class="terminal-copy-status" role="status" aria-live="polite"></span>
</div>
}
@if (!string.IsNullOrEmpty(State?.WorkingDirectory))
{
<div class="terminal-directory-container">
<FluentButton Id="@_directoryButtonId"
Class="terminal-directory aspire-button"
Appearance="ButtonAppearance.Transparent"
AdditionalAttributes="@DirectoryCopyAttributes">
<span class="terminal-directory-content">
<span class="terminal-directory-text">
<span class="terminal-directory-measure" aria-hidden="true">@State.WorkingDirectory</span>
<span class="terminal-directory-display" aria-hidden="true"></span>
</span>
<span class="terminal-directory-copy-icons" aria-hidden="true">
<FluentIcon Class="copy-icon" Icon="Icons.Regular.Size16.Copy" Color="Color.Primary" />
<FluentIcon Class="checkmark-icon" Icon="Icons.Regular.Size16.Checkmark" Color="Color.Primary" Style="display:none" />
</span>
</span>
</FluentButton>
<span class="terminal-copy-status" role="status" aria-live="polite"></span>
</div>
}
</div>
Loading
Loading