AX Agent UI와 응답 마감 엔진을 claw-code 기준으로 1차 재구성
Some checks failed
Release Gate / gate (push) Has been cancelled
Some checks failed
Release Gate / gate (push) Has been cancelled
사이드바, 메시지 축, 빈 상태, 컴포저를 더 얇고 밀도 높은 구조로 재배치하고 보조 상태 스트립 노출을 줄였습니다. 반응형 폭 계산을 다시 조정해 창 크기 변화에서도 메시지와 컴포저가 같은 중심선으로 자연스럽게 줄어들게 했습니다. 응답 취소와 오류 마감은 AxAgentExecutionEngine의 FinalizeExecutionContent로 공통화해 전송과 재생성의 후처리 경로를 맞췄습니다. 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\ 경고 0 오류 0
This commit is contained in:
@@ -810,6 +810,10 @@ ow + toggle 시각 언어로 통일했습니다.
|
|||||||
- [SettingsWindow.xaml](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/SettingsWindow.xaml), [ChatWindow.xaml](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml) 에서는 메인 설정과 AX Agent 내부 설정의 `계획 모드` 행을 숨겼고, [SettingsViewModel.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/ViewModels/SettingsViewModel.cs), [AppStateService.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/AppStateService.cs) 에서도 항상 `off`만 저장/반영되게 정리했습니다.
|
- [SettingsWindow.xaml](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/SettingsWindow.xaml), [ChatWindow.xaml](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml) 에서는 메인 설정과 AX Agent 내부 설정의 `계획 모드` 행을 숨겼고, [SettingsViewModel.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/ViewModels/SettingsViewModel.cs), [AppStateService.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/AppStateService.cs) 에서도 항상 `off`만 저장/반영되게 정리했습니다.
|
||||||
- 계획 확인 팝업은 [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs), [PlanViewerWindow.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/PlanViewerWindow.cs) 기준으로 AX Agent 창을 owner로 받아 리소스를 그대로 합치게 바꿨고, 채팅 본문에 별도 인라인 승인 버튼을 다시 꽂지 않도록 정리했습니다.
|
- 계획 확인 팝업은 [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs), [PlanViewerWindow.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/PlanViewerWindow.cs) 기준으로 AX Agent 창을 owner로 받아 리소스를 그대로 합치게 바꿨고, 채팅 본문에 별도 인라인 승인 버튼을 다시 꽂지 않도록 정리했습니다.
|
||||||
- 업데이트: 2026-04-05 16:20 (KST)
|
- 업데이트: 2026-04-05 16:20 (KST)
|
||||||
|
- `claw-code` 기준 UI/엔진 재구성 1차도 반영했습니다. [ChatWindow.xaml](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml) 에서 AX Agent 메인 레이아웃의 사이드바 폭, 메시지 축, 빈 상태 카드, 컴포저 외곽선을 더 압축해 메시지 중심 구조로 다시 정리했고, 상단/보조 스트립과 토큰 카드 노출도 더 보수적으로 줄였습니다.
|
||||||
|
- [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 에서는 반응형 폭 계산을 다시 조정해 창이 좁아질 때 메시지 축과 컴포저가 같은 중심선을 따라 자연스럽게 줄어들게 했고, Chat 탭에서는 보조 상태 스트립을 거의 숨기고 Cowork/Code도 실패/승인 대기 같은 핵심 상태만 남기도록 정리했습니다.
|
||||||
|
- 엔진 쪽은 [AxAgentExecutionEngine.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs) 에 `FinalizeExecutionContent(...)` 를 추가해 취소/오류/빈 응답 정규화를 UI 바깥으로 넘겼고, 전송/재생성 마감 흐름이 같은 helper를 타도록 맞췄습니다. 내부 설정 오버레이 연결은 유지했습니다.
|
||||||
|
- 업데이트: 2026-04-05 16:33 (KST)
|
||||||
- 검증: `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 15:16 (KST)
|
- 업데이트: 2026-04-05 15:16 (KST)
|
||||||
|
|
||||||
|
|||||||
@@ -4575,3 +4575,9 @@ ow + toggle ?쒓컖 ?몄뼱濡??ㅼ떆 ?뺣젹?덈떎.
|
|||||||
- [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 의 `CreatePlanDecisionCallback()`은 더 이상 채팅 본문에 인라인 승인 버튼을 추가하지 않고, [PlanViewerWindow.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/PlanViewerWindow.cs) 를 AX Agent 창 owner와 merged resources 기준으로 생성해 플랜 팝업이 AX Agent 테마와 같은 리소스 축을 따르도록 바꿨습니다.
|
- [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs) 의 `CreatePlanDecisionCallback()`은 더 이상 채팅 본문에 인라인 승인 버튼을 추가하지 않고, [PlanViewerWindow.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/PlanViewerWindow.cs) 를 AX Agent 창 owner와 merged resources 기준으로 생성해 플랜 팝업이 AX Agent 테마와 같은 리소스 축을 따르도록 바꿨습니다.
|
||||||
- 검증 예정: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify\ -p:IntermediateOutputPath=obj\verify\`
|
- 검증 예정: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify\ -p:IntermediateOutputPath=obj\verify\`
|
||||||
- 업데이트: 2026-04-05 16:20 (KST)
|
- 업데이트: 2026-04-05 16:20 (KST)
|
||||||
|
- `claw-code` 기준 UI/엔진 재구성 1차도 진행했습니다. [ChatWindow.xaml](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml) 에서 AX Agent 메인 레이아웃의 사이드바 폭을 줄이고, 메시지/빈 상태/컴포저의 기본 폭과 패딩, 라운드, 그림자 강도를 다시 조정해 메시지 중심 구조로 압축했습니다.
|
||||||
|
- 보조 상태 UI도 더 얇게 만들었습니다. [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs)의 대화 상태 스트립은 Chat 탭에서 숨기고 Cowork/Code도 실패/승인 대기/차단 같은 핵심 상태만 보여 주도록 줄였으며, 빠른 스트립도 Chat에서는 열리지 않게 정리했습니다.
|
||||||
|
- 반응형 폭 계산은 같은 파일의 `UpdateResponsiveChatLayout()`에서 다시 조정해 메시지 축 상한을 `840`, 컴포저 축 상한을 `760` 기준으로 맞췄고, 좁은 창에서는 둘이 같은 중심선으로 함께 줄어들도록 재계산하게 했습니다.
|
||||||
|
- 엔진 쪽은 [AxAgentExecutionEngine.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Services/Agent/AxAgentExecutionEngine.cs)에 `FinalizeExecutionContent(...)` 를 추가해 취소/오류/빈 응답 정규화를 공통 helper로 모았습니다. [ChatWindow.xaml.cs](/E:/AX%20Copilot%20-%20Codex/src/AxCopilot/Views/ChatWindow.xaml.cs)의 일반 전송과 재생성은 이제 같은 helper를 써서 응답 마감을 처리합니다.
|
||||||
|
- 검증 예정: `dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify\ -p:IntermediateOutputPath=obj\verify\`
|
||||||
|
- 업데이트: 2026-04-05 16:33 (KST)
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ public sealed class AxAgentExecutionEngine
|
|||||||
ExecutionMode Mode,
|
ExecutionMode Mode,
|
||||||
IReadOnlyList<string> PromptStack,
|
IReadOnlyList<string> PromptStack,
|
||||||
List<ChatMessage> Messages);
|
List<ChatMessage> Messages);
|
||||||
|
public sealed record FinalizedContent(string Content, bool Cancelled, string? FailureReason);
|
||||||
public sealed record SessionMutationResult(
|
public sealed record SessionMutationResult(
|
||||||
ChatConversation CurrentConversation,
|
ChatConversation CurrentConversation,
|
||||||
ChatConversation UpdatedConversation);
|
ChatConversation UpdatedConversation);
|
||||||
@@ -162,6 +163,22 @@ public sealed class AxAgentExecutionEngine
|
|||||||
return normalized;
|
return normalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FinalizedContent FinalizeExecutionContent(string? currentContent, Exception? error = null, bool cancelled = false)
|
||||||
|
{
|
||||||
|
if (cancelled)
|
||||||
|
{
|
||||||
|
var content = string.IsNullOrWhiteSpace(currentContent) ? "(취소됨)" : currentContent!;
|
||||||
|
return new FinalizedContent(content, true, "사용자가 작업을 중단했습니다.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error != null)
|
||||||
|
{
|
||||||
|
return new FinalizedContent($"⚠ 오류: {error.Message}", false, error.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new FinalizedContent(currentContent ?? string.Empty, false, null);
|
||||||
|
}
|
||||||
|
|
||||||
public SessionMutationResult AppendExecutionEvent(
|
public SessionMutationResult AppendExecutionEvent(
|
||||||
ChatSessionStateService session,
|
ChatSessionStateService session,
|
||||||
ChatStorageService storage,
|
ChatStorageService storage,
|
||||||
|
|||||||
@@ -406,7 +406,7 @@
|
|||||||
<!-- 축소 아이콘 바 (사이드바 닫힘 시 표시) -->
|
<!-- 축소 아이콘 바 (사이드바 닫힘 시 표시) -->
|
||||||
<ColumnDefinition x:Name="IconBarColumn" Width="0"/>
|
<ColumnDefinition x:Name="IconBarColumn" Width="0"/>
|
||||||
<!-- 사이드바 (열림 시 표시) -->
|
<!-- 사이드바 (열림 시 표시) -->
|
||||||
<ColumnDefinition x:Name="SidebarColumn" Width="256" MinWidth="0"/>
|
<ColumnDefinition x:Name="SidebarColumn" Width="220" MinWidth="0"/>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
<!-- 미리보기 스플리터 -->
|
<!-- 미리보기 스플리터 -->
|
||||||
<ColumnDefinition x:Name="SplitterColumn" Width="0"/>
|
<ColumnDefinition x:Name="SplitterColumn" Width="0"/>
|
||||||
@@ -477,7 +477,7 @@
|
|||||||
BorderThickness="0,0,1,0">
|
BorderThickness="0,0,1,0">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="52"/>
|
<RowDefinition Height="48"/>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
@@ -487,18 +487,18 @@
|
|||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<!-- 헤더 -->
|
<!-- 헤더 -->
|
||||||
<Grid Grid.Row="0" Margin="14,0">
|
<Grid Grid.Row="0" Margin="12,0">
|
||||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||||
<Border Background="{DynamicResource HintBackground}" CornerRadius="7"
|
<Border Background="{DynamicResource HintBackground}" CornerRadius="6"
|
||||||
BorderBrush="{DynamicResource BorderColor}"
|
BorderBrush="{DynamicResource BorderColor}"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
Width="24" Height="24">
|
Width="22" Height="22">
|
||||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="12"
|
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="11"
|
||||||
Foreground="{DynamicResource AccentColor}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
Foreground="{DynamicResource AccentColor}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||||
</Border>
|
</Border>
|
||||||
<TextBlock Text="AX Agent" FontSize="13.5" FontWeight="SemiBold"
|
<TextBlock Text="AX Agent" FontSize="13" FontWeight="SemiBold"
|
||||||
Foreground="{DynamicResource PrimaryText}"
|
Foreground="{DynamicResource PrimaryText}"
|
||||||
VerticalAlignment="Center" Margin="9,0,0,0"/>
|
VerticalAlignment="Center" Margin="8,0,0,0"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
@@ -507,8 +507,8 @@
|
|||||||
<StackPanel>
|
<StackPanel>
|
||||||
<Border x:Name="SidebarNewChatTrigger"
|
<Border x:Name="SidebarNewChatTrigger"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
CornerRadius="8"
|
CornerRadius="7"
|
||||||
Padding="9,7"
|
Padding="8,6"
|
||||||
Cursor="Hand"
|
Cursor="Hand"
|
||||||
MouseEnter="SidebarNewChatTrigger_MouseEnter"
|
MouseEnter="SidebarNewChatTrigger_MouseEnter"
|
||||||
MouseLeave="SidebarNewChatTrigger_MouseLeave"
|
MouseLeave="SidebarNewChatTrigger_MouseLeave"
|
||||||
@@ -523,7 +523,7 @@
|
|||||||
Foreground="{DynamicResource SecondaryText}" VerticalAlignment="Center"/>
|
Foreground="{DynamicResource SecondaryText}" VerticalAlignment="Center"/>
|
||||||
<TextBlock Grid.Column="1" Text="새 대화"
|
<TextBlock Grid.Column="1" Text="새 대화"
|
||||||
Foreground="{DynamicResource PrimaryText}"
|
Foreground="{DynamicResource PrimaryText}"
|
||||||
FontSize="11" Margin="7,0,0,0" VerticalAlignment="Center"/>
|
FontSize="10.8" Margin="7,0,0,0" VerticalAlignment="Center"/>
|
||||||
<TextBlock x:Name="SidebarNewChatShortcutHint"
|
<TextBlock x:Name="SidebarNewChatShortcutHint"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Text="Ctrl+N"
|
Text="Ctrl+N"
|
||||||
@@ -536,8 +536,8 @@
|
|||||||
|
|
||||||
<Border x:Name="SidebarSearchTrigger"
|
<Border x:Name="SidebarSearchTrigger"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
CornerRadius="8"
|
CornerRadius="7"
|
||||||
Padding="9,7"
|
Padding="8,6"
|
||||||
Cursor="Hand"
|
Cursor="Hand"
|
||||||
MouseEnter="SidebarSearchTrigger_MouseEnter"
|
MouseEnter="SidebarSearchTrigger_MouseEnter"
|
||||||
MouseLeave="SidebarSearchTrigger_MouseLeave"
|
MouseLeave="SidebarSearchTrigger_MouseLeave"
|
||||||
@@ -552,7 +552,7 @@
|
|||||||
Foreground="{DynamicResource SecondaryText}" VerticalAlignment="Center"/>
|
Foreground="{DynamicResource SecondaryText}" VerticalAlignment="Center"/>
|
||||||
<TextBlock Grid.Column="1" Text="검색"
|
<TextBlock Grid.Column="1" Text="검색"
|
||||||
Foreground="{DynamicResource PrimaryText}"
|
Foreground="{DynamicResource PrimaryText}"
|
||||||
FontSize="11" Margin="7,0,0,0" VerticalAlignment="Center"/>
|
FontSize="10.8" Margin="7,0,0,0" VerticalAlignment="Center"/>
|
||||||
<TextBlock x:Name="SidebarSearchShortcutHint"
|
<TextBlock x:Name="SidebarSearchShortcutHint"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Text="Ctrl+K"
|
Text="Ctrl+K"
|
||||||
@@ -921,7 +921,7 @@
|
|||||||
<Border x:Name="AgentProgressBar" Grid.Row="2" Visibility="Collapsed"
|
<Border x:Name="AgentProgressBar" Grid.Row="2" Visibility="Collapsed"
|
||||||
Background="{DynamicResource HintBackground}"
|
Background="{DynamicResource HintBackground}"
|
||||||
BorderBrush="{DynamicResource SeparatorColor}" BorderThickness="0,0,0,1"
|
BorderBrush="{DynamicResource SeparatorColor}" BorderThickness="0,0,0,1"
|
||||||
Padding="12,3,12,3">
|
Padding="10,2,10,2">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
@@ -1181,10 +1181,10 @@
|
|||||||
VerticalScrollBarVisibility="Auto"
|
VerticalScrollBarVisibility="Auto"
|
||||||
HorizontalScrollBarVisibility="Disabled"
|
HorizontalScrollBarVisibility="Disabled"
|
||||||
Background="{DynamicResource LauncherBackground}"
|
Background="{DynamicResource LauncherBackground}"
|
||||||
Padding="24,14,24,8">
|
Padding="18,10,18,6">
|
||||||
<StackPanel x:Name="MessagePanel"
|
<StackPanel x:Name="MessagePanel"
|
||||||
Margin="0,0,0,20"
|
Margin="0,0,0,14"
|
||||||
MaxWidth="880"
|
MaxWidth="840"
|
||||||
HorizontalAlignment="Center">
|
HorizontalAlignment="Center">
|
||||||
<StackPanel.RenderTransform>
|
<StackPanel.RenderTransform>
|
||||||
<TranslateTransform/>
|
<TranslateTransform/>
|
||||||
@@ -1196,8 +1196,8 @@
|
|||||||
<Grid x:Name="EmptyState" Grid.Row="3"
|
<Grid x:Name="EmptyState" Grid.Row="3"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
MaxWidth="880"
|
MaxWidth="840"
|
||||||
Margin="24,8,24,8">
|
Margin="18,8,18,8">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="16"/>
|
<RowDefinition Height="16"/>
|
||||||
@@ -1208,24 +1208,24 @@
|
|||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
Margin="0,10,0,2">
|
Margin="0,10,0,2">
|
||||||
<Border x:Name="EmptyIcon" CornerRadius="18" Width="54" Height="54"
|
<Border x:Name="EmptyIcon" CornerRadius="14" Width="44" Height="44"
|
||||||
HorizontalAlignment="Center" Margin="0,0,0,14"
|
HorizontalAlignment="Center" Margin="0,0,0,12"
|
||||||
Background="{DynamicResource ItemBackground}"
|
Background="{DynamicResource ItemBackground}"
|
||||||
BorderBrush="{DynamicResource BorderColor}"
|
BorderBrush="{DynamicResource BorderColor}"
|
||||||
BorderThickness="1">
|
BorderThickness="1">
|
||||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="30"
|
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="22"
|
||||||
Foreground="{DynamicResource AccentColor}"
|
Foreground="{DynamicResource AccentColor}"
|
||||||
HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<TextBlock x:Name="EmptyStateTitle" Text="작업을 시작하세요" FontSize="20" FontWeight="SemiBold"
|
<TextBlock x:Name="EmptyStateTitle" Text="작업을 시작하세요" FontSize="18" FontWeight="SemiBold"
|
||||||
Foreground="{DynamicResource PrimaryText}" HorizontalAlignment="Center"/>
|
Foreground="{DynamicResource PrimaryText}" HorizontalAlignment="Center"/>
|
||||||
<TextBlock x:Name="EmptyStateDesc" Text="프롬프트를 입력하거나 아래 작업 유형을 선택하면 됩니다"
|
<TextBlock x:Name="EmptyStateDesc" Text="프롬프트를 입력하거나 아래 작업 유형을 선택하면 됩니다"
|
||||||
FontSize="12" Foreground="{DynamicResource SecondaryText}"
|
FontSize="11.5" Foreground="{DynamicResource SecondaryText}"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
TextAlignment="Center"
|
TextAlignment="Center"
|
||||||
Width="340"
|
Width="320"
|
||||||
Margin="0,8,0,0"/>
|
Margin="0,6,0,0"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<ScrollViewer x:Name="TopicPresetScrollViewer"
|
<ScrollViewer x:Name="TopicPresetScrollViewer"
|
||||||
@@ -1560,9 +1560,9 @@
|
|||||||
|
|
||||||
<!-- ── 입력 바 ── -->
|
<!-- ── 입력 바 ── -->
|
||||||
<Border x:Name="ComposerShell" Grid.Row="4"
|
<Border x:Name="ComposerShell" Grid.Row="4"
|
||||||
Margin="18,0,18,20"
|
Margin="18,0,18,16"
|
||||||
Width="Auto"
|
Width="Auto"
|
||||||
MaxWidth="820"
|
MaxWidth="760"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Bottom">
|
VerticalAlignment="Bottom">
|
||||||
<StackPanel HorizontalAlignment="Stretch">
|
<StackPanel HorizontalAlignment="Stretch">
|
||||||
@@ -1571,9 +1571,9 @@
|
|||||||
Background="{DynamicResource LauncherBackground}"
|
Background="{DynamicResource LauncherBackground}"
|
||||||
BorderBrush="{DynamicResource BorderColor}"
|
BorderBrush="{DynamicResource BorderColor}"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
CornerRadius="14"
|
CornerRadius="12"
|
||||||
Padding="10,8,10,8"
|
Padding="9,7,9,7"
|
||||||
Margin="0,0,0,6">
|
Margin="0,0,0,5">
|
||||||
<Border.Effect>
|
<Border.Effect>
|
||||||
<DropShadowEffect BlurRadius="10" ShadowDepth="0" Opacity="0.05"/>
|
<DropShadowEffect BlurRadius="10" ShadowDepth="0" Opacity="0.05"/>
|
||||||
</Border.Effect>
|
</Border.Effect>
|
||||||
@@ -1628,7 +1628,7 @@
|
|||||||
<StackPanel x:Name="DraftQueuePanel"
|
<StackPanel x:Name="DraftQueuePanel"
|
||||||
Visibility="Collapsed"
|
Visibility="Collapsed"
|
||||||
Margin="0,0,0,8"/>
|
Margin="0,0,0,8"/>
|
||||||
<Border x:Name="InputGlowBorder" CornerRadius="16" Opacity="0"
|
<Border x:Name="InputGlowBorder" CornerRadius="14" Opacity="0"
|
||||||
Margin="-3" IsHitTestVisible="False">
|
Margin="-3" IsHitTestVisible="False">
|
||||||
<Border.BorderBrush>
|
<Border.BorderBrush>
|
||||||
<LinearGradientBrush x:Name="RainbowBrush" StartPoint="0,0" EndPoint="1,1">
|
<LinearGradientBrush x:Name="RainbowBrush" StartPoint="0,0" EndPoint="1,1">
|
||||||
@@ -1651,10 +1651,10 @@
|
|||||||
<!-- 실제 입력 영역 -->
|
<!-- 실제 입력 영역 -->
|
||||||
<Border x:Name="InputBorder"
|
<Border x:Name="InputBorder"
|
||||||
Background="{DynamicResource LauncherBackground}"
|
Background="{DynamicResource LauncherBackground}"
|
||||||
CornerRadius="12" Padding="6"
|
CornerRadius="10" Padding="5"
|
||||||
BorderBrush="{DynamicResource BorderColor}" BorderThickness="1">
|
BorderBrush="{DynamicResource BorderColor}" BorderThickness="1">
|
||||||
<Border.Effect>
|
<Border.Effect>
|
||||||
<DropShadowEffect BlurRadius="14" ShadowDepth="0" Opacity="0.06"/>
|
<DropShadowEffect BlurRadius="10" ShadowDepth="0" Opacity="0.04"/>
|
||||||
</Border.Effect>
|
</Border.Effect>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
@@ -1665,12 +1665,11 @@
|
|||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<!-- Row 0: 모델 셀렉터 + 템플릿 버튼 -->
|
<!-- Row 0: 모델 셀렉터 + 템플릿 버튼 -->
|
||||||
<Grid Grid.Row="0" Margin="2,0,2,2">
|
<Grid Grid.Row="0" Margin="1,0,1,2">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
<ColumnDefinition Width="*"/>
|
<ColumnDefinition Width="*"/>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
<ColumnDefinition Width="Auto"/>
|
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Button x:Name="BtnModelSelector"
|
<Button x:Name="BtnModelSelector"
|
||||||
Style="{StaticResource OutlineHoverBtn}"
|
Style="{StaticResource OutlineHoverBtn}"
|
||||||
@@ -1688,7 +1687,7 @@
|
|||||||
VerticalAlignment="Center" Margin="0,0,4,0"/>
|
VerticalAlignment="Center" Margin="0,0,4,0"/>
|
||||||
<TextBlock x:Name="ModelLabel" FontSize="11.5"
|
<TextBlock x:Name="ModelLabel" FontSize="11.5"
|
||||||
Foreground="{DynamicResource SecondaryText}"
|
Foreground="{DynamicResource SecondaryText}"
|
||||||
MaxWidth="360"
|
MaxWidth="300"
|
||||||
TextTrimming="CharacterEllipsis"
|
TextTrimming="CharacterEllipsis"
|
||||||
VerticalAlignment="Center"/>
|
VerticalAlignment="Center"/>
|
||||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="8"
|
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="8"
|
||||||
@@ -1698,13 +1697,14 @@
|
|||||||
</Button>
|
</Button>
|
||||||
<Border x:Name="TokenUsageCard"
|
<Border x:Name="TokenUsageCard"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Margin="5,0,5,0"
|
Margin="4,0,0,0"
|
||||||
Padding="5,2"
|
Padding="4,2"
|
||||||
CornerRadius="7"
|
CornerRadius="7"
|
||||||
BorderBrush="{DynamicResource BorderColor}"
|
BorderBrush="{DynamicResource BorderColor}"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
Background="{DynamicResource ItemBackground}"
|
Background="{DynamicResource ItemBackground}"
|
||||||
VerticalAlignment="Center">
|
VerticalAlignment="Center"
|
||||||
|
Visibility="Collapsed">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
@@ -1772,7 +1772,7 @@
|
|||||||
</Border>
|
</Border>
|
||||||
<Button x:Name="BtnTemplateSelector"
|
<Button x:Name="BtnTemplateSelector"
|
||||||
Style="{StaticResource OutlineHoverBtn}"
|
Style="{StaticResource OutlineHoverBtn}"
|
||||||
Grid.Column="3"
|
Grid.Column="2"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Margin="0"
|
Margin="0"
|
||||||
MinHeight="24"
|
MinHeight="24"
|
||||||
|
|||||||
@@ -8460,16 +8460,17 @@ public partial class ChatWindow : Window
|
|||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
assistantContent = string.IsNullOrWhiteSpace(assistantContent) ? "(취소됨)" : assistantContent;
|
var finalized = _chatEngine.FinalizeExecutionContent(assistantContent, cancelled: true);
|
||||||
draftCancelled = true;
|
assistantContent = finalized.Content;
|
||||||
draftFailure = "사용자가 작업을 중단했습니다.";
|
draftCancelled = finalized.Cancelled;
|
||||||
|
draftFailure = finalized.FailureReason;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
var errMsg = $"⚠ 오류: {ex.Message}";
|
var finalized = _chatEngine.FinalizeExecutionContent(assistantContent, ex);
|
||||||
assistantContent = errMsg;
|
assistantContent = finalized.Content;
|
||||||
ShowToast("실패한 요청은 작업 요약에서 다시 시도할 수 있습니다.", "\uE783", 2600);
|
ShowToast("실패한 요청은 작업 요약에서 다시 시도할 수 있습니다.", "\uE783", 2600);
|
||||||
draftFailure = ex.Message;
|
draftFailure = finalized.FailureReason;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -8735,20 +8736,18 @@ public partial class ChatWindow : Window
|
|||||||
sb.AppendLine("You are AX Copilot Agent. You can read, write, and edit files using the provided tools.");
|
sb.AppendLine("You are AX Copilot Agent. You can read, write, and edit files using the provided tools.");
|
||||||
sb.AppendLine($"Today's date: {DateTime.Now:yyyy년 M월 d일} ({DateTime.Now:yyyy-MM-dd}, {DateTime.Now:dddd}).");
|
sb.AppendLine($"Today's date: {DateTime.Now:yyyy년 M월 d일} ({DateTime.Now:yyyy-MM-dd}, {DateTime.Now:dddd}).");
|
||||||
sb.AppendLine("Available skills: excel_create (.xlsx), docx_create (.docx), csv_create (.csv), markdown_create (.md), html_create (.html), script_create (.bat/.ps1), document_review (품질 검증), format_convert (포맷 변환).");
|
sb.AppendLine("Available skills: excel_create (.xlsx), docx_create (.docx), csv_create (.csv), markdown_create (.md), html_create (.html), script_create (.bat/.ps1), document_review (품질 검증), format_convert (포맷 변환).");
|
||||||
sb.AppendLine("Only present a step-by-step execution plan when the user explicitly asks for a plan or when the session is already in plan mode.");
|
sb.AppendLine("Only present a step-by-step plan when the user explicitly asks for a plan or when the task is too ambiguous to execute safely.");
|
||||||
sb.AppendLine("For ordinary Cowork requests, proceed directly with the work instead of stopping for plan approval.");
|
sb.AppendLine("For ordinary Cowork requests, proceed directly with the work and focus on producing the real artifact.");
|
||||||
sb.AppendLine("After creating files, summarize what was created and include the actual output path.");
|
sb.AppendLine("After creating files, summarize what was created and include the actual output path.");
|
||||||
sb.AppendLine("Do not stop after a single step. Continue autonomously until the request is completed or a concrete blocker (permission denial, missing dependency, hard error) is encountered.");
|
sb.AppendLine("Do not stop after a single step. Continue autonomously until the request is completed or a concrete blocker (permission denial, missing dependency, hard error) is encountered.");
|
||||||
sb.AppendLine("When adapting external references, rewrite names/structure/comments to AX Copilot style. Avoid clone-like outputs.");
|
sb.AppendLine("When adapting external references, rewrite names/structure/comments to AX Copilot style. Avoid clone-like outputs.");
|
||||||
sb.AppendLine("IMPORTANT: When creating documents with dates, always use today's actual date above. Never use placeholder or fictional dates.");
|
sb.AppendLine("IMPORTANT: When creating documents with dates, always use today's actual date above. Never use placeholder or fictional dates.");
|
||||||
sb.AppendLine("IMPORTANT: When asked to create a document with multiple sections (reports, proposals, analyses, etc.), you MUST:");
|
sb.AppendLine("IMPORTANT: For reports, proposals, analyses, and manuals with multiple sections:");
|
||||||
sb.AppendLine(" 1. First, plan the document: decide the exact sections (headings), their order, and key points for each section based on the topic.");
|
sb.AppendLine(" 1. Decide the document structure internally first.");
|
||||||
sb.AppendLine(" 2. Call document_plan with sections_hint = your planned section titles (comma-separated). Example: sections_hint=\"회사 개요, 사업 현황, 재무 분석, SWOT, 전략 제언, 결론\"");
|
sb.AppendLine(" 2. Use document_plan only when it improves the actual output, not as a mandatory user-facing approval step.");
|
||||||
sb.AppendLine(" This ensures the document structure matches YOUR plan, not a generic template.");
|
sb.AppendLine(" 3. Then immediately create the real output file with html_create, docx_create, markdown_create, or file_write.");
|
||||||
sb.AppendLine(" 3. Then immediately call html_create (or docx_create/file_write) using the scaffold from document_plan.");
|
sb.AppendLine(" 4. Fill every section with real content. Do not stop at an outline or plan only.");
|
||||||
sb.AppendLine(" 4. Write actual detailed content for EVERY section — no skipping, no placeholders, no minimal content.");
|
sb.AppendLine(" 5. The task is complete only after the actual document file has been created or updated.");
|
||||||
sb.AppendLine(" 5. Do NOT call html_create directly without document_plan for multi-section documents.");
|
|
||||||
sb.AppendLine(" 6. Do not finish with a plan only. The task is complete only after the document file has actually been created or updated.");
|
|
||||||
|
|
||||||
// 문서 품질 검증 루프
|
// 문서 품질 검증 루프
|
||||||
sb.AppendLine("\n## Document Quality Review");
|
sb.AppendLine("\n## Document Quality Review");
|
||||||
@@ -8854,10 +8853,10 @@ public partial class ChatWindow : Window
|
|||||||
sb.AppendLine("3. ANALYZE: Use grep (with context_lines=2) + file_read to deeply understand the code you'll modify.");
|
sb.AppendLine("3. ANALYZE: Use grep (with context_lines=2) + file_read to deeply understand the code you'll modify.");
|
||||||
sb.AppendLine(" - Always check callers/references: grep for function/class names to find all usage points.");
|
sb.AppendLine(" - Always check callers/references: grep for function/class names to find all usage points.");
|
||||||
sb.AppendLine(" - Read test files related to the code you're changing to understand expected behavior.");
|
sb.AppendLine(" - Read test files related to the code you're changing to understand expected behavior.");
|
||||||
sb.AppendLine("4. PLAN: Present your analysis + impact assessment. List ALL files that will be modified.");
|
sb.AppendLine("4. PLAN: Build an internal execution outline and impact assessment before editing.");
|
||||||
|
sb.AppendLine(" - Present the outline explicitly only when the user asks for a plan or the change is clearly high risk.");
|
||||||
sb.AppendLine(" - Explain WHY each change is needed and what could break.");
|
sb.AppendLine(" - Explain WHY each change is needed and what could break.");
|
||||||
sb.AppendLine(" - If you touch shared services, interfaces, models, controllers, view-models, app startup, or dependency registration, treat it as a high-impact change.");
|
sb.AppendLine(" - If you touch shared services, interfaces, models, controllers, view-models, app startup, or dependency registration, treat it as a high-impact change and call out the impact clearly.");
|
||||||
sb.AppendLine(" - Wait for user approval before proceeding.");
|
|
||||||
sb.AppendLine("5. IMPLEMENT: Apply changes using file_edit (preferred — shows diff). Use file_write only for new files.");
|
sb.AppendLine("5. IMPLEMENT: Apply changes using file_edit (preferred — shows diff). Use file_write only for new files.");
|
||||||
sb.AppendLine(" - Make the MINIMUM changes needed. Don't refactor unrelated code.");
|
sb.AppendLine(" - Make the MINIMUM changes needed. Don't refactor unrelated code.");
|
||||||
sb.AppendLine(" - Prefer file_edit with replace_all=false for precision edits.");
|
sb.AppendLine(" - Prefer file_edit with replace_all=false for precision edits.");
|
||||||
@@ -9258,7 +9257,18 @@ public partial class ChatWindow : Window
|
|||||||
|
|
||||||
if (ConversationStatusStrip != null && ConversationStatusStripLabel != null)
|
if (ConversationStatusStrip != null && ConversationStatusStripLabel != null)
|
||||||
{
|
{
|
||||||
if (string.Equals(status.StripKind, "permission_waiting", StringComparison.OrdinalIgnoreCase))
|
var showCompactStrip = !string.Equals(_activeTab, "Chat", StringComparison.OrdinalIgnoreCase)
|
||||||
|
&& (string.Equals(status.StripKind, "permission_waiting", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| string.Equals(status.StripKind, "failed_run", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| string.Equals(status.StripKind, "permission_denied", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| string.Equals(status.StripKind, "queue_blocked", StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
if (!showCompactStrip)
|
||||||
|
{
|
||||||
|
ConversationStatusStrip.Visibility = Visibility.Collapsed;
|
||||||
|
ConversationStatusStripLabel.Text = "";
|
||||||
|
}
|
||||||
|
else if (string.Equals(status.StripKind, "permission_waiting", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
ConversationStatusStrip.Visibility = Visibility.Visible;
|
ConversationStatusStrip.Visibility = Visibility.Visible;
|
||||||
ConversationStatusStrip.Background = BrushFromHex("#FFF7ED");
|
ConversationStatusStrip.Background = BrushFromHex("#FFF7ED");
|
||||||
@@ -9266,14 +9276,6 @@ public partial class ChatWindow : Window
|
|||||||
ConversationStatusStripLabel.Foreground = BrushFromHex("#C2410C");
|
ConversationStatusStripLabel.Foreground = BrushFromHex("#C2410C");
|
||||||
ConversationStatusStripLabel.Text = status.StripText;
|
ConversationStatusStripLabel.Text = status.StripText;
|
||||||
}
|
}
|
||||||
else if (string.Equals(status.StripKind, "running", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
ConversationStatusStrip.Visibility = Visibility.Visible;
|
|
||||||
ConversationStatusStrip.Background = BrushFromHex("#DBEAFE");
|
|
||||||
ConversationStatusStrip.BorderBrush = BrushFromHex("#93C5FD");
|
|
||||||
ConversationStatusStripLabel.Foreground = BrushFromHex("#1D4ED8");
|
|
||||||
ConversationStatusStripLabel.Text = status.StripText;
|
|
||||||
}
|
|
||||||
else if (string.Equals(status.StripKind, "failed_run", StringComparison.OrdinalIgnoreCase)
|
else if (string.Equals(status.StripKind, "failed_run", StringComparison.OrdinalIgnoreCase)
|
||||||
|| string.Equals(status.StripKind, "permission_denied", StringComparison.OrdinalIgnoreCase))
|
|| string.Equals(status.StripKind, "permission_denied", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
@@ -9299,14 +9301,6 @@ public partial class ChatWindow : Window
|
|||||||
ConversationStatusStripLabel.Foreground = BrushFromHex("#B45309");
|
ConversationStatusStripLabel.Foreground = BrushFromHex("#B45309");
|
||||||
ConversationStatusStripLabel.Text = status.StripText;
|
ConversationStatusStripLabel.Text = status.StripText;
|
||||||
}
|
}
|
||||||
else if (string.Equals(status.StripKind, "background", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
ConversationStatusStrip.Visibility = Visibility.Visible;
|
|
||||||
ConversationStatusStrip.Background = BrushFromHex("#EFF6FF");
|
|
||||||
ConversationStatusStrip.BorderBrush = BrushFromHex("#BFDBFE");
|
|
||||||
ConversationStatusStripLabel.Foreground = BrushFromHex("#1D4ED8");
|
|
||||||
ConversationStatusStripLabel.Text = status.StripText;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ConversationStatusStrip.Visibility = Visibility.Collapsed;
|
ConversationStatusStrip.Visibility = Visibility.Collapsed;
|
||||||
@@ -9323,8 +9317,10 @@ public partial class ChatWindow : Window
|
|||||||
|| BtnQuickRunningFilter == null || BtnQuickHotSort == null)
|
|| BtnQuickRunningFilter == null || BtnQuickHotSort == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var hasQuickSignal = _runningConversationCount > 0
|
var allowQuickStrip = !string.Equals(_activeTab, "Chat", StringComparison.OrdinalIgnoreCase);
|
||||||
|| _spotlightConversationCount > 0;
|
var hasQuickSignal = allowQuickStrip
|
||||||
|
&& (_runningConversationCount > 0
|
||||||
|
|| _spotlightConversationCount > 0);
|
||||||
|
|
||||||
ConversationQuickStrip.Visibility = hasQuickSignal
|
ConversationQuickStrip.Visibility = hasQuickSignal
|
||||||
? Visibility.Visible
|
? Visibility.Visible
|
||||||
@@ -10993,12 +10989,11 @@ public partial class ChatWindow : Window
|
|||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
assistantContent = string.IsNullOrWhiteSpace(assistantContent) ? "(취소됨)" : assistantContent;
|
assistantContent = _chatEngine.FinalizeExecutionContent(assistantContent, cancelled: true).Content;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
var errMsg = $"⚠ 오류: {ex.Message}";
|
assistantContent = _chatEngine.FinalizeExecutionContent(assistantContent, ex).Content;
|
||||||
assistantContent = errMsg;
|
|
||||||
ShowToast("실패한 요청은 작업 요약에서 다시 시도할 수 있습니다.", "\uE783", 2600);
|
ShowToast("실패한 요청은 작업 요약에서 다시 시도할 수 있습니다.", "\uE783", 2600);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -11039,16 +11034,16 @@ public partial class ChatWindow : Window
|
|||||||
if (viewportWidth < 200)
|
if (viewportWidth < 200)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// claw-code처럼 창이 줄어들면 메시지 축과 컴포저가 함께 자연스럽게 줄어들도록,
|
// claw-code처럼 메시지 축과 입력축이 같은 중심선을 공유하도록,
|
||||||
// 남는 본문 폭을 기준으로 상한만 두고 반응형 폭을 다시 계산합니다.
|
// 본문 폭 상한을 조금 더 낮추고 창 폭 변화에 더 부드럽게 반응시킵니다.
|
||||||
var contentWidth = Math.Max(360, viewportWidth - 48);
|
var contentWidth = Math.Max(340, viewportWidth - 32);
|
||||||
var messageWidth = Math.Clamp(contentWidth * 0.9, 360, 920);
|
var messageWidth = Math.Clamp(contentWidth * 0.86, 340, 840);
|
||||||
var composerWidth = Math.Clamp(contentWidth * 0.82, 360, 820);
|
var composerWidth = Math.Clamp(contentWidth * 0.78, 340, 760);
|
||||||
|
|
||||||
if (contentWidth < 760)
|
if (contentWidth < 760)
|
||||||
{
|
{
|
||||||
messageWidth = Math.Clamp(contentWidth - 8, 340, 820);
|
messageWidth = Math.Clamp(contentWidth - 10, 332, 760);
|
||||||
composerWidth = Math.Clamp(contentWidth - 28, 332, 760);
|
composerWidth = Math.Clamp(contentWidth - 20, 328, 700);
|
||||||
}
|
}
|
||||||
|
|
||||||
var changed = false;
|
var changed = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user