feat: show draft preset chips under the welcome message on mobile/vscode

On narrow surfaces (mobile, vscode) the composer sits at the bottom and
only the welcome message is centered, so the preset chips had nowhere
sensible to live and were desktop-only. Render them under the centered
welcome message there instead.

Extract the shared preset list (draftPresets.ts) and chip row
(DraftPresetChips) so both layouts reuse them. Since the command-aware
submit lives in ChatInput, ChatContainer triggers it through a new
input-store channel (requestPresetSubmit / consumePendingPresetSubmit)
that ChatInput consumes. Mini-chat stays excluded — too small for the row.
This commit is contained in:
Bohdan Triapitsyn
2026-05-30 02:04:32 +03:00
parent a85a9ae451
commit 57d36f6c1b
5 changed files with 115 additions and 42 deletions
+18
View File
@@ -88,11 +88,19 @@ export type InputState = {
pendingInputText: string | null
pendingInputMode: "replace" | "append" | "append-inline"
pendingSyntheticParts: SyntheticContextPart[] | null
/**
* Text a draft preset chip asked to submit immediately. Set by surfaces that
* render the chips outside ChatInput (e.g. under the welcome message on
* narrow layouts); consumed by ChatInput, which owns the command-aware submit.
*/
pendingPresetSubmit: string | null
attachedFiles: AttachedFile[]
activeEditorFile: VSCodeActiveEditorFile | null
setPendingInputText: (text: string | null, mode?: "replace" | "append" | "append-inline") => void
consumePendingInputText: () => { text: string; mode: "replace" | "append" | "append-inline" } | null
requestPresetSubmit: (text: string) => void
consumePendingPresetSubmit: () => string | null
setPendingSyntheticParts: (parts: SyntheticContextPart[] | null) => void
consumePendingSyntheticParts: () => SyntheticContextPart[] | null
addAttachedFile: (file: File) => Promise<void>
@@ -110,6 +118,7 @@ export const useInputStore = create<InputState>()((set, get) => ({
pendingInputText: null,
pendingInputMode: "replace",
pendingSyntheticParts: null,
pendingPresetSubmit: null,
attachedFiles: [],
activeEditorFile: null,
@@ -123,6 +132,15 @@ export const useInputStore = create<InputState>()((set, get) => ({
return { text: pendingInputText, mode: pendingInputMode }
},
requestPresetSubmit: (text) => set({ pendingPresetSubmit: text }),
consumePendingPresetSubmit: () => {
const { pendingPresetSubmit } = get()
if (pendingPresetSubmit === null) return null
set({ pendingPresetSubmit: null })
return pendingPresetSubmit
},
setPendingSyntheticParts: (parts) => set({ pendingSyntheticParts: parts }),
consumePendingSyntheticParts: () => {