AX Agent 사이드바 상호작용 프레젠테이션 분리 및 구조 개선 후속 정리
Some checks failed
Release Gate / gate (push) Has been cancelled
Some checks failed
Release Gate / gate (push) Has been cancelled
- ChatWindow에서 검색/새 대화 사이드바 interaction을 SidebarInteractionPresentation partial로 분리 - 검색 열기/닫기 애니메이션과 hover 상태 변경을 메인 창 orchestration 코드 밖으로 이동 - README와 DEVELOPMENT 문서에 2026-04-06 11:03 (KST) 기준 구조 개선 완료 범위와 남은 후속 작업 수준 반영 - dotnet build 검증 경고 0, 오류 0 확인
This commit is contained in:
@@ -1191,3 +1191,6 @@ MIT License
|
|||||||
- 업데이트: 2026-04-06 10:56 (KST)
|
- 업데이트: 2026-04-06 10:56 (KST)
|
||||||
- 대화 목록 관리 interaction을 [ChatWindow.ConversationManagementPresentation.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.ConversationManagementPresentation.cs) 로 분리했다. 제목 인라인 편집 `EnterTitleEditMode(...)` 와 대화 메뉴 `ShowConversationMenu(...)`가 메인 [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 밖으로 이동해, 고정/이름 변경/카테고리 변경/삭제 같은 목록 관리 UI 책임도 별도 presentation surface에서 다루게 정리했다.
|
- 대화 목록 관리 interaction을 [ChatWindow.ConversationManagementPresentation.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.ConversationManagementPresentation.cs) 로 분리했다. 제목 인라인 편집 `EnterTitleEditMode(...)` 와 대화 메뉴 `ShowConversationMenu(...)`가 메인 [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 밖으로 이동해, 고정/이름 변경/카테고리 변경/삭제 같은 목록 관리 UI 책임도 별도 presentation surface에서 다루게 정리했다.
|
||||||
- 이 단계까지 완료된 구조 개선은 상태선/권한/도구 결과 카탈로그화, inline ask/plan 분리, footer/Git/preset/list/message/timeline 분리, 그리고 conversation management 분리까지다. 이제 남은 건 큰 구조 개선이 아니라 개별 surface polish와 후속 UX 고도화 수준이다.
|
- 이 단계까지 완료된 구조 개선은 상태선/권한/도구 결과 카탈로그화, inline ask/plan 분리, footer/Git/preset/list/message/timeline 분리, 그리고 conversation management 분리까지다. 이제 남은 건 큰 구조 개선이 아니라 개별 surface polish와 후속 UX 고도화 수준이다.
|
||||||
|
- 업데이트: 2026-04-06 11:03 (KST)
|
||||||
|
- 좌측 sidebar의 검색/새 대화 interaction을 [ChatWindow.SidebarInteractionPresentation.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.SidebarInteractionPresentation.cs) 로 분리했다. 검색 트리거 hover, 새 대화 hover, 검색 열기/닫기 애니메이션이 메인 [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 밖으로 이동해, 메인 창은 runtime/transcript orchestration에 더 집중하고 sidebar UX는 별도 presentation surface에서 다루게 정리했다.
|
||||||
|
- 큰 구조 개선 계획 기준으로는 이제 sidebar interaction까지 분리 완료 상태이며, 이후 남는 작업은 공통 시각 언어 polish나 실제 사용 흐름 기반 미세 UX 튜닝 같은 후속 개선 영역이다.
|
||||||
|
|||||||
@@ -4931,3 +4931,5 @@ ow + toggle ?쒓컖 ?몄뼱濡??ㅼ떆 ?뺣젹?덈떎.
|
|||||||
- Document update: 2026-04-06 10:44 (KST) - This consolidates timeline-related helpers in one place and leaves the main chat window file with less transcript-specific rendering logic around `RenderMessages()`.
|
- Document update: 2026-04-06 10:44 (KST) - This consolidates timeline-related helpers in one place and leaves the main chat window file with less transcript-specific rendering logic around `RenderMessages()`.
|
||||||
- Document update: 2026-04-06 10:56 (KST) - Split conversation-management interactions out of `ChatWindow.xaml.cs` into `ChatWindow.ConversationManagementPresentation.cs`. Inline title editing and the conversation action popup (pin/unpin, rename, category change, delete) now live in a dedicated presentation partial.
|
- Document update: 2026-04-06 10:56 (KST) - Split conversation-management interactions out of `ChatWindow.xaml.cs` into `ChatWindow.ConversationManagementPresentation.cs`. Inline title editing and the conversation action popup (pin/unpin, rename, category change, delete) now live in a dedicated presentation partial.
|
||||||
- Document update: 2026-04-06 10:56 (KST) - With this pass, the remaining large structure-improvement track is effectively complete; follow-up work is now mostly UX polish and surface-level tuning rather than further decomposition of the main chat window orchestration file.
|
- Document update: 2026-04-06 10:56 (KST) - With this pass, the remaining large structure-improvement track is effectively complete; follow-up work is now mostly UX polish and surface-level tuning rather than further decomposition of the main chat window orchestration file.
|
||||||
|
- Document update: 2026-04-06 11:03 (KST) - Split sidebar search/new-chat interactions out of `ChatWindow.xaml.cs` into `ChatWindow.SidebarInteractionPresentation.cs`. Hover state changes, sidebar search open/close transitions, and new-chat trigger behavior now live in a dedicated presentation partial.
|
||||||
|
- Document update: 2026-04-06 11:03 (KST) - This leaves the main chat window even more orchestration-focused and effectively closes the last obvious sidebar interaction block from the large structure-improvement plan. Remaining work is now follow-up UX polish rather than major decomposition.
|
||||||
|
|||||||
107
src/AxCopilot/Views/ChatWindow.SidebarInteractionPresentation.cs
Normal file
107
src/AxCopilot/Views/ChatWindow.SidebarInteractionPresentation.cs
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Animation;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
|
||||||
|
namespace AxCopilot.Views;
|
||||||
|
|
||||||
|
public partial class ChatWindow
|
||||||
|
{
|
||||||
|
private void SidebarSearchTrigger_MouseEnter(object sender, MouseEventArgs e)
|
||||||
|
{
|
||||||
|
if (SidebarSearchTrigger != null)
|
||||||
|
SidebarSearchTrigger.Background = TryFindResource("ItemHoverBackground") as Brush ?? Brushes.Transparent;
|
||||||
|
if (SidebarSearchShortcutHint != null)
|
||||||
|
SidebarSearchShortcutHint.Visibility = Visibility.Visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SidebarSearchTrigger_MouseLeave(object sender, MouseEventArgs e)
|
||||||
|
{
|
||||||
|
if (SidebarSearchTrigger != null)
|
||||||
|
SidebarSearchTrigger.Background = Brushes.Transparent;
|
||||||
|
if (SidebarSearchShortcutHint != null)
|
||||||
|
SidebarSearchShortcutHint.Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SidebarSearchTrigger_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
OpenSidebarSearch();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SidebarNewChatTrigger_MouseEnter(object sender, MouseEventArgs e)
|
||||||
|
{
|
||||||
|
if (SidebarNewChatTrigger != null)
|
||||||
|
SidebarNewChatTrigger.Background = TryFindResource("ItemHoverBackground") as Brush ?? Brushes.Transparent;
|
||||||
|
if (SidebarNewChatShortcutHint != null)
|
||||||
|
SidebarNewChatShortcutHint.Visibility = Visibility.Visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SidebarNewChatTrigger_MouseLeave(object sender, MouseEventArgs e)
|
||||||
|
{
|
||||||
|
if (SidebarNewChatTrigger != null)
|
||||||
|
SidebarNewChatTrigger.Background = Brushes.Transparent;
|
||||||
|
if (SidebarNewChatShortcutHint != null)
|
||||||
|
SidebarNewChatShortcutHint.Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SidebarNewChatTrigger_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
BtnNewChat_Click(sender, new RoutedEventArgs());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BtnSidebarSearchClose_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
CloseSidebarSearch(clearText: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OpenSidebarSearch()
|
||||||
|
{
|
||||||
|
if (SidebarSearchEditor == null || SidebarSearchTrigger == null || SidebarSearchEditorScale == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SidebarSearchTrigger.Visibility = Visibility.Collapsed;
|
||||||
|
SidebarSearchEditor.Visibility = Visibility.Visible;
|
||||||
|
SidebarSearchEditor.Opacity = 0;
|
||||||
|
SidebarSearchEditorScale.ScaleX = 0.85;
|
||||||
|
|
||||||
|
var duration = TimeSpan.FromMilliseconds(160);
|
||||||
|
SidebarSearchEditor.BeginAnimation(OpacityProperty, new DoubleAnimation(0, 1, duration));
|
||||||
|
SidebarSearchEditorScale.BeginAnimation(System.Windows.Media.ScaleTransform.ScaleXProperty, new DoubleAnimation(0.85, 1, duration)
|
||||||
|
{
|
||||||
|
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut }
|
||||||
|
});
|
||||||
|
|
||||||
|
Dispatcher.BeginInvoke(new Action(() =>
|
||||||
|
{
|
||||||
|
SearchBox?.Focus();
|
||||||
|
SearchBox?.SelectAll();
|
||||||
|
}), DispatcherPriority.Background);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CloseSidebarSearch(bool clearText)
|
||||||
|
{
|
||||||
|
if (SidebarSearchEditor == null || SidebarSearchTrigger == null || SidebarSearchEditorScale == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (clearText && SearchBox != null && !string.IsNullOrEmpty(SearchBox.Text))
|
||||||
|
SearchBox.Text = "";
|
||||||
|
|
||||||
|
var duration = TimeSpan.FromMilliseconds(140);
|
||||||
|
var opacityAnim = new DoubleAnimation(1, 0, duration);
|
||||||
|
opacityAnim.Completed += (_, _) =>
|
||||||
|
{
|
||||||
|
SidebarSearchEditor.Visibility = Visibility.Collapsed;
|
||||||
|
SidebarSearchTrigger.Visibility = Visibility.Visible;
|
||||||
|
SidebarSearchTrigger.Background = Brushes.Transparent;
|
||||||
|
if (SidebarSearchShortcutHint != null)
|
||||||
|
SidebarSearchShortcutHint.Visibility = Visibility.Collapsed;
|
||||||
|
};
|
||||||
|
SidebarSearchEditor.BeginAnimation(OpacityProperty, opacityAnim);
|
||||||
|
SidebarSearchEditorScale.BeginAnimation(System.Windows.Media.ScaleTransform.ScaleXProperty, new DoubleAnimation(1, 0.85, duration)
|
||||||
|
{
|
||||||
|
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseIn }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2087,102 +2087,6 @@ public partial class ChatWindow : Window
|
|||||||
|
|
||||||
// ─── 검색 ────────────────────────────────────────────────────────────
|
// ─── 검색 ────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
private void SidebarSearchTrigger_MouseEnter(object sender, MouseEventArgs e)
|
|
||||||
{
|
|
||||||
if (SidebarSearchTrigger != null)
|
|
||||||
SidebarSearchTrigger.Background = TryFindResource("ItemHoverBackground") as Brush ?? Brushes.Transparent;
|
|
||||||
if (SidebarSearchShortcutHint != null)
|
|
||||||
SidebarSearchShortcutHint.Visibility = Visibility.Visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SidebarSearchTrigger_MouseLeave(object sender, MouseEventArgs e)
|
|
||||||
{
|
|
||||||
if (SidebarSearchTrigger != null)
|
|
||||||
SidebarSearchTrigger.Background = Brushes.Transparent;
|
|
||||||
if (SidebarSearchShortcutHint != null)
|
|
||||||
SidebarSearchShortcutHint.Visibility = Visibility.Collapsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SidebarSearchTrigger_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
|
||||||
{
|
|
||||||
OpenSidebarSearch();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SidebarNewChatTrigger_MouseEnter(object sender, MouseEventArgs e)
|
|
||||||
{
|
|
||||||
if (SidebarNewChatTrigger != null)
|
|
||||||
SidebarNewChatTrigger.Background = TryFindResource("ItemHoverBackground") as Brush ?? Brushes.Transparent;
|
|
||||||
if (SidebarNewChatShortcutHint != null)
|
|
||||||
SidebarNewChatShortcutHint.Visibility = Visibility.Visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SidebarNewChatTrigger_MouseLeave(object sender, MouseEventArgs e)
|
|
||||||
{
|
|
||||||
if (SidebarNewChatTrigger != null)
|
|
||||||
SidebarNewChatTrigger.Background = Brushes.Transparent;
|
|
||||||
if (SidebarNewChatShortcutHint != null)
|
|
||||||
SidebarNewChatShortcutHint.Visibility = Visibility.Collapsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SidebarNewChatTrigger_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
|
||||||
{
|
|
||||||
BtnNewChat_Click(sender, new RoutedEventArgs());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BtnSidebarSearchClose_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
CloseSidebarSearch(clearText: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OpenSidebarSearch()
|
|
||||||
{
|
|
||||||
if (SidebarSearchEditor == null || SidebarSearchTrigger == null || SidebarSearchEditorScale == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
SidebarSearchTrigger.Visibility = Visibility.Collapsed;
|
|
||||||
SidebarSearchEditor.Visibility = Visibility.Visible;
|
|
||||||
SidebarSearchEditor.Opacity = 0;
|
|
||||||
SidebarSearchEditorScale.ScaleX = 0.85;
|
|
||||||
|
|
||||||
var duration = TimeSpan.FromMilliseconds(160);
|
|
||||||
SidebarSearchEditor.BeginAnimation(OpacityProperty, new DoubleAnimation(0, 1, duration));
|
|
||||||
SidebarSearchEditorScale.BeginAnimation(System.Windows.Media.ScaleTransform.ScaleXProperty, new DoubleAnimation(0.85, 1, duration)
|
|
||||||
{
|
|
||||||
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut }
|
|
||||||
});
|
|
||||||
|
|
||||||
Dispatcher.BeginInvoke(new Action(() =>
|
|
||||||
{
|
|
||||||
SearchBox?.Focus();
|
|
||||||
SearchBox?.SelectAll();
|
|
||||||
}), DispatcherPriority.Background);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CloseSidebarSearch(bool clearText)
|
|
||||||
{
|
|
||||||
if (SidebarSearchEditor == null || SidebarSearchTrigger == null || SidebarSearchEditorScale == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (clearText && SearchBox != null && !string.IsNullOrEmpty(SearchBox.Text))
|
|
||||||
SearchBox.Text = "";
|
|
||||||
|
|
||||||
var duration = TimeSpan.FromMilliseconds(140);
|
|
||||||
var opacityAnim = new DoubleAnimation(1, 0, duration);
|
|
||||||
opacityAnim.Completed += (_, _) =>
|
|
||||||
{
|
|
||||||
SidebarSearchEditor.Visibility = Visibility.Collapsed;
|
|
||||||
SidebarSearchTrigger.Visibility = Visibility.Visible;
|
|
||||||
SidebarSearchTrigger.Background = Brushes.Transparent;
|
|
||||||
if (SidebarSearchShortcutHint != null)
|
|
||||||
SidebarSearchShortcutHint.Visibility = Visibility.Collapsed;
|
|
||||||
};
|
|
||||||
SidebarSearchEditor.BeginAnimation(OpacityProperty, opacityAnim);
|
|
||||||
SidebarSearchEditorScale.BeginAnimation(System.Windows.Media.ScaleTransform.ScaleXProperty, new DoubleAnimation(1, 0.85, duration)
|
|
||||||
{
|
|
||||||
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseIn }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SearchBox_TextChanged(object sender, TextChangedEventArgs e)
|
private void SearchBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||||
{
|
{
|
||||||
_conversationSearchTimer.Stop();
|
_conversationSearchTimer.Stop();
|
||||||
|
|||||||
Reference in New Issue
Block a user