Files
ClaudeDo/src/ClaudeDo.Ui/Views/Modals/ListSettingsModalView.axaml
T
2026-10-01 11:03:02 +02:00

268 lines
15 KiB
XML

<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:ClaudeDo.Ui.ViewModels.Modals"
xmlns:ctl="using:ClaudeDo.Ui.Views.Controls"
xmlns:loc="using:ClaudeDo.Ui.Localization"
xmlns:conv="using:ClaudeDo.Ui.Converters"
x:Class="ClaudeDo.Ui.Views.Modals.ListSettingsModalView"
x:DataType="vm:ListSettingsModalViewModel"
Title="{loc:Tr modals.listSettings.title}"
Width="640" Height="720"
CanResize="True"
MinWidth="560" MinHeight="520"
WindowDecorations="BorderOnly"
ExtendClientAreaToDecorationsHint="True"
ExtendClientAreaTitleBarHeightHint="-1"
WindowStartupLocation="CenterOwner"
Background="{DynamicResource SurfaceBrush}">
<Window.KeyBindings>
<KeyBinding Gesture="Escape" Command="{Binding CancelCommand}"/>
<KeyBinding Gesture="Enter" Command="{Binding SaveCommand}"/>
</Window.KeyBindings>
<ctl:ModalShell Title="{Binding HeaderTitle}" CloseCommand="{Binding CancelCommand}">
<ctl:ModalShell.Footer>
<Grid ColumnDefinitions="Auto,*,Auto" VerticalAlignment="Center">
<Button Grid.Column="0" Content="{Binding DeleteLabel}" Classes="danger"
Command="{Binding DeleteCommand}" MinWidth="90"/>
<StackPanel Grid.Column="2" Orientation="Horizontal" Spacing="8">
<Button Classes="btn" Content="{loc:Tr settings.cancel}" Command="{Binding CancelCommand}" MinWidth="90"/>
<Button Content="{loc:Tr settings.save}" Classes="primary" Command="{Binding SaveCommand}" MinWidth="90"/>
</StackPanel>
</Grid>
</ctl:ModalShell.Footer>
<!-- Body: category sidebar + tab-content host, mirroring the Settings modal. -->
<Grid ColumnDefinitions="150,1,*">
<ListBox Grid.Column="0" Name="Nav" SelectedIndex="0"
Background="Transparent" Margin="12,16,8,8"
VerticalAlignment="Top">
<ListBoxItem Content="{loc:Tr modals.listSettings.sectionGeneral}"/>
<ListBoxItem Content="{loc:Tr modals.listSettings.sectionIcon}"/>
<!-- A folder runs nothing, so it has neither agent config nor a verify command. The
TabItems stay in place (index-driven host) and just become unreachable. -->
<ListBoxItem Content="{loc:Tr modals.listSettings.sectionAgent}"
IsVisible="{Binding !IsFolder}"/>
<ListBoxItem Content="{loc:Tr modals.listSettings.sectionVerify}"
IsVisible="{Binding !IsFolder}"/>
</ListBox>
<Border Grid.Column="1" Background="{DynamicResource LineBrush}" Width="1" Margin="0,8"/>
<!-- The TabControl is the content host (index driven by the sidebar); its header strip is
re-templated away. PART_ItemsPresenter must stay (collapsed): SelectedContent is
resolved via ContainerFromIndex, and without a presenter no container is realized
-> SelectedContent is null and the body renders empty. -->
<TabControl Grid.Column="2" Padding="20,16" SelectedIndex="{Binding #Nav.SelectedIndex, Mode=OneWay}">
<TabControl.Template>
<ControlTemplate TargetType="TabControl">
<Panel>
<ItemsPresenter Name="PART_ItemsPresenter"
ItemsPanel="{TemplateBinding ItemsPanel}"
IsVisible="False"/>
<ContentPresenter Name="PART_SelectedContentHost"
Padding="{TemplateBinding Padding}"
Content="{TemplateBinding SelectedContent}"
ContentTemplate="{TemplateBinding SelectedContentTemplate}"/>
</Panel>
</ControlTemplate>
</TabControl.Template>
<!-- GENERAL -->
<TabItem Header="{loc:Tr modals.listSettings.sectionGeneral}">
<ScrollViewer>
<StackPanel Spacing="12" Margin="0,8,0,0">
<!-- Create flow only: turns this into a sidebar folder (name + icon, nothing else).
Deliberately not a second sidebar button — the "+" and the repo-import button
already sit there. -->
<StackPanel Spacing="4" IsVisible="{Binding CanToggleFolder}">
<CheckBox IsChecked="{Binding IsFolder, Mode=TwoWay}"
Content="{loc:Tr modals.listSettings.createAsFolder}"/>
<TextBlock Text="{loc:Tr modals.listSettings.createAsFolderHint}"
Opacity="0.6" FontSize="12" TextWrapping="Wrap"/>
</StackPanel>
<StackPanel Spacing="4">
<TextBlock Classes="field-label" Text="{loc:Tr modals.listSettings.name}"/>
<TextBox Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
<!-- Colour: swatches follow the accent preset (brushes mutated in place), the picker stores a literal hex.
The empty ring is "default". Shared by lists (dot) and folders (name + guide line). -->
<StackPanel Spacing="4">
<TextBlock Classes="field-label" Text="{loc:Tr modals.listSettings.color}"/>
<ListBox ItemsSource="{x:Static vm:ListSettingsModalViewModel.SwatchOptions}"
SelectedItem="{Binding SelectedSwatch, Mode=TwoWay}"
Background="Transparent" BorderThickness="0"
HorizontalAlignment="Left">
<ListBox.Styles>
<Style Selector="ListBoxItem">
<Setter Property="Padding" Value="2"/>
<Setter Property="MinHeight" Value="0"/>
</Style>
<Style Selector="Border.swatch">
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="{DynamicResource LineBrightBrush}"/>
</Style>
<Style Selector="ListBoxItem:selected Border.swatch">
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="BorderBrush" Value="{DynamicResource TextBrush}"/>
</Style>
</ListBox.Styles>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate x:DataType="x:String">
<Border Classes="swatch" Width="20" Height="20" CornerRadius="10"
Background="{Binding Converter={x:Static conv:ColorBrushConverter.Instance}, ConverterParameter=Surface2Brush}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel Orientation="Horizontal" Spacing="8" Margin="0,4,0,0">
<TextBlock Text="{loc:Tr modals.listSettings.colorCustom}" VerticalAlignment="Center"/>
<Border Classes="custom-swatch" Classes.on="{Binding IsCustomColor}" CornerRadius="4" Padding="2">
<Border.Styles>
<Style Selector="Border.custom-swatch">
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="BorderBrush" Value="Transparent"/>
</Style>
<Style Selector="Border.custom-swatch.on">
<Setter Property="BorderBrush" Value="{DynamicResource TextBrush}"/>
</Style>
</Border.Styles>
<ColorPicker Color="{Binding CustomColor, Mode=TwoWay}" IsAlphaEnabled="False" IsAlphaVisible="False"/>
</Border>
</StackPanel>
<TextBlock Text="{loc:Tr modals.listSettings.colorHint}"
Opacity="0.6" FontSize="12" TextWrapping="Wrap"/>
</StackPanel>
<StackPanel Spacing="4" IsVisible="{Binding !IsFolder}">
<TextBlock Classes="field-label" Text="{loc:Tr modals.listSettings.workingDirectory}"/>
<Grid ColumnDefinitions="*,Auto">
<TextBox Grid.Column="0" Text="{Binding WorkingDir}" PlaceholderText="{loc:Tr modals.listSettings.workingDirectoryPlaceholder}" />
<Button Classes="btn" Grid.Column="1" Content="{loc:Tr modals.listSettings.browse}" Margin="8,0,0,0" Click="BrowseClicked" />
</Grid>
<TextBlock Text="{Binding WorkingDirWarning}"
IsVisible="{Binding WorkingDirWarning, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
Foreground="{DynamicResource StatusErrorBrush}" FontSize="12" TextWrapping="Wrap"/>
</StackPanel>
<StackPanel Spacing="4" IsVisible="{Binding !IsFolder}">
<TextBlock Classes="field-label" Text="{loc:Tr modals.listSettings.baseBranch}"/>
<TextBox Text="{Binding BaseBranch, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
PlaceholderText="{loc:Tr modals.listSettings.baseBranchPlaceholder}"/>
<TextBlock Text="{loc:Tr modals.listSettings.baseBranchHint}"
Opacity="0.6" FontSize="12" TextWrapping="Wrap"/>
</StackPanel>
<StackPanel Spacing="4" IsVisible="{Binding !IsFolder}">
<TextBlock Classes="field-label" Text="{loc:Tr modals.listSettings.defaultCommitType}"/>
<ComboBox ItemsSource="{Binding CommitTypeOptions}"
SelectedItem="{Binding DefaultCommitType, Mode=TwoWay}"
HorizontalAlignment="Left" MinWidth="160" />
</StackPanel>
<StackPanel Spacing="4" IsVisible="{Binding !IsFolder}">
<CheckBox IsChecked="{Binding IsManual, Mode=TwoWay}"
Content="{loc:Tr modals.listSettings.manualList}"/>
<TextBlock Text="{loc:Tr modals.listSettings.manualListHint}"
Opacity="0.6" FontSize="12" TextWrapping="Wrap"/>
</StackPanel>
<StackPanel Spacing="4" IsVisible="{Binding !IsFolder}">
<CheckBox IsChecked="{Binding FindingsTracked, Mode=TwoWay}"
Content="{loc:Tr modals.listSettings.findingsTracked}"/>
<TextBlock Text="{loc:Tr modals.listSettings.findingsTrackedHint}"
Opacity="0.6" FontSize="12" TextWrapping="Wrap"/>
</StackPanel>
<StackPanel Spacing="4" IsVisible="{Binding !IsFolder}">
<CheckBox IsChecked="{Binding PowerUseAllowed, Mode=TwoWay}"
Content="{loc:Tr modals.listSettings.powerUseAllowed}"/>
<TextBlock Text="{loc:Tr modals.listSettings.powerUseAllowedHint}"
Opacity="0.6" FontSize="12" TextWrapping="Wrap"/>
</StackPanel>
<StackPanel Spacing="4" IsVisible="{Binding ShowTicketProject}">
<TextBlock Classes="field-label" Text="{loc:Tr modals.listSettings.ticketProject}"/>
<ComboBox ItemsSource="{Binding TicketProjects}"
SelectedItem="{Binding SelectedTicketProject, Mode=TwoWay}"
DisplayMemberBinding="{Binding Display}"
HorizontalAlignment="Left" MinWidth="240"/>
</StackPanel>
</StackPanel>
</ScrollViewer>
</TabItem>
<!-- ICON -->
<TabItem Header="{loc:Tr modals.listSettings.sectionIcon}">
<ScrollViewer>
<StackPanel Spacing="8" Margin="0,8,0,0">
<TextBlock Classes="field-label" Text="{loc:Tr modals.listSettings.icon}"/>
<TextBox Text="{Binding IconSearch}"
Watermark="{loc:Tr modals.listSettings.iconSearchWatermark}"/>
<TextBlock Text="{loc:Tr modals.listSettings.iconSearchTruncated}"
IsVisible="{Binding IconResultsTruncated}"
Opacity="0.6" FontSize="12" TextWrapping="Wrap"/>
<ListBox ItemsSource="{Binding Icons}"
SelectedItem="{Binding SelectedIconOption, Mode=TwoWay}"
Background="Transparent" BorderThickness="0"
HorizontalAlignment="Left">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate x:DataType="x:String">
<!-- No Foreground here on purpose: the icon inherits the container's, so the
selected/hover states of ListBoxItem reach it (see Ui/CLAUDE.md). -->
<PathIcon Width="20" Height="20" Margin="6"
ToolTip.Tip="{Binding}"
Data="{Binding Converter={StaticResource IconKey}}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBlock Text="{loc:Tr modals.listSettings.iconHint}"
Opacity="0.6" FontSize="12" TextWrapping="Wrap"/>
</StackPanel>
</ScrollViewer>
</TabItem>
<!-- AGENT -->
<TabItem Header="{loc:Tr modals.listSettings.sectionAgent}">
<ScrollViewer>
<StackPanel Spacing="12" Margin="0,8,0,0">
<Button Classes="btn" HorizontalAlignment="Right"
Content="{loc:Tr modals.listSettings.resetAgentSettings}"
Command="{Binding Agent.ResetAllCommand}" />
<ctl:AgentConfigEditor DataContext="{Binding Agent}" ShowAgentBrowse="True"/>
</StackPanel>
</ScrollViewer>
</TabItem>
<!-- VERIFICATION -->
<TabItem Header="{loc:Tr modals.listSettings.sectionVerify}">
<ScrollViewer>
<StackPanel Spacing="4" Margin="0,8,0,0">
<TextBlock Classes="field-label" Text="{loc:Tr modals.listSettings.verifyCommand}"/>
<TextBox Text="{Binding VerifyCommand, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
PlaceholderText="{loc:Tr modals.listSettings.verifyCommandPlaceholder}"/>
<TextBlock Text="{loc:Tr modals.listSettings.verifyCommandHint}"
Opacity="0.6" FontSize="12" TextWrapping="Wrap"/>
</StackPanel>
</ScrollViewer>
</TabItem>
</TabControl>
</Grid>
</ctl:ModalShell>
</Window>