fix: centered input + default stream

This commit is contained in:
2026-04-29 15:12:44 +02:00
parent 18f293ce67
commit 6e409592b5
2 changed files with 47 additions and 41 deletions
+45 -39
View File
@@ -39,7 +39,7 @@ export default function ChatUI({
stop: [''], stop: [''],
repeatPenalty: 1.1, repeatPenalty: 1.1,
seed: 0, seed: 0,
stream: false, stream: true,
keepAlive: '5m', keepAlive: '5m',
}); });
@@ -108,7 +108,8 @@ export default function ChatUI({
if (!res.ok) { if (!res.ok) {
let message = 'Request failed'; let message = 'Request failed';
if (res.status === 500) message = 'Server error (likely model too large or OOM)'; if (res.status === 500)
message = 'Server error (likely model too large or OOM)';
else if (res.status === 401) message = 'Unauthorized'; else if (res.status === 401) message = 'Unauthorized';
else message = data?.message ?? data?.error ?? message; else message = data?.message ?? data?.error ?? message;
throw new Error(message); throw new Error(message);
@@ -179,54 +180,59 @@ export default function ChatUI({
/> />
</header> </header>
{/* Messages */} {/* Messages + centered input when empty */}
<main className="flex-1 overflow-y-auto flex flex-col p-6"> <main className="flex-1 overflow-y-auto flex flex-col p-6">
<div className="w-full max-w-2xl mx-auto space-y-3"> {messages.length === 0 ? (
{messages.map((msg, i) => ( /* ── Empty state: input centered within the chat column only ── */
<div key={i} className="text-sm"> <div className="flex-1 flex flex-col items-center justify-center">
<b>{msg.role === 'user' ? 'You' : 'AI'}:</b> {msg.content} <p className="text-primary text-sm mb-3 opacity-60">
{/* Blinking cursor shown on the last message while streaming */}
{loading &&
settings.stream &&
i === messages.length - 1 &&
msg.role === ASSISTANT_ROLE && (
<span className="inline-block w-[2px] h-[1em] bg-current ml-0.5 align-middle animate-pulse" />
)}
</div>
))}
{loading && !settings.stream && (
<div className="text-xs text-muted">Thinking...</div>
)}
</div>
</main>
{/* Input — floats center when empty, slides to bottom on first message */}
<div
className={`
transition-all duration-500 ease-in-out
${
messages.length === 0
? 'absolute inset-0 flex items-center justify-center pointer-events-none'
: 'p-4'
}
`}
>
<div className="w-full max-w-2xl mx-auto pointer-events-auto transition-all duration-500 ease-in-out">
{messages.length === 0 && (
<p className="text-center text-primary text-sm mb-3 opacity-60">
Start a conversation… Start a conversation…
</p> </p>
)} <input
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={(e) =>
e.key === 'Enter' && !loading && sendMessage()
}
disabled={loading}
className="w-full max-w-2xl p-3 rounded-xl bg-black/20 border border-muted outline-none disabled:opacity-50"
placeholder="Message..."
/>
</div>
) : (
/* ── Active chat: messages list ── */
<div className="w-full max-w-2xl mx-auto space-y-3">
{messages.map((msg, i) => (
<div key={i} className="text-sm">
<b>{msg.role === 'user' ? 'You' : 'AI'}:</b> {msg.content}
{loading &&
settings.stream &&
i === messages.length - 1 &&
msg.role === ASSISTANT_ROLE && (
<span className="inline-block w-[2px] h-[1em] bg-current ml-0.5 align-middle animate-pulse" />
)}
</div>
))}
{loading && !settings.stream && (
<div className="text-xs text-muted">Thinking...</div>
)}
</div>
)}
</main>
{/* Input bar — only shown once conversation has started */}
{messages.length > 0 && (
<div className="p-4">
<input <input
value={input} value={input}
onChange={(e) => setInput(e.target.value)} onChange={(e) => setInput(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && !loading && sendMessage()} onKeyDown={(e) => e.key === 'Enter' && !loading && sendMessage()}
disabled={loading} disabled={loading}
className="w-full p-3 rounded-xl bg-black/20 border border-muted outline-none disabled:opacity-50" className="w-full max-w-2xl mx-auto block p-3 rounded-xl bg-black/20 border border-muted outline-none disabled:opacity-50"
placeholder="Message..." placeholder="Message..."
/> />
</div> </div>
</div> )}
</div> </div>
</div> </div>
); );