Skip to content

feat(docs): add custom landing page with scroll-driven intersection demos - #778

Merged
thebuilder merged 6 commits into
mainfrom
claude/custom-landing-page-scroll-f48e30
Aug 5, 2026
Merged

feat(docs): add custom landing page with scroll-driven intersection demos#778
thebuilder merged 6 commits into
mainfrom
claude/custom-landing-page-scroll-f48e30

Conversation

@thebuilder

Copy link
Copy Markdown
Owner

What & why

The docs previously landed visitors straight in the documentation. This adds a dedicated custom landing page at / that sells the package and demonstrates the library on the page itself.

The concept is "the page observes itself": every section is instrumented with the real library, so scrolling is the demo. A live Observer HUD (and the hero instrument) report the active section, intersectionRatio, and impression count as you scroll, all driven by real useInView/useOnInView.

Sections

Each demonstrates a real use-case:

  • Hero — value prop, copyable install (npm/pnpm/yarn/bun), CTAs, live telemetry instrument
  • Reveal band — feature cards animate in on scroll (useInView({ triggerOnce }))
  • Three-APIs scrollspy — sticky code panel follows whichever API is in view; cards are also click-to-pin, with a scroll reclaiming control
  • Impression strip — tiles fire once via useOnInView into a live counter
  • Playground — reuses the existing ObserverDemo island
  • Closing CTA + footer

Implementation

  • Built on Blume custom pages: pages/index.astro wrapping PageLayout, composing pages/_home/Landing.tsx (+ primitives.tsx, home.css).
  • Progressive enhancement: content is fully visible with no JS, for crawlers, and under prefers-reduced-motion; the hidden-until-seen state is applied only by the observer after hydration. Motion is limited to transform/opacity.
  • Routing: docs/index.mdxdocs/overview.mdx (/overview). The Docs tab keeps path: "/" with href: "/overview", so every existing /api, /guides, /testing URL, the sidebar, and tab highlighting are preserved; only the landing takes /.
  • Sets logo.text: "" so the default PageLayout logo no longer prints the site title beside the mark.

Reviewer notes

  • Blume's PageLayout does not forward the components.ts Logo override to its header (unlike RootLayout), so the landing header reproduces the docs logo behavior (theme-aware currentColor, docs h-8 size, mobile text-only crop matching logo-text.svg) in landing-scoped CSS.
  • A bespoke home Open Graph card requires deployment.site in the Blume config, which is unset site-wide today (deploy-time config, unaffected by this change).

Verification

  • ✅ biome (lint/format) clean
  • ✅ impeccable design detector: no findings
  • blume check typecheck: 0 errors
  • blume build: 112 pages, landing + /overview prerendered
  • ✅ checked desktop + mobile, light + dark

🤖 Generated with Claude Code

Replace the "land directly in the docs" experience with a dedicated
marketing landing page at `/` that sells the package and demonstrates
the library on the page itself.

The concept is "the page observes itself": every section is instrumented
with the real library, so scrolling is the demo. A live Observer HUD and
hero instrument report the active section, intersectionRatio, and
impression count as you scroll, all driven by real useInView/useOnInView.

Sections, each showing a real use-case:
- Hero with copyable install (npm/pnpm/yarn/bun) and a live instrument
- Reveal band: cards animate in on scroll (useInView + triggerOnce)
- Three-APIs scrollspy: sticky code panel follows the in-view API;
  cards are also click-to-pin, with scroll reclaiming control
- Impression strip: tiles fire once via useOnInView into a live counter
- Playground: reuses the existing ObserverDemo island
- Closing CTA + footer

Built on Blume custom pages (pages/index.astro + PageLayout). Progressive
enhancement throughout: content is fully visible with no JS, for crawlers,
and under prefers-reduced-motion; the hidden-until-seen state is applied
only by the observer after hydration. Motion uses transform/opacity.

Routing: docs/index.mdx moves to docs/overview.mdx (/overview). The Docs
tab keeps path "/" with href "/overview", preserving every existing
/api, /guides, /testing URL, the sidebar, and tab highlighting; only the
landing takes "/". logo.text is set to "" so the default PageLayout logo
no longer prints the site title beside the mark.

Verified: biome clean, design detector no findings, typecheck 0 errors,
production build (112 pages) with the landing and /overview prerendered;
checked desktop + mobile in light and dark.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@bolt-new-by-stackblitz

Copy link
Copy Markdown

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
react-intersection-observer Ready Ready Preview Aug 5, 2026 7:54am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
react-intersection-observer-storybook Skipped Skipped Aug 5, 2026 7:54am

