feat(ui): add reusable ModalShell control
This commit is contained in:
43
src/ClaudeDo.Ui/Views/Controls/ModalShell.axaml
Normal file
43
src/ClaudeDo.Ui/Views/Controls/ModalShell.axaml
Normal file
@@ -0,0 +1,43 @@
|
||||
<ResourceDictionary xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ctl="using:ClaudeDo.Ui.Views.Controls">
|
||||
<ControlTheme x:Key="{x:Type ctl:ModalShell}" TargetType="ctl:ModalShell">
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate>
|
||||
<Border Background="{DynamicResource SurfaceBrush}"
|
||||
BorderBrush="{DynamicResource LineBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="{DynamicResource ModalCornerRadius}"
|
||||
ClipToBounds="True">
|
||||
<DockPanel>
|
||||
<Border Name="PART_TitleBar" DockPanel.Dock="Top" Height="36"
|
||||
Background="{DynamicResource DeepBrush}"
|
||||
BorderBrush="{DynamicResource LineBrush}"
|
||||
BorderThickness="0,0,0,1">
|
||||
<Grid ColumnDefinitions="*,Auto" Margin="14,0">
|
||||
<TextBlock Text="{TemplateBinding Title}"
|
||||
FontFamily="{DynamicResource MonoFont}"
|
||||
FontSize="{DynamicResource FontSizeMono}"
|
||||
LetterSpacing="1.4"
|
||||
Foreground="{DynamicResource TextBrush}"
|
||||
VerticalAlignment="Center"/>
|
||||
<Button Grid.Column="1" Classes="icon-btn" Content="✕"
|
||||
FontSize="{DynamicResource FontSizeBody}"
|
||||
Command="{TemplateBinding CloseCommand}"
|
||||
VerticalAlignment="Center"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
<Border Name="PART_Footer" DockPanel.Dock="Bottom"
|
||||
Background="{DynamicResource DeepBrush}"
|
||||
BorderBrush="{DynamicResource LineBrush}"
|
||||
BorderThickness="0,1,0,0"
|
||||
IsVisible="{TemplateBinding Footer, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||
<ContentPresenter Content="{TemplateBinding Footer}" Margin="16,8"/>
|
||||
</Border>
|
||||
<ContentPresenter Content="{TemplateBinding Content}"/>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
</ControlTheme>
|
||||
</ResourceDictionary>
|
||||
38
src/ClaudeDo.Ui/Views/Controls/ModalShell.axaml.cs
Normal file
38
src/ClaudeDo.Ui/Views/Controls/ModalShell.axaml.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System;
|
||||
using System.Windows.Input;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Input;
|
||||
|
||||
namespace ClaudeDo.Ui.Views.Controls;
|
||||
|
||||
/// <summary>Reusable modal chrome: titlebar (drag + close) wrapping a body and optional footer.</summary>
|
||||
public class ModalShell : ContentControl
|
||||
{
|
||||
public static readonly StyledProperty<string?> TitleProperty =
|
||||
AvaloniaProperty.Register<ModalShell, string?>(nameof(Title));
|
||||
|
||||
public static readonly StyledProperty<object?> FooterProperty =
|
||||
AvaloniaProperty.Register<ModalShell, object?>(nameof(Footer));
|
||||
|
||||
public static readonly StyledProperty<ICommand?> CloseCommandProperty =
|
||||
AvaloniaProperty.Register<ModalShell, ICommand?>(nameof(CloseCommand));
|
||||
|
||||
public string? Title { get => GetValue(TitleProperty); set => SetValue(TitleProperty, value); }
|
||||
public object? Footer { get => GetValue(FooterProperty); set => SetValue(FooterProperty, value); }
|
||||
public ICommand? CloseCommand { get => GetValue(CloseCommandProperty); set => SetValue(CloseCommandProperty, value); }
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
if (e.NameScope.Find<Border>("PART_TitleBar") is { } bar)
|
||||
bar.PointerPressed += OnTitleBarPressed;
|
||||
}
|
||||
|
||||
private void OnTitleBarPressed(object? sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed && VisualRoot is Window w)
|
||||
w.BeginMoveDrag(e);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user