History

fix: remove duplicate toggle button and black lines around composer

seroxdesign committed 9 months ago

Commit 7e3ae931 parent 5bc16297 files · +96 −46Browse files

Unified · Split

7 files
  1. frontend/src/app/chat/_components/input/tool-belt.tsx +1 −1
  2. frontend/src/app/chat/_components/layout/chat-toolbelt-dock.tsx +1 −1
  3. frontend/src/app/chat/_components/layout/unified-sidebar.tsx +0 −11
  4. swift-client/sources/features/chat/chat-detail-view.swift +8 −2
  5. swift-client/sources/features/chat/chat-message-row.swift +8 −4
  6. swift-client/sources/features/chat/chat-streaming-message-view.swift +59 −18
  7. swift-client/sources/features/chat/chat-usage-bar.swift +19 −9
frontend/src/app/chat/_components/input/tool-belt.tsx+1−1
@@ -263,7 +263,7 @@ export function ToolBelt({ · 262 unmodified lines
263 const canSend = value.trim() || attachments.length > 0;263 const canSend = value.trim() || attachments.length > 0;
264 264
265 return (265 return (
266 <div className="px-2 md:px-3 pb-0 bg-(--background)">266 <div className="px-2 md:px-3 pb-0">
267 <div className="w-full max-w-none md:max-w-4xl md:mx-auto px-0 md:px-0">267 <div className="w-full max-w-none md:max-w-4xl md:mx-auto px-0 md:px-0">
268 <AttachmentsPreview268 <AttachmentsPreview
269 attachments={attachments}269 attachments={attachments}
frontend/src/app/chat/_components/layout/chat-toolbelt-dock.tsx+1−1
@@ -11,7 +11,7 @@ export function ChatToolbeltDock({ toolBelt, showEmptyState }: ChatToolbeltDockP · 10 unmodified lines
11 return (11 return (
12 <div className="fixed left-0 right-0 bottom-0 z-20 md:static">12 <div className="fixed left-0 right-0 bottom-0 z-20 md:static">
13 {/* Mobile: flush to bottom, no extra padding */}13 {/* Mobile: flush to bottom, no extra padding */}
14 <div className="md:hidden bg-[hsl(30,5%,10.5%)]">14 <div className="md:hidden">
15 {toolBelt}15 {toolBelt}
16 </div>16 </div>
17 {!showEmptyState && (17 {!showEmptyState && (
frontend/src/app/chat/_components/layout/unified-sidebar.tsx+0−11
@@ -117,17 +117,6 @@ export function UnifiedSidebar({ · 116 unmodified lines
117 {children}117 {children}
118 </div>118 </div>
119 119
120 {/* Toggle button when closed */}
121 {!isOpen && (
122 <button
123 onClick={onToggle}
124 className="hidden md:flex items-center justify-center w-8 h-8 mt-4 mr-2 rounded-lg bg-white/[0.03] hover:bg-white/[0.06] border border-white/[0.06] text-[#666] hover:text-[#888] transition-colors flex-shrink-0"
125 title="Open sidebar"
126 >
127 <PanelRightOpen className="h-4 w-4" />
128 </button>
129 )}
130
131 {/* Resizable sidebar */}120 {/* Resizable sidebar */}
132 {isOpen && (121 {isOpen && (
133 <div122 <div
swift-client/sources/features/chat/chat-detail-view.swift+8−2
@@ -16,11 +16,17 @@ struct ChatDetailView: View { · 15 unmodified lines
16 ScrollView {16 ScrollView {
17 VStack(spacing: 12) {17 VStack(spacing: 12) {
18 if let modelId = model.sessionModel {18 if let modelId = model.sessionModel {
19 HStack {19 HStack(spacing: 6) {
20 Text(modelId).font(AppTheme.captionFont).foregroundColor(AppTheme.muted)20 Image(systemName: "cpu")
21 .font(.system(size: 10))
22 .foregroundColor(AppTheme.accentStrong)
23 Text(modelId)
24 .font(AppTheme.captionFont.weight(.medium))
25 .foregroundColor(AppTheme.muted)
21 Spacer()26 Spacer()
22 }27 }
23 .padding(.horizontal, 4)28 .padding(.horizontal, 4)
29 .padding(.bottom, 4)
24 }30 }
25 if let error = model.error {31 if let error = model.error {
26 HStack {32 HStack {
swift-client/sources/features/chat/chat-message-row.swift+8−4
@@ -27,10 +27,14 @@ struct ChatMessageRow: View { · 26 unmodified lines
27 Text(message.content ?? "")27 Text(message.content ?? "")
28 .font(AppTheme.bodyFont)28 .font(AppTheme.bodyFont)
29 .foregroundColor(AppTheme.foreground)29 .foregroundColor(AppTheme.foreground)
30 .padding(.horizontal, 14)30 .padding(.horizontal, 16)
31 .padding(.vertical, 10)31 .padding(.vertical, 12)
32 .background(AppTheme.card)32 .background(AppTheme.accent.opacity(0.25))
33 .cornerRadius(16)33 .cornerRadius(18)
34 .overlay(
35 RoundedRectangle(cornerRadius: 18)
36 .stroke(AppTheme.accent.opacity(0.4), lineWidth: 1)
37 )
34 }38 }
35 }39 }
36 40
swift-client/sources/features/chat/chat-streaming-message-view.swift+59−18
@@ -1,3 +1,4 @@
1// CRITICAL
1import SwiftUI2import SwiftUI
2 3
3struct ChatStreamingMessageView: View {4struct ChatStreamingMessageView: View {
@@ -6,27 +7,67 @@ struct ChatStreamingMessageView: View { · 2 unmodified lines
6 let onShowActions: (AgentMeta) -> Void7 let onShowActions: (AgentMeta) -> Void
7 8
8 var body: some View {9 var body: some View {
9 let message = StoredMessage(10 VStack(alignment: .leading, spacing: 10) {
10 id: "streaming",11 // Streaming content
11 role: "assistant",12 if !service.streamingContent.isEmpty {
12 content: service.streamingContent,13 MarkdownText(content: service.streamingContent)
13 model: nil,14 .foregroundColor(AppTheme.foreground)
14 toolCalls: nil15 }
15 )16
16 let meta = AgentMeta(17 // Live thinking/tracing indicator
17 thinkingBlocks: service.streamingReasoning.isEmpty ? [] : [service.streamingReasoning],18 if !service.streamingReasoning.isEmpty || !service.streamingToolCalls.isEmpty {
18 toolCalls: service.streamingToolCalls,19 StreamingMetaIndicator(
19 toolResults: []20 reasoning: service.streamingReasoning,
20 )21 toolCalls: service.streamingToolCalls
21 ChatMessageRow(22 )
22 message: message,23 }
23 isStreaming: true,24 }
24 meta: meta,25 .frame(maxWidth: .infinity, alignment: .leading)
25 onShowActions: { onShowActions($0) }
26 )
27 .id("streaming")26 .id("streaming")
28 .onChange(of: service.streamingContent) { _, _ in27 .onChange(of: service.streamingContent) { _, _ in
29 scrollProxy.scrollTo("streaming", anchor: .bottom)28 scrollProxy.scrollTo("streaming", anchor: .bottom)
30 }29 }
30 .onChange(of: service.streamingReasoning) { _, _ in
31 scrollProxy.scrollTo("streaming", anchor: .bottom)
32 }
33 }
34}
35
36private struct StreamingMetaIndicator: View {
37 let reasoning: String
38 let toolCalls: [ToolCall]
39
40 var body: some View {
41 VStack(alignment: .leading, spacing: 8) {
42 if !reasoning.isEmpty {
43 HStack(spacing: 6) {
44 Image(systemName: "brain")
45 .font(.system(size: 10))
46 .foregroundColor(AppTheme.accentStrong)
47 Text("Reasoning...")
48 .font(AppTheme.captionFont)
49 .foregroundColor(AppTheme.accentStrong)
50 }
51 .padding(.horizontal, 10)
52 .padding(.vertical, 5)
53 .background(AppTheme.accent.opacity(0.15))
54 .cornerRadius(8)
55 }
56
57 if !toolCalls.isEmpty {
58 HStack(spacing: 6) {
59 Image(systemName: "wrench.and.screwdriver")
60 .font(.system(size: 10))
61 .foregroundColor(AppTheme.warning)
62 Text("Using \(toolCalls.count) tool\(toolCalls.count == 1 ? "" : "s")...")
63 .font(AppTheme.captionFont)
64 .foregroundColor(AppTheme.warning)
65 }
66 .padding(.horizontal, 10)
67 .padding(.vertical, 5)
68 .background(AppTheme.warning.opacity(0.15))
69 .cornerRadius(8)
70 }
71 }
31 }72 }
32}73}
swift-client/sources/features/chat/chat-usage-bar.swift+19−9
@@ -1,3 +1,4 @@
1// CRITICAL
1import SwiftUI2import SwiftUI
2 3
3struct ChatUsageBar: View {4struct ChatUsageBar: View {
@@ -5,12 +6,12 @@ struct ChatUsageBar: View { · 1 unmodified line
5 6
6 var body: some View {7 var body: some View {
7 if let usage {8 if let usage {
8 HStack(spacing: 12) {9 HStack(spacing: 8) {
9 UsagePill(label: "Prompt", value: usage.promptTokens)10 UsagePill(label: "Input", value: usage.promptTokens, color: AppTheme.accentStrong)
10 UsagePill(label: "Completion", value: usage.completionTokens)11 UsagePill(label: "Output", value: usage.completionTokens, color: AppTheme.success)
11 UsagePill(label: "Total", value: usage.totalTokens)12 UsagePill(label: "Total", value: usage.totalTokens, color: AppTheme.foreground)
12 }13 }
13 .padding(.horizontal, 16)14 .padding(.horizontal, 4)
14 }15 }
15 }16 }
16}17}
@@ -18,15 +19,24 @@ struct ChatUsageBar: View { · 1 unmodified line
18struct UsagePill: View {19struct UsagePill: View {
19 let label: String20 let label: String
20 let value: Int21 let value: Int
22 let color: Color
21 23
22 var body: some View {24 var body: some View {
23 VStack(spacing: 2) {25 HStack(spacing: 4) {
24 Text(label).font(AppTheme.captionFont).foregroundColor(AppTheme.muted)26 Text(label)
25 Text("\(value)").font(AppTheme.monoFont)27 .font(AppTheme.captionFont)
28 .foregroundColor(AppTheme.muted)
29 Text("\(value)")
30 .font(AppTheme.monoFont.weight(.medium))
31 .foregroundColor(color)
26 }32 }
27 .padding(.vertical, 6)33 .padding(.vertical, 6)
28 .padding(.horizontal, 10)34 .padding(.horizontal, 10)
29 .background(AppTheme.card)35 .background(AppTheme.card)
30 .cornerRadius(10)36 .cornerRadius(8)
37 .overlay(
38 RoundedRectangle(cornerRadius: 8)
39 .stroke(AppTheme.border, lineWidth: 1)
40 )
31 }41 }
32}42}