Theseus 0.3.116: Pick AI is its own strip button; Claude chip no longer crowds the search box

The AI picker is now a sibling of the AI launch button in the sidebar
strip, not a chevron badge glued to its corner. Launch button still
opens the current engine in the left panel on click (right-click still
opens the picker, kept as a power-user shortcut). The new pick button
is a full-size strip icon with a three-row list glyph and its own
tooltip; keyboard Enter / Space activates it.

The Claude connector chip in the toolbar gained max-width + ellipsis
on its label, plus flex-shrink wiring, so the Claude 3 tabs string
never grows past 160 px and the search box keeps its text visible
even when the connector is actively streaming.
This commit is contained in:
Local Dev 2026-10-27 14:31:26 +02:00
parent f87173fde4
commit 33a84e70b0
3 changed files with 27 additions and 24 deletions

View file

@ -350,11 +350,14 @@
connector extension. Body opens its panel; ✕ stops the connector. The
dot pulses while a tool call runs. Tabs it is driving get .tab.agent. */
.agentchip { display: inline-flex; align-items: center; background: rgb(217 119 87 / .16);
max-width: 160px; flex: 0 1 auto; min-width: 0;
border: 1px solid rgb(217 119 87 / .55); border-radius: 999px; color: #e08a6c; font-size: 12px; font-weight: 600; overflow: hidden; flex: none; }
.agentchip .agcore { background: transparent; border: none; color: inherit; font: inherit; padding: 5px 9px 5px 10px;
min-width: 0; overflow: hidden;
cursor: pointer; white-space: nowrap; display: inline-flex; align-items: center; gap: 6px; }
.agentchip .agcore:hover { background: rgb(217 119 87 / .12); }
.agentchip .adot { width: 7px; height: 7px; border-radius: 50%; background: #d97757; }
.agentchip .adot { width: 7px; height: 7px; border-radius: 50%; background: #d97757; flex: none; }
.agentchip #agentLabel { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; margin-left: 6px; }
.agentchip.busy .adot { animation: agpulse 0.9s ease-in-out infinite; }
@keyframes agpulse { 50% { opacity: .25; transform: scale(.7); } }
.agentchip .agstop { background: transparent; border: none; border-left: 1px solid rgb(217 119 87 / .35);

View file

@ -1,6 +1,6 @@
{
"name": "theseus-navigator",
"version": "0.3.115",
"version": "0.3.116",
"license": "MPL-2.0",
"description": "Theseus Navigator — a browser that follows the thread. By Silent Mode, a Deviant project.",
"author": "Silent Mode",

View file

@ -49,27 +49,25 @@
.gear { color: var(--mut); margin-bottom: 2px; }
.gear:hover { color: var(--ink); }
.gear svg { width: 17px; height: 17px; }
.llm { color: var(--mut); margin-bottom: 2px; position: relative; }
.llm { color: var(--mut); margin-bottom: 2px; }
.llm:hover { color: var(--ink); }
.llm.on { background: var(--acid-tint); box-shadow: inset 2px 0 0 var(--acid); color: var(--ink); }
.llm .glyph { font-size: 16px; line-height: 1; }
.llm img { width: 18px; height: 18px; display: block; }
/* Chevron is the discoverable "pick AI" affordance — kept small so it
doesn't crowd the AI icon, but with the acid accent so it reads at
a glance and a bigger hit target through padding. */
.llm .chev { position: absolute; right: -2px; bottom: -2px; width: 14px; height: 14px;
display: grid; place-items: center; color: var(--bg); background: var(--acid);
border: 2px solid var(--bg); border-radius: 50%; font-size: 9px; font-weight: 800;
line-height: 1; padding: 0; cursor: pointer; box-shadow: 0 1px 3px rgba(0,0,0,.5); }
.llm .chev:hover { background: #fff; }
.llm .chev:focus-visible { outline: 2px solid var(--acid); outline-offset: 2px; }
/* Separate "Pick AI engine" button — a sibling of the launch button
so the two affordances read as distinct. Dot-grid glyph conveys
"picker" without copying the chevron's old meaning. */
.llmpick { color: var(--mut); margin-bottom: 2px; }
.llmpick:hover { color: var(--acid); }
.llmpick svg { width: 14px; height: 14px; display: block; }
</style></head>
<body>
<div class="strip">
<div class="spacer"></div>
<div class="icons" id="icons"></div>
<div class="spacer"></div>
<button class="icon llm" id="llmBtn" hidden><span class="glyph" id="llmGlyph">✨</span><span class="tt" id="llmTip">AI</span><span class="chev" id="llmChev" role="button" tabindex="0" aria-label="Pick AI engine" title="Pick AI engine">▾</span></button>
<button class="icon llm" id="llmBtn" hidden><span class="glyph" id="llmGlyph">✨</span><span class="tt" id="llmTip">AI</span></button>
<button class="icon llmpick" id="llmPick" hidden title="Pick AI engine" aria-label="Pick AI engine"><svg viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><circle cx="3" cy="4" r="1.4"/><circle cx="3" cy="8" r="1.4"/><circle cx="3" cy="12" r="1.4"/><rect x="6" y="3.2" width="8" height="1.6" rx=".8"/><rect x="6" y="7.2" width="8" height="1.6" rx=".8"/><rect x="6" y="11.2" width="8" height="1.6" rx=".8"/></svg><span class="tt">Pick AI</span></button>
<button class="icon gear" id="gearBtn" title="Sidebar settings"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg><span class="tt">Sidebar settings</span></button>
</div>
<script src="strip-icons.js"></script>
@ -84,26 +82,26 @@
// LLM button: click opens the current default LLM in the left panel.
// Right-click (or the small chevron badge) opens the AI picker menu.
const llmBtn = document.getElementById("llmBtn");
const llmPick = document.getElementById("llmPick");
const llmGlyph = document.getElementById("llmGlyph");
const llmTip = document.getElementById("llmTip");
const llmChev = document.getElementById("llmChev");
llmBtn.addEventListener("click", (e) => {
if (e.target === llmChev) return; // chevron handles its own click
Q && Q.open && Q.open("llm");
});
// Launch button: opens (or toggles) the current AI engine in the panel.
llmBtn.addEventListener("click", () => { Q && Q.open && Q.open("llm"); });
// Right-click on the launch button still opens the picker (power-user shortcut).
llmBtn.addEventListener("contextmenu", (e) => {
e.preventDefault();
const r = llmBtn.getBoundingClientRect();
Q && Q.llmMenu && Q.llmMenu({ x: r.left, y: r.top, width: r.width, height: r.height });
});
llmChev.addEventListener("keydown", (e) => {
if (e.key === "Enter" || e.key === " ") { e.preventDefault(); e.stopPropagation(); const r = llmBtn.getBoundingClientRect(); Q && Q.llmMenu && Q.llmMenu({ x: r.left, y: r.top, width: r.width, height: r.height }); }
});
llmChev.addEventListener("click", (e) => {
e.stopPropagation();
const r = llmBtn.getBoundingClientRect();
// Pick button: a sibling icon that opens the picker overlay. Anchored at
// the pick button so the overlay sits beside it.
llmPick.addEventListener("click", () => {
const r = llmPick.getBoundingClientRect();
Q && Q.llmMenu && Q.llmMenu({ x: r.left, y: r.top, width: r.width, height: r.height });
});
llmPick.addEventListener("keydown", (e) => {
if (e.key === "Enter" || e.key === " ") { e.preventDefault(); const r = llmPick.getBoundingClientRect(); Q && Q.llmMenu && Q.llmMenu({ x: r.left, y: r.top, width: r.width, height: r.height }); }
});
const { BRAND, svgFor: brandForLink, hostOf } = window.StripIcons;
function letterIcon(b, L) { b.classList.add("letter"); b.prepend(document.createTextNode((L.title || "?").slice(0, 1).toUpperCase())); }
// One order for web apps and extension panels (main keeps it); drag an
@ -193,6 +191,7 @@
const engines = (llm && llm.engines) || [];
if (engines.length) {
llmBtn.hidden = false;
llmPick.hidden = false;
llmBtn.classList.toggle("on", !!(llm && llm.open));
const curId = (llm && llm.current) || engines[0].id;
const cur = engines.find((e) => e.id === curId) || engines[0];
@ -210,6 +209,7 @@
}
} else {
llmBtn.hidden = true;
llmPick.hidden = true;
}
}
Q && Q.getState && Q.getState().then(render).catch(() => render(null));