QoL: borderless cards, PWA cache strategy, avatar dropdown crash, wide→narrow overflow - #13
Merged
Merged
Conversation
PWA shell updates were sometimes stuck on the previous deploy because both
Firebase Hosting (no-cache for HTML/SW) and the SW (precached index.html)
served stale content.
- firebase/firebase.json: explicit `no-store, no-cache, must-revalidate,
max-age=0` for /index.html, /sw.js, /workbox-*.js, /registerSW.js, and
/manifest.webmanifest. Hashed assets still get immutable 1y cache.
- vite.config.ts: drop `*.html` from precache; override the plugin's
default `navigateFallback: "index.html"` (which would emit a broken
`createHandlerBoundToURL("index.html")` route that throws at install
time once *.html isn't precached); add a NetworkFirst handler for
`request.mode === "navigate"` with an explicit `/__/auth/` denylist so
the SW doesn't intercept Firebase Auth's redirect handler;
skipWaiting + clientsClaim so a fresh deploy lands on the next nav
without a manual reload prompt.
- src/shared/api/firebase.ts: switch to `initializeFirestore({
localCache: memoryLocalCache() })`. The IDB cache was a foot-gun for a
PWA — stale docs survived sign-out on shared machines, and the IDB
layer occasionally held a write lock that kept a freshly-deployed
shell stuck reading old data. Memory cache is rebuilt each page load
— predictable and ACL-safe.
…roup Clicking the avatar in the app bar opened a popover that immediately threw `[kobalte]: useMenuGroupContext must be used within a Menu.Group` — DropdownMenuLabel rendered Kobalte's `Menu.GroupLabel` directly inside `DropdownMenuContent` with no surrounding `Menu.Group`, so the context hook had nothing to read. Wrap the GroupLabel in `KMenu.Group` inside the primitive so callers keep the same `<DropdownMenuLabel>` ergonomics. The wrapper adds one extra `<div role="group">` to the DOM; no padding/layout change since the inner span still owns the spacing.
UI polish + responsive fixes: - Card / ShotTile: drop the visible 1px border in favour of shadow-sm + a soft ring (black/0.04 light, white/0.06 dark). Hover on interactive cards lifts to shadow-md. Card radius bumps to xl. - App bar: remove the "Doctorina · Screenshots" word-mark — the tab title + favicon already brand the app. Just the dot stays (plus the FAKE chip in fake-backend mode). The link itself keeps a 36-px tap area so dropping the text didn't shrink the click target to a 10×10 dot. - App bar / layout: harden the wide→narrow resize path. Add `min-w-0` to the app-bar flex container and nav, `shrink-0` to the brand / back-link / right cluster, and `overflow-x-clip` + `min-w-0` on the layout root so an inner flex child measuring its min-content for one frame can't push the page wider than the viewport. `clip` is chosen over `hidden` so the sticky AppBar keeps working. - Run page: the implicit grid track on `<div class="grid gap-5">` was sizing to its content's min-width, which at 320px viewport let the Run-header card overflow ~64 px past the right edge (clipped silently by overflow-x-clip). Switch to `grid-cols-1 min-w-0` so the column shrinks. Branch chip in RunHeader also gets `max-w-[9rem] sm:max-w-[14rem]` so the chip itself fits at 320 px. - Run card: language pills keep `select-none` on the decorative per-element spans; Badge variant stays SELECTABLE (we reverted the earlier base-level `select-none` because branch names, PR numbers, and commit SHAs render through Badge and users copy them).
|
Visit the preview URL for this PR (updated for commit f80e5fc): https://doctorina-test--pr13-feat-qol-pwa-cards-a-ile7u211.web.app (expires Tue, 09 Jun 2026 08:54:18 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 Sign: 940779a7026f52ecc13c172c30df0d2af2c19e77 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Quality-of-life sweep prompted by three user reports + a multi-agent review pass.
Three commits, three concerns:
fix(deploy)— PWA shell updates were stuckfirebase/firebase.json: explicitno-store, no-cache, must-revalidate, max-age=0for/index.html,/sw.js,/workbox-*.js,/registerSW.js,/manifest.webmanifest. Hashed assets keep their immutable 1-year cache.vite.config.ts: drop*.htmlfrom precache, override the plugin's defaultnavigateFallback: "index.html"(which would emitcreateHandlerBoundToURL("index.html")— a route that throws at install once*.htmlisn't precached), add a NetworkFirst handler forrequest.mode === "navigate"that explicitly skips/__/auth/so Firebase Auth's redirect handler is untouched.skipWaiting+clientsClaimso a deploy lands on the next navigation.src/shared/api/firebase.ts: switch toinitializeFirestore({ localCache: memoryLocalCache() })— the IDB cache is a foot-gun for a PWA (stale docs survive sign-out on shared machines; write lock kept the freshly-deployed shell reading old data). Memory cache is rebuilt each load.fix(ui)— avatar dropdown crashedDropdownMenuLabelrendered Kobalte'sMenu.GroupLabeldirectly insideDropdownMenuContentwith no surroundingMenu.Group, so opening the avatar menu immediately threwuseMenuGroupContext must be used within a Menu.Group. Wrapped the GroupLabel inKMenu.Groupinside the primitive. Same caller ergonomics.feat(qol)— UI polish + responsiveshadow-sm+ a soft ring (black/0.04light,white/0.06dark). Card radius bumps toxl. Interactive cards lift toshadow-mdon hover.min-w-0on app-bar flex container + nav;shrink-0on brand, back-link, and right cluster;overflow-x-clip+min-w-0on layout root (clip, nothidden, so sticky still works).<div class="grid gap-5">was sizing to its content's min-width, letting the RunHeader card overflow ~64 px past the viewport. Switch togrid-cols-1 min-w-0. Branch chip getsmax-w-[9rem] sm:max-w-[14rem].select-noneinto the Badge variant, which silently broke copying branch names / PR # / commit SHAs. Reverted;select-nonelives on the decorative language pills inrun-card.tsxwhere it belongs.Multi-agent review pass
Spawned 3 reviewers in parallel (project-rules, correctness, CSS/responsive/a11y) before committing. Findings folded back into the diff:
NavigationRoute(createHandlerBoundToURL("/index.html"))even after I removednavigateFallback, because vite-plugin-pwa silently defaults it to"index.html". Confirmed by readingnode_modules/vite-plugin-pwa/dist/index.js:838. Fixed by settingnavigateFallback: undefinedexplicitly.select-noneon Badge variant base blocked copying. Reverted, moved to specific decorative chips./__/auth/*. Added denylist to itsurlPattern.:where(...) ::selectionrule was dead because of cascade order. Dropped (the existinguser-select: noneon interactive roles already covers it).overflow-x-clipwas hiding a real card-overflow at 320px on the run page. Fixed the underlying grid track sizing instead of just hiding it.Test plan
bun run check(Biome) — cleanbun run typecheck— cleanbun run test— 140/140bun run build— generated SW grepped to confirmNavigationRouteis gone and/__/auth/is denylistedCache-Control: no-storeon/index.html,/sw.js)/__/auth/handlerredirect is NOT intercepted by the SW🤖 Generated with Claude Code