206 lines
7.5 KiB
Markdown
206 lines
7.5 KiB
Markdown
# 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:
|
|
|
|
```yaml
|
|
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
|
|
|
|
```yaml
|
|
# 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:
|
|
|
|
```yaml
|
|
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:
|
|
|
|
```yaml
|
|
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:
|
|
|
|
```twig
|
|
{# 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` | **Update** — `active_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
|