diff --git a/src/ClaudeDo.App/App.axaml.cs b/src/ClaudeDo.App/App.axaml.cs index 1c2317d9..0aaead40 100644 --- a/src/ClaudeDo.App/App.axaml.cs +++ b/src/ClaudeDo.App/App.axaml.cs @@ -3,6 +3,7 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; +using ClaudeDo.Ui; using ClaudeDo.Ui.Services; using ClaudeDo.Ui.ViewModels; using ClaudeDo.Ui.Views; @@ -22,6 +23,8 @@ public partial class App : Application public override void Initialize() { AvaloniaXamlLoader.Load(this); + if (_services?.GetService() is { } settings) + AccentPresetService.Apply(AccentPresets.Find(settings.AccentPreset)); } public override void OnFrameworkInitializationCompleted() diff --git a/src/ClaudeDo.Localization/locales/de.json b/src/ClaudeDo.Localization/locales/de.json index 309f4fcc..930d8594 100644 --- a/src/ClaudeDo.Localization/locales/de.json +++ b/src/ClaudeDo.Localization/locales/de.json @@ -31,7 +31,11 @@ "weekdayFriday": "Freitag", "weekdaySaturday": "Samstag", "sessionSkills": "Session-Skills", - "sessionSkillsHint": "Gilt für jede Aufgabe. Kombiniert sich mit Listen- und Aufgaben-Auswahl." + "sessionSkillsHint": "Gilt für jede Aufgabe. Kombiniert sich mit Listen- und Aufgaben-Auswahl.", + "accentPreset": "Akzentfarbe", + "accentPresetMoss": "Moos", + "accentPresetPeat": "Torf", + "accentPresetSea": "Meer" }, "worktrees": { "strategy": "Strategie", diff --git a/src/ClaudeDo.Localization/locales/en.json b/src/ClaudeDo.Localization/locales/en.json index 06001fb6..0c6d30c1 100644 --- a/src/ClaudeDo.Localization/locales/en.json +++ b/src/ClaudeDo.Localization/locales/en.json @@ -31,7 +31,11 @@ "weekdayFriday": "Friday", "weekdaySaturday": "Saturday", "sessionSkills": "Session skills", - "sessionSkillsHint": "Applied to every task. Combines with list- and task-level selections." + "sessionSkillsHint": "Applied to every task. Combines with list- and task-level selections.", + "accentPreset": "Accent color", + "accentPresetMoss": "Moss", + "accentPresetPeat": "Peat", + "accentPresetSea": "Sea" }, "worktrees": { "strategy": "Strategy", diff --git a/src/ClaudeDo.Ui/AccentPresets.cs b/src/ClaudeDo.Ui/AccentPresets.cs new file mode 100644 index 00000000..76e8252c --- /dev/null +++ b/src/ClaudeDo.Ui/AccentPresets.cs @@ -0,0 +1,43 @@ +using Avalonia.Media; +using ClaudeDo.Ui.Localization; +using ClaudeDo.Ui.ViewModels; +using CommunityToolkit.Mvvm.ComponentModel; + +namespace ClaudeDo.Ui; + +public sealed record AccentPreset(string Name, string Accent, string Dim, string Soft, string Glow); + +public static class AccentPresets +{ + // Hue 88 — moss/sage green (original) + public static readonly AccentPreset Moss = new("moss", "#FF7C9166", "#FF64785A", "#FF3E4B39", "#387C9166"); + // Hue ~40 — warm earthy brown/terra + public static readonly AccentPreset Peat = new("peat", "#FF9A7B5C", "#FF7F6449", "#FF4D3C2C", "#389A7B5C"); + // Hue ~180 — cool teal/sea-green + public static readonly AccentPreset Sea = new("sea", "#FF5B8F8C", "#FF4A7573", "#FF263D3C", "#385B8F8C"); + + public static readonly IReadOnlyList All = [Moss, Peat, Sea]; + public static AccentPreset Default => Moss; + + public static AccentPreset Find(string? name) => + All.FirstOrDefault(p => p.Name == name) ?? Default; +} + +public sealed partial class AccentPresetSwatchViewModel : ViewModelBase +{ + public AccentPreset Preset { get; } + + [ObservableProperty] private bool _isSelected; + + public Color DisplayColor { get; } + + public string DisplayName => + Loc.T($"settings.general.accentPreset{char.ToUpperInvariant(Preset.Name[0])}{Preset.Name.Substring(1)}"); + + public AccentPresetSwatchViewModel(AccentPreset preset, bool selected) + { + Preset = preset; + _isSelected = selected; + DisplayColor = Color.Parse(preset.Accent); + } +} diff --git a/src/ClaudeDo.Ui/AppSettings.cs b/src/ClaudeDo.Ui/AppSettings.cs index e9c90375..09a82aff 100644 --- a/src/ClaudeDo.Ui/AppSettings.cs +++ b/src/ClaudeDo.Ui/AppSettings.cs @@ -8,6 +8,7 @@ public sealed class AppSettings public string DbPath { get; set; } = "~/.todo-app/todo.db"; public string SignalRUrl { get; set; } = "http://127.0.0.1:47821/hub"; public string Language { get; set; } = ""; + public string AccentPreset { get; set; } = ""; private static readonly string ConfigPath = Paths.Expand("~/.todo-app/ui.config.json"); diff --git a/src/ClaudeDo.Ui/Services/AccentPresetService.cs b/src/ClaudeDo.Ui/Services/AccentPresetService.cs new file mode 100644 index 00000000..4b51fb7c --- /dev/null +++ b/src/ClaudeDo.Ui/Services/AccentPresetService.cs @@ -0,0 +1,24 @@ +using Avalonia; +using Avalonia.Media; + +namespace ClaudeDo.Ui.Services; + +public static class AccentPresetService +{ + public static void Apply(AccentPreset preset) + { + if (Application.Current is not { } app) return; + + SetBrushColor(app, "AccentBrush", preset.Accent); + SetBrushColor(app, "AccentDimBrush", preset.Dim); + SetBrushColor(app, "AccentSoftBrush", preset.Soft); + SetBrushColor(app, "AccentGlowBrush", preset.Glow); + SetBrushColor(app, "MossBrush", preset.Accent); + } + + private static void SetBrushColor(Application app, string key, string hex) + { + if (app.TryGetResource(key, null, out var value) && value is SolidColorBrush brush) + brush.Color = Color.Parse(hex); + } +} diff --git a/src/ClaudeDo.Ui/ViewModels/Modals/Settings/GeneralSettingsTabViewModel.cs b/src/ClaudeDo.Ui/ViewModels/Modals/Settings/GeneralSettingsTabViewModel.cs index 2965cada..a95c7b76 100644 --- a/src/ClaudeDo.Ui/ViewModels/Modals/Settings/GeneralSettingsTabViewModel.cs +++ b/src/ClaudeDo.Ui/ViewModels/Modals/Settings/GeneralSettingsTabViewModel.cs @@ -4,6 +4,7 @@ using ClaudeDo.Localization; using ClaudeDo.Ui.Services; using ClaudeDo.Ui.ViewModels.Agent; using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Input; namespace ClaudeDo.Ui.ViewModels.Modals.Settings; @@ -27,6 +28,27 @@ public sealed partial class GeneralSettingsTabViewModel : ViewModelBase public ObservableCollection SessionSkills { get; } = new(); + public ObservableCollection AccentPresetSwatches { get; } = new(); + private Action? _persistAccent; + + public void InitAccentPresets(string saved, Action persist) + { + _persistAccent = persist; + var current = AccentPresets.Find(saved); + AccentPresetSwatches.Clear(); + foreach (var p in AccentPresets.All) + AccentPresetSwatches.Add(new AccentPresetSwatchViewModel(p, p.Name == current.Name)); + } + + [RelayCommand] + private void SelectAccentPreset(AccentPreset preset) + { + foreach (var s in AccentPresetSwatches) + s.IsSelected = s.Preset.Name == preset.Name; + AccentPresetService.Apply(preset); + _persistAccent?.Invoke(preset.Name); + } + /// One editable row per model alias: the effort and turn budget a run gets under that /// model. Supplies the global defaults; list- and task-level max-turns overrides still win. public ObservableCollection ModelPresets { get; } = new(); diff --git a/src/ClaudeDo.Ui/ViewModels/Modals/SettingsModalViewModel.cs b/src/ClaudeDo.Ui/ViewModels/Modals/SettingsModalViewModel.cs index b28c1f77..d6fc071c 100644 --- a/src/ClaudeDo.Ui/ViewModels/Modals/SettingsModalViewModel.cs +++ b/src/ClaudeDo.Ui/ViewModels/Modals/SettingsModalViewModel.cs @@ -36,6 +36,11 @@ public sealed partial class SettingsModalViewModel : ViewModelBase appSettings.Language = code; appSettings.Save(); }); + General.InitAccentPresets(appSettings.AccentPreset, preset => + { + appSettings.AccentPreset = preset; + appSettings.Save(); + }); Worktrees = new WorktreesSettingsTabViewModel(worker); Files = new FilesSettingsTabViewModel(worker); Prime = prime; diff --git a/src/ClaudeDo.Ui/Views/Modals/SettingsModalView.axaml b/src/ClaudeDo.Ui/Views/Modals/SettingsModalView.axaml index 77fe0b62..2c2e3c3d 100644 --- a/src/ClaudeDo.Ui/Views/Modals/SettingsModalView.axaml +++ b/src/ClaudeDo.Ui/Views/Modals/SettingsModalView.axaml @@ -2,6 +2,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:vm="using:ClaudeDo.Ui.ViewModels.Modals" xmlns:settings="using:ClaudeDo.Ui.ViewModels.Modals.Settings" + xmlns:ui="using:ClaudeDo.Ui" xmlns:agent="using:ClaudeDo.Ui.ViewModels.Agent" xmlns:services="using:ClaudeDo.Ui.Services" xmlns:ctl="using:ClaudeDo.Ui.Views.Controls" @@ -61,6 +62,39 @@ + + + + + + + + + + + + + + +