Skip to content

Rework Intro page into a scroll-snapped hero with interactive map - #717

Draft
Shikhar16078 wants to merge 4 commits into
masterfrom
feat/rework-hero-section
Draft

Rework Intro page into a scroll-snapped hero with interactive map#717
Shikhar16078 wants to merge 4 commits into
masterfrom
feat/rework-hero-section

Conversation

@Shikhar16078

Copy link
Copy Markdown

No linked issue — this came out of an interactive design/iteration session, not a tracked issue.

Summary: Replaces the old Intro page (a single ~80vh block with logo, welcome text, and a plain list of "Common Objectives" links) with three full-viewport, scroll-snapped sections: a hero intro, a live interactive world map, and a redesigned Common Objectives grid — so the landing page lets people explore the map immediately instead of only linking out to it.

Changes

  • User experience
    • Intro page is now three full-viewport sections (IntroScrollContainer/IntroScrollSection) that snap section-to-section on scroll, each fading/sliding in via a new useRevealOnScroll hook (the hero itself skips the animation since it's visible on first paint).
    • A dot nav (bottom-right) and a bouncing "scroll down" chevron on the hero let users jump directly to any section — scroll-snap sections otherwise have no visible affordance telling users there's more below.
    • The map section embeds EntityMap directly (pan/zoom/click-to-pin, same component the Data page uses), showing 60 languages at rest and progressively revealing up to 300 as the user zooms in, so the view is never too sparse or an overwhelming ~8,500-entity blob.
    • Common Objectives rows (label + input + GO button) now align into a consistent grid instead of drifting to different horizontal positions depending on label length, and use a pill style consistent with the rest of the app.
  • Logical changes
    • PageNavBar now publishes its real rendered height as a --navbar-height CSS var (measured via ResizeObserver, not hardcoded, since it wraps to two rows on narrow viewports) so the hero can size sections as calc(100vh - navbar).
    • EntityMap gained an optional onZoomChange callback prop (backward compatible — the Data page's existing usage doesn't pass it) so the map section can react to zoom level.
  • Refactors
    • None beyond what's described above; CommonObjectives.tsx was restructured internally (grid + display: contents trick) but its external API/usage is unchanged.

Out of scope/Future work: Common Objectives' navigation still does a full page reload (window.location.href) rather than SPA navigation — left as-is since it predates this change and wasn't part of the ask. The dot nav stays visible (fixed position) even once scrolled past the hero into the footer — minor, not fixed here.

Test Plan and Screenshots

How to test the changes in this PR: npm run dev, visit /intro. Scroll through all three sections (or use the dot nav / chevron), try the map's zoom controls and click a territory to pin it, submit a Common Objectives row via click and via Enter key, and check dark mode + a narrow/short viewport (e.g. mobile emulation) where hero content can exceed one screen.

Introduction

image

Interactive Map

image

Common Objectives

image

Checklist

Summary

  • Clear description of what and why
  • Scope kept focused; note follow-ups if any
  • Set yourself as assignee
  • Mention the issue — no issue exists yet, see note above

Testing

  • npm run lint
  • npm run build
  • npm run test
    • Added IntersectionObserver stub to src/tests/setupTests.ts for the new useRevealOnScroll hook
  • npm run dev -- tried out the website directly
    • Include screenshots — see Introduction/Interactive Map/Common Objectives above
    • Write comments on manual testing — see Test Plan above; also verified via Playwright across desktop (1440×900) and mobile (390×700) viewports, dark mode, and keyboard/Enter-to-submit
  • Updated Playwright screenshot baselines (e2e/screenshots.spec.ts-snapshots/intro-page.png, consent-banner.png); full suite passes

Changes

Visual changes

  • Purely new/reworked view — see Test Plan above for how to reproduce (/intro)

Data changes

  • Not applicable — no data files touched.

Internal changes

  • Logical changes — see above (--navbar-height CSS var, EntityMap's onZoomChange prop)
  • New files under src/pages/intro/ (mirrors the existing src/pages/dataviews/ pattern) and src/shared/hooks/useRevealOnScroll.ts
  • Explanatory comments added where the code isn't self-evident (e.g. why allowSidebar is required on the hero's map, why sections use min-height not height, why display: contents is used in CommonObjectives)

Docs

  • Code is self-documenting, or comments added where needed
  • No README/markdown doc updates needed for this change

Shikhar16078 and others added 3 commits July 14, 2026 13:56
Replaces the old single static block (logo + welcome text + objectives,
all crammed into one ~80vh container) with three full-viewport,
scroll-snapped sections: a hero intro, a live interactive world map, and
Common Objectives — so the landing page actually lets people explore the
map immediately instead of only linking out to it from a list.

- IntroScrollContainer/IntroScrollSection: the scroll-snap mechanics.
  Sections use min-height (not height) so overflowing content on short/
  narrow viewports grows the section instead of being clipped and made
  unreachable by the mandatory snap.
- useRevealOnScroll: new IntersectionObserver-based hook (this codebase
  had none) driving each section's fade/slide-in; skips the effect
  entirely under prefers-reduced-motion. The hero opts out of animating
  since it's visible on first paint — animating it risked a flash of
  invisible content.
- useIntroSectionNav + IntroSectionNav: dot navigation and a "scroll
  down" chevron on the hero, since scroll-snap sections otherwise have
  no visible affordance telling users there's more below. Computes
  scroll targets from each section's actual DOM offsetTop rather than
  assuming uniform heights, since sections can legitimately vary (see
  the min-height point above).
- IntroMapSection: embeds EntityMap directly with allowSidebar (required,
  not optional — its non-sidebar click path expects a DetailsPanel that
  only exists on the Data page) and progressively reveals more languages
  as the user zooms in (60 at rest, up to 300 at max zoom), since showing
  either too few or the full ~8,500-language set both looked bad. Reads
  EntityMap's zoom level via a new onZoomChange callback prop.
- PageNavBar now publishes its real rendered height as a --navbar-height
  CSS var (measured, not hardcoded, since it wraps to two rows on narrow
  viewports) so the hero can size sections as calc(100vh - navbar).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Each row's label text and its input/button controls were laid out with
ad-hoc inline-flex + margins, so the controls landed at a different
horizontal position per row depending on that row's label length (and
two of the four rows have no input field at all, making it worse).

Switches ObjectiveList to a 3-column CSS grid (label | input-or-spacer |
GO button) so every row's controls line up regardless of label length.
Each Objective renders its form with display: contents so the form
doesn't introduce its own box between the grid and its children, while
still fully working for onSubmit/Enter-to-submit. Also gives the inputs
and GO buttons a pill style consistent with the rest of the app's
bordered/rounded control language instead of bare default elements.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
intro-page.png and consent-banner.png needed updating to match the
reworked Intro page. The other 8 baselines (data/about/lucky-search
pages, untouched by this branch) also came back with diffs when
regenerated — verified via a throwaway diff against the old baselines
that this is font-rendering/anti-aliasing drift between whatever
environment originally produced them and the local Chromium install
here (ghosted/doubled text, no layout change), not a real regression.
Refreshing all of them keeps the whole suite consistent with this
environment; full suite passes cleanly against the new set.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Cloudflare Pages preview

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant