From 3addd3420be8e97ce50d5028c52934ea66a0b85f Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 1 Jan 2026 11:04:40 +0100 Subject: [PATCH] fix: tidy web chat composer layout --- CHANGELOG.md | 1 + .../Sources/ClawdisChatUI/ChatComposer.swift | 55 +++++++++---------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09a8b8093..62052b741 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -41,6 +41,7 @@ - Android Chat UI: use `onPrimary` for user bubble text to preserve contrast (thanks @Syhids). - Control UI: sync sidebar navigation with the URL for deep-linking, and auto-scroll chat to the latest message. - Control UI: disable Web Chat + Talk when no iOS/Android node is connected; refreshed Web Chat styling and keyboard send. +- macOS Web Chat: fix composer layout so the connection pill and send button stay inside the input field. - macOS: bundle Control UI assets into the app relay so the packaged app can serve them (thanks @mbelinky). - Talk Mode: wait for chat history to surface the assistant reply before starting TTS (macOS/iOS/Android). - iOS Talk Mode: fix chat completion wait to time out even if no events arrive (prevents “Thinking…” hangs). diff --git a/apps/shared/ClawdisKit/Sources/ClawdisChatUI/ChatComposer.swift b/apps/shared/ClawdisKit/Sources/ClawdisChatUI/ChatComposer.swift index 878718cfa..6723067e8 100644 --- a/apps/shared/ClawdisKit/Sources/ClawdisChatUI/ChatComposer.swift +++ b/apps/shared/ClawdisKit/Sources/ClawdisChatUI/ChatComposer.swift @@ -131,28 +131,31 @@ struct ClawdisChatComposer: View { } private var editor: some View { - RoundedRectangle(cornerRadius: 12, style: .continuous) - .strokeBorder(ClawdisChatTheme.composerBorder) - .background( - RoundedRectangle(cornerRadius: 12, style: .continuous) - .fill(ClawdisChatTheme.composerField)) - .overlay { - VStack(alignment: .leading, spacing: 4) { - self.editorOverlay - HStack(alignment: .bottom, spacing: 6) { - if self.showsConnectionPill { - self.connectionPill - } - Spacer(minLength: 0) - self.sendButton - } + VStack(alignment: .leading, spacing: 8) { + self.editorOverlay + + Rectangle() + .fill(ClawdisChatTheme.divider) + .frame(height: 1) + .padding(.horizontal, 2) + + HStack(alignment: .center, spacing: 8) { + if self.showsConnectionPill { + self.connectionPill } + Spacer(minLength: 0) + self.sendButton } - .padding(self.editorPadding) - .frame( - minHeight: self.editorMinHeight, - idealHeight: self.editorMinHeight, - maxHeight: self.editorMaxHeight) + } + .padding(.horizontal, 10) + .padding(.vertical, 8) + .background( + RoundedRectangle(cornerRadius: 12, style: .continuous) + .fill(ClawdisChatTheme.composerField) + .overlay( + RoundedRectangle(cornerRadius: 12, style: .continuous) + .strokeBorder(ClawdisChatTheme.composerBorder))) + .padding(self.editorPadding) } private var connectionPill: some View { @@ -192,6 +195,10 @@ struct ClawdisChatComposer: View { TextEditor(text: self.$viewModel.input) .font(.system(size: 15)) .scrollContentBackground(.hidden) + .frame( + minHeight: self.textMinHeight, + idealHeight: self.textMinHeight, + maxHeight: self.textMaxHeight) .padding(.horizontal, 4) .padding(.vertical, 4) .focused(self.$isFocused) @@ -268,14 +275,6 @@ struct ClawdisChatComposer: View { self.style == .onboarding ? 5 : 6 } - private var editorMinHeight: CGFloat { - self.style == .onboarding ? 34 : 40 - } - - private var editorMaxHeight: CGFloat { - self.style == .onboarding ? 60 : 84 - } - private var textMinHeight: CGFloat { self.style == .onboarding ? 24 : 28 }