From b62363684552eb58607e8bf61cb728f430d27a08 Mon Sep 17 00:00:00 2001 From: Josh Robertson Date: Thu, 15 Oct 2026 13:49:42 -0400 Subject: [PATCH 1/5] fix(web): limit bars with many accounts no longer clip names to one letter --- .../components/usage/UsageLimitsPooled.tsx | 52 +++++++++++++++---- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/apps/web/src/components/usage/UsageLimitsPooled.tsx b/apps/web/src/components/usage/UsageLimitsPooled.tsx index b8603d30af73..bf1ac08ec68b 100644 --- a/apps/web/src/components/usage/UsageLimitsPooled.tsx +++ b/apps/web/src/components/usage/UsageLimitsPooled.tsx @@ -14,10 +14,11 @@ import { remainingPercent, } from "@t3tools/shared/usageLimits"; import { AlertTriangleIcon, ExternalLinkIcon, TicketIcon } from "lucide-react"; -import { Fragment, type ReactNode, useState } from "react"; +import { Fragment, type ReactNode, useCallback, useState } from "react"; import { ensureLocalApi } from "../../localApi"; import { usePrimarySettings } from "../../hooks/useSettings"; +import { observeResize } from "../../lib/observeResize"; import { cn } from "../../lib/utils"; import { formatUpcomingTimestamp } from "../../timestampFormat"; import { ProviderInstanceIcon } from "../chat/ProviderInstanceIcon"; @@ -231,6 +232,7 @@ function PoolSegment({ color, now, index, + labeled, showAccountName, }: { readonly account: LimitAccount; @@ -240,6 +242,8 @@ function PoolSegment({ readonly now: number; /** 1-based position in the bar, shown on the strip and its legend row to tie them together. */ readonly index: number; + /** The segment has room for its own label; otherwise it shows its position and a legend row. */ + readonly labeled: boolean; readonly showAccountName: boolean; }) { const [open, setOpen] = useState(false); @@ -255,7 +259,10 @@ function PoolSegment({ type="button" style={{ gridColumn: index, gridRow: 1 }} aria-label={`${account.displayName ?? (account.email ? accountInitials(account.email) : account.driver)}: ${remaining}% left${resetsIn ? `, ${resetsIn}` : ""}${credits ? `, ${credits} reset ${credits === 1 ? "credit" : "credits"} banked` : ""}`} - className="relative h-5 min-w-0 cursor-pointer overflow-hidden rounded-md bg-muted text-start outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background data-[popup-open]:ring-1 data-[popup-open]:ring-inset data-[popup-open]:ring-border @2xl/pool:h-8" + className={cn( + "relative min-w-0 cursor-pointer overflow-hidden rounded-md bg-muted text-start outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background data-[popup-open]:ring-1 data-[popup-open]:ring-inset data-[popup-open]:ring-border", + labeled ? "h-8" : "h-5", + )} /> } > @@ -278,11 +285,19 @@ function PoolSegment({ ) : null} {index} -
+
{showAccountName ? (
- + {labeled ? null : ( + + )} {account.redeem ? ( } - className="min-w-0 @2xl/pool:hidden" + className="min-w-0" > [reset.member.account.key, reset])); + const columns = pool.columns.length; + const [labeled, setLabeled] = useState(false); + const observeWidth = useCallback( + (bar: HTMLDivElement) => + observeResize(bar, ([entry]) => { + if (entry) setLabeled(entry.contentRect.width >= columns * LABELED_SEGMENT_MIN_WIDTH); + }), + [columns], + ); return ( -
+
1} /> ) : null, From b28307ce44dc24272c9428a80202b1e811958abd Mon Sep 17 00:00:00 2001 From: Josh Robertson Date: Thu, 15 Oct 2026 14:06:36 -0400 Subject: [PATCH 2/5] fix(web): measure the limits bar without a ResizeObserver loop --- apps/web/src/components/usage/UsageLimitsPooled.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/apps/web/src/components/usage/UsageLimitsPooled.tsx b/apps/web/src/components/usage/UsageLimitsPooled.tsx index bf1ac08ec68b..2b3ae6573212 100644 --- a/apps/web/src/components/usage/UsageLimitsPooled.tsx +++ b/apps/web/src/components/usage/UsageLimitsPooled.tsx @@ -471,8 +471,8 @@ const LABELED_SEGMENT_MIN_WIDTH = 224; * When every segment has room, each carries its own label. Otherwise the bar * is a bare strip and a legend below lists the accounts in the same order; * both open the same popover. Room depends on the account count as well as - * the bar's width, so the bar measures itself rather than using a container - * query. + * the bar's width, so the bar measures its width rather than using a + * container query. */ function PoolBar({ pool, @@ -494,7 +494,9 @@ function PoolBar({ [columns], ); return ( -
+
+ {/* Empty so its size never changes with the layout: measuring the bar itself would loop. */} +
Date: Thu, 15 Oct 2026 15:56:25 -0400 Subject: [PATCH 3/5] fix(web): count the gaps between limit segments when choosing labels --- apps/web/src/components/usage/UsageLimitsPooled.tsx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/apps/web/src/components/usage/UsageLimitsPooled.tsx b/apps/web/src/components/usage/UsageLimitsPooled.tsx index 2b3ae6573212..cf8800b2a773 100644 --- a/apps/web/src/components/usage/UsageLimitsPooled.tsx +++ b/apps/web/src/components/usage/UsageLimitsPooled.tsx @@ -14,7 +14,7 @@ import { remainingPercent, } from "@t3tools/shared/usageLimits"; import { AlertTriangleIcon, ExternalLinkIcon, TicketIcon } from "lucide-react"; -import { Fragment, type ReactNode, useCallback, useState } from "react"; +import { Fragment, type ReactNode, useCallback, useRef, useState } from "react"; import { ensureLocalApi } from "../../localApi"; import { usePrimarySettings } from "../../hooks/useSettings"; @@ -486,10 +486,14 @@ function PoolBar({ const restores = new Map(pool.resets.map((reset) => [reset.member.account.key, reset])); const columns = pool.columns.length; const [labeled, setLabeled] = useState(false); + const gridRef = useRef(null); const observeWidth = useCallback( - (bar: HTMLDivElement) => - observeResize(bar, ([entry]) => { - if (entry) setLabeled(entry.contentRect.width >= columns * LABELED_SEGMENT_MIN_WIDTH); + (probe: HTMLDivElement) => + observeResize(probe, ([entry]) => { + if (!entry || !gridRef.current) return; + const gap = Number.parseFloat(getComputedStyle(gridRef.current).columnGap) || 0; + const segmentWidth = (entry.contentRect.width - gap * (columns - 1)) / columns; + setLabeled(segmentWidth >= LABELED_SEGMENT_MIN_WIDTH); }), [columns], ); @@ -498,6 +502,7 @@ function PoolBar({ {/* Empty so its size never changes with the layout: measuring the bar itself would loop. */}
From 57d4f1af23f8b2a615ed416ee46089df77adda6a Mon Sep 17 00:00:00 2001 From: Josh Robertson Date: Thu, 15 Oct 2026 15:57:29 -0400 Subject: [PATCH 4/5] fix(web): drop aria-hidden from the empty limits bar probe --- apps/web/src/components/usage/UsageLimitsPooled.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/components/usage/UsageLimitsPooled.tsx b/apps/web/src/components/usage/UsageLimitsPooled.tsx index cf8800b2a773..d2569005422e 100644 --- a/apps/web/src/components/usage/UsageLimitsPooled.tsx +++ b/apps/web/src/components/usage/UsageLimitsPooled.tsx @@ -500,7 +500,7 @@ function PoolBar({ return (
{/* Empty so its size never changes with the layout: measuring the bar itself would loop. */} -
+
Date: Mon, 19 Oct 2026 15:42:38 +0000 Subject: [PATCH 5/5] fix(web): measure pooled usage before first paint --- apps/web/src/components/usage/UsageLimitsPooled.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/src/components/usage/UsageLimitsPooled.tsx b/apps/web/src/components/usage/UsageLimitsPooled.tsx index 8ff468851c5a..2c393ad982c6 100644 --- a/apps/web/src/components/usage/UsageLimitsPooled.tsx +++ b/apps/web/src/components/usage/UsageLimitsPooled.tsx @@ -14,7 +14,7 @@ import { remainingPercent, } from "@t3tools/shared/usageLimits"; import { AlertTriangleIcon, ExternalLinkIcon, TicketIcon } from "lucide-react"; -import { Fragment, type ReactNode, useEffect, useRef, useState } from "react"; +import { Fragment, type ReactNode, useLayoutEffect, useRef, useState } from "react"; import { ensureLocalApi } from "../../localApi"; import { usePrimarySettings } from "../../hooks/useSettings"; @@ -451,7 +451,7 @@ function PoolBar({ const [dimensions, setDimensions] = useState({ width: 0, gap: 0 }); const probeRef = useRef(null); const gridRef = useRef(null); - useEffect(() => { + useLayoutEffect(() => { const probe = probeRef.current; const grid = gridRef.current; if (!probe || !grid) return;