From 22761aa5473fa08ec5283cd575930a99a1887d74 Mon Sep 17 00:00:00 2001 From: aivsomkar Date: Wed, 19 Aug 2026 17:00:45 +0530 Subject: [PATCH] Fold the chat header chips to icon bubbles when the column is narrow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the Computer or Inspector panel open the chat column drops to ~700px and the header row — Stop, + Task, usage, working folder, model, icons — wrapped onto three lines and crushed the bot avatar and name to nothing. The header is now a CSS container (@container/chathead); below 4xl each chip folds to an icon-only shape and the right group stops shrinking so the name truncates instead: - Stop → round bubble with the square - + Task → round bubble with the plus (count-only bubble once there are several tasks) - usage → one short figure: cost when known, else tokens - working folder → rounded square with the folder icon - model → rounded square with the provider mark Full labels still ride the tooltips. Wide headers are unchanged. Co-Authored-By: Claude Fable 5 --- src/components/ChatView.tsx | 30 +++++++++++++++++++++--------- src/components/ModelPicker.tsx | 18 +++++++++++++++--- src/components/TaskPicker.tsx | 21 +++++++++++++++------ src/lib/compact-chip.ts | 14 ++++++++++++++ 4 files changed, 65 insertions(+), 18 deletions(-) create mode 100644 src/lib/compact-chip.ts diff --git a/src/components/ChatView.tsx b/src/components/ChatView.tsx index 7e16ccad8d..48cef498e9 100644 --- a/src/components/ChatView.tsx +++ b/src/components/ChatView.tsx @@ -47,6 +47,7 @@ import { ReactionBar, ReactionChips } from "./Reactions"; import { SpeakButton } from "./SpeakButton"; import { CallButton, CallOverlay } from "./CallView"; import { cn } from "@/lib/cn"; +import { COMPACT_BUBBLE, COMPACT_SQUARE } from "@/lib/compact-chip"; import { useFocusMessage } from "@/lib/focus-message"; import { webhookMessageView } from "@/lib/webhook-message"; import { BOTTOM_FOLLOW_THRESHOLD, shouldResumeBottomFollow } from "@/lib/bottom-follow"; @@ -803,7 +804,9 @@ export function ChatView({ bot }: { bot: Bot }) { {/* Header */}
}
-
+
{bot.busy && ( )} @@ -1022,13 +1028,16 @@ function UsageChip({ bot }: { bot: Bot }) { ] .filter(Boolean) .join("\n"); + // folded: one figure — cost when the engine reports one, else tokens + const short = usage.costUsd !== null ? formatUsd(usage.costUsd) : formatTokens(usage.input + usage.output); return ( ); } @@ -1045,11 +1054,14 @@ function WorkingFolderChip({ bot }: { bot: Bot }) { return ( ); } diff --git a/src/components/ModelPicker.tsx b/src/components/ModelPicker.tsx index 535d27c0aa..f98047d7a0 100644 --- a/src/components/ModelPicker.tsx +++ b/src/components/ModelPicker.tsx @@ -10,6 +10,7 @@ import { ProviderMark } from "./ProviderIcons"; import { EngineSetup, needsCli, needsSignIn } from "./EngineSetup"; import { EngineGroupLabel } from "./EngineGroupLabel"; import { cn } from "@/lib/cn"; +import { COMPACT_SQUARE } from "@/lib/compact-chip"; type ModelOption = InstanceInfo["models"]["options"][number]; const COMPACT_MODEL_COUNT = 5; @@ -206,12 +207,23 @@ export function ModelPicker({ bot, className }: { bot: Bot; className?: string } }} aria-expanded={open} aria-haspopup="dialog" - className="flex items-center gap-1.5 rounded-full border border-hairline/40 bg-raised/60 py-1 pl-2 pr-2.5 text-[13px] text-ink hover:bg-raised" + className={cn( + "flex items-center gap-1.5 rounded-full border border-hairline/40 bg-raised/60 py-1 pl-2 pr-2.5 text-[13px] text-ink hover:bg-raised", + // in a narrow chat header fold to a rounded square with just the + // provider mark; the model name rides the tooltip (a bot with no + // resolved engine keeps its label — the mark is what would hide it) + active && COMPACT_SQUARE, + )} title={active ? `${active.displayName} · ${modelLabel(active, selection.model)}` : selection.model} > {active && } - {modelLabel(active, selection.model)} - + + {modelLabel(active, selection.model)} + + {open && ( diff --git a/src/components/TaskPicker.tsx b/src/components/TaskPicker.tsx index f6625211d7..62afc65302 100644 --- a/src/components/TaskPicker.tsx +++ b/src/components/TaskPicker.tsx @@ -8,6 +8,7 @@ import { useEffect, useRef, useState } from "react"; import { Check, ChevronDown, Plus, Trash2 } from "lucide-react"; import { useStore, formatTime, type Bot, type Task } from "@/state/store"; import { cn } from "@/lib/cn"; +import { COMPACT_BUBBLE } from "@/lib/compact-chip"; import { formatTokens } from "@/lib/format-tokens"; /** Quiet per-task token tally — input+output combined, because one honest @@ -57,9 +58,13 @@ export function TaskPicker({ bot }: { bot: Bot }) { onClick={() => dispatch({ type: "newTask", botId: bot.id })} disabled={bot.busy} title={bot.busy ? "Let this turn finish first" : "New task — a fresh context on this bot"} - className="flex items-center gap-1 rounded-full border border-hairline/40 px-2.5 py-1 text-[12.5px] text-ink-secondary hover:bg-raised hover:text-ink disabled:opacity-40" + className={cn( + "flex items-center gap-1 rounded-full border border-hairline/40 px-2.5 py-1 text-[12.5px] text-ink-secondary hover:bg-raised hover:text-ink disabled:opacity-40", + COMPACT_BUBBLE, + )} > - Task + + Task ); } @@ -84,11 +89,15 @@ export function TaskPicker({ bot }: { bot: Bot }) { {open && ( diff --git a/src/lib/compact-chip.ts b/src/lib/compact-chip.ts new file mode 100644 index 0000000000..b12ae4d1fe --- /dev/null +++ b/src/lib/compact-chip.ts @@ -0,0 +1,14 @@ +// Chat-header chips fold to icon-only shapes when the header is narrow — +// the computer/inspector panel is open or the window is small — so the +// row stops wrapping and crushing the bot's name. The header is the +// `@container/chathead`; below 4xl (56rem) these variants kick in. +// +// Kept as plain literal strings so Tailwind's scanner sees every class. + +/** Round bubble, icon only — Stop, + Task. */ +export const COMPACT_BUBBLE = + "@max-4xl/chathead:size-[30px] @max-4xl/chathead:justify-center @max-4xl/chathead:gap-0 @max-4xl/chathead:p-0"; + +/** Rounded square, icon only — working folder, model. */ +export const COMPACT_SQUARE = + "@max-4xl/chathead:size-[30px] @max-4xl/chathead:justify-center @max-4xl/chathead:gap-0 @max-4xl/chathead:rounded-md @max-4xl/chathead:p-0";