diff --git a/README.md b/README.md index 4850360..b13a53d 100644 --- a/README.md +++ b/README.md @@ -1086,3 +1086,7 @@ MIT License - 업데이트: 2026-04-06 01:00 (KST) - AX Agent 메시지 hover 액션을 보강해 복사/편집/재생성/수정 후 재시도/좋아요·싫어요가 실제로 보이도록 정리했다. 사용자/assistant 메시지 액션 바를 완전 숨김 대신 기본 저강도 노출 + hover 강조 방식으로 바꿔, 마우스를 올렸을 때 액션이 안 보이던 문제를 줄였다. - assistant 응답에는 응답시간과 총 토큰 수를 메시지 메타로 저장해 transcript 아래에 함께 표시되게 했다. 반영 위치는 [ChatModels.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Models/ChatModels.cs), [AxAgentExecutionEngine.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs), [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 이다. +- 업데이트: 2026-04-06 01:08 (KST) + - `claw-code`의 `SessionPreview`/`PreviewBox` 흐름을 참고해 AX Agent 프리뷰도 같은 시각 언어로 정리했다. 새 파일 [AgentPreviewSurfaceFactory.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/AgentPreviewSurfaceFactory.cs)를 추가해 권한 프리뷰 카드의 제목/요약/본문 박스 구조를 공통화했다. + - [PermissionRequestWindow.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/PermissionRequestWindow.cs)의 일반 프리뷰, 파일 편집 프리뷰, 파일 생성 2열 프리뷰를 이 공통 surface로 맞춰 `preview box` 언어를 통일했다. + - [ChatWindow.xaml](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml), [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs)의 우측 파일 프리뷰 패널에는 파일명/경로/형식·크기 메타를 보여주는 헤더를 추가하고, 텍스트 프리뷰 본문도 별도 bordered preview box 안에 렌더되게 바꿨다. diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index b968923..12c4c74 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -4846,3 +4846,8 @@ ow + toggle ?쒓컖 ?몄뼱濡??ㅼ떆 ?뺣젹?덈떎. - [AxAgentExecutionEngine.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs) 의 `CommitAssistantMessage()` / `FinalizeAssistantTurn()`은 응답 메타를 함께 커밋하도록 확장했다. - [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 에서는 실행 완료 시 `_llm.LastTokenUsage`, 누적 에이전트 토큰, 응답 경과 시간을 assistant 메시지에 저장하고, transcript 렌더 시 `응답시간 · 총 토큰` 메타를 assistant bubble 아래에 함께 표시하도록 연결했다. - 사용자/assistant 메시지 액션 바는 완전 숨김(Opacity 0) 대신 기본 저강도 노출 + hover 시 100% 강조로 바꿨다. 이로써 메시지에 마우스를 올렸을 때 복사/편집/재생성/수정 후 재시도/좋아요·싫어요가 보이지 않던 UX 문제를 줄였다. +- 업데이트: 2026-04-06 01:08 (KST) + - `claw-code`의 `SessionPreview.tsx`, `PreviewBox.tsx`를 참고해 AX Agent 프리뷰 surface를 공통화했다. [AgentPreviewSurfaceFactory.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/AgentPreviewSurfaceFactory.cs)를 추가해 `title + summary + preview box` 구조를 재사용 가능한 helper로 분리했다. + - [PermissionRequestWindow.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/PermissionRequestWindow.cs) 의 `BuildPreviewCard`, `BuildFileEditPreviewCard`, `BuildFileWriteTwoColumnPreviewCard`는 이 helper를 쓰도록 정리해 권한 승인 프리뷰가 같은 preview 언어를 따르도록 맞췄다. + - [ChatWindow.xaml](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml) 의 우측 프리뷰 패널 헤더를 `파일명 / 경로 / 형식·크기 메타` 구조로 재배치하고, [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 에 `SetPreviewHeader`, `SetPreviewHeaderState`를 추가해 현재 탭 파일 메타를 표시하도록 했다. + - 텍스트 프리뷰 본문도 bordered preview box 안에 렌더되게 바꿔, AX Agent 파일 프리뷰와 transcript/승인 프리뷰 사이 시각 언어를 더 가깝게 맞췄다. diff --git a/src/AxCopilot/Views/AgentPreviewSurfaceFactory.cs b/src/AxCopilot/Views/AgentPreviewSurfaceFactory.cs new file mode 100644 index 0000000..85f1ca9 --- /dev/null +++ b/src/AxCopilot/Views/AgentPreviewSurfaceFactory.cs @@ -0,0 +1,85 @@ +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; + +namespace AxCopilot.Views; + +internal static class AgentPreviewSurfaceFactory +{ + internal static Border CreateSurface( + string title, + string summary, + UIElement body, + Brush primary, + Brush secondary, + Brush itemBackground, + Brush borderBrush, + Thickness? margin = null) + { + return new Border + { + Background = itemBackground, + BorderBrush = borderBrush, + BorderThickness = new Thickness(1), + CornerRadius = new CornerRadius(12), + Padding = new Thickness(12, 10, 12, 10), + Margin = margin ?? new Thickness(0, 8, 0, 0), + Child = new StackPanel + { + Children = + { + new TextBlock + { + Text = title, + FontSize = 12, + FontWeight = FontWeights.SemiBold, + Foreground = primary, + }, + new TextBlock + { + Text = summary, + FontSize = 11, + Foreground = secondary, + Margin = new Thickness(0, 2, 0, 8), + TextWrapping = TextWrapping.Wrap, + }, + body + } + } + }; + } + + internal static Border CreatePreviewBox( + string content, + Brush primary, + Brush secondary, + Brush borderBrush, + double maxHeight, + bool monospace = true) + { + var panel = new Border + { + Background = Brushes.Transparent, + BorderBrush = new SolidColorBrush(Color.FromArgb(0x20, 0x80, 0x80, 0x80)), + BorderThickness = new Thickness(1), + CornerRadius = new CornerRadius(8), + Padding = new Thickness(8, 6, 8, 6), + Child = new ScrollViewer + { + MaxHeight = maxHeight, + VerticalScrollBarVisibility = ScrollBarVisibility.Auto, + Content = new TextBlock + { + Text = string.IsNullOrWhiteSpace(content) ? "(empty)" : content, + Foreground = primary, + FontFamily = monospace ? new FontFamily("Consolas") : new FontFamily("Pretendard"), + FontSize = 11.2, + TextWrapping = TextWrapping.Wrap, + LineHeight = 18, + } + } + }; + + return panel; + } +} diff --git a/src/AxCopilot/Views/ChatWindow.xaml b/src/AxCopilot/Views/ChatWindow.xaml index cd4cc33..9889027 100644 --- a/src/AxCopilot/Views/ChatWindow.xaml +++ b/src/AxCopilot/Views/ChatWindow.xaml @@ -5240,43 +5240,88 @@ BorderBrush="{DynamicResource BorderColor}" BorderThickness="1,0,0,0"> - - - - - - - - - - - - - - + Padding="12,10,12,8"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + VerticalScrollBarVisibility="Auto" Padding="16,14"> + + + = 1024 * 1024 + ? $"{fileInfo.Length / 1024d / 1024d:F1} MB" + : $"{Math.Max(1, fileInfo.Length / 1024d):F0} KB" + : "파일 없음"; + + PreviewHeaderTitle.Text = string.IsNullOrWhiteSpace(fileName) ? "미리보기" : fileName; + PreviewHeaderSubtitle.Text = filePath; + PreviewHeaderMeta.Text = string.IsNullOrWhiteSpace(extension) + ? sizeText + : $"{extension} · {sizeText}"; + } + + private void SetPreviewHeaderState(string state) + { + if (PreviewHeaderMeta != null && !string.IsNullOrWhiteSpace(state)) + PreviewHeaderMeta.Text = state; + } + private bool _webViewInitialized; private static readonly string WebView2DataFolder = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @@ -17617,6 +17648,9 @@ public partial class ChatWindow : Window { _previewTabs.Clear(); _activePreviewTab = null; + if (PreviewHeaderTitle != null) PreviewHeaderTitle.Text = "미리보기"; + if (PreviewHeaderSubtitle != null) PreviewHeaderSubtitle.Text = "선택한 파일이 여기에 표시됩니다"; + if (PreviewHeaderMeta != null) PreviewHeaderMeta.Text = "파일 메타"; PreviewColumn.Width = new GridLength(0); SplitterColumn.Width = new GridLength(0); PreviewPanel.Visibility = Visibility.Collapsed; diff --git a/src/AxCopilot/Views/PermissionRequestWindow.cs b/src/AxCopilot/Views/PermissionRequestWindow.cs index 2fd8a0e..6241717 100644 --- a/src/AxCopilot/Views/PermissionRequestWindow.cs +++ b/src/AxCopilot/Views/PermissionRequestWindow.cs @@ -581,48 +581,19 @@ internal sealed class PermissionRequestWindow : Window Brush border, UiExpressionProfile uiProfile) { - return new Border - { - Background = itemBg, - BorderBrush = border, - BorderThickness = new Thickness(1), - CornerRadius = new CornerRadius(10), - Padding = new Thickness(10, 8, 10, 8), - Margin = new Thickness(0, 8, 0, 0), - Child = new StackPanel - { - Children = - { - new TextBlock - { - Text = title, - FontSize = 11.5, - FontWeight = FontWeights.SemiBold, - Foreground = primary, - }, - new TextBlock - { - Text = summary, - FontSize = 11, - Foreground = secondary, - Margin = new Thickness(0, 2, 0, 6), - }, - new TextBox - { - Text = content, - IsReadOnly = true, - BorderThickness = new Thickness(0), - Background = Brushes.Transparent, - Foreground = primary, - FontFamily = new FontFamily("Consolas"), - FontSize = 11, - MaxHeight = uiProfile.PreviewMaxHeight, - TextWrapping = TextWrapping.Wrap, - VerticalScrollBarVisibility = ScrollBarVisibility.Auto, - } - } - } - }; + return AgentPreviewSurfaceFactory.CreateSurface( + title, + summary, + AgentPreviewSurfaceFactory.CreatePreviewBox( + content, + primary, + secondary, + border, + uiProfile.PreviewMaxHeight), + primary, + secondary, + itemBg, + border); } private static Border BuildFileEditPreviewCard( @@ -679,41 +650,19 @@ internal sealed class PermissionRequestWindow : Window }); } - return new Border - { - Background = itemBg, - BorderBrush = border, - BorderThickness = new Thickness(1), - CornerRadius = new CornerRadius(10), - Padding = new Thickness(10, 8, 10, 8), - Margin = new Thickness(0, 8, 0, 0), - Child = new StackPanel - { - Children = - { - new TextBlock - { - Text = title, - FontSize = 11.5, - FontWeight = FontWeights.SemiBold, - Foreground = primary, - }, - new TextBlock - { - Text = summary, - FontSize = 11, - Foreground = secondary, - Margin = new Thickness(0, 2, 0, 6), - }, - new ScrollViewer - { - MaxHeight = uiProfile.PreviewMaxHeight, - VerticalScrollBarVisibility = ScrollBarVisibility.Auto, - Content = body, - } - } - } - }; + return AgentPreviewSurfaceFactory.CreateSurface( + title, + summary, + AgentPreviewSurfaceFactory.CreatePreviewBox( + string.Join("\n", body.Children.OfType().Select(tb => tb.Text)), + primary, + secondary, + border, + uiProfile.PreviewMaxHeight), + primary, + secondary, + itemBg, + border); } private static Border BuildFileWriteTwoColumnPreviewCard( @@ -764,36 +713,14 @@ internal sealed class PermissionRequestWindow : Window Grid.SetColumn(newPanel, 2); grid.Children.Add(newPanel); - return new Border - { - Background = itemBg, - BorderBrush = border, - BorderThickness = new Thickness(1), - CornerRadius = new CornerRadius(10), - Padding = new Thickness(10, 8, 10, 8), - Margin = new Thickness(0, 8, 0, 0), - Child = new StackPanel - { - Children = - { - new TextBlock - { - Text = title, - FontSize = 11.5, - FontWeight = FontWeights.SemiBold, - Foreground = primary, - }, - new TextBlock - { - Text = summary, - FontSize = 11, - Foreground = secondary, - Margin = new Thickness(0, 2, 0, 6), - }, - grid, - } - } - }; + return AgentPreviewSurfaceFactory.CreateSurface( + title, + summary, + grid, + primary, + secondary, + itemBg, + border); } private static Border BuildWriteColumn( @@ -1161,8 +1088,8 @@ internal sealed class PermissionRequestWindow : Window Owner = owner, }; - if (owner.Resources.MergedDictionaries.Count > 0) - dialog.Resources.MergedDictionaries.Add(owner.Resources); + dialog.WindowStartupLocation = WindowStartupLocation.CenterOwner; + dialog.Resources.MergedDictionaries.Add(owner.Resources); dialog.ShowDialog(); return dialog._result;