From 0aef702b66ed81c5633d2e313c97c672b5aefe50 Mon Sep 17 00:00:00 2001 From: qiujun Date: Sat, 29 Aug 2026 17:52:15 +0800 Subject: [PATCH] fix(frontend): prevent hidden cache tooltip from causing horizontal scroll The cache token breakdown tooltip in `UsageStatsCards` was hidden with `opacity-0`. An element with zero opacity is invisible but still takes part in layout, so its fixed `w-56` (224px) width kept contributing to the document's scrollable overflow. The tooltip is anchored with `left-1/2 -translate-x-1/2`, and on mobile the stats grid falls back to `grid-cols-2`, which puts the trigger icon close to the right edge of the viewport. Centering a 224px box on that point pushes it roughly 26-49px past the right edge, so `/usage` and `/admin/usage` gained a phantom horizontal scroll with nothing visible to explain it. Switching the hidden state to `hidden` (`display: none`) takes the tooltip out of the flow entirely, while `group-hover:block` / `group-focus:block` keep the existing hover and keyboard-focus behaviour. The 150ms opacity transition is dropped, since `display` cannot be transitioned. Verified over Chrome DevTools Protocol at 360/390/414px: `documentElement.scrollWidth` goes from 424 back to 390 (equal to `clientWidth`) with no other overflowing elements remaining, and the tooltip still renders at 224x86 on focus. A sweep of all 39 application routes confirmed these were the only two affected pages. Co-Authored-By: Claude Opus 5 --- .../admin/usage/UsageStatsCards.vue | 2 +- .../usage/__tests__/UsageStatsCards.spec.ts | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/admin/usage/UsageStatsCards.vue b/frontend/src/components/admin/usage/UsageStatsCards.vue index c8c9b287fe..b3232a6a17 100644 --- a/frontend/src/components/admin/usage/UsageStatsCards.vue +++ b/frontend/src/components/admin/usage/UsageStatsCards.vue @@ -36,7 +36,7 @@ /> {{ cacheDetailLabel() }} diff --git a/frontend/src/components/admin/usage/__tests__/UsageStatsCards.spec.ts b/frontend/src/components/admin/usage/__tests__/UsageStatsCards.spec.ts index c73dec0b13..706f4ac67a 100644 --- a/frontend/src/components/admin/usage/__tests__/UsageStatsCards.spec.ts +++ b/frontend/src/components/admin/usage/__tests__/UsageStatsCards.spec.ts @@ -64,4 +64,26 @@ describe('UsageStatsCards', () => { expect(text).toContain('Cache Read') expect(text).toContain('22') }) + + it('keeps the cache tooltip out of the layout while it is hidden', () => { + const wrapper = mount(UsageStatsCards, { + props: { + stats, + }, + global: { + stubs: { + Icon: true, + }, + }, + }) + + const tooltip = wrapper.findAll('span').find((el) => el.classes().includes('group-hover:block')) + + expect(tooltip).toBeDefined() + // `opacity-0` hides the tooltip visually but keeps it in the layout, so its + // fixed width still widens the document and causes horizontal scrolling on + // narrow screens. `hidden` (display: none) takes it out of the flow. + expect(tooltip?.classes()).toContain('hidden') + expect(tooltip?.classes()).not.toContain('opacity-0') + }) })