Merge PR #277: standardize titlebars

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Scott Hanselman 2026-05-05 16:43:35 -07:00
commit b356697e02
11 changed files with 135 additions and 22 deletions

View File

@ -20,6 +20,7 @@ public sealed class WelcomeDialog : WindowEx
public WelcomeDialog()
{
Title = LocalizationHelper.GetString("WindowTitle_Welcome");
ExtendsContentIntoTitleBar = true;
this.SetWindowSize(480, 440);
this.CenterOnScreen();
this.SetIcon("Assets\\openclaw.ico");
@ -123,7 +124,37 @@ public sealed class WelcomeDialog : WindowEx
Grid.SetRow(buttonPanel, 2);
root.Children.Add(buttonPanel);
Content = root;
// Wrap content with custom titlebar
var outerGrid = new Grid();
outerGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(48) });
outerGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
var titleBar = new Grid { Padding = new Thickness(16, 0, 140, 0) };
var titleIcon = new TextBlock
{
Text = "🦞",
FontSize = 20,
VerticalAlignment = VerticalAlignment.Center,
Margin = new Thickness(0, 0, 10, 0)
};
var titleTextBlock = new TextBlock
{
Text = LocalizationHelper.GetString("WindowTitle_Welcome"),
FontSize = 13,
Style = (Style)Application.Current.Resources["CaptionTextBlockStyle"],
VerticalAlignment = VerticalAlignment.Center
};
var titleStack = new StackPanel { Orientation = Orientation.Horizontal };
titleStack.Children.Add(titleIcon);
titleStack.Children.Add(titleTextBlock);
titleBar.Children.Add(titleStack);
Grid.SetRow(titleBar, 0);
outerGrid.Children.Add(titleBar);
Grid.SetRow(root, 1);
outerGrid.Children.Add(root);
Content = outerGrid;
SetTitleBar(titleBar);
Closed += (s, e) => _tcs.TrySetResult(_result);

View File

@ -55,6 +55,7 @@ public sealed class OnboardingWindow : WindowEx
: null;
Title = LocalizationHelper.GetString("Onboarding_Title");
ExtendsContentIntoTitleBar = true;
this.SetWindowSize(720, 900);
this.CenterOnScreen();
this.SetIcon("Assets\\openclaw.ico");
@ -99,19 +100,50 @@ public sealed class OnboardingWindow : WindowEx
_chatOverlay.Visibility = Visibility.Collapsed;
_chatOverlay.VerticalAlignment = VerticalAlignment.Top;
// Root grid: functional UI host fills everything, overlay sits on top (except nav bar)
// Root grid: titlebar row + content area
_rootGrid = new Grid
{
Background = GetThemeBrush("SolidBackgroundFillColorBaseBrush")
};
_rootGrid.Children.Add(_host);
_rootGrid.Children.Add(_chatOverlay);
_rootGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(48) });
_rootGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
// Custom title bar — matches HubWindow treatment
var titleBar = new Grid { Padding = new Thickness(16, 0, 140, 0) };
var titleIcon = new TextBlock
{
Text = "🦞",
FontSize = 20,
VerticalAlignment = VerticalAlignment.Center,
Margin = new Thickness(0, 0, 10, 0)
};
var titleText = new TextBlock
{
Text = LocalizationHelper.GetString("Onboarding_Title"),
FontSize = 13,
Style = (Style)Application.Current.Resources["CaptionTextBlockStyle"],
VerticalAlignment = VerticalAlignment.Center
};
var titleStack = new StackPanel { Orientation = Orientation.Horizontal };
titleStack.Children.Add(titleIcon);
titleStack.Children.Add(titleText);
titleBar.Children.Add(titleStack);
Grid.SetRow(titleBar, 0);
_rootGrid.Children.Add(titleBar);
SetTitleBar(titleBar);
// Content area
var contentGrid = new Grid();
contentGrid.Children.Add(_host);
contentGrid.Children.Add(_chatOverlay);
Grid.SetRow(contentGrid, 1);
_rootGrid.Children.Add(contentGrid);
Content = _rootGrid;
Closed += OnClosed;
// Size the overlay after layout — leave space for the nav bar
// Nav bar is ~60px + VStack bottom padding 20px = 80px minimum
_rootGrid.SizeChanged += (_, args) =>
// Size the overlay after layout — leave space for the nav bar (~84px)
// contentGrid is already in row 1 (below titlebar), so no need to subtract titlebar height
contentGrid.SizeChanged += (_, args) =>
{
_chatOverlay.Height = Math.Max(0, args.NewSize.Height - 84);
};

