From 2f88ef48272129dc847c229ebde20e2e0196dcfe Mon Sep 17 00:00:00 2001 From: Danila Poyarkov Date: Fri, 14 Aug 2026 13:21:29 +0300 Subject: [PATCH] refactor(ui): unify chat composer controls - Add a canonical 24, 28, and 32 pixel control scale - Rebuild the AI prompt as a multiline compound input - Keep property-panel icon actions at the explicit compact size --- src/components/chat/ChatInput.vue | 229 +++++++++--------- .../properties/AppearanceSection.vue | 4 +- .../LayoutSection/AutoLayoutControls.vue | 2 +- .../LayoutSection/LayoutSection.vue | 2 +- src/components/properties/PositionSection.vue | 18 +- src/components/properties/StrokeSection.vue | 4 +- .../properties/TypographySection.vue | 8 +- src/components/ui/AppInput.vue | 3 +- src/components/ui/IconButton.vue | 5 +- src/components/ui/InputGroup.vue | 49 ++++ src/theme/control.ts | 13 + src/theme/icon-button.ts | 7 +- src/theme/input-group.ts | 27 +++ src/theme/input.ts | 12 +- 14 files changed, 236 insertions(+), 147 deletions(-) create mode 100644 src/components/ui/InputGroup.vue create mode 100644 src/theme/control.ts create mode 100644 src/theme/input-group.ts diff --git a/src/components/chat/ChatInput.vue b/src/components/chat/ChatInput.vue index dc8525b30..78c8f09b5 100644 --- a/src/components/chat/ChatInput.vue +++ b/src/components/chat/ChatInput.vue @@ -5,9 +5,8 @@ import { computed, onBeforeUnmount, ref } from 'vue' import ChatProfileSelect from '@/components/chat/ChatProfileSelect.vue' import ProviderModelSelect from '@/components/chat/ProviderModelSelect.vue' -import AppInput from '@/components/ui/AppInput.vue' -import Tip from '@/components/ui/Tip.vue' -import { useButtonUI } from '@/components/ui/button' +import IconButton from '@/components/ui/IconButton.vue' +import InputGroup from '@/components/ui/InputGroup.vue' import { useAIChat } from '@/app/ai/chat/use' import { designModelProfile, designModelProfiles } from '@/app/ai/models' import { validateReferenceImageFile } from '@/app/ai/reference-image/prepare' @@ -62,18 +61,6 @@ const acpAgentName = computed(() => { const isCustomProvider = computed( () => providerID.value === 'openai-compatible' || providerID.value === 'anthropic-compatible' ) -const stopButton = useButtonUI({ - tone: 'ghost', - shape: 'rounded', - size: 'sm', - ui: { base: 'shrink-0 border border-border px-2 py-1.5' } -}) -const sendButton = useButtonUI({ - tone: 'accent', - shape: 'rounded', - size: 'sm', - ui: { base: 'shrink-0 px-2.5 py-1.5 font-medium' } -}) const customModelName = computed(() => customModelID.value.trim()) const usesCustomModel = computed( () => !!providerDef.value.supportsCustomModel && !!customModelName.value @@ -113,6 +100,13 @@ function handlePaste(event: ClipboardEvent) { onBeforeUnmount(clearReference) +function handleInputKeydown(event: KeyboardEvent) { + if (event.code !== 'Enter' || event.shiftKey || event.isComposing) return + event.preventDefault() + const target = event.currentTarget + if (target instanceof HTMLElement) target.closest('form')?.requestSubmit() +} + function handleSubmit(e: Event) { e.preventDefault() const text = input.value.trim() @@ -127,113 +121,114 @@ function handleSubmit(e: Event) {