feat: add stacked layout for chat input when content wraps

Add dynamic layout switching that moves input buttons below the text
area when content height exceeds initial height. Includes height
tracking, state management via checkStacked(), and CSS grid updates
for stacked mode on desktop only.
This commit is contained in:
Andrew Beal 2026-03-22 20:07:26 +00:00
parent e0a5dc6582
commit 5f63f7c744

View file

@ -49,6 +49,7 @@
let userInstructionAreaActive: boolean = false;
let userInstructionActive: boolean = true;
let stacked: boolean = false;
let userRequest: string = "";
@ -57,6 +58,7 @@
let countdownIntervalId: ReturnType<typeof setInterval> | null = null;
let countdownSecondsRemaining: number = 0;
let inputInitialHeight: number = 0;
const diffOpenedRef: EventRef = eventService.on(Event.DiffOpened, () => { inputMode = InputMode.Diff; focusInput(); });
const diffClosedRef: EventRef = eventService.on(Event.DiffClosed, () => { inputMode = InputMode.Normal; focusInput(); });
@ -64,6 +66,7 @@
onMount(async () => {
userInstructionActive = (await aiPrompt.userInstruction()).trim() !== "";
inputInitialHeight = textareaElement.innerHeight;
});
onDestroy(() => {
@ -73,6 +76,18 @@
stopCountdown();
});
function checkStacked() {
if (textareaElement.textContent.trim() === "") {
stacked = false;
return;
}
if (textareaElement.innerHeight > inputInitialHeight) {
stacked = true;
return;
}
}
export function focusInput(onMobile: boolean = false) {
// don't focus on mobile, it's annoying
if (onMobile || !Platform.isMobile) {
@ -247,6 +262,7 @@
textareaElement.textContent = "";
userRequest = "";
checkStacked();
if (Platform.isMobile) {
textareaElement.blur();
@ -399,6 +415,8 @@
if (userRequest.trim() === "") {
textareaElement.textContent = "";
}
checkStacked();
}
}
@ -471,7 +489,7 @@
}
</script>
<div id="input-container" class:edit-mode={editModeActive}>
<div id="input-container" class:edit-mode={editModeActive} class:stacked>
<div id="input-display-container" style:padding-top={attachments.length > 0 ? "var(--size-4-2)" : 0}>
<InputDisplay bind:this={inputDisplay} {editModeActive}/>
</div>
@ -739,6 +757,31 @@
background-color: var(--alt-interactive-accent-hover);
}
/* Stacked layout: input above, buttons below (desktop only, when content wraps) */
#input-container.stacked {
grid-template-rows: auto auto auto auto var(--size-4-3) 1fr var(--size-4-2) auto var(--size-4-3);
}
#input-container.stacked #input-field {
grid-column: 2 / 11;
}
#input-container.stacked #user-instruction-button {
grid-row: 8;
}
#input-container.stacked #edit-mode-button {
grid-row: 8;
}
#input-container.stacked #planning-mode-button {
grid-row: 8;
}
#input-container.stacked #submit-button {
grid-row: 8;
}
/* Narrow/mobile layout: input above, buttons below */
:global(.is-mobile) #input-container {
grid-template-rows: auto auto auto auto var(--size-4-3) 1fr var(--size-4-2) auto var(--size-4-3);