AX Agent 채팅창 반응형 폭 계산 적용
Some checks failed
Release Gate / gate (push) Has been cancelled

- ChatWindow의 ComposerShell 고정폭을 제거하고 실제 본문 영역 폭 기준으로 MessagePanel, EmptyState, ComposerShell을 함께 재계산하도록 정리함

- 창 크기 변경 시 메시지 축과 입력창이 자연스럽게 함께 줄고 늘어나도록 Loaded와 SizeChanged에 반응형 레이아웃 갱신을 연결함

- README와 DEVELOPMENT 문서에 2026-04-05 14:16 (KST) 기준 작업 이력을 반영하고 Release 빌드 경고 0 오류 0을 확인함
This commit is contained in:
2026-04-05 13:13:15 +09:00
parent 382c78e32f
commit b24afba2d8
4 changed files with 68 additions and 9 deletions

View File

@@ -773,8 +773,10 @@ ow + toggle 시각 언어로 통일했습니다.
- 업데이트: 2026-04-05 14:00 (KST) - 업데이트: 2026-04-05 14:00 (KST)
- 메시지 행 UI도 `claw-code` 기준으로 한 단계 더 눌렀습니다. [ChatWindow.xaml](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml) 의 `MessagePanel` 하단 여백을 더 줄여 본문 축이 컴포저와 가깝게 이어지도록 했고, [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 에서 사용자/assistant 메시지 카드의 좌우 마진, 코너 라운드, 패딩, 폰트 크기, 타임스탬프 크기를 전반적으로 낮췄습니다. - 메시지 행 UI도 `claw-code` 기준으로 한 단계 더 눌렀습니다. [ChatWindow.xaml](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml) 의 `MessagePanel` 하단 여백을 더 줄여 본문 축이 컴포저와 가깝게 이어지도록 했고, [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 에서 사용자/assistant 메시지 카드의 좌우 마진, 코너 라운드, 패딩, 폰트 크기, 타임스탬프 크기를 전반적으로 낮췄습니다.
- assistant 헤더는 아이콘과 이름을 더 작고 옅게 줄였고, 액션 바 버튼도 패딩과 간격을 축소해 메시지 본문보다 덜 튀게 만들었습니다. 같은 방향으로 실행 로그 배너(`AddAgentEventBanner`)도 좌우 마진, 아이콘/라벨 크기, 토큰 배지와 요약 텍스트 밀도를 낮춰, Cowork/Code에서 로그가 메시지보다 먼저 보이던 느낌을 줄였습니다. - assistant 헤더는 아이콘과 이름을 더 작고 옅게 줄였고, 액션 바 버튼도 패딩과 간격을 축소해 메시지 본문보다 덜 튀게 만들었습니다. 같은 방향으로 실행 로그 배너(`AddAgentEventBanner`)도 좌우 마진, 아이콘/라벨 크기, 토큰 배지와 요약 텍스트 밀도를 낮춰, Cowork/Code에서 로그가 메시지보다 먼저 보이던 느낌을 줄였습니다.
- 폭 계산도 `claw-code`처럼 반응형으로 다시 맞췄습니다. [ChatWindow.xaml](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml)의 `ComposerShell` 고정폭을 걷어내고, [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs)의 `UpdateResponsiveChatLayout()`가 실제 본문 폭 기준으로 `MessagePanel`, `EmptyState`, `ComposerShell` 폭을 함께 다시 계산하도록 연결했습니다.
- 이제 창이 작아질 때 메시지 축과 입력창이 따로 놀지 않고 같은 축으로 같이 줄어들며, 창이 넓을 때는 적당한 상한을 유지한 채 자연스럽게 넓어집니다. 초기 로드와 `SizeChanged` 모두 같은 반응형 계산을 타도록 붙였습니다.
- 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\` 경고 0 / 오류 0 - 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\` 경고 0 / 오류 0
- 업데이트: 2026-04-05 14:09 (KST) - 업데이트: 2026-04-05 14:16 (KST)
--- ---

View File

@@ -4536,5 +4536,7 @@ ow + toggle ?쒓컖 ?몄뼱濡??ㅼ떆 ?뺣젹?덈떎.
- 빈 상태는 부유 애니메이션이 있는 그라디언트 아이콘을 제거하고, 작은 정적 카드형 아이콘 + 짧은 문구로 바꿨습니다. 상단 `AgentProgressBar`는 패딩과 프로그레스 바 높이를 줄였고, 컴포저는 `800px` 축으로 넓히면서 `DraftPreviewCard`, `InputGlowBorder`, `InputBorder`의 라운드/그림자 강도를 낮춰 장식량을 줄였습니다. - 빈 상태는 부유 애니메이션이 있는 그라디언트 아이콘을 제거하고, 작은 정적 카드형 아이콘 + 짧은 문구로 바꿨습니다. 상단 `AgentProgressBar`는 패딩과 프로그레스 바 높이를 줄였고, 컴포저는 `800px` 축으로 넓히면서 `DraftPreviewCard`, `InputGlowBorder`, `InputBorder`의 라운드/그림자 강도를 낮춰 장식량을 줄였습니다.
- 메시지 행 자체도 `claw-code` 방향으로 더 눌렀습니다. [ChatWindow.xaml](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml)의 `MessagePanel` 하단 여백을 줄였고, [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs)의 `AddMessageBubble(...)`에서 사용자/assistant 카드의 좌우 마진, 코너 라운드, 패딩, 폰트 크기, 타임스탬프 크기를 전반적으로 축소했습니다. - 메시지 행 자체도 `claw-code` 방향으로 더 눌렀습니다. [ChatWindow.xaml](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml)의 `MessagePanel` 하단 여백을 줄였고, [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs)의 `AddMessageBubble(...)`에서 사용자/assistant 카드의 좌우 마진, 코너 라운드, 패딩, 폰트 크기, 타임스탬프 크기를 전반적으로 축소했습니다.
- assistant 헤더는 아이콘/이름을 더 작고 옅게 조정해 메시지 본문이 먼저 읽히도록 바꿨고, 액션 바 버튼도 패딩과 간격을 줄여 hover 시에도 과하게 튀지 않게 맞췄습니다. `AddAgentEventBanner(...)` 역시 좌우 마진, 아이콘/라벨, 토큰 배지, 요약 텍스트 밀도를 함께 낮춰 실행 로그가 본문보다 먼저 보이던 시각적 압박을 줄였습니다. - assistant 헤더는 아이콘/이름을 더 작고 옅게 조정해 메시지 본문이 먼저 읽히도록 바꿨고, 액션 바 버튼도 패딩과 간격을 줄여 hover 시에도 과하게 튀지 않게 맞췄습니다. `AddAgentEventBanner(...)` 역시 좌우 마진, 아이콘/라벨, 토큰 배지, 요약 텍스트 밀도를 함께 낮춰 실행 로그가 본문보다 먼저 보이던 시각적 압박을 줄였습니다.
- 폭 계산도 `claw-code`식 반응형 축으로 다시 맞췄습니다. [ChatWindow.xaml](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml)의 `ComposerShell` 고정폭을 제거하고, [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs)에 `UpdateResponsiveChatLayout()`를 추가해 `MessageScroll.ActualWidth` 기준으로 `MessagePanel`, `EmptyState`, `ComposerShell` 폭을 함께 다시 계산합니다.
- 이 변경으로 창이 줄어들 때 메시지 축과 컴포저가 함께 자연스럽게 줄고, 넓어질 때는 적절한 상한만 유지한 채 부드럽게 넓어집니다. 초기 `Loaded`와 창 `SizeChanged` 둘 다 같은 계산 경로를 타게 연결했습니다.
- 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify\ -p:IntermediateOutputPath=obj\verify\` 경고 0 / 오류 0 - 검증: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify\ -p:IntermediateOutputPath=obj\verify\` 경고 0 / 오류 0
- 업데이트: 2026-04-05 14:09 (KST) - 업데이트: 2026-04-05 14:16 (KST)

View File

@@ -1552,8 +1552,8 @@
<!-- ── 입력 바 ── --> <!-- ── 입력 바 ── -->
<Border x:Name="ComposerShell" Grid.Row="4" <Border x:Name="ComposerShell" Grid.Row="4"
Margin="18,0,18,20" Margin="18,0,18,20"
Width="800" Width="Auto"
MaxWidth="800" MaxWidth="820"
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Bottom"> VerticalAlignment="Bottom">
<StackPanel HorizontalAlignment="Stretch"> <StackPanel HorizontalAlignment="Stretch">

View File

@@ -124,6 +124,8 @@ public partial class ChatWindow : Window
private readonly Dictionary<string, ChatConversation> _pendingConversationPersists = new(StringComparer.OrdinalIgnoreCase); private readonly Dictionary<string, ChatConversation> _pendingConversationPersists = new(StringComparer.OrdinalIgnoreCase);
private readonly HashSet<string> _expandedDraftQueueTabs = new(StringComparer.OrdinalIgnoreCase); private readonly HashSet<string> _expandedDraftQueueTabs = new(StringComparer.OrdinalIgnoreCase);
private AgentEvent? _pendingAgentUiEvent; private AgentEvent? _pendingAgentUiEvent;
private double _lastResponsiveComposerWidth;
private double _lastResponsiveMessageWidth;
private void ApplyQuickActionVisual(Button button, bool active, string activeBg, string activeFg) private void ApplyQuickActionVisual(Button button, bool active, string activeBg, string activeFg)
{ {
if (button?.Content is not string text) if (button?.Content is not string text)
@@ -288,6 +290,7 @@ public partial class ChatWindow : Window
UpdateSidebarModeMenu(); UpdateSidebarModeMenu();
RefreshContextUsageVisual(); RefreshContextUsageVisual();
UpdateTopicPresetScrollMode(); UpdateTopicPresetScrollMode();
UpdateResponsiveChatLayout();
UpdateInputBoxHeight(); UpdateInputBoxHeight();
InputBox.Focus(); InputBox.Focus();
MessageScroll.ScrollChanged += MessageScroll_ScrollChanged; MessageScroll.ScrollChanged += MessageScroll_ScrollChanged;
@@ -299,6 +302,7 @@ public partial class ChatWindow : Window
BuildTopicButtons(); BuildTopicButtons();
RestoreLastConversations(); RestoreLastConversations();
RefreshConversationList(); RefreshConversationList();
UpdateResponsiveChatLayout();
UpdateTaskSummaryIndicators(); UpdateTaskSummaryIndicators();
ScheduleGitBranchRefresh(); ScheduleGitBranchRefresh();
@@ -369,7 +373,12 @@ public partial class ChatWindow : Window
ApplyHoverScaleAnimation(BtnSend, 1.12); ApplyHoverScaleAnimation(BtnSend, 1.12);
ApplyHoverScaleAnimation(BtnStop, 1.12); ApplyHoverScaleAnimation(BtnStop, 1.12);
}; };
SizeChanged += (_, _) => UpdateTopicPresetScrollMode(); SizeChanged += (_, _) =>
{
UpdateTopicPresetScrollMode();
if (UpdateResponsiveChatLayout())
RenderMessages(preserveViewport: true);
};
Closed += (_, _) => Closed += (_, _) =>
{ {
_settings.SettingsChanged -= Settings_SettingsChanged; _settings.SettingsChanged -= Settings_SettingsChanged;
@@ -11045,15 +11054,61 @@ public partial class ChatWindow : Window
/// <summary>채팅 본문 폭을 세 탭에서 동일한 기준으로 맞춥니다.</summary> /// <summary>채팅 본문 폭을 세 탭에서 동일한 기준으로 맞춥니다.</summary>
private double GetMessageMaxWidth() private double GetMessageMaxWidth()
{ {
var hostWidth = ComposerShell?.ActualWidth ?? 0; var hostWidth = _lastResponsiveComposerWidth;
if (hostWidth < 100)
hostWidth = ComposerShell?.ActualWidth ?? 0;
if (hostWidth < 100) if (hostWidth < 100)
hostWidth = MessageScroll?.ActualWidth ?? 0; hostWidth = MessageScroll?.ActualWidth ?? 0;
if (hostWidth < 100) if (hostWidth < 100)
hostWidth = 1120; // 초기화 전 기준 폭 hostWidth = 1120;
// 컴포저와 메시지 버블이 같은 레이아웃 축을 쓰도록 여백만 제외한 폭을 공통 적용
var maxW = hostWidth - 44; var maxW = hostWidth - 44;
return Math.Clamp(maxW, 320, 720); return Math.Clamp(maxW, 320, 760);
}
private bool UpdateResponsiveChatLayout()
{
var viewportWidth = MessageScroll?.ActualWidth ?? 0;
if (viewportWidth < 200)
viewportWidth = ActualWidth;
if (viewportWidth < 200)
return false;
// claw-code처럼 창이 줄어들면 메시지 축과 컴포저가 함께 자연스럽게 줄어들도록,
// 남는 본문 폭을 기준으로 상한만 두고 반응형 폭을 다시 계산합니다.
var contentWidth = Math.Max(360, viewportWidth - 48);
var messageWidth = Math.Clamp(contentWidth * 0.9, 360, 920);
var composerWidth = Math.Clamp(contentWidth * 0.82, 360, 820);
if (contentWidth < 760)
{
messageWidth = Math.Clamp(contentWidth - 8, 340, 820);
composerWidth = Math.Clamp(contentWidth - 28, 332, 760);
}
var changed = false;
if (Math.Abs(_lastResponsiveMessageWidth - messageWidth) > 1)
{
_lastResponsiveMessageWidth = messageWidth;
if (MessagePanel != null)
MessagePanel.MaxWidth = messageWidth;
if (EmptyState != null)
EmptyState.MaxWidth = messageWidth;
changed = true;
}
if (Math.Abs(_lastResponsiveComposerWidth - composerWidth) > 1)
{
_lastResponsiveComposerWidth = composerWidth;
if (ComposerShell != null)
{
ComposerShell.Width = composerWidth;
ComposerShell.MaxWidth = composerWidth;
}
changed = true;
}
return changed;
} }
private StackPanel CreateStreamingContainer(out TextBlock streamText) private StackPanel CreateStreamingContainer(out TextBlock streamText)