feat(ui): add reusable ModalShell control
This commit is contained in:
@@ -9,6 +9,7 @@
|
|||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
<ResourceInclude Source="avares://ClaudeDo.Ui/Design/Tokens.axaml" />
|
<ResourceInclude Source="avares://ClaudeDo.Ui/Design/Tokens.axaml" />
|
||||||
|
<ResourceInclude Source="avares://ClaudeDo.Ui/Views/Controls/ModalShell.axaml" />
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
|
||||||
<!-- Converters -->
|
<!-- Converters -->
|
||||||
|
|||||||
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