redesign: Concrete Brutalism — warm concrete palette, Inconsolata + Instrument Sans

Kill the AI slop. New design language:
- Warm concrete grays (#1a1917 base) with hot orange (#F26522) accent
- Inconsolata mono for body, Instrument Sans for headings
- Zero border-radius everywhere — brutalist, no rounded corners
- Thick 4px type slabs on messages (green/red/blue/yellow)
- Thick 2px borders on all structural elements
- Agent messages in warm card bg, names in hot orange
- Ape emoji logo in sidebar
- Command terminal compose box with > prompt
- Blocky type selector buttons

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-29 20:52:00 +02:00
parent 9e375fd953
commit 0ab3d64daa
7 changed files with 234 additions and 207 deletions

View File

@@ -1,5 +1,6 @@
import { useState } from "react";
import type { Message } from "@/types/Message";
import { cn } from "@/lib/utils";
interface Props {
message: Message;
@@ -7,19 +8,12 @@ interface Props {
onReply: (id: string) => void;
}
const TYPE_BORDER: Record<string, string> = {
text: "",
code: "border-l-2 border-amber-500/70",
result: "border-l-2 border-emerald-500/70",
error: "border-l-2 border-red-500/70",
plan: "border-l-2 border-blue-500/70",
};
const TYPE_LABEL: Record<string, { text: string; color: string }> = {
code: { text: "CODE", color: "text-amber-500" },
result: { text: "RES", color: "text-emerald-500" },
error: { text: "ERR", color: "text-red-500" },
plan: { text: "PLAN", color: "text-blue-500" },
const TYPE_CONFIG: Record<string, { border: string; label: string; labelBg: string }> = {
text: { border: "border-l-transparent", label: "", labelBg: "" },
code: { border: "border-l-[var(--color-msg-code)]", label: "CODE", labelBg: "bg-[var(--color-msg-code)]/15 text-[var(--color-msg-code)]" },
result: { border: "border-l-[var(--color-msg-result)]", label: "RESULT", labelBg: "bg-[var(--color-msg-result)]/15 text-[var(--color-msg-result)]" },
error: { border: "border-l-[var(--color-msg-error)]", label: "ERROR", labelBg: "bg-[var(--color-msg-error)]/15 text-[var(--color-msg-error)]" },
plan: { border: "border-l-[var(--color-msg-plan)]", label: "PLAN", labelBg: "bg-[var(--color-msg-plan)]/15 text-[var(--color-msg-plan)]" },
};
function timeAgo(dateStr: string): string {
@@ -36,120 +30,116 @@ export function MessageItem({ message, replyTarget, onReply }: Props) {
const [metaOpen, setMetaOpen] = useState(false);
const isAgent = message.user.role === "agent";
const isDeleted = !!message.deleted_at;
const border = TYPE_BORDER[message.type] || "";
const label = TYPE_LABEL[message.type];
const cfg = TYPE_CONFIG[message.type] || TYPE_CONFIG.text;
const meta = message.metadata as Record<string, string> | null;
return (
<div
className={`group relative px-3 py-2 md:px-4 transition-colors hover:bg-white/[0.03] ${
isAgent ? "bg-white/[0.02]" : ""
}`}
>
{/* Agent glow — left edge */}
{isAgent && (
<div className="absolute left-0 top-0 bottom-0 w-0.5 bg-blue-500/30" />
className={cn(
"group border-b border-border/50 border-l-4 transition-colors",
cfg.border,
isAgent ? "bg-card" : "bg-background",
"hover:bg-muted/30",
)}
>
{/* Reply context */}
{replyTarget && (
<div className="mb-1 text-[10px] md:text-[11px] text-muted-foreground flex items-center gap-1 opacity-60 pl-7 md:pl-9">
<span>^</span>
<span className="font-medium">{replyTarget.user.display_name}</span>
<span className="truncate max-w-40 md:max-w-80">{replyTarget.content}</span>
<div className="px-4 pt-1.5 text-[10px] text-muted-foreground flex items-center gap-1">
<span className="text-primary font-bold">^</span>
<span className="font-bold">{replyTarget.user.display_name}</span>
<span className="truncate max-w-40 md:max-w-80 opacity-60">{replyTarget.content}</span>
</div>
)}
<div className={`flex items-start gap-2 md:gap-3 ${border} ${border ? "pl-2 md:pl-3" : ""}`}>
{/* Avatar — small on mobile */}
<div
className={`w-5 h-5 md:w-6 md:h-6 flex-shrink-0 flex items-center justify-center text-[9px] md:text-[10px] font-bold rounded-sm ${
isAgent
? "bg-blue-500/20 text-blue-400"
: "bg-secondary text-muted-foreground"
}`}
>
{message.user.display_name[0]}
<div className="px-4 py-2">
{/* Header */}
<div className="flex items-center gap-2 text-[11px] flex-wrap">
{/* Name */}
<span className={cn(
"font-sans font-bold text-xs",
isAgent ? "text-primary" : "text-foreground"
)}>
{message.user.display_name}
</span>
{/* Agent badge */}
{isAgent && (
<span className="font-mono text-[9px] font-bold px-1.5 py-0.5 bg-primary/15 text-primary uppercase tracking-wider">
AGT
</span>
)}
{/* Type badge */}
{cfg.label && (
<span className={cn("font-mono text-[9px] font-bold px-1.5 py-0.5 uppercase tracking-wider", cfg.labelBg)}>
{cfg.label}
</span>
)}
{/* Time */}
<span className="text-muted-foreground font-mono tabular-nums md:hidden text-[10px]">
{timeAgo(message.created_at)}
</span>
<span className="text-muted-foreground font-mono tabular-nums hidden md:inline text-[10px]">
{new Date(message.created_at).toLocaleTimeString("en-US", {
hour12: false, hour: "2-digit", minute: "2-digit", second: "2-digit",
})}
</span>
{/* Seq */}
<span className="text-muted-foreground/30 font-mono tabular-nums text-[10px] hidden md:inline">
#{Number(message.seq)}
</span>
{/* Reply button */}
<button
type="button"
onClick={() => onReply(message.id)}
className="font-sans text-[10px] font-bold uppercase tracking-wider text-muted-foreground md:opacity-0 md:group-hover:opacity-60 hover:!text-primary transition-all ml-auto min-w-[44px] min-h-[44px] md:min-w-0 md:min-h-0 flex items-center justify-end"
>
Reply
</button>
</div>
<div className="flex-1 min-w-0">
{/* Header */}
<div className="flex items-center gap-1.5 md:gap-2 text-[10px] md:text-[11px] flex-wrap">
<span className={`font-bold ${isAgent ? "text-blue-400" : "text-foreground"}`}>
{message.user.display_name}
</span>
{isAgent && (
<span className="text-[9px] px-1 bg-blue-500/20 rounded-sm text-blue-400">
AGT
</span>
)}
{label && (
<span className={`text-[9px] md:text-[10px] font-bold ${label.color}`}>
{label.text}
</span>
)}
{/* Mobile: relative time. Desktop: full time */}
<span className="text-muted-foreground tabular-nums md:hidden">
{timeAgo(message.created_at)}
</span>
<span className="text-muted-foreground tabular-nums hidden md:inline">
{new Date(message.created_at).toLocaleTimeString("en-US", {
hour12: false, hour: "2-digit", minute: "2-digit", second: "2-digit",
})}
</span>
<span className="text-muted-foreground/40 tabular-nums hidden md:inline">
#{Number(message.seq)}
</span>
{/* Reply — always visible on mobile (no hover), hover on desktop */}
<button
type="button"
onClick={() => onReply(message.id)}
className="text-[9px] md:text-[10px] text-muted-foreground md:opacity-0 md:group-hover:opacity-60 hover:!opacity-100 transition-opacity ml-auto min-w-[44px] min-h-[44px] md:min-w-0 md:min-h-0 flex items-center justify-end"
>
REPLY
</button>
</div>
{/* Content */}
<div className={`mt-0.5 text-[12px] md:text-[13px] leading-relaxed break-words ${
message.type === "code" ? "bg-black/20 px-2 py-1 rounded-sm whitespace-pre-wrap overflow-x-auto" : ""
} ${message.type === "error" ? "text-red-400" : ""}`}>
{isDeleted ? (
<span className="italic text-muted-foreground/40">[deleted]</span>
) : (
message.content
)}
</div>
{/* Agent metadata — tap to expand on mobile, always compact on desktop */}
{meta && isAgent && (
<>
{/* Desktop: inline strip */}
<div className="hidden md:flex mt-1 gap-3 text-[10px] text-muted-foreground/50">
{meta.model && <span>{meta.model}</span>}
{meta.hostname && <span>{meta.hostname}</span>}
{meta.cwd && <span>{meta.cwd}</span>}
{meta.skill && <span className="text-blue-400/50">{meta.skill}</span>}
</div>
{/* Mobile: tap to expand */}
<button
type="button"
onClick={() => setMetaOpen(!metaOpen)}
className="md:hidden mt-1 text-[9px] text-muted-foreground/40 min-h-[32px] flex items-center"
>
{metaOpen ? "hide meta" : `${meta.model || "agent"} ...`}
</button>
{metaOpen && (
<div className="md:hidden mt-0.5 text-[10px] text-muted-foreground/50 space-y-0.5">
{meta.model && <div>model: {meta.model}</div>}
{meta.hostname && <div>host: {meta.hostname}</div>}
{meta.cwd && <div>cwd: {meta.cwd}</div>}
{meta.skill && <div className="text-blue-400/50">skill: {meta.skill}</div>}
</div>
)}
</>
{/* Content */}
<div className={cn(
"mt-1 text-[13px] leading-relaxed break-words font-mono",
message.type === "code" && "bg-muted px-3 py-2 border-2 border-border whitespace-pre-wrap overflow-x-auto",
message.type === "error" && "text-[var(--color-msg-error)]",
)}>
{isDeleted ? (
<span className="italic text-muted-foreground/40">[deleted]</span>
) : (
message.content
)}
</div>
{/* Agent metadata */}
{meta && isAgent && (
<>
<div className="hidden md:flex mt-1.5 gap-3 text-[10px] font-mono text-muted-foreground/50">
{meta.model && <span>{meta.model}</span>}
{meta.hostname && <span>{meta.hostname}</span>}
{meta.cwd && <span className="text-muted-foreground/30">{meta.cwd}</span>}
{meta.skill && <span className="text-primary/50">{meta.skill}</span>}
</div>
<button
type="button"
onClick={() => setMetaOpen(!metaOpen)}
className="md:hidden mt-1 text-[9px] font-mono text-muted-foreground/40 min-h-[32px] flex items-center"
>
{metaOpen ? "[-] hide" : `[+] ${meta.model || "meta"}`}
</button>
{metaOpen && (
<div className="md:hidden mt-0.5 text-[10px] font-mono text-muted-foreground/50 space-y-0.5 pl-2 border-l-2 border-border">
{meta.model && <div>{meta.model}</div>}
{meta.hostname && <div>{meta.hostname}</div>}
{meta.cwd && <div>{meta.cwd}</div>}
{meta.skill && <div className="text-primary/50">{meta.skill}</div>}
</div>
)}
</>
)}
</div>
</div>
);