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 <noreply@anthropic.com>
This commit is contained in:
qiujun
2026-08-29 17:57:36 +08:00
co-authored by Claude Opus 5
parent b5827cfd54
commit 0aef702b66
2 changed files with 23 additions and 1 deletions
@@ -36,7 +36,7 @@
/>
</svg>
<span
class="pointer-events-none absolute left-1/2 top-full z-30 mt-2 w-56 -translate-x-1/2 rounded-lg border border-gray-200 bg-white p-3 text-left text-xs text-gray-700 opacity-0 shadow-lg transition-opacity duration-150 group-hover:opacity-100 group-focus:opacity-100 dark:border-dark-600 dark:bg-dark-800 dark:text-dark-200"
class="pointer-events-none absolute left-1/2 top-full z-30 mt-2 hidden w-56 -translate-x-1/2 rounded-lg border border-gray-200 bg-white p-3 text-left text-xs text-gray-700 shadow-lg group-hover:block group-focus:block dark:border-dark-600 dark:bg-dark-800 dark:text-dark-200"
>
<span class="mb-2 block font-medium text-gray-900 dark:text-white">
{{ cacheDetailLabel() }}
@@ -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')
})
})