ui: generous whitespace — floating compose, spacious messages + header

- Compose: floating bordered container with inner padding, no top border
- Compose: bottom bar with prefix + "enter to send" hint
- Messages: increased padding (py-3/4, px-4/5)
- Header: more breathing room (py-3/4, px-4/6)
- Modern 2026 spacing throughout

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-29 21:01:20 +02:00
parent 80239e3805
commit 98a46b962f
3 changed files with 33 additions and 29 deletions

View File

@@ -121,7 +121,7 @@ export default function App() {
</div> </div>
<div className="flex-1 flex flex-col min-w-0"> <div className="flex-1 flex flex-col min-w-0">
<div className="px-3 py-2 md:px-4 border-b-2 border-border flex items-center gap-2"> <div className="px-4 py-3 md:px-6 md:py-4 border-b-2 border-border flex items-center gap-3">
<Sheet open={sheetOpen} onOpenChange={setSheetOpen}> <Sheet open={sheetOpen} onOpenChange={setSheetOpen}>
<SheetTrigger className="md:hidden p-1 h-8 w-8 text-muted-foreground hover:text-primary font-mono font-bold text-lg"> <SheetTrigger className="md:hidden p-1 h-8 w-8 text-muted-foreground hover:text-primary font-mono font-bold text-lg">
= =

View File

@@ -71,8 +71,8 @@ export function ComposeBox({
return ( return (
<div className={cn( <div className={cn(
"border-t-2 transition-colors px-3 py-2 md:px-4 pb-[env(safe-area-inset-bottom,8px)]", "transition-colors px-4 py-4 md:px-6 md:py-5 pb-[env(safe-area-inset-bottom,16px)]",
focused ? "border-primary bg-card" : "border-border bg-background", focused ? "bg-card" : "bg-background",
)}> )}>
{/* Reply chip */} {/* Reply chip */}
{replyTo && ( {replyTo && (
@@ -89,21 +89,12 @@ export function ComposeBox({
</div> </div>
)} )}
<div className="flex items-end gap-2"> {/* Floating input container */}
{/* Type prefix — click to cycle */} <div className={cn(
<button "border-2 transition-colors px-4 py-3 md:px-5 md:py-4",
type="button" focused ? "border-primary/40 bg-muted/30" : "border-border bg-muted/10",
onClick={() => cycleType(1)} )}>
className={cn( {/* Textarea */}
"font-mono text-sm font-bold pb-1 min-w-[20px] transition-colors select-none",
meta.color,
)}
title={`${msgType} (Tab to cycle, Ctrl+1-5 to select)`}
>
{meta.prefix}
</button>
{/* Auto-growing textarea — no send button */}
<textarea <textarea
ref={inputRef} ref={inputRef}
value={content} value={content}
@@ -123,7 +114,6 @@ export function ComposeBox({
e.preventDefault(); e.preventDefault();
cycleType(-1); cycleType(-1);
} }
// Ctrl+1-5 for type
if (e.ctrlKey && e.key >= "1" && e.key <= "5") { if (e.ctrlKey && e.key >= "1" && e.key <= "5") {
e.preventDefault(); e.preventDefault();
const types: MessageType[] = ["text", "code", "result", "error", "plan"]; const types: MessageType[] = ["text", "code", "result", "error", "plan"];
@@ -134,19 +124,33 @@ export function ComposeBox({
disabled={sending} disabled={sending}
rows={1} rows={1}
className={cn( className={cn(
"flex-1 bg-transparent text-sm font-mono text-foreground placeholder:text-muted-foreground/30 resize-none focus:outline-none leading-relaxed py-0.5", "w-full bg-transparent text-sm font-mono text-foreground placeholder:text-muted-foreground/30 resize-none focus:outline-none leading-relaxed",
sending && "opacity-30", sending && "opacity-30",
)} )}
/> />
{/* Subtle type indicator — shows current type name */} {/* Bottom bar — prefix + type indicator */}
<span className={cn( <div className="flex items-center justify-between mt-3 pt-2">
"text-[9px] font-mono uppercase tracking-widest pb-1 transition-opacity", <button
meta.color, type="button"
content ? "opacity-60" : "opacity-30", onClick={() => cycleType(1)}
)}> className={cn(
{msgType} "font-mono text-xs font-bold transition-colors select-none",
</span> meta.color,
)}
title={`${msgType} (Tab to cycle)`}
>
{meta.prefix}
</button>
<span className={cn(
"text-[9px] font-mono uppercase tracking-[0.2em] transition-opacity",
meta.color,
content ? "opacity-60" : "opacity-25",
)}>
{msgType} · enter to send
</span>
</div>
</div> </div>
</div> </div>
); );

View File

@@ -66,7 +66,7 @@ export function MessageItem({ message, replyTarget, onReply }: Props) {
</div> </div>
)} )}
<div className="px-4 py-2"> <div className="px-4 py-3 md:px-5 md:py-4">
{/* Header */} {/* Header */}
<div className="flex items-center gap-2 text-[11px] flex-wrap"> <div className="flex items-center gap-2 text-[11px] flex-wrap">
{/* Name */} {/* Name */}