View File

@ -1018,8 +1018,8 @@ public sealed class NodeService : IDisposable
{
_canvasWindow = new CanvasWindow();
_canvasWindow.SetTrustedGatewayOrigin(GatewayUrl, _token);
_canvasWindow.Activate();
}
_canvasWindow?.Activate();
}
// Mutable context shared with GatewayActionTransport. SessionKey is updated

View File

@ -2305,6 +2305,9 @@ On your gateway host (Mac/Linux), run:
<data name="CanvasWindowReloadToolTip.Content" xml:space="preserve">
<value>Reload</value>
</data>
<data name="CanvasReloadButton_AutomationName" xml:space="preserve">
<value>Reload Canvas</value>
</data>
<data name="TrayMenuWindow_winexWindowEx_2.Title" xml:space="preserve">
<value>OpenClaw Menu</value>
</data>

View File

@ -2238,6 +2238,9 @@ Sur votre hôte passerelle (Mac/Linux), exécutez :
<data name="CanvasWindowReloadToolTip.Content" xml:space="preserve">
<value>Recharger</value>
</data>
<data name="CanvasReloadButton_AutomationName" xml:space="preserve">
<value>Recharger le canvas</value>
</data>
<data name="TrayMenuWindow_winexWindowEx_2.Title" xml:space="preserve">
<value>OpenClaw Menu</value>
</data>

View File

@ -2238,6 +2238,9 @@ Voer op uw gateway-host (Mac/Linux) uit:
<data name="CanvasWindowReloadToolTip.Content" xml:space="preserve">
<value>Opnieuw laden</value>
</data>
<data name="CanvasReloadButton_AutomationName" xml:space="preserve">
<value>Canvas opnieuw laden</value>
</data>
<data name="TrayMenuWindow_winexWindowEx_2.Title" xml:space="preserve">
<value>OpenClaw Menu</value>
</data>

View File

@ -2238,6 +2238,9 @@
<data name="CanvasWindowReloadToolTip.Content" xml:space="preserve">
<value>重新加载</value>
</data>
<data name="CanvasReloadButton_AutomationName" xml:space="preserve">
<value>重新加载 Canvas</value>
</data>
<data name="TrayMenuWindow_winexWindowEx_2.Title" xml:space="preserve">
<value>OpenClaw Menu</value>
</data>

View File

@ -2238,6 +2238,9 @@
<data name="CanvasWindowReloadToolTip.Content" xml:space="preserve">
<value>重新載入</value>
</data>
<data name="CanvasReloadButton_AutomationName" xml:space="preserve">
<value>重新載入 Canvas</value>
</data>
<data name="TrayMenuWindow_winexWindowEx_2.Title" xml:space="preserve">
<value>OpenClaw Menu</value>
</data>

View File

