feat(ui): 디자인 마무리 — AI 작업종류 옵션 + 큐 accent bar + 빈 상태 + polish
디자인 세션 마지막 단계(순차 workflow). Linear/Geist 영감 polish + AI 작업 선택 UI. - AI 작업종류 ComboBox(요약/번역/교정) + 번역 대상언어 → BuildOptions의 opts.Ai.Task/TargetLanguage 연결. 이제 Codex로 번역·교정도 가능 - 큐 row 좌측 형식색 accent bar + hover, 빈 상태(Browse + 안내) 개선 - FormatShiftTheme: FsNumStyle/FsLossPillStyle/FsListRowStyle/FsIconButtonStyle 재사용 스타일
This commit is contained in:
parent
5c7a4a9ee3
commit
e30559b3cd
3 changed files with 226 additions and 61 deletions
|
|
@ -375,4 +375,82 @@
|
|||
<Setter Property="Height" Value="8"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<!-- ============================================================
|
||||
UX polish 스타일 (단계 1) — Linear/Geist 영감, 절제된 확장
|
||||
============================================================ -->
|
||||
|
||||
<!-- 숫자/통계용: 모노 + tabular 숫자 정렬(자리 흔들림 방지) -->
|
||||
<Style x:Key="FsNumStyle" TargetType="TextBlock" BasedOn="{StaticResource FsMonoStyle}">
|
||||
<Setter Property="Typography.NumeralAlignment" Value="Tabular"/>
|
||||
<Setter Property="Typography.NumeralStyle" Value="Lining"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource FsTextSecondary}"/>
|
||||
<Setter Property="TextOptions.TextFormattingMode" Value="Display"/>
|
||||
</Style>
|
||||
|
||||
<!-- 손실 등급 pill: Background는 코드에서 FsLoss*Bg 주입 -->
|
||||
<Style x:Key="FsLossPillStyle" TargetType="Border">
|
||||
<Setter Property="CornerRadius" Value="4"/>
|
||||
<Setter Property="Padding" Value="6,1"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
|
||||
<!-- 큐/이력 row 공통 컨테이너: 투명 → hover 시 surface, 부드러운 fade -->
|
||||
<Style x:Key="FsListRowStyle" TargetType="Border">
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="CornerRadius" Value="8"/>
|
||||
<Setter Property="BorderThickness" Value="1"/>
|
||||
<Setter Property="BorderBrush" Value="Transparent"/>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Background" Value="{StaticResource FsBgSurfaceHover}"/>
|
||||
<Setter Property="BorderBrush" Value="{StaticResource FsBorderHairline}"/>
|
||||
<Trigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="Opacity"
|
||||
From="0.85" To="1" Duration="0:0:0.12"/>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</Trigger.EnterActions>
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!-- 32x32 아이콘 버튼(설정 ⚙, 삭제 ×): 투명 → hover surface, radius 6 -->
|
||||
<Style x:Key="FsIconButtonStyle" TargetType="Button">
|
||||
<Setter Property="Width" Value="32"/>
|
||||
<Setter Property="Height" Value="32"/>
|
||||
<Setter Property="Background" Value="Transparent"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource FsTextSecondary}"/>
|
||||
<Setter Property="BorderThickness" Value="0"/>
|
||||
<Setter Property="FontSize" Value="15"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="HorizontalContentAlignment" Value="Center"/>
|
||||
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="PART_Bd"
|
||||
Background="{TemplateBinding Background}"
|
||||
CornerRadius="6">
|
||||
<ContentPresenter HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
TextElement.Foreground="{TemplateBinding Foreground}"
|
||||
TextElement.FontSize="{TemplateBinding FontSize}"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="PART_Bd" Property="Background" Value="{StaticResource FsBgSurfaceHover}"/>
|
||||
<Setter Property="Foreground" Value="{StaticResource FsTextPrimary}"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="PART_Bd" Property="Opacity" Value="0.4"/>
|
||||
<Setter Property="Cursor" Value="Arrow"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
|
|
|
|||
|
|
@ -190,6 +190,30 @@
|
|||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
<!-- AI Task -->
|
||||
<StackPanel x:Name="AiTaskPanel" Margin="0,0,0,32">
|
||||
<TextBlock Text="AI 작업" Style="{StaticResource FsLabelStyle}"/>
|
||||
<ComboBox x:Name="AiTaskCombo" Margin="0,8,0,0"
|
||||
SelectedIndex="0"
|
||||
SelectionChanged="OnAiTaskChanged">
|
||||
<ComboBoxItem Content="요약"/>
|
||||
<ComboBoxItem Content="번역"/>
|
||||
<ComboBoxItem Content="교정"/>
|
||||
</ComboBox>
|
||||
<TextBlock x:Name="AiTaskHint" Margin="0,6,0,0"
|
||||
Style="{StaticResource FsCaptionStyle}"
|
||||
Text="텍스트(txt·md·docx) 출력 시 LLM이 적용합니다"/>
|
||||
<StackPanel x:Name="AiTargetLangPanel" Margin="0,10,0,0"
|
||||
Visibility="Collapsed">
|
||||
<TextBlock Text="대상 언어" Style="{StaticResource FsCaptionStyle}"
|
||||
Margin="0,0,0,4"/>
|
||||
<TextBox x:Name="AiTargetLangBox"
|
||||
Style="{StaticResource FsPathInputStyle}"
|
||||
Text="영어"
|
||||
ToolTip="번역 대상 언어 (예: 영어)"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Stats Box -->
|
||||
<Border Background="{StaticResource FsBgInput}"
|
||||
BorderBrush="{StaticResource FsBorderSubtle}"
|
||||
|
|
@ -365,20 +389,43 @@
|
|||
<!-- Active Queue view -->
|
||||
<Grid x:Name="ActiveQueueView" Visibility="Collapsed">
|
||||
<Grid x:Name="DropZoneEmpty">
|
||||
<Border Background="{StaticResource FsBgBase}">
|
||||
<Border Background="{StaticResource FsBgBase}" Padding="32">
|
||||
<!-- 점선 드롭존: 절제된 dashed 보더 + 중앙 정렬 안내 -->
|
||||
<Grid MaxWidth="440"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center">
|
||||
<!-- 점선 테두리(드롭존 느낌) -->
|
||||
<Rectangle RadiusX="10" RadiusY="10"
|
||||
Stroke="{StaticResource FsBorderHairline}"
|
||||
StrokeThickness="1.25"
|
||||
StrokeDashArray="5 4"
|
||||
Fill="#04FFFFFF"/>
|
||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Margin="48">
|
||||
<Path Width="48" Height="48" Stretch="Uniform"
|
||||
Margin="48,56">
|
||||
<Path Width="44" Height="44" Stretch="Uniform"
|
||||
HorizontalAlignment="Center"
|
||||
Stroke="{StaticResource FsAccentBlue}" StrokeThickness="1.5"
|
||||
Data="M21,15 L21,19 C21,20.1 20.1,21 19,21 L5,21 C3.9,21 3,20.1 3,19 L3,15 M7,10 L12,15 L17,10 M12,15 L12,3"/>
|
||||
<TextBlock Margin="0,16,0,0" FontSize="16" FontWeight="SemiBold"
|
||||
<TextBlock Margin="0,18,0,0" FontSize="16" FontWeight="SemiBold"
|
||||
Foreground="{StaticResource FsTextPrimary}"
|
||||
HorizontalAlignment="Center"
|
||||
Text="Drop files anywhere to queue"/>
|
||||
<TextBlock Margin="0,4,0,0" Style="{StaticResource FsCaptionStyle}"
|
||||
<TextBlock Margin="0,6,0,0" Style="{StaticResource FsCaptionStyle}"
|
||||
HorizontalAlignment="Center"
|
||||
Text="PNG · JPG · GIF · HEIC · RAW · PDF · DOCX · HTML · HWP/HWPX"/>
|
||||
TextAlignment="Center"
|
||||
Text="이미지 · 문서 · 데이터 · 영상 · 오디오 등 무엇이든"/>
|
||||
<Button Margin="0,22,0,0"
|
||||
HorizontalAlignment="Center"
|
||||
Style="{StaticResource FsSecondaryButtonStyle}"
|
||||
Padding="18,8"
|
||||
Content="Browse…"
|
||||
Command="{Binding AddFilesCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
|
||||
<TextBlock Margin="0,12,0,0" Style="{StaticResource FsCaptionStyle}"
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="{StaticResource FsTextTertiary}"
|
||||
Text="또는 Ctrl+O"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
<ScrollViewer x:Name="ActiveQueueScroll" VerticalScrollBarVisibility="Auto"
|
||||
|
|
@ -386,7 +433,8 @@
|
|||
<ItemsControl x:Name="ActiveQueueList">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Margin="0,0,0,8" Padding="12,10" CornerRadius="6"
|
||||
<!-- row hover: FsListRowStyle 느낌(투명→surface hover, hairline 보더) + 좌측 형식색 accent bar -->
|
||||
<Border x:Name="QueueRow" Margin="0,0,0,8" Padding="0" CornerRadius="6"
|
||||
Background="{StaticResource FsBgPanel}"
|
||||
BorderBrush="{StaticResource FsBorderSubtle}"
|
||||
BorderThickness="1"
|
||||
|
|
@ -394,6 +442,16 @@
|
|||
PreviewMouseLeftButtonUp="OnQueueRowClick"
|
||||
Tag="{Binding}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="2"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<!-- 좌측 2px 세로 accent bar: 해당 파일 형식색 -->
|
||||
<Border Grid.Column="0"
|
||||
Width="2"
|
||||
Background="{Binding FormatBrush}"
|
||||
CornerRadius="6,0,0,6"/>
|
||||
<Grid Grid.Column="1" Margin="12,10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="40"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
|
|
@ -434,19 +492,30 @@
|
|||
Foreground="{Binding StateBrush}"
|
||||
VerticalAlignment="Center"/>
|
||||
<Button Grid.Column="4"
|
||||
Style="{StaticResource FsSecondaryButtonStyle}"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
Padding="6"
|
||||
Style="{StaticResource FsIconButtonStyle}"
|
||||
Width="28" Height="28"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Right"
|
||||
ToolTip="큐에서 제거"
|
||||
Click="OnRemoveQueueItem"
|
||||
Tag="{Binding}">
|
||||
<Path Width="14" Height="14" Stretch="Uniform"
|
||||
<Path Width="13" Height="13" Stretch="Uniform"
|
||||
Stroke="{StaticResource FsTextTertiary}"
|
||||
StrokeThickness="2"
|
||||
Data="M18,6 L6,18 M6,6 L18,18"/>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
<DataTemplate.Triggers>
|
||||
<!-- row hover: 배경 살짝 밝게 + hairline 보더 -->
|
||||
<Trigger SourceName="QueueRow" Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="QueueRow" Property="Background"
|
||||
Value="{StaticResource FsBgSurfaceHover}"/>
|
||||
<Setter TargetName="QueueRow" Property="BorderBrush"
|
||||
Value="{StaticResource FsBorderHairline}"/>
|
||||
</Trigger>
|
||||
</DataTemplate.Triggers>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
|
|
|||
|
|
@ -258,6 +258,14 @@ public partial class MainWindow : Wpf.Ui.Controls.FluentWindow
|
|||
};
|
||||
}
|
||||
|
||||
private void OnAiTaskChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
// 번역(인덱스 1)일 때만 대상 언어 입력을 표시
|
||||
if (AiTargetLangPanel is null) return;
|
||||
AiTargetLangPanel.Visibility =
|
||||
(AiTaskCombo?.SelectedIndex == 1) ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
private void OnPickOutputFolderClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var dlg = new Microsoft.Win32.OpenFolderDialog { Title = "출력 폴더 선택" };
|
||||
|
|
@ -286,6 +294,16 @@ public partial class MainWindow : Wpf.Ui.Controls.FluentWindow
|
|||
opts.OutputLocation = OutputLocation.SubfolderBesideSource;
|
||||
}
|
||||
|
||||
// AI 작업 종류 (txt↔txt / md↔md 등 텍스트 변환 시 LlmProvider가 사용)
|
||||
opts.Ai.Task = (AiTaskCombo?.SelectedIndex ?? 0) switch
|
||||
{
|
||||
1 => "translate",
|
||||
2 => "proofread",
|
||||
_ => "summarize",
|
||||
};
|
||||
var targetLang = AiTargetLangBox?.Text?.Trim();
|
||||
opts.Ai.TargetLanguage = string.IsNullOrEmpty(targetLang) ? null : targetLang;
|
||||
|
||||
return opts;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue