Skip to content

feat(overview): sticky eyebrow + bigger green nav + keyboard & swipe nav#587

Merged
HenryLach merged 3 commits into
mainfrom
feat/sticky-nav-keyboard-swipe
May 19, 2026
Merged

feat(overview): sticky eyebrow + bigger green nav + keyboard & swipe nav#587
HenryLach merged 3 commits into
mainfrom
feat/sticky-nav-keyboard-swipe

Conversation

@HenryLach
Copy link
Copy Markdown
Owner

Three layered improvements to the slide-deck navigation UX, all landing in one PR since they reinforce each other.

1. Sticky eyebrow header

.eyebrow now uses position: sticky; top: 0 so the title, wordmark, and prev/index/next controls dock to the top of the viewport on both desktop and mobile once the page is scrolled. Sticky (not fixed) keeps it in normal flow until it hits viewport top, so there's no body padding-top compensation and no content jumping. Background fills with --bg, plus a 1px border-bottom for separation when scrolled.

2. Larger, green nav controls

  • .page-nav font-size doubles (calc(var(--fs-lg) * 2)) so the prev/index/next glyphs read as primary actions instead of subtle hints.
  • Color switches from --text-faint to --green (matching the eyebrow title color).
  • Hover bumps to --text with a tiny translateY(-1px) for tactile feedback.
  • Each control has a 44×44 minimum hit area via min-width / min-height / padding, satisfying touch-target guidance on phones.
  • Disabled state stays gray + low-opacity so first-page-prev and last-page-next still read as inactive.

3. Keyboard + swipe navigation (nav.js)

New shared script, ~3 KB, vanilla browser APIs only, no dependencies. Loaded by every page via <script src="nav.js"></script> before </body>.

Keyboard: ArrowLeft / ArrowRight synthesize a click on the existing prev / next anchors. Ignores modifier-key shortcuts and editable targets (input, textarea, contenteditable) so it never hijacks normal browser shortcuts or form input.

Touch: horizontal swipes (≥70px X movement, and at least 2× more X than Y) fire prev / next. Unless the swipe started inside a horizontally scrollable container (e.g. the page-09 git-graph card or the page-08 wave cards) — in which case the inner pan keeps working. The check walks up the DOM ancestor chain looking for any element with scrollWidth > clientWidth.

No-op on the index page (no .page-nav element to find), safe to load everywhere.

To verify before merging

Same three checks on the PR branch:

  • Desktop: scroll any page → eyebrow docks at top. Click anywhere outside a form, hit ← and → to navigate. Buttons should be visibly green and roughly 2x the previous size.
  • Phone: swipe left/right anywhere except on page 09's git-graph card and page 08's wave cards — those should still pan horizontally inside without triggering page nav.
  • Page 09 + 08: confirm the special horizontal-scroll areas still work (swipe inside them moves the inner content, not the page).

No release. Pure docs/microsite enhancement.

HenryLach added 3 commits May 18, 2026 19:51
Three layered improvements to the slide-deck navigation UX, all
landing in one PR since they reinforce each other.

1. Sticky eyebrow header
   .eyebrow now uses position: sticky; top: 0 so the title, wordmark,
   and prev/index/next controls dock to the top of the viewport on
   both desktop and mobile once the page is scrolled. Sticky (vs
   fixed) keeps it in normal flow until it hits the viewport top, so
   there's no body padding-top compensation and no content jumping.
   Background fills with --bg, plus a 1px border-bottom for separation.

2. Larger, green nav controls
   .page-nav font-size doubles (calc(var(--fs-lg) * 2)) so the prev /
   index / next glyphs read as primary actions instead of subtle hints.
   Color switches from --text-faint to --green (matching the eyebrow
   title color), with hover bumping to --text and a tiny translateY
   for tactile feedback. Each control now has a 44x44 minimum hit area
   via min-width / min-height / padding, satisfying touch-target
   guidance on phones. Disabled state stays gray + low-opacity so
   first-page-prev and last-page-next still read as inactive.

3. Keyboard + swipe navigation (nav.js)
   New shared script, loaded by every page:

     keyboard : ArrowLeft / ArrowRight synthesize a click on the
                existing prev / next anchors. Ignores modifier-key
                shortcuts and editable targets so it never hijacks
                normal browser shortcuts or form input.

     touch    : horizontal swipes (>= 70px X movement, and at least
                2x more X than Y) fire prev / next. UNLESS the swipe
                started inside a horizontally scrollable container
                (e.g. page-09 git-graph, page-08 wave cards), in
                which case the inner pan keeps working. Walked
                via scrollWidth > clientWidth check up the DOM
                ancestor chain.

   The script is loaded by an unconditional <script src='nav.js'>
   tag at the end of every page's body. It's a no-op on the index
   (no .page-nav element to find), so it's safe to load everywhere
   for uniformity.

   ~3 KB, no dependencies, vanilla browser APIs only.

Verified all 18 HTML files still parse as valid UTF-8 HTML.
…age load

Previously, body had padding-top: var(--page-pad-y) (24-48px depending on
viewport breakpoint). On a fresh page load the eyebrow sat below that
padding band and only docked to top: 0 once the user scrolled past it.
The visual effect was a noticeable 'jump' where extra whitespace above
the eyebrow disappeared once scroll started.

Zeroing just the top edge of body padding (keeping --page-pad-x on the
sides and --page-pad-y on the bottom) puts the eyebrow flush against
the viewport top from the moment the page renders. Sticky positioning
then keeps it there throughout scroll, so the docked state is the only
state the user ever sees.
Page 8 is the tallest layout in the deck (3 wave cards with nested lane
grids + a row of summary rule cards). With the shared 48px body
padding-bottom it spills just past one 16:9 viewport height on standard
desktop monitors, surfacing a vertical scrollbar that isn't desirable
for a slide-style presentation page.

Page-specific override sets body padding-bottom: 20px on this page only,
which is enough to fit the content within one viewport at the default
desktop scale without sacrificing breathing room beneath the rules
cards. Other pages retain the shared --page-pad-y bottom padding.
@HenryLach HenryLach merged commit ac684c0 into main May 19, 2026
1 check passed
@HenryLach HenryLach deleted the feat/sticky-nav-keyboard-swipe branch May 19, 2026 00:10
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