fix(ui): expand prompt via rows, keep placeholder padding
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { createSignal, Show, onMount, For, onCleanup, createEffect, on, untrack, createMemo } from "solid-js"
|
import { createSignal, Show, onMount, For, onCleanup, createEffect, on, untrack } from "solid-js"
|
||||||
import { ArrowBigUp, ArrowBigDown } from "lucide-solid"
|
import { ArrowBigUp, ArrowBigDown } from "lucide-solid"
|
||||||
import UnifiedPicker from "./unified-picker"
|
import UnifiedPicker from "./unified-picker"
|
||||||
import ExpandButton from "./expand-button"
|
import ExpandButton from "./expand-button"
|
||||||
@@ -50,45 +50,6 @@ export default function PromptInput(props: PromptInputProps) {
|
|||||||
const [expandState, setExpandState] = createSignal<"normal" | "expanded">("normal")
|
const [expandState, setExpandState] = createSignal<"normal" | "expanded">("normal")
|
||||||
const SELECTION_INSERT_MAX_LENGTH = 2000
|
const SELECTION_INSERT_MAX_LENGTH = 2000
|
||||||
let textareaRef: HTMLTextAreaElement | undefined
|
let textareaRef: HTMLTextAreaElement | undefined
|
||||||
let containerRef: HTMLDivElement | undefined
|
|
||||||
|
|
||||||
// Fixed line height for expanded state (15 lines as suggested by dev)
|
|
||||||
|
|
||||||
// Fixed line height for web/mobile expanded state (15 lines as suggested)
|
|
||||||
const EXPANDED_LINES = 15
|
|
||||||
const LINE_HEIGHT = 24
|
|
||||||
const FIXED_EXPANDED_HEIGHT = EXPANDED_LINES * LINE_HEIGHT // 360px
|
|
||||||
|
|
||||||
const calculateExpandedHeight = () => {
|
|
||||||
if (!containerRef) {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
const root = containerRef.closest(".session-view")
|
|
||||||
if (!root) {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
const rootRect = root.getBoundingClientRect()
|
|
||||||
|
|
||||||
// Reserve minimum space for message section
|
|
||||||
// Use larger reserve for landscape orientation (less vertical space)
|
|
||||||
const isLandscape = typeof window !== "undefined" && window.innerWidth > window.innerHeight
|
|
||||||
const MIN_MESSAGE_SPACE = isLandscape ? 150 : 200
|
|
||||||
const availableForInput = rootRect.height - MIN_MESSAGE_SPACE
|
|
||||||
|
|
||||||
return availableForInput
|
|
||||||
}
|
|
||||||
|
|
||||||
const expandedHeight = createMemo(() => {
|
|
||||||
const state = expandState()
|
|
||||||
if (state === "normal") return "auto"
|
|
||||||
|
|
||||||
// Use fixed height, but cap at available space
|
|
||||||
// This prevents overflow in landscape or small screens
|
|
||||||
const availableHeight = calculateExpandedHeight()
|
|
||||||
const maxHeight = Math.min(FIXED_EXPANDED_HEIGHT, availableHeight * 0.6)
|
|
||||||
return `${Math.max(maxHeight, 150)}px` // Minimum 150px to be useful
|
|
||||||
})
|
|
||||||
|
|
||||||
const getPlaceholder = () => {
|
const getPlaceholder = () => {
|
||||||
if (mode() === "shell") {
|
if (mode() === "shell") {
|
||||||
@@ -1093,7 +1054,6 @@ export default function PromptInput(props: PromptInputProps) {
|
|||||||
return (
|
return (
|
||||||
<div class="prompt-input-container">
|
<div class="prompt-input-container">
|
||||||
<div
|
<div
|
||||||
ref={containerRef}
|
|
||||||
class={`prompt-input-wrapper relative ${isDragging() ? "border-2" : ""}`}
|
class={`prompt-input-wrapper relative ${isDragging() ? "border-2" : ""}`}
|
||||||
style={
|
style={
|
||||||
isDragging()
|
isDragging()
|
||||||
@@ -1214,17 +1174,11 @@ export default function PromptInput(props: PromptInputProps) {
|
|||||||
</For>
|
</For>
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
<div
|
<div class={`prompt-input-field-container ${expandState() === "expanded" ? "is-expanded" : ""}`}>
|
||||||
class="prompt-input-field-container"
|
<div class={`prompt-input-field ${expandState() === "expanded" ? "is-expanded" : ""}`}>
|
||||||
style={{
|
|
||||||
"height": expandedHeight(),
|
|
||||||
"transition": "height 0.25s ease",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div class="prompt-input-field">
|
|
||||||
<textarea
|
<textarea
|
||||||
ref={textareaRef}
|
ref={textareaRef}
|
||||||
class={`prompt-input ${mode() === "shell" ? "shell-mode" : ""}`}
|
class={`prompt-input ${mode() === "shell" ? "shell-mode" : ""} ${expandState() === "expanded" ? "is-expanded" : ""}`}
|
||||||
placeholder={getPlaceholder()}
|
placeholder={getPlaceholder()}
|
||||||
value={prompt()}
|
value={prompt()}
|
||||||
onInput={handleInput}
|
onInput={handleInput}
|
||||||
@@ -1233,11 +1187,8 @@ export default function PromptInput(props: PromptInputProps) {
|
|||||||
onFocus={() => setIsFocused(true)}
|
onFocus={() => setIsFocused(true)}
|
||||||
onBlur={() => setIsFocused(false)}
|
onBlur={() => setIsFocused(false)}
|
||||||
disabled={props.disabled}
|
disabled={props.disabled}
|
||||||
rows={4}
|
rows={expandState() === "expanded" ? 15 : 4}
|
||||||
style={{
|
style={attachments().length > 0 ? { "padding-top": "8px" } : undefined}
|
||||||
"padding-top": attachments().length > 0 ? "8px" : "0",
|
|
||||||
"overflow-y": expandState() !== "normal" ? "auto" : "visible",
|
|
||||||
}}
|
|
||||||
spellcheck={false}
|
spellcheck={false}
|
||||||
autocorrect="off"
|
autocorrect="off"
|
||||||
autoCapitalize="off"
|
autoCapitalize="off"
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
/* Prompt input & attachment styles */
|
|
||||||
.prompt-input-container {
|
.prompt-input-container {
|
||||||
@apply flex flex-col border-t;
|
@apply flex flex-col border-t;
|
||||||
border-color: var(--border-base);
|
border-color: var(--border-base);
|
||||||
@@ -27,12 +26,10 @@
|
|||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
transition: height 0.25s ease;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.prompt-input-field {
|
.prompt-input-field {
|
||||||
position: absolute;
|
position: relative;
|
||||||
inset: 0;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
@@ -50,6 +47,19 @@
|
|||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.prompt-input-field-container.is-expanded {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-input-field.is-expanded {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-input.is-expanded {
|
||||||
|
height: auto;
|
||||||
|
min-height: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.prompt-input-overlay {
|
.prompt-input-overlay {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -218,7 +228,6 @@
|
|||||||
height: 1rem;
|
height: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.hint {
|
.hint {
|
||||||
@apply text-xs;
|
@apply text-xs;
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
@@ -306,4 +315,4 @@
|
|||||||
gap: 0;
|
gap: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user