From d4b05a0d9024413ee62bd14e064ee4b0cdf5a307 Mon Sep 17 00:00:00 2001 From: amosblomqvist Date: Mon, 14 Sep 2026 10:04:20 +0300 Subject: [PATCH] Stats bar round 1 (owner): model-control dropdown discipline for the stats popover Same treatment the model/thinking controls got (df4433f): the per-turn stats popover now closes on any pointerdown outside the bar and on Escape. Also centered over the stats bar (left-1/2 -translate-x-1/2) instead of left-aligning with the quiz box, which looked odd. Verified live: popover centered over the bar (centers within 2px); Escape closes; click outside closes; click inside stays open. --- components/stats-bar.tsx | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/components/stats-bar.tsx b/components/stats-bar.tsx index 7716ca7..819416a 100644 --- a/components/stats-bar.tsx +++ b/components/stats-bar.tsx @@ -1,6 +1,6 @@ "use client"; -import { useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { contextWindow, sessionCost, turnCost, type ChatSettings, type TurnUsage } from "@/src/core"; import { formatTokens, formatUsd, prettyModel } from "@/components/usage-format"; import { ModelControl } from "@/components/model-picker"; @@ -33,6 +33,24 @@ export function StatsBar({ onSettingsSaved: (settings: ChatSettings) => void; }) { const [open, setOpen] = useState(false); + // Same dropdown discipline as the model control (owner, df4433f treatment, + // stats round 1): close on any pointerdown outside the bar or on Escape. + const barRef = useRef(null); + useEffect(() => { + if (!open) return; + const onPointerDown = (e: PointerEvent) => { + if (barRef.current && !barRef.current.contains(e.target as Node)) setOpen(false); + }; + const onKeyDown = (e: KeyboardEvent) => { + if (e.key === "Escape") setOpen(false); + }; + document.addEventListener("pointerdown", onPointerDown); + document.addEventListener("keydown", onKeyDown); + return () => { + document.removeEventListener("pointerdown", onPointerDown); + document.removeEventListener("keydown", onKeyDown); + }; + }, [open]); const ctx = contextWindow({ turns }); const { cost, unpriced } = sessionCost({ turns }); // Honest cost: show dollars only when at least one turn priced; @@ -48,6 +66,7 @@ export function StatsBar({ // (so its transparent gradient area never blocks scrolling) — this row // must re-enable events or every control on it is dead (the model- // control wave caught this live: buttons rendered, clicks never landed). + ref={barRef} className="pointer-events-auto relative flex items-center justify-between gap-3 px-3 pt-1.5 text-xs text-muted-foreground" >