feat(ui): add About modal opened from Help menu
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@ using ClaudeDo.Data;
|
||||
using ClaudeDo.Data.Models;
|
||||
using ClaudeDo.Ui.Services;
|
||||
using ClaudeDo.Ui.ViewModels.Islands;
|
||||
using ClaudeDo.Ui.ViewModels.Modals;
|
||||
using ClaudeDo.Ui.ViewModels.Planning;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
@@ -35,6 +36,9 @@ public sealed partial class IslandsShellViewModel : ViewModelBase
|
||||
// Set by MainWindow to open the conflict resolution dialog.
|
||||
public Func<ConflictResolutionViewModel, Task>? ShowConflictDialog { get; set; }
|
||||
|
||||
// Set by MainWindow to open the About dialog.
|
||||
public Func<AboutModalViewModel, Task>? ShowAboutModal { get; set; }
|
||||
|
||||
[ObservableProperty] private bool _isUpdateBannerVisible;
|
||||
[ObservableProperty] private string? _updateBannerLatestVersion;
|
||||
[ObservableProperty] private string? _inlineUpdateStatus;
|
||||
@@ -222,6 +226,13 @@ public sealed partial class IslandsShellViewModel : ViewModelBase
|
||||
if (InlineUpdateStatus == text) InlineUpdateStatus = null;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task OpenAbout()
|
||||
{
|
||||
var vm = new AboutModalViewModel();
|
||||
if (ShowAboutModal is not null) await ShowAboutModal(vm);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private async Task CheckForUpdatesAsync()
|
||||
{
|
||||
|
||||
34
src/ClaudeDo.Ui/ViewModels/Modals/AboutModalViewModel.cs
Normal file
34
src/ClaudeDo.Ui/ViewModels/Modals/AboutModalViewModel.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using ClaudeDo.Data;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
namespace ClaudeDo.Ui.ViewModels.Modals;
|
||||
|
||||
public sealed partial class AboutModalViewModel : ViewModelBase
|
||||
{
|
||||
public string AppVersion { get; } =
|
||||
Assembly.GetExecutingAssembly().GetName().Version?.ToString(3) ?? "0.0.0";
|
||||
public string DataFolderPath { get; } = Paths.AppDataRoot();
|
||||
public string LogsFolderPath { get; } = Path.Combine(Paths.AppDataRoot(), "logs");
|
||||
public string WorkerConfigPath { get; } = Path.Combine(Paths.AppDataRoot(), "worker.config.json");
|
||||
|
||||
public Action? CloseAction { get; set; }
|
||||
|
||||
[RelayCommand] private void Close() => CloseAction?.Invoke();
|
||||
|
||||
[RelayCommand]
|
||||
private void OpenPath(string? path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path)) return;
|
||||
try
|
||||
{
|
||||
var target = File.Exists(path) ? path : (Directory.Exists(path) ? path : null);
|
||||
if (target is null) return;
|
||||
Process.Start(new ProcessStartInfo("explorer.exe", $"\"{target}\"") { UseShellExecute = true });
|
||||
}
|
||||
catch { /* ignore */ }
|
||||
}
|
||||
}
|
||||
@@ -67,6 +67,7 @@
|
||||
Foreground="{DynamicResource TextDimBrush}">
|
||||
<MenuItem Header="Check for updates"
|
||||
Command="{Binding CheckForUpdatesCommand}"/>
|
||||
<MenuItem Header="About…" Command="{Binding OpenAboutCommand}"/>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</StackPanel>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using ClaudeDo.Ui.ViewModels;
|
||||
using ClaudeDo.Ui.Views.Modals;
|
||||
using ClaudeDo.Ui.Views.Planning;
|
||||
|
||||
namespace ClaudeDo.Ui.Views;
|
||||
@@ -23,6 +24,13 @@ public partial class MainWindow : Window
|
||||
var modal = new ConflictResolutionView { DataContext = conflictVm };
|
||||
await modal.ShowDialog(this);
|
||||
};
|
||||
vm.ShowAboutModal = async (aboutVm) =>
|
||||
{
|
||||
var dlg = new AboutModalView { DataContext = aboutVm };
|
||||
var tcs = new TaskCompletionSource<bool>();
|
||||
aboutVm.CloseAction = () => { dlg.Close(); tcs.TrySetResult(true); };
|
||||
await dlg.ShowDialog(this);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
49
src/ClaudeDo.Ui/Views/Modals/AboutModalView.axaml
Normal file
49
src/ClaudeDo.Ui/Views/Modals/AboutModalView.axaml
Normal file
@@ -0,0 +1,49 @@
|
||||
<Window xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:vm="using:ClaudeDo.Ui.ViewModels.Modals"
|
||||
x:Class="ClaudeDo.Ui.Views.Modals.AboutModalView"
|
||||
x:DataType="vm:AboutModalViewModel"
|
||||
Title="About ClaudeDo"
|
||||
Width="480" Height="280"
|
||||
SystemDecorations="None"
|
||||
ExtendClientAreaToDecorationsHint="True"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
Background="{DynamicResource SurfaceBrush}">
|
||||
<Window.KeyBindings>
|
||||
<KeyBinding Gesture="Escape" Command="{Binding CloseCommand}"/>
|
||||
</Window.KeyBindings>
|
||||
<Border BorderBrush="{DynamicResource LineBrush}" BorderThickness="1">
|
||||
<Grid RowDefinitions="36,*,52">
|
||||
<Border Grid.Row="0" Background="{DynamicResource DeepBrush}"
|
||||
BorderBrush="{DynamicResource LineBrush}" BorderThickness="0,0,0,1">
|
||||
<Grid ColumnDefinitions="*,Auto" Margin="14,0">
|
||||
<TextBlock Text="ABOUT" FontFamily="{DynamicResource MonoFont}" FontSize="11"
|
||||
LetterSpacing="1.4" Foreground="{DynamicResource TextBrush}" VerticalAlignment="Center"/>
|
||||
<Button Grid.Column="1" Classes="icon-btn" Content="✕" FontSize="12"
|
||||
Command="{Binding CloseCommand}" VerticalAlignment="Center"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
<ScrollViewer Grid.Row="1" Padding="20,16">
|
||||
<Grid RowDefinitions="Auto,Auto,Auto,Auto" ColumnDefinitions="90,*,Auto" RowSpacing="10">
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Text="Version" Foreground="{DynamicResource TextDimBrush}" VerticalAlignment="Center"/>
|
||||
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding AppVersion}" FontFamily="{DynamicResource MonoFont}" VerticalAlignment="Center"/>
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Text="Data" Foreground="{DynamicResource TextDimBrush}" VerticalAlignment="Center"/>
|
||||
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding DataFolderPath}" FontFamily="{DynamicResource MonoFont}" TextTrimming="CharacterEllipsis" VerticalAlignment="Center"/>
|
||||
<Button Grid.Row="1" Grid.Column="2" Content="Open" Command="{Binding OpenPathCommand}" CommandParameter="{Binding DataFolderPath}"/>
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Text="Logs" Foreground="{DynamicResource TextDimBrush}" VerticalAlignment="Center"/>
|
||||
<TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding LogsFolderPath}" FontFamily="{DynamicResource MonoFont}" TextTrimming="CharacterEllipsis" VerticalAlignment="Center"/>
|
||||
<Button Grid.Row="2" Grid.Column="2" Content="Open" Command="{Binding OpenPathCommand}" CommandParameter="{Binding LogsFolderPath}"/>
|
||||
<TextBlock Grid.Row="3" Grid.Column="0" Text="Config" Foreground="{DynamicResource TextDimBrush}" VerticalAlignment="Center"/>
|
||||
<TextBlock Grid.Row="3" Grid.Column="1" Text="{Binding WorkerConfigPath}" FontFamily="{DynamicResource MonoFont}" TextTrimming="CharacterEllipsis" VerticalAlignment="Center"/>
|
||||
<Button Grid.Row="3" Grid.Column="2" Content="Open" Command="{Binding OpenPathCommand}" CommandParameter="{Binding WorkerConfigPath}"/>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
<Border Grid.Row="2" Background="{DynamicResource DeepBrush}"
|
||||
BorderBrush="{DynamicResource LineBrush}" BorderThickness="0,1,0,0">
|
||||
<StackPanel Orientation="Horizontal" Spacing="8" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="16,0">
|
||||
<Button Content="Close" Command="{Binding CloseCommand}" MinWidth="90"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Window>
|
||||
10
src/ClaudeDo.Ui/Views/Modals/AboutModalView.axaml.cs
Normal file
10
src/ClaudeDo.Ui/Views/Modals/AboutModalView.axaml.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace ClaudeDo.Ui.Views.Modals;
|
||||
|
||||
public partial class AboutModalView : Window
|
||||
{
|
||||
public AboutModalView() => InitializeComponent();
|
||||
private void InitializeComponent() => AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
Reference in New Issue
Block a user