Files
2026-10-10 14:58:04 +03:00

1040 lines
59 KiB
XML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="SbLauncher" Width="1120" Height="790"
WindowStyle="None" AllowsTransparency="False" Background="{DynamicResource Bg}"
ResizeMode="NoResize" WindowStartupLocation="CenterScreen"
TextOptions.TextFormattingMode="Display"
FontFamily="Segoe UI" UseLayoutRounding="True" SnapsToDevicePixels="True">
<!--
ТЕМЫ.
Ниже два словаря — Theme.Dark и Theme.Light. Приложение при старте копирует
выбранный в Application.Resources, а весь интерфейс ссылается на токены
через {DynamicResource}. Поэтому смена темы происходит вживую.
ВАЖНО: именно DynamicResource, а не StaticResource — последний берёт
значение один раз при разборе XAML и на подмену палитры не реагирует.
Чтобы добавить цвет: заведите ключ в ОБОИХ словарях и ссылайтесь на него.
-->
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary x:Key="Theme.Dark">
<LinearGradientBrush x:Key="Bg" StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#101113" Offset="0"/>
<GradientStop Color="#17191D" Offset="0.5"/>
<GradientStop Color="#1C1F25" Offset="1"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="Panel" Color="#DD1B1E23"/>
<SolidColorBrush x:Key="Card" Color="#C0252931"/>
<SolidColorBrush x:Key="CardHover" Color="#D7333944"/>
<SolidColorBrush x:Key="CardSel" Color="#D2354052"/>
<SolidColorBrush x:Key="Stroke" Color="#3AADB7C6"/>
<SolidColorBrush x:Key="GlassEdge" Color="#45C3CFDF"/>
<SolidColorBrush x:Key="Text" Color="#F1F3F6"/>
<SolidColorBrush x:Key="Muted" Color="#A5AFBD"/>
<SolidColorBrush x:Key="Accent" Color="#78A9FF"/>
<SolidColorBrush x:Key="AccentHover" Color="#98BEFF"/>
<SolidColorBrush x:Key="AccentDim" Color="#5385DC"/>
<SolidColorBrush x:Key="OnAccent" Color="#101820"/>
<SolidColorBrush x:Key="SoftBg" Color="#AA282D36"/>
<SolidColorBrush x:Key="SoftHover" Color="#CE353D49"/>
<SolidColorBrush x:Key="SwitchTrack" Color="#FF363C46"/>
<SolidColorBrush x:Key="SwitchThumb" Color="#F4F6FA"/>
<SolidColorBrush x:Key="BadgeBg" Color="#FF303844"/>
<SolidColorBrush x:Key="PingBg" Color="#A6191D24"/>
<SolidColorBrush x:Key="LogBg" Color="#D214171C"/>
<SolidColorBrush x:Key="LogText" Color="#BECBD9"/>
<SolidColorBrush x:Key="ScrollTrack" Color="#182D3540"/>
<SolidColorBrush x:Key="ScrollThumb" Color="#706A778B"/>
<SolidColorBrush x:Key="ScrollThumbHover" Color="#ACA7B4C7"/>
<SolidColorBrush x:Key="HeroRing" Color="#948BA4C9"/>
<SolidColorBrush x:Key="HeroRingDim" Color="#3D93AACA"/>
<RadialGradientBrush x:Key="GlowA">
<GradientStop Color="#28687890" Offset="0"/>
<GradientStop Color="#00687890" Offset="1"/>
</RadialGradientBrush>
<RadialGradientBrush x:Key="GlowB">
<GradientStop Color="#1C4B6F9C" Offset="0"/>
<GradientStop Color="#004B6F9C" Offset="1"/>
</RadialGradientBrush>
<!-- смысловые цвета: их же читает код для статуса и пинга -->
<SolidColorBrush x:Key="Ok" Color="#6BDBAE"/>
<SolidColorBrush x:Key="Warn" Color="#E8BF78"/>
<SolidColorBrush x:Key="Bad" Color="#F28794"/>
<SolidColorBrush x:Key="Idle" Color="#A5AFBD"/>
<SolidColorBrush x:Key="Na" Color="#85918E"/>
<sys:Double x:Key="ShadowOpacity">0.35</sys:Double>
</ResourceDictionary>
<ResourceDictionary x:Key="Theme.Light">
<LinearGradientBrush x:Key="Bg" StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#F3F4F6" Offset="0"/>
<GradientStop Color="#E8EBEF" Offset="0.5"/>
<GradientStop Color="#EFF1F4" Offset="1"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="Panel" Color="#EBF8F9FB"/>
<SolidColorBrush x:Key="Card" Color="#FFFFFF"/>
<SolidColorBrush x:Key="CardHover" Color="#F7F9FC"/>
<SolidColorBrush x:Key="CardSel" Color="#E3EAF3"/>
<SolidColorBrush x:Key="Stroke" Color="#CDD3DC"/>
<SolidColorBrush x:Key="GlassEdge" Color="#D5DAE2"/>
<SolidColorBrush x:Key="Text" Color="#242B35"/>
<SolidColorBrush x:Key="Muted" Color="#606C7B"/>
<SolidColorBrush x:Key="Accent" Color="#405B80"/>
<SolidColorBrush x:Key="AccentHover" Color="#4E6D96"/>
<SolidColorBrush x:Key="AccentDim" Color="#344C6E"/>
<SolidColorBrush x:Key="OnAccent" Color="#FFFFFF"/>
<SolidColorBrush x:Key="SoftBg" Color="#E9EDF2"/>
<SolidColorBrush x:Key="SoftHover" Color="#F6F8FB"/>
<SolidColorBrush x:Key="SwitchTrack" Color="#C5CDD7"/>
<SolidColorBrush x:Key="SwitchThumb" Color="#FFFFFF"/>
<SolidColorBrush x:Key="BadgeBg" Color="#E0E6EE"/>
<SolidColorBrush x:Key="PingBg" Color="#EDF1F5"/>
<SolidColorBrush x:Key="LogBg" Color="#F8F9FB"/>
<SolidColorBrush x:Key="LogText" Color="#49586B"/>
<SolidColorBrush x:Key="ScrollTrack" Color="#18758499"/>
<SolidColorBrush x:Key="ScrollThumb" Color="#8895A6"/>
<SolidColorBrush x:Key="ScrollThumbHover" Color="#687A90"/>
<SolidColorBrush x:Key="HeroRing" Color="#905F7591"/>
<SolidColorBrush x:Key="HeroRingDim" Color="#407D8FA6"/>
<RadialGradientBrush x:Key="GlowA">
<GradientStop Color="#127689A2" Offset="0"/>
<GradientStop Color="#007689A2" Offset="1"/>
</RadialGradientBrush>
<RadialGradientBrush x:Key="GlowB">
<GradientStop Color="#108398B4" Offset="0"/>
<GradientStop Color="#008398B4" Offset="1"/>
</RadialGradientBrush>
<SolidColorBrush x:Key="Ok" Color="#207553"/>
<SolidColorBrush x:Key="Warn" Color="#95620D"/>
<SolidColorBrush x:Key="Bad" Color="#BD3848"/>
<SolidColorBrush x:Key="Idle" Color="#606C7B"/>
<SolidColorBrush x:Key="Na" Color="#606C7B"/>
<sys:Double x:Key="ShadowOpacity">0.10</sys:Double>
</ResourceDictionary>
<!-- Одинаковая прокрутка во всех ScrollViewer/ListBox/TextBox. -->
<Style x:Key="ScrollPageButton" TargetType="RepeatButton">
<Setter Property="Focusable" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RepeatButton">
<Border Background="Transparent"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ScrollGrip" TargetType="Thumb">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Thumb">
<Border x:Name="Grip" Margin="2,1" CornerRadius="4"
Background="{DynamicResource ScrollThumb}"/>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Grip" Property="Background" Value="{DynamicResource ScrollThumbHover}"/>
</Trigger>
<Trigger Property="IsDragging" Value="True">
<Setter TargetName="Grip" Property="Background" Value="{DynamicResource Accent}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ControlTemplate x:Key="VerticalScroll" TargetType="ScrollBar">
<Border Background="{DynamicResource ScrollTrack}" Width="10">
<Track x:Name="PART_Track" IsDirectionReversed="True"
Orientation="Vertical" ViewportSize="{TemplateBinding ViewportSize}"
Minimum="{TemplateBinding Minimum}" Maximum="{TemplateBinding Maximum}"
Value="{Binding Value, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}">
<Track.DecreaseRepeatButton>
<RepeatButton Style="{StaticResource ScrollPageButton}" Command="ScrollBar.PageUpCommand"/>
</Track.DecreaseRepeatButton>
<Track.Thumb><Thumb Style="{StaticResource ScrollGrip}"/></Track.Thumb>
<Track.IncreaseRepeatButton>
<RepeatButton Style="{StaticResource ScrollPageButton}" Command="ScrollBar.PageDownCommand"/>
</Track.IncreaseRepeatButton>
</Track>
</Border>
</ControlTemplate>
<ControlTemplate x:Key="HorizontalScroll" TargetType="ScrollBar">
<Border Background="{DynamicResource ScrollTrack}" Height="10">
<Track x:Name="PART_Track" Orientation="Horizontal"
ViewportSize="{TemplateBinding ViewportSize}"
Minimum="{TemplateBinding Minimum}" Maximum="{TemplateBinding Maximum}"
Value="{Binding Value, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}">
<Track.DecreaseRepeatButton>
<RepeatButton Style="{StaticResource ScrollPageButton}" Command="ScrollBar.PageLeftCommand"/>
</Track.DecreaseRepeatButton>
<Track.Thumb><Thumb Style="{StaticResource ScrollGrip}"/></Track.Thumb>
<Track.IncreaseRepeatButton>
<RepeatButton Style="{StaticResource ScrollPageButton}" Command="ScrollBar.PageRightCommand"/>
</Track.IncreaseRepeatButton>
</Track>
</Border>
</ControlTemplate>
<Style TargetType="ScrollBar">
<Setter Property="Width" Value="10"/>
<Setter Property="Template" Value="{StaticResource VerticalScroll}"/>
<Style.Triggers>
<Trigger Property="Orientation" Value="Horizontal">
<Setter Property="Width" Value="Auto"/>
<Setter Property="Height" Value="10"/>
<Setter Property="Template" Value="{StaticResource HorizontalScroll}"/>
</Trigger>
</Style.Triggers>
</Style>
<!-- ─── кнопка-таблетка (основное действие) ────────────────────────── -->
<Style x:Key="Pill" TargetType="Button">
<Setter Property="Foreground" Value="{DynamicResource OnAccent}"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="B" CornerRadius="24" Background="{DynamicResource Accent}"
BorderBrush="{DynamicResource GlassEdge}" BorderThickness="1"
Padding="30,13">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="B" Property="Background" Value="{DynamicResource AccentHover}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="B" Property="Background" Value="{DynamicResource AccentDim}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ─── вторичная кнопка ───────────────────────────────────────────── -->
<Style x:Key="Soft" TargetType="Button">
<Setter Property="Foreground" Value="{DynamicResource Muted}"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="B" CornerRadius="12" Background="{DynamicResource SoftBg}"
BorderBrush="{DynamicResource Stroke}" BorderThickness="1" Padding="14,8">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="B" Property="Background" Value="{DynamicResource SoftHover}"/>
<Setter Property="Foreground" Value="{DynamicResource Text}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ─── кнопка опасного действия (удаление) ────────────────────────── -->
<Style x:Key="SoftDanger" TargetType="Button">
<Setter Property="Foreground" Value="{DynamicResource Muted}"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="B" CornerRadius="12" Background="{DynamicResource SoftBg}"
BorderBrush="{DynamicResource Stroke}" BorderThickness="1" Padding="14,8">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="B" Property="Background" Value="{DynamicResource SoftHover}"/>
<Setter TargetName="B" Property="BorderBrush" Value="{DynamicResource Bad}"/>
<Setter Property="Foreground" Value="{DynamicResource Bad}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ─── контекстное меню ───────────────────────────────────────────── -->
<Style TargetType="ContextMenu">
<Setter Property="Background" Value="{DynamicResource Panel}"/>
<Setter Property="BorderBrush" Value="{DynamicResource Stroke}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContextMenu">
<Border CornerRadius="8" Background="{DynamicResource Panel}"
BorderBrush="{DynamicResource Stroke}" BorderThickness="1" Padding="4">
<Border.Effect>
<DropShadowEffect BlurRadius="14" ShadowDepth="3" Direction="270"
Opacity="{DynamicResource ShadowOpacity}" Color="Black"/>
</Border.Effect>
<StackPanel IsItemsHost="True"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="MenuItem">
<Setter Property="Foreground" Value="{DynamicResource Text}"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="MenuItem">
<Border x:Name="B" CornerRadius="6" Background="Transparent" Padding="12,7">
<ContentPresenter ContentSource="Header" HorizontalAlignment="Left" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="B" Property="Background" Value="{DynamicResource SoftHover}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ─── кнопки заголовка ───────────────────────────────────────────── -->
<Style x:Key="Chrome" TargetType="Button">
<Setter Property="Foreground" Value="{DynamicResource Muted}"/>
<Setter Property="FontSize" Value="13"/>
<Setter Property="Width" Value="40"/>
<Setter Property="Height" Value="30"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="B" CornerRadius="7" Background="Transparent">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="B" Property="Background" Value="{DynamicResource SoftHover}"/>
<Setter Property="Foreground" Value="{DynamicResource Text}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ─── переключатель ──────────────────────────────────────────────── -->
<Style x:Key="Switch" TargetType="ToggleButton">
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid Width="52" Height="30">
<Border CornerRadius="15" Background="{DynamicResource SwitchTrack}"
BorderBrush="{DynamicResource Stroke}" BorderThickness="1"/>
<Border x:Name="ActiveTrack" CornerRadius="15" Background="{DynamicResource Accent}"
BorderBrush="{DynamicResource Accent}" BorderThickness="1" Opacity="0"/>
<Ellipse x:Name="Thumb" Width="22" Height="22" Fill="{DynamicResource SwitchThumb}"
HorizontalAlignment="Left" VerticalAlignment="Center" Margin="4,0,0,0">
<Ellipse.RenderTransform><TranslateTransform/></Ellipse.RenderTransform>
<Ellipse.Effect>
<DropShadowEffect Color="#50000000" BlurRadius="4" ShadowDepth="1" Opacity="0.35"/>
</Ellipse.Effect>
</Ellipse>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Thumb" Property="Width" Value="26"/>
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard FillBehavior="Stop">
<DoubleAnimation Storyboard.TargetName="Thumb" Storyboard.TargetProperty="Width"
From="22" To="26" Duration="0:0:0.12"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard FillBehavior="Stop">
<DoubleAnimation Storyboard.TargetName="Thumb" Storyboard.TargetProperty="Width"
From="26" To="22" Duration="0:0:0.18"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ─── карточка сервера ───────────────────────────────────────────── -->
<DataTemplate x:Key="ServerCard">
<Border x:Name="Card" CornerRadius="16" Background="{DynamicResource Card}"
BorderBrush="{DynamicResource Stroke}" BorderThickness="1" Margin="0,0,0,10">
<Border.ContextMenu>
<ContextMenu>
<MenuItem Header="Удалить сервер" Command="{Binding DeleteCommand}"/>
</ContextMenu>
</Border.ContextMenu>
<Button Command="{Binding SelectCommand}" CommandParameter="{Binding}"
Cursor="Hand" HorizontalContentAlignment="Stretch">
<Button.Template>
<ControlTemplate TargetType="Button">
<Border Background="Transparent" Padding="14,14">
<ContentPresenter/>
</Border>
</ControlTemplate>
</Button.Template>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="42"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!-- флаг страны; для незнакомого кода — текстовый бейдж -->
<Grid Grid.Column="0" Width="34" HorizontalAlignment="Left">
<Image Source="{Binding Flag}" Width="34" Height="23" Stretch="Fill"
RenderOptions.BitmapScalingMode="HighQuality"/>
<Border x:Name="TextBadge" Width="34" Height="34" CornerRadius="9"
Background="{DynamicResource BadgeBg}" Visibility="Collapsed">
<TextBlock Text="{Binding Badge}" Foreground="{DynamicResource Text}"
FontSize="12" FontWeight="Bold"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</Grid>
<StackPanel Grid.Column="1" VerticalAlignment="Center" Margin="10,0,0,0">
<TextBlock Text="{Binding Title}" Foreground="{DynamicResource Text}"
FontSize="13.5" FontWeight="SemiBold"/>
<TextBlock Text="{Binding Subtitle}" Foreground="{DynamicResource Muted}"
FontSize="11" Margin="0,2,0,0" TextTrimming="CharacterEllipsis"/>
</StackPanel>
<Border Grid.Column="2" CornerRadius="6" Padding="7,3"
Background="{DynamicResource PingBg}" VerticalAlignment="Center">
<TextBlock Text="{Binding PingText}" Foreground="{Binding PingBrush}"
FontSize="11" FontWeight="SemiBold"/>
</Border>
</Grid>
</Button>
</Border>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Flag}" Value="{x:Null}">
<Setter TargetName="TextBadge" Property="Visibility" Value="Visible"/>
</DataTrigger>
<Trigger SourceName="Card" Property="IsMouseOver" Value="True">
<Setter TargetName="Card" Property="Background" Value="{DynamicResource CardHover}"/>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
<!-- ─── поле ввода ─────────────────────────────────────────────────
Consolas: значения здесь — base64-ключ и IP-адрес, в
моноширинном их глазом проверять заметно легче. -->
<Style x:Key="Field" TargetType="TextBox">
<Setter Property="Foreground" Value="{DynamicResource Text}"/>
<Setter Property="CaretBrush" Value="{DynamicResource Text}"/>
<Setter Property="SelectionBrush" Value="{DynamicResource Accent}"/>
<Setter Property="FontFamily" Value="Consolas"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border x:Name="B" CornerRadius="8" Background="{DynamicResource SoftBg}"
BorderBrush="{DynamicResource Stroke}" BorderThickness="1"
Padding="10,7">
<ScrollViewer x:Name="PART_ContentHost" VerticalAlignment="Stretch"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="B" Property="Background" Value="{DynamicResource SoftHover}"/>
</Trigger>
<Trigger Property="IsFocused" Value="True">
<Setter TargetName="B" Property="BorderBrush" Value="{DynamicResource Accent}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ─── элемент выпадающего списка ─────────────────────────────── -->
<Style x:Key="ComboItem" TargetType="ComboBoxItem">
<Setter Property="Foreground" Value="{DynamicResource Text}"/>
<Setter Property="FontFamily" Value="Consolas"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<Border x:Name="B" Background="Transparent" Padding="10,7" CornerRadius="6">
<ContentPresenter/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="B" Property="Background" Value="{DynamicResource CardHover}"/>
</Trigger>
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="B" Property="Background" Value="{DynamicResource CardSel}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ─── редактируемый выпадающий список ────────────────────────────
Шаблон целиком, а не только цвета: штатный ComboBox рисуется
темой Windows и в тёмной палитре выглядит белым пятном.
Обязательные части — PART_EditableTextBox и PART_Popup.
Редактируемый он намеренно: если адаптера нет в списке
(отключён, виртуальный), имя можно вписать руками. -->
<Style x:Key="FieldCombo" TargetType="ComboBox">
<Setter Property="IsEditable" Value="True"/>
<Setter Property="ItemContainerStyle" Value="{StaticResource ComboItem}"/>
<Setter Property="Foreground" Value="{DynamicResource Text}"/>
<Setter Property="FontFamily" Value="Consolas"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<Border x:Name="B" CornerRadius="8" Background="{DynamicResource SoftBg}"
BorderBrush="{DynamicResource Stroke}" BorderThickness="1"/>
<Grid Margin="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
<TextBox x:Name="PART_EditableTextBox" Grid.Column="0"
Background="Transparent" BorderThickness="0"
Foreground="{DynamicResource Text}"
CaretBrush="{DynamicResource Text}"
SelectionBrush="{DynamicResource Accent}"
Padding="9,6" VerticalContentAlignment="Center"/>
<ToggleButton Grid.Column="1" Focusable="False" ClickMode="Press" Cursor="Hand"
IsChecked="{Binding IsDropDownOpen, Mode=TwoWay,
RelativeSource={RelativeSource TemplatedParent}}">
<ToggleButton.Template>
<ControlTemplate TargetType="ToggleButton">
<Border Background="Transparent">
<Path Data="M 0,0 L 8,0 L 4,5 Z" Fill="{DynamicResource Muted}"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
</Grid>
<Popup x:Name="PART_Popup" Placement="Bottom" AllowsTransparency="True"
IsOpen="{TemplateBinding IsDropDownOpen}" Focusable="False"
PopupAnimation="Fade">
<Border Background="{DynamicResource Panel}" CornerRadius="8"
BorderBrush="{DynamicResource Stroke}" BorderThickness="1"
Margin="0,4,0,0" Padding="4"
MinWidth="{Binding ActualWidth, RelativeSource={RelativeSource TemplatedParent}}">
<ScrollViewer MaxHeight="220" VerticalScrollBarVisibility="Auto">
<ItemsPresenter/>
</ScrollViewer>
</Border>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter TargetName="B" Property="BorderBrush" Value="{DynamicResource Accent}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ─── переключатель вкладок «лог / настройки» ─────────────────
Цвет активной вкладки приходит из ViewModel ключом палитры,
поэтому переживает смену темы. -->
<Style x:Key="Tab" TargetType="Button">
<Setter Property="FontSize" Value="10.5"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Width" Value="112"/>
<Setter Property="Height" Value="32"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="Transparent" CornerRadius="10">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ─── подпись поля ───────────────────────────────────────────── -->
<Style x:Key="FieldLabel" TargetType="TextBlock">
<Setter Property="Foreground" Value="{DynamicResource Text}"/>
<Setter Property="FontSize" Value="12"/>
<!-- Top, а не Center: под полем идёт подсказка, и по центру
всей колонки подпись уезжала бы ниже самого поля. -->
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="Margin" Value="0,9,12,0"/>
</Style>
<!-- ─── заголовок группы ───────────────────────────────────────── -->
<Style x:Key="GroupLabel" TargetType="TextBlock">
<Setter Property="Foreground" Value="{DynamicResource Muted}"/>
<Setter Property="FontSize" Value="10.5"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Margin" Value="0,0,0,10"/>
</Style>
<!-- ─── подсказка под полем ────────────────────────────────────── -->
<Style x:Key="Hint" TargetType="TextBlock">
<Setter Property="FontSize" Value="10.5"/>
<Setter Property="Margin" Value="0,4,0,0"/>
<Setter Property="TextWrapping" Value="Wrap"/>
</Style>
</ResourceDictionary>
</Window.Resources>
<!-- ══════════════════════════════════════════════════════════════════ -->
<Border Background="{DynamicResource Bg}"
BorderBrush="{DynamicResource Stroke}" BorderThickness="1">
<Grid ClipToBounds="True">
<Grid.RowDefinitions>
<RowDefinition Height="62"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Цветовые пятна статичны: плавный «стеклянный» вид без дорогого blur. -->
<Canvas Grid.RowSpan="2" IsHitTestVisible="False" ClipToBounds="True">
<Ellipse Width="720" Height="720" Fill="{DynamicResource GlowA}"
Canvas.Left="-240" Canvas.Top="-320"/>
<Ellipse Width="740" Height="740" Fill="{DynamicResource GlowB}"
Canvas.Left="570" Canvas.Top="300"/>
</Canvas>
<!-- ─── заголовок ─────────────────────────────────────────────── -->
<Grid x:Name="TitleBar" Grid.Row="0" Background="Transparent">
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="23,0,0,0">
<Image x:Name="LogoImg" Width="31" Height="31" VerticalAlignment="Center"
RenderOptions.BitmapScalingMode="HighQuality"/>
<TextBlock Text="SbLauncher" Foreground="{DynamicResource Text}"
FontSize="15" FontWeight="SemiBold" Margin="11,0,0,0"
VerticalAlignment="Center"/>
<Border Background="{DynamicResource SoftBg}" BorderBrush="{DynamicResource Stroke}"
BorderThickness="1" CornerRadius="10" Margin="12,0,0,0" Padding="8,3">
<TextBlock Text="{Binding VersionText}" Foreground="{DynamicResource Muted}"
FontSize="10" VerticalAlignment="Center"/>
</Border>
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right"
VerticalAlignment="Center" Margin="0,0,12,0">
<Button x:Name="BtnTheme" Style="{StaticResource Chrome}"
FontFamily="Segoe MDL2 Assets" FontSize="14"
ToolTip="{Binding ThemeAction}" AutomationProperties.Name="{Binding ThemeAction}">
<Grid Width="22" Height="22" IsHitTestVisible="False">
<TextBlock x:Name="ThemeSun" Text="&#xE706;" HorizontalAlignment="Center"
VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<TransformGroup><ScaleTransform/><RotateTransform/></TransformGroup>
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock x:Name="ThemeMoon" Text="&#xE708;" HorizontalAlignment="Center"
VerticalAlignment="Center" Opacity="0" RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<TransformGroup><ScaleTransform ScaleX="0.4" ScaleY="0.4"/><RotateTransform Angle="90"/></TransformGroup>
</TextBlock.RenderTransform>
</TextBlock>
</Grid>
</Button>
<Button x:Name="BtnMin" Style="{StaticResource Chrome}" Content="&#x2013;"/>
<Button x:Name="BtnClose" Style="{StaticResource Chrome}" Content="&#x2715;"/>
</StackPanel>
</Grid>
<!-- ─── тело ──────────────────────────────────────────────────── -->
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="335"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- левая колонка: серверы -->
<Border Grid.Column="0" Background="{DynamicResource Panel}" CornerRadius="22"
BorderBrush="{DynamicResource GlassEdge}" BorderThickness="1"
Margin="16,6,0,16">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" Margin="20,20,16,16">
<TextBlock Text="СЕРВЕРЫ" Foreground="{DynamicResource Muted}"
FontSize="11" FontWeight="Bold" VerticalAlignment="Center"/>
<Button Style="{StaticResource Soft}" Content="пинг"
Command="{Binding PingAllCommand}" HorizontalAlignment="Right"
Padding="10,4"/>
</Grid>
<Grid x:Name="ServerListHost" Grid.Row="1" ClipToBounds="True">
<ListBox x:Name="ServerList" ItemsSource="{Binding Servers}"
SelectedItem="{Binding Selected, Mode=TwoWay}"
ItemTemplate="{StaticResource ServerCard}"
Background="Transparent" BorderThickness="0"
Margin="12,0,12,14" Padding="0,0,4,0"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.CanContentScroll="True"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Padding" Value="0"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<ContentPresenter ContentSource="Content"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
<Canvas IsHitTestVisible="False" ClipToBounds="True">
<Border x:Name="ServerSelectionWindow" Visibility="Collapsed"
CornerRadius="16" BorderBrush="{DynamicResource Accent}"
BorderThickness="1.5">
<Border CornerRadius="15" Background="{DynamicResource Accent}" Opacity="0.16"/>
</Border>
</Canvas>
</Grid>
</Grid>
</Border>
<!-- правая колонка -->
<Grid Grid.Column="1" Margin="18,6,18,16">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <!-- статус -->
<RowDefinition Height="Auto"/> <!-- режим -->
<RowDefinition Height="Auto"/> <!-- вкладки -->
<RowDefinition Height="*"/> <!-- лог/настройки-->
</Grid.RowDefinitions>
<!-- статус -->
<Border Grid.Row="0" CornerRadius="24" Background="{DynamicResource Panel}"
BorderBrush="{DynamicResource GlassEdge}" BorderThickness="1" Padding="23,22">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="78"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" Width="66" Height="66" VerticalAlignment="Center">
<Ellipse Fill="{DynamicResource SoftBg}" Stroke="{DynamicResource GlassEdge}"
StrokeThickness="1"/>
<Ellipse Width="62" Height="62" Stroke="{DynamicResource HeroRingDim}"
StrokeThickness="2" Margin="2"/>
<!-- Мягкое заполнение после подключения вместо резкой вспышки. -->
<Ellipse x:Name="ConnectionGlow" Width="58" Height="58" Fill="{DynamicResource Ok}"
RenderTransformOrigin="0.5,0.5" IsHitTestVisible="False">
<Ellipse.RenderTransform><ScaleTransform/></Ellipse.RenderTransform>
<Ellipse.Style>
<Style TargetType="Ellipse">
<Setter Property="Opacity" Value="0"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ConnectionPhase}" Value="connected">
<Setter Property="Opacity" Value="0.18"/>
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard FillBehavior="Stop">
<DoubleAnimation Storyboard.TargetProperty="Opacity"
From="0" To="0.18" Duration="0:0:0.55"/>
<DoubleAnimation Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)"
From="0.82" To="1" Duration="0:0:0.55">
<DoubleAnimation.EasingFunction>
<BackEase Amplitude="0.28" EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)"
From="0.82" To="1" Duration="0:0:0.55">
<DoubleAnimation.EasingFunction>
<BackEase Amplitude="0.28" EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
<!-- Пока соединение меняется, ободок спокойно «дышит». -->
<Ellipse x:Name="ConnectionBreathRing" Width="58" Height="58" Stroke="{DynamicResource Accent}"
StrokeThickness="2.5" IsHitTestVisible="False"
RenderTransformOrigin="0.5,0.5">
<Ellipse.RenderTransform><ScaleTransform/></Ellipse.RenderTransform>
<Ellipse.Style>
<Style TargetType="Ellipse">
<Setter Property="Opacity" Value="0"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ConnectionInProgress}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard x:Name="ConnectionBreath">
<Storyboard RepeatBehavior="Forever" AutoReverse="True">
<DoubleAnimation Storyboard.TargetProperty="Opacity"
From="0.25" To="0.72" Duration="0:0:0.9">
<DoubleAnimation.EasingFunction><SineEase EasingMode="EaseInOut"/></DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)"
From="0.9" To="1.08" Duration="0:0:0.9">
<DoubleAnimation.EasingFunction><SineEase EasingMode="EaseInOut"/></DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)"
From="0.9" To="1.08" Duration="0:0:0.9">
<DoubleAnimation.EasingFunction><SineEase EasingMode="EaseInOut"/></DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions><StopStoryboard BeginStoryboardName="ConnectionBreath"/></DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
<Button x:Name="BtnPower" Width="66" Height="66"
Command="{Binding ConnectCommand}" Cursor="Hand"
ToolTip="{Binding ConnectText}"
AutomationProperties.Name="{Binding ConnectText}">
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid Background="Transparent">
<Viewbox Width="32" Height="32">
<Canvas Width="32" Height="32">
<Path x:Name="PowerRing"
Data="M 9,8 C 5,10 4,14 4,17 C 4,24 9,29 16,29 C 23,29 28,24 28,17 C 28,14 27,10 23,8"
Stroke="{DynamicResource Text}" StrokeThickness="3"
StrokeStartLineCap="Round" StrokeEndLineCap="Round"/>
<Path x:Name="PowerStem" Data="M 16,3 L 16,17"
Stroke="{DynamicResource Text}" StrokeThickness="3"
StrokeStartLineCap="Round" StrokeEndLineCap="Round"/>
</Canvas>
</Viewbox>
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding ConnectionPhase}" Value="connected">
<Setter TargetName="PowerRing" Property="Stroke" Value="{DynamicResource Ok}"/>
<Setter TargetName="PowerStem" Property="Stroke" Value="{DynamicResource Ok}"/>
</DataTrigger>
<DataTrigger Binding="{Binding ConnectionPhase}" Value="connecting">
<Setter TargetName="PowerRing" Property="Stroke" Value="{DynamicResource Accent}"/>
<Setter TargetName="PowerStem" Property="Stroke" Value="{DynamicResource Accent}"/>
</DataTrigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="PowerRing" Property="Stroke" Value="{DynamicResource Accent}"/>
<Setter TargetName="PowerStem" Property="Stroke" Value="{DynamicResource Accent}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="PowerRing" Property="Stroke" Value="{DynamicResource AccentDim}"/>
<Setter TargetName="PowerStem" Property="Stroke" Value="{DynamicResource AccentDim}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
</Grid>
<StackPanel Grid.Column="1" VerticalAlignment="Center" Margin="6,0,10,0">
<TextBlock Text="СОЕДИНЕНИЕ" Foreground="{DynamicResource Muted}"
FontSize="10" FontWeight="SemiBold" Margin="0,0,0,4"/>
<StackPanel Orientation="Horizontal">
<Ellipse Width="8" Height="8" Fill="{Binding StatusBrush}" VerticalAlignment="Center"/>
<TextBlock Text="{Binding StatusTitle}" Foreground="{DynamicResource Text}"
FontSize="23" FontWeight="Light" Margin="9,0,0,0"/>
</StackPanel>
<TextBlock Text="{Binding StatusSub}" Foreground="{DynamicResource Muted}"
FontSize="11.5" Margin="0,5,0,0" TextTrimming="CharacterEllipsis"/>
</StackPanel>
<Button Style="{StaticResource Pill}" Content="{Binding ConnectText}"
Command="{Binding ConnectCommand}"
Grid.Column="2" HorizontalAlignment="Right" VerticalAlignment="Center"/>
</Grid>
</Border>
<!-- режим: через WireGuard или напрямую через адаптер -->
<Border Grid.Row="1" CornerRadius="21" Background="{DynamicResource Panel}"
BorderBrush="{DynamicResource GlassEdge}" BorderThickness="1"
Padding="24,18" Margin="0,13,0,0">
<Grid>
<StackPanel VerticalAlignment="Center">
<TextBlock Text="WireGuard для .ru-трафика" Foreground="{DynamicResource Text}"
FontSize="13" FontWeight="SemiBold"/>
<TextBlock Foreground="{DynamicResource Muted}" FontSize="11" Margin="0,3,0,0"
Text="вкл — VLESS поверх WireGuard · выкл — напрямую через сетевой адаптер"/>
</StackPanel>
<ToggleButton x:Name="WireguardSwitch" Style="{StaticResource Switch}"
IsChecked="{Binding WireguardOn, Mode=TwoWay}"
HorizontalAlignment="Right" VerticalAlignment="Center"/>
</Grid>
</Border>
<!-- вкладки -->
<Border Grid.Row="2" Margin="0,12,0,10" Padding="3"
HorizontalAlignment="Left" CornerRadius="14"
Background="{DynamicResource SoftBg}"
BorderBrush="{DynamicResource GlassEdge}" BorderThickness="1">
<Grid x:Name="TabSelectorHost">
<Border x:Name="TabSelectionWindow" Width="112" HorizontalAlignment="Left"
CornerRadius="10" BorderBrush="{DynamicResource Accent}" BorderThickness="1">
<Border.RenderTransform><TranslateTransform/></Border.RenderTransform>
<Border CornerRadius="9" Background="{DynamicResource Accent}" Opacity="0.16"/>
</Border>
<StackPanel Orientation="Horizontal">
<Button x:Name="BtnTabLog" Style="{StaticResource Tab}" Content="ЛОГ"
Foreground="{Binding TabLogBrush}"/>
<Button x:Name="BtnTabSettings" Style="{StaticResource Tab}" Content="НАСТРОЙКИ"
Foreground="{Binding TabSettingsBrush}"/>
</StackPanel>
</Grid>
</Border>
<!-- Панели скользят в пределах этой области и сохраняют своё содержимое. -->
<Grid x:Name="TabContentHost" Grid.Row="3" ClipToBounds="True">
<!-- ── лог ─────────────────────────────────────────────── -->
<Border x:Name="LogPane"
CornerRadius="21" Background="{DynamicResource LogBg}"
BorderBrush="{DynamicResource GlassEdge}" BorderThickness="1" Padding="4">
<Border.RenderTransform><TranslateTransform/></Border.RenderTransform>
<TextBox x:Name="LogBox" Text="{Binding LogText, Mode=OneWay}"
IsReadOnly="True" BorderThickness="0" Background="Transparent"
Foreground="{Binding LogBrush}" SelectionBrush="{DynamicResource Accent}"
IsInactiveSelectionHighlightEnabled="False"
FontFamily="Consolas" FontSize="11.5"
Padding="14,10" TextWrapping="NoWrap"
VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"/>
</Border>
<!-- ── настройки ───────────────────────────────────────── -->
<Border x:Name="SettingsPane" Visibility="Hidden"
CornerRadius="21" Background="{DynamicResource Panel}"
BorderBrush="{DynamicResource GlassEdge}" BorderThickness="1" Padding="22,18">
<Border.RenderTransform><TranslateTransform/></Border.RenderTransform>
<ScrollViewer VerticalScrollBarVisibility="Auto" Padding="0,0,6,0">
<StackPanel>
<TextBlock Style="{StaticResource GroupLabel}" Text="WIREGUARD"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="128"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Style="{StaticResource FieldLabel}"
Text="Приватный ключ"/>
<StackPanel Grid.Row="0" Grid.Column="1">
<TextBox Style="{StaticResource Field}"
Text="{Binding PrivateKey, Mode=TwoWay}"/>
<TextBlock Style="{StaticResource Hint}" Text="{Binding PrivateKeyHint}"
Foreground="{Binding PrivateKeyHintBrush}"/>
</StackPanel>
<TextBlock Grid.Row="1" Grid.Column="0" Style="{StaticResource FieldLabel}"
Text="Локальный IP" Margin="0,21,12,0"/>
<StackPanel Grid.Row="1" Grid.Column="1" Margin="0,12,0,0">
<TextBox Style="{StaticResource Field}"
Text="{Binding LocalAddress, Mode=TwoWay}"/>
<TextBlock Style="{StaticResource Hint}" Text="{Binding LocalAddressHint}"
Foreground="{Binding LocalAddressHintBrush}"/>
</StackPanel>
</Grid>
<TextBlock Style="{StaticResource GroupLabel}" Text="СЕТЕВОЙ АДАПТЕР"
Margin="0,20,0,10"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="128"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Style="{StaticResource FieldLabel}"
Text="Имя адаптера"/>
<StackPanel Grid.Column="1">
<ComboBox x:Name="AdapterBox" Style="{StaticResource FieldCombo}"
ItemsSource="{Binding AdapterNames}"
Text="{Binding Adapter, Mode=TwoWay}"/>
<TextBlock Style="{StaticResource Hint}" Text="{Binding AdapterHint}"
Foreground="{Binding AdapterHintBrush}"/>
<TextBlock Style="{StaticResource Hint}" Foreground="{DynamicResource Muted}"
Text="нужен, только когда WireGuard выключен"/>
</StackPanel>
</Grid>
<TextBlock Style="{StaticResource GroupLabel}" Text="ДОБАВИТЬ СЕРВЕР"
Margin="0,20,0,10"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBox x:Name="LinkBox" Grid.Column="0" Style="{StaticResource Field}"
Height="88" AcceptsReturn="True" TextWrapping="NoWrap"
VerticalScrollBarVisibility="Auto" MaxLength="2000000"/>
<Button x:Name="BtnAddLink" Grid.Column="1" Style="{StaticResource Soft}"
Content="импортировать" Margin="8,0,0,0" VerticalAlignment="Top"/>
</Grid>
<TextBlock Style="{StaticResource Hint}" Foreground="{DynamicResource Muted}"
Text="Ссылки, текст/base64, URL подписки или sing-box JSON"/>
<TextBlock Style="{StaticResource Hint}" Foreground="{DynamicResource Muted}"
Text="{Binding ImportStatus}" TextWrapping="Wrap"/>
<WrapPanel Margin="0,20,0,0">
<Button Style="{StaticResource Soft}" Content="проверить конфиг"
Command="{Binding CheckConfigCommand}" Margin="0,0,8,8"/>
<Button Style="{StaticResource Soft}" Content="показать конфиг"
Command="{Binding OpenConfigCommand}" Margin="0,0,8,8"/>
<Button Style="{StaticResource Soft}" Content="папка"
Command="{Binding OpenFolderCommand}" Margin="0,0,8,8"/>
<Button Style="{StaticResource Soft}" Content="убить sb.exe"
Command="{Binding KillStrayCommand}" Margin="0,0,8,8"
ToolTip="Прибить зависшие процессы sb.exe, оставшиеся от прошлых запусков"/>
<Button Style="{StaticResource SoftDanger}" Content="удалить сервер"
Command="{Binding DeleteSelectedCommand}" Margin="0,0,8,8"
ToolTip="Удалить выбранный сервер из profiles.json"/>
</WrapPanel>
</StackPanel>
</ScrollViewer>
</Border>
</Grid>
</Grid>
</Grid>
</Grid>
</Border>
</Window>