docs: add home page & content flow design spec

This commit is contained in:
2026-06-19 15:07:10 +02:00
parent 6d54092413
commit dc8b7f58d2
@@ -0,0 +1,226 @@
# Home Page & Content Flow Design Spec
**Goal:** Replace the redirect-based home page with a real home page showing the active trip's feed and map side by side, add a proper past-trips archive, enrich the trip page with a sticky sidebar index, and introduce story cards into all feeds.
**Architecture:** Pure Twig + CSS changes on top of the existing Grav stack. The home page is a new Grav page (`00.home/home.md`) with a new `home.html.twig` template. Feeds (home + dailies) are extended to merge journal entries and story entries into one chronological collection, with stories rendered as visually distinct cards. No new plugins, no build pipeline.
**Tech Stack:** Grav CMS (PHP/Twig), Vanilla CSS, Leaflet.js (already loaded in `dailies.html.twig`)
---
## Global Constraints
- All changes in `user/` — commit with `git -C user`
- No new Grav plugins
- No JS framework — all interactivity is vanilla JS
- No build pipeline — CSS shipped as plain files
- Existing token names in `tokens.css` must not change
- Theme directory: `user/themes/intotheeast/`
- Active trip slug: `config.site.active_trip` (set in `user/config/site.yaml`)
- `system.yaml` `home.alias` redirect must be removed — `/` becomes a real page
- `config.site.active_trip` in `site.yaml` must always be set to a trip slug (even between trips, point it at the last trip) — the home page template has no fallback if this value is empty
---
## 1. URL Structure
| URL | Page file | Template |
|---|---|---|
| `/` | `user/pages/00.home/home.md` | `home.html.twig` (new) |
| `/trips` | `user/pages/01.trips/trips.md` | `trips.html.twig` (update existing) |
| `/trips/<slug>/` | existing | `trip.html.twig` (update existing) |
| `/trips/<slug>/dailies` | existing | `dailies.html.twig` (update existing) |
**system.yaml change:** Remove `home: alias: /trips/japan-korea-2026/dailies`. Set `home: alias: /` (or remove the alias entirely so Grav serves the `00.home` page at `/`).
---
## 2. Home Page (`/`)
### Layout
Two-column CSS grid on desktop. Map left (~45%), entry feed right (~55%).
```
┌─────────────────────────────────────────────────────────┐
│ [Trip name] · 31 journal entries · 4 stories │
├────────────────────────┬────────────────────────────────┤
│ │ [story card] │
│ Leaflet map │ [journal card] │
│ (sticky, │ [journal card] │
│ 45% width) │ [story card] │
│ │ ... │
└────────────────────────┴────────────────────────────────┘
```
- Map is `position: sticky; top: 0; height: 100vh`
- Entry feed is scrollable, sorted descending by date
- Feed contains both journal entries and story entries merged (see §5)
### Data
```twig
{% set slug = config.site.active_trip %}
{% set trip = grav.pages.find('/trips/' ~ slug) %}
{% set dailies = grav.pages.find('/trips/' ~ slug ~ '/dailies') %}
{% set stories_page = grav.pages.find('/trips/' ~ slug ~ '/stories') %}
{% set journal_entries = dailies ? dailies.children.published().order('date', 'desc') : [] %}
{% set story_entries = stories_page ? stories_page.children.published() : [] %}
{# merge and sort handled in template — see §5 #}
```
### Map
Reuse the existing Leaflet setup from `dailies.html.twig` (`feed-map`). Markers come from journal entries with `lat`/`lng` in frontmatter. GPX route line loaded from trip page media if present (same pattern as `map.html.twig`). Clicking a marker scrolls to that entry card in the feed (use `data-entry-id` on cards + `scrollIntoView`).
### Mobile
Stack vertically: map on top at `height: 40vh`, feed below. No hamburger needed — simpler than the dedicated map page.
---
## 3. Past Trips Archive (`/trips`)
Update `trips.html.twig`. Show each trip as a card, sorted newest first.
Each card contains:
- Trip title (links to `/trips/<slug>/`)
- Date range: `date_start` `date_end` from trip page frontmatter (show "Ongoing" if no `date_end`)
- Entry count: journal entries + story entries counted separately
```twig
{% set journal_count = grav.pages.find(trip.route ~ '/dailies').children.published()|length %}
{% set story_count = grav.pages.find(trip.route ~ '/stories').children.published()|length %}
```
Display: **31 journal entries · 4 stories**
The active trip appears as the first card. No special treatment needed beyond chronological ordering — it naturally sits at the top.
---
## 4. Trip Page (`/trips/<slug>/`)
Update `trip.html.twig`. Current state: shows title, dates, nav links, 3 recent entries. Target state:
### Header (update existing `.trip-hero`)
```
Japan & Korea 2026
Jun 2026 Aug 2026 · 31 journal entries · 4 stories
```
Add entry counts below the date line (small, secondary text).
### Two-column layout
Add a right sidebar alongside the existing content:
```
┌──────────────────────────────────┬──────────────────────┐
│ [full chronological feed] │ Journal │
│ (centered, existing max-width) │ Jun 19 Kyoto │
│ │ Jun 18 Osaka │
│ │ ... │
│ │ │
│ │ Stories │
│ │ The night train │
│ │ First ramen │
└──────────────────────────────────┴──────────────────────┘
```
- Right sidebar: `position: sticky; top: 1rem`
- Two sections: **Journal** (list of entry titles as jump-links via `#entry-<slug>`) and **Stories** (same)
- Each item in the sidebar is a jump-link to `#entry-<slug>` anchor on the feed card
- Feed comes from `dailies.children` + `stories.children` merged (see §5)
- On mobile: sidebar collapses to hidden (toggle-able or just hidden — defer this decision to implementation)
### Remove the current "Recent entries" section
The right-sidebar index replaces it. The full merged feed is the main content.
---
## 5. Story Cards in Feeds (home + trip page)
Feeds in both `home.html.twig` and `trip.html.twig` show a merged chronological list of journal entries and story entries.
### Merging collections in Twig
Grav doesn't natively merge two page collections and sort them. Use a Twig loop to build a combined array:
```twig
{% set all_items = [] %}
{% for e in journal_entries %}
{% set all_items = all_items|merge([{'type': 'journal', 'page': e, 'date': e.date}]) %}
{% endfor %}
{% for s in story_entries %}
{% set all_items = all_items|merge([{'type': 'story', 'page': s, 'date': s.date}]) %}
{% endfor %}
{# Sort descending by date #}
{% set all_items = all_items|sort((a, b) => a.date < b.date ? 1 : -1) %}
```
### Journal card (existing format, unchanged)
```html
<article class="entry-card" id="entry-{{ item.page.slug }}" data-lat="{{ item.page.header.lat }}" data-lng="{{ item.page.header.lng }}">
<!-- existing card markup -->
</article>
```
Add `id` and `data-lat`/`data-lng` attributes for sidebar jump-links and map sync.
### Story card (new)
```html
<article class="entry-card entry-card--story" id="entry-{{ item.page.slug }}">
<a class="entry-card-inner" href="{{ item.page.url }}">
{% if hero %}
<div class="entry-card-photo entry-card-photo--story">
<img src="{{ hero.cropResize(720, 405).url }}" alt="{{ item.page.title }}" loading="lazy">
</div>
{% endif %}
<div class="entry-card-body">
<span class="story-badge">✦ Story</span>
<h2 class="entry-title">{{ item.page.title }}</h2>
</div>
</a>
</article>
```
**Visual treatment:** `entry-card--story` gets a teal left border (3px, `var(--color-accent)`) and no excerpt text. The `✦ Story` badge is small-caps, accent color.
### Story page (full-screen)
Story pages (`/trips/<slug>/stories/<story-slug>`) use `stories.html.twig` (already exists). That template should:
- Override `{% block nav %}` to render **only** a fixed escape link — not an empty block, not the global nav
- Escape link: `← Back` fixed top-left, links to `page.parent.parent.url` (the trip page)
Implementation of the Snowfall-style scroll-snap interior is **deferred to Milestone 3** — this spec only covers the story card in the feed and the escape link on the story page.
---
## 6. Navigation
Update `base.html.twig` nav. Current: single "Journal" link pointing to active trip dailies. New:
- **Home** → `/`
- **Past Trips** → `/trips`
The per-trip sub-nav (Journal / Map / Stats / Stories) stays on the trip page — it is not in the global nav.
---
## 7. Files Changed
| File | Change |
|---|---|
| `user/pages/00.home/home.md` | **Create** — new home page, `template: home` |
| `user/themes/intotheeast/templates/home.html.twig` | **Create** — side-by-side map + feed |
| `user/themes/intotheeast/templates/trips.html.twig` | **Update** — trip cards with counts |
| `user/themes/intotheeast/templates/trip.html.twig` | **Update** — counts in header, two-column + sidebar |
| `user/themes/intotheeast/templates/dailies.html.twig` | **Update** — merge stories into feed, story cards, add `id`/`data-` attrs |
| `user/themes/intotheeast/templates/stories.html.twig` | **Update** — add escape link, remove global nav |
| `user/themes/intotheeast/templates/partials/base.html.twig` | **Update** — new nav links |
| `user/themes/intotheeast/css/style.css` | **Update** — home layout, story card styles, sidebar styles |
| `user/config/system.yaml` | **Update** — remove `home.alias` redirect |