Phase A: tab architecture integrated into MainWindow - tab strip UI, per-tab WebView2 lifecycle, new-window->tab w/ deferral, audio indicator/mute, session save/restore, shortcuts; E2E on real window (56 tests GREEN)

This commit is contained in:
Yun Chan 2026-08-15 14:48:17 +09:00
parent be01a116ca
commit b6b7fc341b
7 changed files with 389 additions and 106 deletions

View file

@ -153,6 +153,7 @@
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
@ -209,8 +210,68 @@
</DockPanel>
</Border>
<!-- ===== 탭 스트립 (Phase A) ===== -->
<Border x:Name="TabStripRow" Grid.Row="1" Background="{StaticResource PanelBg}"
BorderBrush="{StaticResource BorderSubtle}" BorderThickness="0,0,0,1" Padding="8,4,8,0">
<DockPanel>
<Button x:Name="NewTabBtn" DockPanel.Dock="Right" Style="{StaticResource IconButton}"
Content="&#xE710;" FontSize="13" ToolTip="새 탭 (Ctrl+T)" Click="NewTab_Click"
Margin="4,0,2,3" VerticalAlignment="Center"/>
<ScrollViewer HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Disabled"
VerticalAlignment="Bottom">
<ItemsControl x:Name="TabList">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="0,0,4,0" MinWidth="130" MaxWidth="220">
<Border x:Name="TabBg" CornerRadius="8,8,0,0"
Background="{StaticResource GlassBg}"
BorderBrush="{StaticResource BorderSubtle}" BorderThickness="1,1,1,0"
Padding="10,7,4,7" MouseLeftButtonUp="Tab_Click"
PreviewMouseDown="Tab_PreviewMouseDown"
ToolTip="{Binding Url}">
<DockPanel>
<Button DockPanel.Dock="Right" Style="{StaticResource CardActionButton}"
Content="&#xE711;" FontSize="9" Padding="5,3" Margin="4,0,0,0"
Click="TabClose_Click" ToolTip="탭 닫기 (Ctrl+W)"
VerticalAlignment="Center"/>
<TextBlock x:Name="AudioIcon" Text="&#xE767;" Style="{StaticResource FluentIcon}"
FontSize="11" Margin="0,0,6,0" VerticalAlignment="Center"
Visibility="Collapsed" Cursor="Hand"
MouseLeftButtonUp="TabAudio_Click"/>
<TextBlock Text="{Binding Title}" TextTrimming="CharacterEllipsis"
FontSize="12" VerticalAlignment="Center"/>
</DockPanel>
</Border>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsActive}" Value="True">
<Setter TargetName="TabBg" Property="Background" Value="{StaticResource CardBg}"/>
<Setter TargetName="TabBg" Property="BorderBrush" Value="{StaticResource AccentFadeBrush}"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsAudioPlaying}" Value="True">
<Setter TargetName="AudioIcon" Property="Visibility" Value="Visible"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsMuted}" Value="True">
<Setter TargetName="AudioIcon" Property="Text" Value="&#xE74F;"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsPinned}" Value="True">
<Setter TargetName="TabBg" Property="Background" Value="{StaticResource AccentFadeBrush}"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</DockPanel>
</Border>
<!-- ===== 본문 ===== -->
<Grid Grid.Row="1">
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
@ -224,7 +285,7 @@
</Grid.RowDefinitions>
<Border Grid.Row="0" ClipToBounds="True" Background="Black">
<wv2:WebView2 Name="Browser"/>
<Grid x:Name="TabHost" Background="Black"/>
</Border>
<!-- 페이지 내 검색 바 (T1-3): WebView2(airspace) 아래에 도킹 -->
@ -320,7 +381,7 @@
</Grid>
<!-- ===== 상태 표시줄 ===== -->
<Border x:Name="StatusBar" Grid.Row="2" Background="{StaticResource PanelBg}"
<Border x:Name="StatusBar" Grid.Row="3" Background="{StaticResource PanelBg}"
BorderBrush="{StaticResource BorderSubtle}" BorderThickness="0,1,0,0" Padding="16,5">
<TextBlock Name="StatusText" Foreground="{StaticResource TextMuted}" FontSize="11"
TextTrimming="CharacterEllipsis" Text="준비"/>