Skip to content

[codex] Stabilize explorer map layout#202

Merged
rdhyee merged 6 commits into
isamplesorg:mainfrom
rdhyee:codex/issue-199-stable-explorer-map
May 12, 2026
Merged

[codex] Stabilize explorer map layout#202
rdhyee merged 6 commits into
isamplesorg:mainfrom
rdhyee:codex/issue-199-stable-explorer-map

Conversation

@rdhyee
Copy link
Copy Markdown
Contributor

@rdhyee rdhyee commented May 11, 2026

Summary

Fixes #199.

This stabilizes the explorer globe layout so the Cesium container is anchored to viewport height instead of deriving its height from grid-column width. It also reserves bounded space for search status text and the view toolbar so loading/search/table controls cannot move the map frame.

Changes

  • Replaced #cesiumContainer aspect-ratio sizing with --explorer-map-height: clamp(500px, 65vh, 680px).
  • Added a mobile map-height override of clamp(360px, 58vh, 520px).
  • Matched .side-panel max height to the same map-height variable.
  • Added scrollbar-gutter: stable and minmax(0, 1fr) for layout-width stability.
  • Wrapped above-map controls in .explorer-controls, reserved a two-line #searchResults live region, and reserved view-toolbar height so table controls do not shift the table/globe anchor.
  • Added Playwright coverage for desktop and mobile layout stability.

Validation

  • quarto render explorer.qmd
  • node --check tests/playwright/explorer-layout-stability.spec.js
  • env NODE_PATH=/Users/raymondyee/C/src/iSamples/isamplesorg.github.io/node_modules /Users/raymondyee/C/src/iSamples/isamplesorg.github.io/node_modules/.bin/playwright test tests/playwright/explorer-layout-stability.spec.js --project=chromium --reporter=line

The focused Playwright spec passed: 2 tests passed on Chromium.

@rdhyee
Copy link
Copy Markdown
Contributor Author

rdhyee commented May 12, 2026

Codex review — round 1

Self-contained Codex round-1 review (no shared context with author). Verbatim per the iterative-review pattern.


Summary

The fixed map-height strategy is sound, and it directly addresses the vertical jump described in #199. I would not merge this exact revision yet: the rendered Quarto HTML does not match the control DOM the CSS assumes, and the new Playwright spec has the known brittle point-mode settle wait.

Per-ask response

1. Quarto raw-html fence

The fence is right for the <script>/<link>/<style> block. Bare HTML is preserved, but Quarto still parses Markdown inside it: rendered docs/explorer.html wraps several controls in <p> tags, e.g. .search-bar > p > input and #tableControls > p > label + input.

That matters because .search-bar input { flex: 1 } no longer makes the input a flex item, and paragraph margins feed into toolbar/control heights. I would also fence the static app markup, or explicitly neutralize those wrappers.

2. #quarto-document-content override

The selector is probably stable enough for Quarto, but it is broad: title, callout, code blocks, and the app all inherit the wider shell. margin: 0 auto is probably not equivalent inside Quarto’s page grid; the transform is the escape hatch. Cleaner options are Quarto page-layout: full or a page-local app wrapper.

3. Reserved search slot

Two lines covers normal messages: “Searching…”, “No results…”, and short result counts. Long user queries and Search error: ${err.message} can exceed it and will scroll. That is acceptable for layout stability, but three lines would be more forgiving.

4. .view-toolbar { min-height: 50px }

Likely enough on desktop. Risky on narrow mobile when #tableControls is visible and wraps, especially with the rendered <p> wrapper. The mobile spec does not exercise table mode, so this gap is currently untested.

5. Map height vs side panel

No functional issue. CSS Grid’s default stretch should make the side panel occupy the row height up to the matching max-height; if content is short, it may look visually sparse because the panel itself has no background.

6. Mobile coverage

The 390×844 math is correct. I would add a small-phone case, e.g. 320×568 or 390×600, mainly to cover the 360px floor and control wrapping behavior.

7. Spec sample cap brittleness

Yes, switch the wait from 'individual samples' to 'Click one for details'. The cap branch in explorer.qmd omits “individual”, so this can time out under dense views or future data changes.

8. waitForClusterBoot / zoomWatcher

Not a no-op. Awaiting zoomWatcher ensures the OJS cell has completed listener registration and boot hydration. A comment would help; alternatively wait for _suppressHashWrite === false.

9. requestRenderMode = false

Fine for Playwright. Each test gets a fresh page, and this matches existing URL-roundtrip practice.

10. aria-live="polite"

No major concern. Search status changes on explicit search actions, not every keystroke, so it should not be spammy.

11. Other

The largest missing test assertion is the rendered control layout: search input width and mobile table-mode top stability. Also consider deriving expected map heights from computed CSS instead of hard-coded 585 / 489.52.

Verdict

BLOCK