@ -20,7 +20,7 @@
</Grid.RowDefinitions>
<!-- Custom title bar -->
<Grid x:Name="AppTitleBar" Grid.Row="0" Height="40" Padding="12,0">
<Grid x:Name="AppTitleBar" Grid.Row="0" Height="48" Padding="16,0,140,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
@ -28,21 +28,21 @@
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="10" VerticalAlignment="Center">
<TextBlock Text="🎨" FontSize="14"/>
<TextBlock Text="🎨" FontSize="20"/>
<TextBlock x:Uid="CanvasWindow_TextBlock_31" Text="OpenClaw Canvas" Style="{StaticResource CaptionTextBlockStyle}"
VerticalAlignment="Center" FontWeight="SemiBold"/>
FontSize="13" VerticalAlignment="Center" FontWeight="SemiBold"/>
</StackPanel>
<StackPanel Grid.Column="2" Orientation="Horizontal" Spacing="2" VerticalAlignment="Center"
Margin="0,0,132,0">
<Button Click="OnRetryClick"
Width="32" Height="32" Padding="0" Background="Transparent" BorderThickness="0">
<ToolTipService.ToolTip>
<ToolTip x:Uid="CanvasWindowReloadToolTip" Content="Reload"/>
</ToolTipService.ToolTip>
<FontIcon Glyph="&#xE72C;" FontSize="13"/>
</Button>
</StackPanel>
<Button x:Name="CanvasTitlebarReloadButton"
Grid.Column="2" Click="OnRetryClick"
AutomationProperties.AutomationId="CanvasTitlebarReloadButton"
Width="28" Height="28" Padding="0" Background="Transparent" BorderThickness="0"
VerticalAlignment="Center" Margin="8,0,0,0">
<ToolTipService.ToolTip>
<ToolTip x:Uid="CanvasWindowReloadToolTip" Content="Reload"/>
</ToolTipService.ToolTip>
<FontIcon Glyph="&#xE72C;" FontSize="12"/>
</Button>
</Grid>
<!-- Content area -->

View File

@ -5,6 +5,7 @@ using System.Threading;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Automation;
using Microsoft.Web.WebView2.Core;
using OpenClaw.Shared;
using OpenClawTray.Helpers;
@ -212,6 +213,9 @@ public sealed partial class CanvasWindow : WindowEx
public CanvasWindow()
{
this.InitializeComponent();
AutomationProperties.SetName(
CanvasTitlebarReloadButton,
LocalizationHelper.GetString("CanvasReloadButton_AutomationName"));
ExtendsContentIntoTitleBar = true;
SetTitleBar(AppTitleBar);
this.SetIcon("Assets\\openclaw.ico");

View File

@ -79,6 +79,7 @@ public sealed class SetupWizardWindow : WindowEx
_draftEnableNodeMode = settings.EnableNodeMode;
Title = LocalizationHelper.GetString("Setup_Title");
ExtendsContentIntoTitleBar = true;
this.SetWindowSize(720, 900);
this.CenterOnScreen();
this.SetIcon("Assets\\openclaw.ico");
@ -370,7 +371,37 @@ public sealed class SetupWizardWindow : WindowEx
Grid.SetRow(navPanel, 3);
root.Children.Add(navPanel);
Content = root;
// Wrap content in a container with custom titlebar
var outerGrid = new Grid();
outerGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(48) });
outerGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
var titleBar = new Grid { Padding = new Thickness(16, 0, 140, 0) };
var titleIcon = new TextBlock
{
Text = "🦞",
FontSize = 20,
VerticalAlignment = VerticalAlignment.Center,
Margin = new Thickness(0, 0, 10, 0)
};
var titleText = new TextBlock
{
Text = LocalizationHelper.GetString("Setup_Title"),
FontSize = 13,
Style = (Style)Application.Current.Resources["CaptionTextBlockStyle"],
VerticalAlignment = VerticalAlignment.Center
};
var titleStack = new StackPanel { Orientation = Orientation.Horizontal };
titleStack.Children.Add(titleIcon);
titleStack.Children.Add(titleText);
titleBar.Children.Add(titleStack);
Grid.SetRow(titleBar, 0);
outerGrid.Children.Add(titleBar);
Grid.SetRow(root, 1);
outerGrid.Children.Add(root);
Content = outerGrid;
SetTitleBar(titleBar);
Logger.Info("[Setup] Wizard opened");
// Load device identity for step 3