Files
intotheeast-com/docs/superpowers/specs/2026-06-21-homepage-redesign.md
T
m038 3d9aa306dc docs: add homepage redesign spec
Covers dual-mode homepage (active trip vs between-trips highlights),
persistent map with GPX in active mode, featured flag on entries/stories,
tagline field on trips, and Admin2 site config blueprint.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 01:18:43 +02:00

7.5 KiB

Homepage Redesign Spec

Date: 2026-06-21 Goal: Make the homepage context-aware: a persistent two-column map+feed layout that switches its right column between an active-trip feed and a curated highlights grid depending on whether Mischa is currently travelling.


1. Mode switch

A travelling toggle in user/config/site.yaml controls which mode the homepage renders. It is exposed in Admin2's Site Configuration panel via a new site config blueprint.

travelling Homepage mode
true Active trip — map + live feed
false Between trips — map + highlights grid

The active_trip value changes format: it now stores the full page route (/trips/italy-2026-demo) instead of the bare slug (italy-2026-demo), because it will be managed via a type: pages dropdown in Admin2 rather than a free-text field.


2. Data model changes

2a. New file: user/blueprints/config/site.yaml

Exposes site config fields in Admin2:

active_trip:
  type: pages
  label: Active Trip
  start_route: '/trips'
  show_root: false
  show_slug: true

travelling:
  type: toggle
  label: Currently Travelling
  highlight: 1
  default: false

2b. user/config/site.yaml — value format update

# Before
active_trip: italy-2026-demo

# After
active_trip: /trips/italy-2026-demo
travelling: false

2c. Trip page blueprint (user/themes/intotheeast/blueprints/trip.yaml)

Add one field:

tagline:
  type: text
  label: Tagline
  help: Short description shown on homepage highlight cards (e.g. "6 weeks from Venice to Sicily by train")

2d. Entry blueprint (user/themes/intotheeast/blueprints/entry.yaml)

Add one field:

featured:
  type: toggle
  label: Featured highlight
  help: Show this entry as a homepage highlight when not travelling
  default: false

2e. Story blueprint (user/themes/intotheeast/blueprints/story.yaml)

Add the same featured toggle (identical definition). Stories are not auto-included — they opt in the same way as journal entries.


3. Layout

The two-column structure is always present regardless of mode.

┌────────────────────────┬────────────────────────────────┐
│                        │                                │
│   MapLibre map         │   Right column                 │
│   (sticky,             │   (switches by mode)           │
│   always visible)      │                                │
│                        │                                │
└────────────────────────┴────────────────────────────────┘
  • Map: left column, ~45% width, position: sticky; top: 0; height: 100vh
  • Right column: ~55% width, scrollable
  • Mobile: map stacks on top at 40vh, right column scrolls below

4. Active trip mode (travelling: true)

Right column

Chronological feed, newest first. Merges journal entries and story cards from the active trip's /dailies and /stories sub-pages. This is the existing feed behaviour — no changes to card markup or order logic.

Trip title and entry counts shown above the feed.

Map

  • Marker per journal entry with lat/lng in frontmatter
  • Journey line connecting markers in order
  • GPX route files loaded from the active trip page media (same pattern as map.html.twig, including the smart connector-suppression logic from the GPX connector spec)
  • Clicking a marker scrolls to that entry card in the feed

Template change (home.html.twig)

The slug-based path construction is replaced with direct route usage:

{# Before #}
{% set slug = config.site.active_trip %}
{% set trip = grav.pages.find('/trips/' ~ slug) %}
{% set dailies_page = grav.pages.find('/trips/' ~ slug ~ '/dailies') %}
{% set stories_page = grav.pages.find('/trips/' ~ slug ~ '/stories') %}

{# After #}
{% set trip_route = config.site.active_trip %}
{% set trip = grav.pages.find(trip_route) %}
{% set dailies_page = grav.pages.find(trip_route ~ '/dailies') %}
{% set stories_page = grav.pages.find(trip_route ~ '/stories') %}

5. Between-trips mode (travelling: false)

Highlight selection logic

  1. Collect all published trip pages from /trips
  2. For each trip, collect all published children from /dailies and /stories where featured: true
  3. From each trip's candidates, pick one at random (random())
  4. Gather the per-trip picks into a pool; if more than 6 trips have candidates, randomly discard down to 6
  5. Shuffle the final pool so cards appear in random order (not grouped by trip)

Right column

A grid of highlight cards. Below the grid, a "Explore all past trips →" CTA linking to /trips.

Grid layout: 3 columns on desktop, 2 on tablet, 1 on mobile.

Highlight card anatomy

┌──────────────────────────┐
│  [hero image]            │
├──────────────────────────┤
│  ✦ Story  / ◎ Journal    │  ← type badge
│  Entry title             │  ← links to entry page
│  Italy 2025              │  ← trip title
│  "tagline from trip"     │  ← trip tagline
│  → View trip             │  ← links to trip page
└──────────────────────────┘
  • Hero image: entry.media.images|first if no hero_image frontmatter field; cropped to 16:9
  • Type badge: ✦ Story (accent colour) or ◎ Journal (muted)
  • Entry title: full clickable link to the entry URL
  • Trip title + tagline: small secondary text; trip title links to the trip page
  • "→ View trip": explicit CTA link to the trip page

Cards with no hero image still render but without an image block.

Map

  • Marker per highlighted entry that has lat/lng in frontmatter
  • No journey line between markers (entries are from different trips)
  • No GPX data loaded
  • Map fits bounds across all markers; falls back to a world-level zoom if no entries have coordinates
  • Clicking a marker scrolls to that highlight card

6. Files changed

File Change
user/blueprints/config/site.yaml Create — exposes active_trip (pages) + travelling (toggle) in Admin2
user/config/site.yaml Updateactive_trip value to full route; add travelling: false
user/themes/intotheeast/blueprints/trip.yaml Update — add tagline text field
user/themes/intotheeast/blueprints/entry.yaml Update — add featured toggle
user/themes/intotheeast/blueprints/story.yaml Update — add featured toggle
user/themes/intotheeast/templates/home.html.twig Update — mode branch, route-based lookup, highlights logic, GPX loading
user/themes/intotheeast/css/style.css Update — highlight card styles, grid layout

No new plugins. No build pipeline. All changes in user/.


7. Constraints

  • post-form.md (pageconfig.parent) remains manually synced with active_trip — this is unchanged behaviour documented in CLAUDE.md
  • The type: pages field in Admin2 is confirmed present in the bundle but untested in a user site config blueprint; if it does not render, fall back to type: select with static trip slug options (one-minute fix, no other code changes needed)
  • Random selection uses Twig's random() — order varies per page load; this is intentional