fix(explorer): popup layout polish — portal tooltips, wider two-column grid#71
Conversation
…n grid - TermInfo popups render through a portal on document.body (position: fixed, positioned from the trigger rect, clamped/flipped to stay on screen, closed on scroll/resize). They are no longer clipped by the modal's overflow and never force a scrollbar. Applies app-wide to every info tooltip. - Widen the modal (max-w-2xl -> max-w-3xl); the five property chips now sit on one row (tightened chip spacing), flex-wrap kept for narrow viewports. - Restructure the info block into a two-column grid (Full HM | Shubnikov, Order | Reference axes; parent/settings/convention span full width; Laue class | Chiral). Order: notation -> structure -> properties. - Always show Full HM (was hidden when short == full, e.g. -42m, -1). - Remove the redundant pyro/ferroelectric footnote (kept in the Polar tooltip). Display/layout only; no computed-output change. Verified by driving the app headlessly (Playwright): -42m shows Full HM, chips on one line, no footnote, portal tooltips un-clipped and on-screen incl. short-viewport clamp. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
UI-only polish for the Explorer group popup, mainly improving tooltip behavior and making the modal content denser/wider without changing any computed tensor output.
Changes:
- Render
TermInfotooltips via adocument.bodyportal with fixed positioning to avoid modal clipping/scrollbars. - Widen
OperationsModaland restructure its info + properties layout into a two-column grid; always show Full HM; remove the redundant pyro/ferroelectric footnote. - Document the Explorer popup polish in
CHANGELOG.md.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/components/TermInfo.tsx | Switches tooltip rendering to a fixed-position portal with viewport-based placement and close-on-interaction behavior. |
| src/components/OperationsModal.tsx | Widens the modal and reorganizes the information layout into a responsive two-column grid; always displays Full HM; removes the extra footnote. |
| CHANGELOG.md | Adds an Unreleased “Fixed” entry describing the Explorer popup layout/tooltip changes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const left = Math.min(Math.max(MARGIN, r.left), window.innerWidth - POPUP_WIDTH - MARGIN); | ||
| const spaceBelow = window.innerHeight - r.bottom; | ||
| const candidateTop = spaceBelow >= POPUP_EST_HEIGHT + GAP || spaceBelow >= r.top | ||
| ? r.bottom + GAP | ||
| : r.top - GAP - POPUP_EST_HEIGHT; | ||
| const top = Math.min(Math.max(MARGIN, candidateTop), window.innerHeight - POPUP_EST_HEIGHT - MARGIN); |
There was a problem hiding this comment.
Fixed in e410cb9 — the clamp now applies Math.max(MARGIN, …) outermost (so a negative upper bound can't win) and the popup width shrinks to min(POPUP_WIDTH, vw - 2*MARGIN), so left/top stay ≥ MARGIN at any viewport size.
| style={{ position: 'fixed', top: coords.top, left: coords.left, width: POPUP_WIDTH }} | ||
| className="z-50 bg-paper text-ink border border-ink shadow-xl normal-case tracking-normal p-3 space-y-2 text-left" |
There was a problem hiding this comment.
Fixed in e410cb9 — the popup now gets maxHeight = innerHeight - top - MARGIN with overflow-y: auto, so a tall brief scrolls inside the popup and never overflows the viewport.
- Clamp with MARGIN winning last and shrink the popup to the viewport width, so left/top can never go negative on very narrow screens (Copilot). - Cap the popup to maxHeight = space below `top` with overflow-y auto, so a tall glossary brief scrolls inside the popup instead of overflowing the viewport. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Summary
Display/layout-only polish of the Explorer group popup (no computed-output change).
TermInfopopups now render throughcreatePortal(document.body)withposition: fixed, positioned from the trigger'sgetBoundingClientRect()(below by default, clamped to stay on screen), and close on scroll/resize. They were previouslyabsoluteinside the modal'soverflow-y-autobody, so they got clipped and could force a scrollbar. This is a shared component — the fix applies app-wide to every info tooltip.max-w-2xl→max-w-3xl; the five property chips now fit one row (chip spacing tightened slightly), withflex-wrapkept as the narrow-viewport safety net.-42m,-1), which read as "missing".grid-cols-1 sm:grid-cols-2; Full HM | Shubnikov, Order | Reference axes, then Parent group / Settings / Convention span full width; Properties shows Laue class | Chiral then the chip row. Order: notation → structure → properties → generators → operations.Verification (headless, Playwright)
Drove the running app and screenshotted:
-42mmodal: Full HM shown (4̄2m), two-column grid, five chips on one line, no footnote.Gates
npm run lint(tsc) — cleannpm run test— 1626 passednpm run build— succeedsBase:
81eddd7.🤖 Generated with Claude Code