1
0
Fork 0

ux: FormatShift Utility 디자인을 메인 윈도우에 충실히 재현

새 메인 윈도우 (1280x960, dark minimal):
- 320px 사이드바 — Target Format(JPG), Encoding Quality 슬라이더(파란색 fill +
  흰 thumb), Output Destination, Skip/Rename/Replace 세그먼트, Stats Box,
  Processing Queue 버튼(disabled→enabled 상태 전이)
- 메인 영역 — pill 탭 3개(Active Queue / Preview / Past Results), 액션 버튼
  (Register Menu / Diagnose / Export Log / Clear All)
- Past Results — 날짜별 그룹화, "Today/Yesterday" 헤더 + Session Savings 뱃지,
  파일 아이콘(PDF/PNG/HEIC/JPG/...), 사이즈/savings/status 컬럼
- Active Queue — 빈 상태 드롭존 + 파일 행, 행 클릭 시 Preview 자동 전환
- Drop hint overlay — 파일 끌어올 때 흐릿한 가이드 표시

핵심 신규 인프라:
- FormatShiftTheme.xaml — 디자인 토큰(색/타이포/슬라이더 스타일/탭 pill 스타일/
  세그먼트 스타일/primary·secondary 버튼) 전부
- PreviewService — 이미지/RAW(Magick), HEIC(libheif decode), PDF(PDFium)을
  720px 긴변 BitmapSource로 렌더. DOCX/HWP/HTML은 안내 문구 fallback
- HistoryStore — 변환 결과 누적(메모리), 날짜별 group + session savings 합산
- Export Log — Past Results를 CSV/JSON으로 저장

기존 기능 통합:
- 사이드바 옵션이 ConvertOptions에 매핑 (Quality, Output Path, Conflict)
- Process Queue 버튼이 ConvertManyAsync 호출 → 결과를 History에 누적
- Register Menu / Diagnose 액션 유지

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Yun Chan 2026-05-06 16:57:49 +09:00
parent 8065bf7373
commit 01467a4d27
5 changed files with 1701 additions and 278 deletions

View file

@ -0,0 +1,293 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Backgrounds -->
<SolidColorBrush x:Key="FsBgBase" Color="#090A0C"/>
<SolidColorBrush x:Key="FsBgPanel" Color="#131417"/>
<SolidColorBrush x:Key="FsBgSurface" Color="#1C1E22"/>
<SolidColorBrush x:Key="FsBgSurfaceHover" Color="#23252A"/>
<SolidColorBrush x:Key="FsBgInput" Color="#0F1012"/>
<!-- Borders -->
<SolidColorBrush x:Key="FsBorderSubtle" Color="#26282D"/>
<SolidColorBrush x:Key="FsBorderStrong" Color="#3A3D45"/>
<!-- Text -->
<SolidColorBrush x:Key="FsTextPrimary" Color="#ECEEFA"/>
<SolidColorBrush x:Key="FsTextSecondary" Color="#8B909A"/>
<SolidColorBrush x:Key="FsTextTertiary" Color="#5D626C"/>
<!-- Accents -->
<SolidColorBrush x:Key="FsAccentBlue" Color="#3B72FF"/>
<SolidColorBrush x:Key="FsAccentGreen" Color="#10B981"/>
<SolidColorBrush x:Key="FsAccentAmber" Color="#F59E0B"/>
<SolidColorBrush x:Key="FsAccentRed" Color="#EF4444"/>
<!-- Format pills -->
<SolidColorBrush x:Key="FsFmtPdf" Color="#E53E3E"/>
<SolidColorBrush x:Key="FsFmtPng" Color="#805AD5"/>
<SolidColorBrush x:Key="FsFmtHeic" Color="#D69E2E"/>
<SolidColorBrush x:Key="FsFmtJpg" Color="#3182CE"/>
<SolidColorBrush x:Key="FsFmtDocx" Color="#2B6CB0"/>
<SolidColorBrush x:Key="FsFmtHtml" Color="#DD6B20"/>
<SolidColorBrush x:Key="FsFmtRaw" Color="#319795"/>
<SolidColorBrush x:Key="FsFmtGif" Color="#9F7AEA"/>
<SolidColorBrush x:Key="FsFmtTiff" Color="#38B2AC"/>
<SolidColorBrush x:Key="FsFmtWebp" Color="#48BB78"/>
<SolidColorBrush x:Key="FsFmtBmp" Color="#718096"/>
<SolidColorBrush x:Key="FsFmtHwp" Color="#9B2C2C"/>
<SolidColorBrush x:Key="FsFmtOther" Color="#4A5568"/>
<!-- Font families -->
<FontFamily x:Key="FsFontSans">Inter, Segoe UI Variable Text, Segoe UI</FontFamily>
<FontFamily x:Key="FsFontMono">JetBrains Mono, Cascadia Mono, Consolas</FontFamily>
<!-- Typography styles -->
<Style x:Key="FsLabelStyle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="{StaticResource FsFontSans}"/>
<Setter Property="FontSize" Value="11"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="Foreground" Value="{StaticResource FsTextSecondary}"/>
<Setter Property="TextOptions.TextFormattingMode" Value="Display"/>
</Style>
<Style x:Key="FsCaptionStyle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="{StaticResource FsFontSans}"/>
<Setter Property="FontSize" Value="11"/>
<Setter Property="Foreground" Value="{StaticResource FsTextTertiary}"/>
</Style>
<Style x:Key="FsBodyStyle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="{StaticResource FsFontSans}"/>
<Setter Property="FontSize" Value="13"/>
<Setter Property="Foreground" Value="{StaticResource FsTextPrimary}"/>
</Style>
<Style x:Key="FsMonoStyle" TargetType="TextBlock">
<Setter Property="FontFamily" Value="{StaticResource FsFontMono}"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Foreground" Value="{StaticResource FsTextSecondary}"/>
</Style>
<!-- Slider style: 2px track, 14px round thumb, blue fill up to value -->
<Style x:Key="FsSliderStyle" TargetType="Slider">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="{StaticResource FsAccentBlue}"/>
<Setter Property="MinHeight" Value="20"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="IsMoveToPointEnabled" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Slider">
<Grid>
<Border Height="2" CornerRadius="1"
Background="{StaticResource FsBorderStrong}"
VerticalAlignment="Center"/>
<Track x:Name="PART_Track">
<Track.DecreaseRepeatButton>
<RepeatButton Command="Slider.DecreaseLarge">
<RepeatButton.Template>
<ControlTemplate TargetType="RepeatButton">
<Border Height="2" CornerRadius="1"
Background="{StaticResource FsAccentBlue}"
VerticalAlignment="Center"/>
</ControlTemplate>
</RepeatButton.Template>
</RepeatButton>
</Track.DecreaseRepeatButton>
<Track.Thumb>
<Thumb>
<Thumb.Template>
<ControlTemplate TargetType="Thumb">
<Ellipse Width="14" Height="14"
Fill="{StaticResource FsTextPrimary}"/>
</ControlTemplate>
</Thumb.Template>
</Thumb>
</Track.Thumb>
<Track.IncreaseRepeatButton>
<RepeatButton Command="Slider.IncreaseLarge">
<RepeatButton.Template>
<ControlTemplate TargetType="RepeatButton">
<Border Background="Transparent"/>
</ControlTemplate>
</RepeatButton.Template>
</RepeatButton>
</Track.IncreaseRepeatButton>
</Track>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Tab pill style -->
<Style x:Key="FsTabPillStyle" TargetType="ToggleButton">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="{StaticResource FsTextSecondary}"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Padding" Value="14,6"/>
<Setter Property="FontSize" Value="13"/>
<Setter Property="FontWeight" Value="Medium"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border x:Name="PART_Bd" CornerRadius="20"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"
TextElement.Foreground="{TemplateBinding Foreground}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="PART_Bd" Property="Background" Value="{StaticResource FsAccentBlue}"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="PART_Bd" Property="Background" Value="{StaticResource FsBgSurfaceHover}"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsChecked" Value="True"/>
<Condition Property="IsMouseOver" Value="True"/>
</MultiTrigger.Conditions>
<Setter TargetName="PART_Bd" Property="Background" Value="{StaticResource FsAccentBlue}"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Segment button style (Skip / Rename / Replace) -->
<Style x:Key="FsSegmentStyle" TargetType="ToggleButton">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Foreground" Value="{StaticResource FsTextSecondary}"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="FontWeight" Value="Medium"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border x:Name="PART_Bd" CornerRadius="4" Padding="0,6">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"
TextElement.Foreground="{TemplateBinding Foreground}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="PART_Bd" Property="Background" Value="{StaticResource FsBgSurface}"/>
<Setter Property="Foreground" Value="{StaticResource FsTextPrimary}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Primary button (Processing Queue / Run) -->
<Style x:Key="FsPrimaryButtonStyle" TargetType="Button">
<Setter Property="Background" Value="{StaticResource FsAccentBlue}"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Padding" Value="12"/>
<Setter Property="FontSize" Value="13"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="PART_Bd"
Background="{TemplateBinding Background}"
CornerRadius="6"
Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"
TextElement.Foreground="{TemplateBinding Foreground}"
TextElement.FontSize="{TemplateBinding FontSize}"
TextElement.FontWeight="{TemplateBinding FontWeight}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="PART_Bd" Property="Opacity" Value="0.5"/>
<Setter Property="Cursor" Value="Arrow"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="PART_Bd" Property="Background" Value="#2D5DDB"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Secondary button -->
<Style x:Key="FsSecondaryButtonStyle" TargetType="Button">
<Setter Property="Background" Value="{StaticResource FsBgSurface}"/>
<Setter Property="Foreground" Value="{StaticResource FsTextPrimary}"/>
<Setter Property="BorderBrush" Value="{StaticResource FsBorderSubtle}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="12,6"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="FontWeight" Value="Medium"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="PART_Bd"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="6"
Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"
TextElement.Foreground="{TemplateBinding Foreground}"
TextElement.FontSize="{TemplateBinding FontSize}"
TextElement.FontWeight="{TemplateBinding FontWeight}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="PART_Bd" Property="Background" Value="{StaticResource FsBgSurfaceHover}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Tab badge -->
<Style x:Key="FsTabBadgeStyle" TargetType="Border">
<Setter Property="CornerRadius" Value="10"/>
<Setter Property="Padding" Value="6,1"/>
<Setter Property="Background" Value="{StaticResource FsBgSurface}"/>
</Style>
<!-- Path input box -->
<Style x:Key="FsPathInputStyle" TargetType="TextBox">
<Setter Property="Background" Value="{StaticResource FsBgInput}"/>
<Setter Property="Foreground" Value="{StaticResource FsTextSecondary}"/>
<Setter Property="BorderBrush" Value="{StaticResource FsBorderSubtle}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="10,8"/>
<Setter Property="FontFamily" Value="{StaticResource FsFontMono}"/>
<Setter Property="FontSize" Value="11"/>
<Setter Property="CaretBrush" Value="{StaticResource FsTextPrimary}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="6"
Padding="{TemplateBinding Padding}">
<ScrollViewer x:Name="PART_ContentHost"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>