Codex round-1 review (verbatim posted to PR isamplesorg#202 thread) BLOCKed on
two items:

1. Quarto Markdown-parses inside the bare static-layout HTML and wraps
   `<input>` / `<label>` in `<p>` tags (e.g. `.search-bar > p > input`).
   This breaks `.search-bar input { flex: 1 }` and adds paragraph
   margins to control rows. Pre-existing on main, but in-scope here.
   Fix: wrap both the `.explorer-controls` block AND the `.globe-layout`
   + `#tableContainer` block in `{=html}` raw-html fences.

2. Layout-stability spec waited on the substring 'individual samples'
   in `#phaseMsg`, which misses the cap-reached done-state branch
   (`explorer.qmd:1611` — "<N> samples in view (showing M ...)" with
   no "individual" word). Same brittleness Codex flagged on PR isamplesorg#214.
   Switch to 'Click one for details' — common denominator across both
   done-state branches.

Also addressed Codex NITs:

- Added small-phone case (320×568) exercising the clamp-floor branch
  at the 360px floor — the 390×844 case never hits this.
- Replaced hardcoded `585` / `489.52` heights with a probe-element
  approach: a hidden `<div style="height: var(--explorer-map-height)">`
  whose `getBoundingClientRect()` resolves the `clamp(...)` to a real
  px value. `getComputedStyle().getPropertyValue('--explorer-map-height')`
  returns the unresolved `clamp(...)` literal, not a px value (this is
  why my first attempt failed with NaN).
- Documented the `waitForClusterBoot` `value('zoomWatcher')` await as
  intentional synchronization (cell finishes => listeners registered),
  not a stray return value.

Kept (per Codex review):
- `requestRenderMode = false` mutation pattern matches URL-roundtrip
  spec, no cleanup needed (fresh page per test).
- `#searchResults` 2-line reserved slot — Codex acknowledged 3 lines
  would be more forgiving but the 2-line policy is acceptable for
  layout stability.

Verification: all 3 layout-stability tests pass in ~23s. All 5
url-roundtrip specs pass against the modified explorer.qmd (no
regression in the recently-landed isamplesorg#214 contract).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rdhyee
Copy link
Copy Markdown
Contributor Author

rdhyee commented May 12, 2026

Codex review — round 2

Verbatim Codex round-2 review. LGTM, ready to merge.

Codex's only non-blocking nit (consistency: desktop test still hardcoded 585 while mobile cases use the probe) addressed in a follow-up commit — extracted a resolveMapHeightPx(page) helper and used it from all three tests.


Summary

No block-level issues found in the round-2 diff. The raw HTML fence boundaries look right, the probe-element approach is appropriate for resolving the CSS clamp(), and the small-phone test covers the intended floor branch.

I did not rerun Playwright locally; this is a static re-review of the checked-out files.

Per-ask response

1. P-wrap fix scope

The boundary is right. Static interactive HTML is inside the two {=html} fences:

  • explorer.qmd: search controls, view toggle, label, and maxSamples input.
  • explorer.qmd: globe layout, side panel filters, share button, and table pager buttons.

The only other interactive-looking markup found by rg is inside OJS/JS template strings, so Pandoc will not p-wrap it.

2. Probe-element approach

Yes, this is the right idiom here. getPropertyValue('--explorer-map-height') returns the unresolved custom property, while a hidden element gives the used pixel height after var() + clamp() resolution.

The probe and #cesiumContainer should resolve identically for the current CSS because the value only depends on root variables and viewport units. They could diverge only if this later changes to context-dependent sizing, container units, inherited overrides, padding/borders, or min/max constraints on the real element.

3. Small-phone test correctness

Correct. At 320×568, the mobile media query applies, 58vh = 329.44px, and clamp(360px, 58vh, 520px) resolves to 360px.

expect(expectedMapHeight).toBe(360) is fine in Chromium for this floor branch. A tolerance would be slightly more consistent with the rest of the spec, but I would not block on it.

4. PR title [codex]

I would strip [codex] before squash merge unless the repo intentionally uses that convention. Provenance is better kept in PR metadata; commit history usually reads better without tool prefixes.

5. Anything else

One non-blocking nit: the desktop assertion still hardcodes 585 at explorer-layout-stability.spec.js. The mobile cases now use the probe, so the desktop case could use the same helper for consistency.

Verdict

LGTM, ready to merge

Codex round-2 review noted the desktop test still hardcoded `585` while
the mobile cases switched to a probe-element approach. Extract the
probe inline into `resolveMapHeightPx(page)` and use it from all three
tests — desktop, mobile, small-phone.

Desktop assertion now derives expected height the same way as the
mobile cases (probe of `var(--explorer-map-height)` → measured px) and
sanity-bounds the result to the desktop clamp range [500, 680].

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rdhyee rdhyee marked this pull request as ready for review May 12, 2026 23:13
@rdhyee rdhyee merged commit 058230d into isamplesorg:main May 12, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

explorer: map position and size jump between views because surrounding elements shift

1 participant