Skip to content

Extract a shared viewport-clamped popover wrapper; NetworkSwitcher and SettingsPopover both overflow mobile with no clamp at all #3945

Description

@JSONbored

Context

Two header controls render a fixed-width Radix PopoverContent with no viewport clamp at all: NetworkSwitcher (apps/ui/src/components/metagraphed/network-switcher.tsx:84, className="w-80 p-3 space-y-3" — a fixed 320px panel) and SettingsPopover (apps/ui/src/components/metagraphed/settings-popover.tsx:40, className="w-72 p-3 space-y-4" — a fixed 288px panel). Neither has a max-w-[calc(100vw-...)] or w-[min(...)] fallback, and the shared underlying primitive (apps/ui/src/components/ui/popover.tsx:22, base class w-72) doesn't clamp either. Both trigger buttons render unconditionally in the always-visible header row (app-shell.tsx:144-163, a plain flex items-center gap-1 div, no responsive hiding). On a 375px viewport, align="end" anchors the panel near the trigger; Radix's collision-avoidance can reposition the panel but does not shrink its fixed width, so on narrow devices the panel overflows the viewport edge. This is the same bug class already tracked for NavOmnibox under #3454/#3457, except neither of these two components even has that issue's partial clamp fallback.

Requirement

Both NetworkSwitcher and SettingsPopover's popover panels must never render wider than the viewport, at any width down to 320px. Rather than patching each one's className individually (which would leave a third copy-pasted clamp to keep in sync if a future popover is added), extract one shared, viewport-clamped popover-content wrapper and have both components use it.

Deliverable

  • New shared primitive: a thin wrapper around the existing apps/ui/src/components/ui/popover.tsx PopoverContent — e.g. ClampedPopoverContent — that always applies a max-w-[calc(100vw-1.5rem)] (or equivalent w-[min(20rem,calc(100vw-1.5rem))]) class alongside whatever fixed width the caller passes, so the fixed width becomes a maximum, not the actual rendered width on narrow viewports.
  • Files to change: apps/ui/src/components/metagraphed/network-switcher.tsx:84 and apps/ui/src/components/metagraphed/settings-popover.tsx:40 — both PopoverContent usages swap to the new wrapper (or get the clamp class added directly, if a shared wrapper is judged like overkill for two call sites — reviewer's call, but a shared primitive is preferred since a third consumer is likely).
  • What "done" looks like concretely: at 320-375px, opening either popover shows the full panel content within the viewport bounds, with no horizontal scroll and no content hidden behind the device edge.

Acceptance criteria

  • network-switcher.tsx and settings-popover.tsx both appear in the diff
  • At 320px and 375px viewport widths, neither popover's panel extends past the left or right viewport edge
  • Desktop/tablet rendering of both popovers is visually unchanged (same fixed width where it already fits)
  • No change to either popover's content (menu items, settings toggles) — this is a container-width fix only
  • Includes a before/after screenshot table at mobile (375px) and tablet (768px), both themes, for both popovers, per the repo's UI-PR requirement for any change touching visual output
  • Since opening a popover is itself a click-triggered reveal a static "page load" screenshot can't show, include a short screen recording (GIF/MP4) of each popover opening at 375px alongside the static before/after shots

Non-goals

Size

Size: S — keep this PR small (aim for ≤10 files / ≤1000 LOC).

Part of #2542.

Metadata

Metadata

Assignees

No one assigned

    Labels

    gittensor:bugGittensor-scored bug fix or unsolicited PR — scores a 0.05x multiplier.

    Projects

    Status
    Todo

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions