From 6b83d3248bc46849b2c7aa922fe13c375e649810 Mon Sep 17 00:00:00 2001 From: amosblomqvist Date: Fri, 25 Sep 2026 02:26:37 +0300 Subject: [PATCH] Tooltip subtlety round: 500ms rest delay, quiet chip, parens suffixes, drops + trims MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Owner round 2026-09-25, over 09c0f6e. The wave's tooltips read as distracting; this round makes them quiet: - Delay: TOOLTIP_DELAY_MS = 500 in the primitive — tooltips appear when you pause on a control, never in passing (Radix focus-opens stay instant by design; keyboard users don't wait). - Vanish on leave: disableHoverableContent — the chip is un-hoverable, so the instant the cursor leaves the trigger it's gone, even mid-move onto the chip's own pixels. - Look: bg-accent (#2a2a2a, the hover-chip tone) instead of the white bg-foreground slab; 11px; px-2 py-1; arrow culled (nothing purely decorative); text-foreground/85. - Suffix: parentheses, not em-dash — "Dictate (⌘D)"; the registry source unchanged (still override-aware). - Drops (owner-selected): send square, start square, stats summary — the icons/numbers describe themselves. - Home logo kept but to the RIGHT with its real shortcut "Home (⌘G)" (jump-graph routes to /, the same destination). - Trims: "Model selector (⌘K)", "Thinking level", "Graph costs — click for details", "How much of this session isn't mapped yet". - Added: Import Notes gets "Import notes into the graph" — the one button whose destination wasn't obvious. Pins: TOOLTIP_DELAY_MS=500; hintText parens expectations updated. Live-verified on :3001 — 508ms hover delay measured, close within 10ms of pointerout, chip styles probed (rgb(42,42,42), 11px, 4px/8px), arrow gone, all new labels + sides confirmed, drops carry no tooltip and no aria-describedby. --- components/composer.tsx | 20 ++++++----------- components/extraction-coverage.tsx | 5 ++--- components/graph-view.tsx | 28 ++++++++++++++--------- components/home.tsx | 14 ++++-------- components/model-picker.tsx | 11 ++++----- components/sidebar.tsx | 10 ++++++++- components/stats-bar.tsx | 36 +++++++++++++----------------- components/ui/hint.tsx | 11 ++++----- components/ui/tooltip.tsx | 31 ++++++++++++++++++++----- tests/tooltip-mechanism.test.tsx | 19 +++++++++++----- 10 files changed, 105 insertions(+), 80 deletions(-) diff --git a/components/composer.tsx b/components/composer.tsx index 93b614b..ce766e4 100644 --- a/components/composer.tsx +++ b/components/composer.tsx @@ -133,18 +133,13 @@ export function Composer({ ) : ( - - - )} ); diff --git a/components/extraction-coverage.tsx b/components/extraction-coverage.tsx index f4e05fe..5a7cd8f 100644 --- a/components/extraction-coverage.tsx +++ b/components/extraction-coverage.tsx @@ -292,9 +292,8 @@ export function CoverageRing({ chatId, refreshKey = 0 }: { chatId: string; refre return (
+ + {importing ? "Importing…" : "Import notes…"} + +
{!isEmpty && ( // Rendering settings — own component; the gear toggles it. The diff --git a/components/home.tsx b/components/home.tsx index cbd7a0c..2161978 100644 --- a/components/home.tsx +++ b/components/home.tsx @@ -5,7 +5,6 @@ import { useRouter } from "next/navigation"; import { CornerDownLeftIcon } from "lucide-react"; import { GraphView } from "@/components/graph-view"; import { SetupDialog } from "@/components/setup-dialog"; -import { Hint } from "@/components/ui/hint"; import { useStrongKeyless, useZeroKeys, ZeroKeysPill } from "@/components/setup-cta"; import { useDefaultSettings } from "@/components/default-settings"; import { DictationBar, useDictation } from "@/components/dictation"; @@ -177,21 +176,16 @@ export function Home({ initialSettings, initialConfigured }: { initialSettings: rows={1} className="field-sizing-content lh-input max-h-48 min-h-10 flex-1 resize-none bg-transparent px-2.5 py-2 outline-none placeholder:text-muted-foreground" /> - - - + {/* Same as the chat view's under-composer stats bar (owner) — no session yet, so the LEFT side renders nothing (wave 7 sweep) diff --git a/components/model-picker.tsx b/components/model-picker.tsx index 5f4c02b..15d4536 100644 --- a/components/model-picker.tsx +++ b/components/model-picker.tsx @@ -254,9 +254,10 @@ export function ModelControl() { return (
@@ -276,8 +277,8 @@ export function ModelControl() { - + {/* No tooltip — the numbers describe themselves and the popover + speaks on click (owner, subtlety round 2026-09-25). */} + {open && (
) { return ( @@ -19,9 +32,16 @@ function TooltipProvider({ } function Tooltip({ + disableHoverableContent = true, ...props }: React.ComponentProps) { - return + return ( + + ) } function TooltipTrigger({ @@ -32,7 +52,7 @@ function TooltipTrigger({ function TooltipContent({ className, - sideOffset = 0, + sideOffset = 6, children, ...props }: React.ComponentProps) { @@ -42,16 +62,15 @@ function TooltipContent({ data-slot="tooltip-content" sideOffset={sideOffset} className={cn( - "z-50 w-fit origin-(--radix-tooltip-content-transform-origin) animate-in rounded-md bg-foreground px-3 py-1.5 text-xs text-balance text-background fade-in-0 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95", + "z-50 w-fit origin-(--radix-tooltip-content-transform-origin) animate-in rounded-md bg-accent px-2 py-1 text-[11px] text-foreground/85 text-balance fade-in-0 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95", className )} {...props} > {children} - ) } -export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } +export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } \ No newline at end of file diff --git a/tests/tooltip-mechanism.test.tsx b/tests/tooltip-mechanism.test.tsx index 0339384..0e838b0 100644 --- a/tests/tooltip-mechanism.test.tsx +++ b/tests/tooltip-mechanism.test.tsx @@ -17,18 +17,19 @@ import { describe, it } from "node:test"; import { createElement } from "react"; import { renderToStaticMarkup } from "react-dom/server"; import { Hint, hintText } from "../components/ui/hint.tsx"; +import { TOOLTIP_DELAY_MS } from "../components/ui/tooltip.tsx"; import { AUTO_UPDATE_HINT } from "../components/settings/settings-dialog.tsx"; -describe("hintText — the em-dash composition", () => { +describe("hintText — the parenthesized composition", () => { it("a registry action appends the LIVE binding (override-aware source)", () => { - assert.equal(hintText("Dictate", "toggle-dictation"), "Dictate — ⌘D"); - assert.equal(hintText("Settings", "open-settings"), "Settings — ⌘,"); - assert.equal(hintText("Search sessions", "sessions-search"), "Search sessions — ⌘⇧F"); + assert.equal(hintText("Dictate", "toggle-dictation"), "Dictate (⌘D)"); + assert.equal(hintText("Settings", "open-settings"), "Settings (⌘,)"); + assert.equal(hintText("Search sessions", "sessions-search"), "Search sessions (⌘⇧F)"); }); it("surface-owned keys ride the binding prop (no registry entry)", () => { - assert.equal(hintText("Close", undefined, "escape"), "Close — Esc"); - assert.equal(hintText("Send", undefined, "enter"), "Send — ↵"); + assert.equal(hintText("Close", undefined, "escape"), "Close (Esc)"); + assert.equal(hintText("Send", undefined, "enter"), "Send (↵)"); }); it("no shortcut = the label alone, no dangling dash", () => { @@ -37,6 +38,12 @@ describe("hintText — the em-dash composition", () => { }); }); +describe("subtlety round pins (owner 2026-09-25)", () => { + it("the rest delay is 500ms — tooltips appear on pause, never in passing", () => { + assert.equal(TOOLTIP_DELAY_MS, 500); + }); +}); + describe("spot-pins: the dev-speak cull (owner copy review at merge)", () => { it("the auto-update hint is honest user language — no stream jargon", () => { assert.equal(AUTO_UPDATE_HINT, "Automatic updates arrive in an upcoming release");