@pkg-pr-new

pkg-pr-new Bot commented Aug 4, 2026

Copy link
Copy Markdown
npm i https://pkg.pr.new/react-intersection-observer@778

commit: 2b46df1

Scroll-reveal fix: below-the-fold sections started visible (server-
rendered) and then faded out once the client:load island hydrated and
marked them not-yet-in-view. Elements now start hidden before first
paint and only ever animate in.

- An inline head script sets `data-rio-js` on <html> when JS is present
  and motion is allowed; `:root[data-rio-js] .rio-reveal` does the
  hiding. With no JS or reduced motion the flag is absent and all
  content stays visible (crawlers/no-JS lose nothing).
- Reveal is now class-based (`rio-reveal` + `is-visible`); the island
  only adds `is-visible` on enter, so motion is one-way.

Fallow audit (CI) now passes:
- Treat `apps/docs/pages/**/*.astro` as entry points and ignore the
  `blume:data` virtual module, so Blume routes are no longer reported as
  unused files / unlisted dependencies.
- Remove the dead `export const client` from Landing (it is imported with
  an explicit `client:load`, so the islands-folder convention export was
  unused).
- Extract the shared "Read the docs / GitHub" pair (removes the clone)
  and lift the scrollspy state into `useScrollspy`; simplify the observer
  `report` with `mostVisible`/`sameActive` helpers to clear the CRAP and
  unit-size thresholds.
- Animate the telemetry bars with transform: scaleX instead of width.

Verified: biome clean, fallow audit exits 0, typecheck 0 errors, build
112 pages; reveals start hidden and animate in with no fade-out.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Give the home page a bespoke 1200x630 social card that matches the
landing's dark-violet instrument aesthetic — logo lockup, headline, and
the live "observer" panel — instead of Blume's limited generated card.

- scripts/generate-og.mjs renders the card with Takumi (the renderer
  Blume already bundles) driven directly, so the layout isn't bound to
  Blume's og config surface. Fonts come from Inter Tight / IBM Plex Mono
  with a graceful fallback to the built-in font when offline. Run once
  and commit the PNG; Vercel serves the static file and never renders
  Takumi at build. Regenerate with `pnpm --filter docs og`.
- Wire it via PageLayout's `ogImage="/og-home.png"`, which resolves to an
  absolute og:image/twitter:image against the site URL Blume auto-detects
  on Vercel; the card ships summary_large_image.
- Add takumi-js as a docs devDependency and mark the generator an entry
  in .fallowrc.json so the audit stays green.

Also darken the primary button: the theme accent is a light violet in
dark mode, so white label text was low-contrast. A dedicated
`--rio-btn` violet (oklch 0.56) carries white text well in both themes.

Verified: card renders 1200x630, og:image + twitter tags emit, biome
clean, fallow audit exits 0, typecheck 0 errors, build 112 pages.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The card was unbalanced: the logo floated alone top-left over a large
void while the instrument spanned nearly the full height on the right,
and the headline sat low, centred in the gap.

- Group the logo lockup with the headline and subline into one left
  "message" column so the brand anchors the column instead of floating.
- Match the instrument's height to that column (align stretch + the panel
  distributes its rows) so the two columns share top and bottom edges, and
  centre the whole band as a unit for equal top/bottom margins.
- Give the viewport field purpose: a threshold line with a target chip
  sitting on it (echoing the page's instrument), replacing the empty box
  and the near-invisible progress bar.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The static "instrument screenshot" on the right didn't earn its space.
Replace it with the product's actual idea: the right zone is the
viewport, and an observed element (brand-gradient media card with an
"in view" verdict and content lines) has crossed the viewport boundary
and clips the card's right edge — an intersection, rendered.

Also shrink the logo lockup a touch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two fixes to the intersection graphic:
- The element was clipped ~72px short of the edge by the root's right
  padding; drop it so the element runs off the real right edge.
- Replace the disconnected vertical line with a soft violet seam on the
  right edge itself — the viewport boundary the element intersects — with
  the "viewport" label naming it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel
vercel Bot temporarily deployed to Preview – react-intersection-observer-storybook August 5, 2026 07:54 Inactive
@thebuilder
thebuilder merged commit 8697b1a into main Aug 5, 2026
10 checks passed
@thebuilder
thebuilder deleted the claude/custom-landing-page-scroll-f48e30 branch August 5, 2026 07:55
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.

1 participant