docs: add Tuscany demo stories implementation plan

This commit is contained in:
2026-06-19 23:34:38 +02:00
parent 64dbcefd9b
commit 640016c54f
@@ -0,0 +1,301 @@
# Tuscany Demo Stories Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Add three Italy 2025 Tuscany demo stories that showcase distinct story-mode composition patterns.
**Architecture:** Three `story.md` files in `user/docs/demo/trips/italy-2025/04.stories/`, committed to the user repo. One Makefile line added to `demo-load` to copy the folder into pages, committed to the main repo. No image files — shortcode image params reference filenames that won't resolve without real photos, consistent with the existing Japan demo story.
**Tech Stack:** Grav CMS page frontmatter (YAML), Markdown prose, story-blocks shortcodes (chapter-break, scrolly-section, pull-quote, snap-gallery), Makefile.
## Global Constraints
- Story pages live at `user/docs/demo/trips/italy-2025/04.stories/<n>.<slug>/story.md` (note: `user/` is a separate git repo — all story commits use `git -C user ...`)
- Shortcode syntax: `[chapter-break title="..." number="..." image="..." alt="..." /]`, `[scrolly-section image="..." alt="..." caption="..."]...[/scrolly-section]`, `[pull-quote image="..."]...[/pull-quote]` (image param optional), `[snap-gallery images="a.jpg,b.jpg" captions="Cap 1,Cap 2" alts="Alt 1,Alt 2" /]`
- ScrollySection steps separated by `---` on its own line inside the shortcode tags
- All frontmatter fields required: `title`, `date`, `location_name`, `location_country`, `lat`, `lng`, `hero_image`, `hero_alt`, `published: true`
- `end_date` optional (Story 2 only)
- Makefile changes go in the **main repo** (`git add Makefile && git commit ...` — no `-C user`)
- Dev server: `http://localhost:8081`, Docker container: `intotheeast_grav`
---
### Task 1: Three story.md files
**Files:**
- Create: `user/docs/demo/trips/italy-2025/04.stories/01.val-dorcia-dawn/story.md`
- Create: `user/docs/demo/trips/italy-2025/04.stories/02.long-climb-montalcino/story.md`
- Create: `user/docs/demo/trips/italy-2025/04.stories/03.one-evening-siena/story.md`
**Interfaces:**
- Produces: three story pages loadable by `make demo-load` into `user/pages/01.trips/italy-2025/04.stories/`
- Consumed by: Task 2 (Makefile verification)
- [ ] **Create the demo stories directory**
```bash
mkdir -p user/docs/demo/trips/italy-2025/04.stories/01.val-dorcia-dawn
mkdir -p user/docs/demo/trips/italy-2025/04.stories/02.long-climb-montalcino
mkdir -p user/docs/demo/trips/italy-2025/04.stories/03.one-evening-siena
```
- [ ] **Create Story 1: `01.val-dorcia-dawn/story.md`**
Pattern: gallery-led. Demonstrates two snap-galleries, chapter-break as scene divider, text-only pull-quote (no image param).
```markdown
---
title: The Val d'Orcia at Dawn
date: 2025-09-05
location_name: Val d'Orcia
location_country: Italy
lat: 43.078
lng: 11.676
hero_image: hero.jpg
hero_alt: Cypress-lined dirt road at first light, Tuscany
published: true
---
We left camp before the heat arrived. At six in the morning the Val d'Orcia belongs entirely to the light — long shadows, pale gold, not a car on the white roads. The kind of silence that has texture.
[snap-gallery images="dawn-wide.jpg,rolling-hills.jpg,cypress-allee.jpg,dirt-road.jpg" captions="First light on the valley floor,The hills fold endlessly east,The cypress road — every photo you have ever seen of Tuscany,Dust rising behind us on the gravel" alts="Wide valley at dawn with golden light,Rolling green hills under morning sky,Long avenue of cypress trees,White gravel road with dust cloud" /]
We stopped twice before nine. Once for a puncture, once because the view demanded it.
[chapter-break image="heat-haze.jpg" title="The Hour Before Heat" alt="Hazy hillside shimmering in early morning warmth" /]
By ten the temperature had shifted. The colours changed too — softer, more diffuse, the sky turning white at the edges. We dropped into the lower valley and the road surface changed from gravel to packed earth, then back again.
[snap-gallery images="gravel-detail.jpg,wheel-shadow.jpg,water-bottle.jpg,road-shadow.jpg" captions="The texture of Tuscan gravel — coarser than it looks,Long shadow at the day's first steep pitch,Half a litre left and forty kilometres to go,The road ahead disappears into the heat" alts="Close-up of pale gravel surface,Bicycle wheel casting shadow on road,Half-empty water bottle in cage,Road vanishing into bright haze" /]
[pull-quote]
The best hours of a cycling day are the ones nobody sees. Four in the morning to ten. Then it belongs to the sun.
[/pull-quote]
We made Pienza by noon. It was already thirty degrees and the ice cream queue was six deep.
```
- [ ] **Create Story 2: `02.long-climb-montalcino/story.md`**
Pattern: scrollytelling-led. Demonstrates two scrolly-sections with different step counts (3 vs. 5), pull-quote with image, chapter-break with number.
```markdown
---
title: The Long Climb to Montalcino
date: 2025-09-05
end_date: 2025-09-06
location_name: Montalcino
location_country: Italy
lat: 43.058
lng: 11.489
hero_image: hero.jpg
hero_alt: Hairpin road climbing through olive groves towards a hilltop town
published: true
---
The profile showed fourteen kilometres at an average of six percent. In practice it was steeper at the bottom and gentler at the top, which is the worst possible arrangement. We started climbing at two in the afternoon, which was also the worst possible decision.
[scrolly-section image="climb-road.jpg" alt="Empty road rising steeply through olive groves" caption="SP55 — 14km, 840m elevation gain"]
The first kilometre is the most honest. You find out immediately whether your legs have anything to say.
---
By the halfway point the olive groves had given way to scrub oak and the road had narrowed to a single lane. No cars had passed in forty minutes. The silence was absolute except for breathing.
---
Then, at the last bend before the top, the town appeared. Just the outline of it — a tower, a wall, rooftops. It was enough.
[/scrolly-section]
[chapter-break image="town-gate.jpg" title="Montalcino" number="II" alt="Medieval town gate with stone archway" /]
[pull-quote image="vineyard.jpg" alt="Rows of Brunello vines descending from hilltop town"]
From the top you could see the whole valley we had spent two days riding through. It looked completely flat from up here.
[/pull-quote]
We found a bar in the main piazza. The owner brought two glasses of water without being asked. Then two more. Then a small plate of bread and oil that nobody ordered. We sat there for an hour.
[scrolly-section image="piazza.jpg" alt="Shaded medieval piazza with stone buildings" caption="Piazza del Popolo, Montalcino"]
The piazza at five in the afternoon is a different place from the piazza at noon. People have returned from wherever they go during the heat.
---
A wine shop with barrels in the window and a handwritten list on a chalkboard. We looked at it for a long time and bought nothing. The prices were very reasonable and this felt suspicious.
---
A cat on a warm stone wall, watching traffic that did not exist. It had clearly been watching this traffic for years.
---
The fortress walls turn amber just before sunset. You could photograph this from a hundred different angles and it would look the same in all of them: very good.
---
The descent back to the valley takes twenty minutes. The climb took two and a half hours. This ratio never stops feeling wrong.
[/scrolly-section]
We found the agriturismo by following a handwritten sign nailed to a cypress tree. It was exactly what it promised to be.
```
- [ ] **Create Story 3: `03.one-evening-siena/story.md`**
Pattern: mood/fragment piece. Demonstrates pull-quote as opening element, 2-step scrolly-section (minimum), snap-gallery as mid-story element, pull-quote with image as closing element.
```markdown
---
title: One Evening in Siena
date: 2025-09-05
location_name: Siena
location_country: Italy
lat: 43.318
lng: 11.330
hero_image: hero.jpg
hero_alt: The Piazza del Campo at dusk, terracotta rooftops fading to blue
published: true
---
[pull-quote]
Siena is not a city that tries to impress you. It has been here for a thousand years and intends to be here for a thousand more. You fit around it.
[/pull-quote]
We rolled in at half past six, legs finished, panniers heavier than they started. The Campo appeared without warning at the end of a narrow street and we both stopped pedalling at exactly the same moment.
[scrolly-section image="campo.jpg" alt="Piazza del Campo seen from the upper rim, sloping shell-shaped square"]
The square fills from the edges inward as evening comes. First the locals — people who have been here before and know which bench faces west. Then the tourists, then the pigeons, then the shadows.
---
A busker with a cello at the top of the slope. A couple arguing quietly in a language I couldn't place. Three children running in a circle for reasons nobody questioned. The ordinary business of a city at the end of a summer day.
[/scrolly-section]
[snap-gallery images="campo-dusk.jpg,doorway.jpg,gelato.jpg" captions="The Campo at the moment the light goes warm,A doorway on Via di Città — every doorway in Siena looks like this,The mandatory stop: stracciatella, obviously" alts="Wide shot of Campo at golden hour,Ornate stone doorway with iron lantern,Close-up of gelato cone with city behind" /]
We found a place to eat down three flights of stairs in a basement that appeared to have no ventilation and no menu. It was perfect. The relief of sitting down after eight hours on a bike is a specific physical sensation that is difficult to describe to anyone who has not experienced it.
[pull-quote image="sunset.jpg" alt="Sunset view over Siena rooftops from high vantage point"]
Cycling makes you earn every place you arrive at. Siena earned.
[/pull-quote]
```
- [ ] **Verify shortcode syntax in all three files**
Check that every shortcode tag opens and closes correctly:
```bash
grep -n "\[chapter-break\|\[scrolly-section\|\[/scrolly-section\]\|\[pull-quote\|\[/pull-quote\]\|\[snap-gallery" \
user/docs/demo/trips/italy-2025/04.stories/01.val-dorcia-dawn/story.md \
user/docs/demo/trips/italy-2025/04.stories/02.long-climb-montalcino/story.md \
user/docs/demo/trips/italy-2025/04.stories/03.one-evening-siena/story.md
```
Expected: every `[scrolly-section` has a matching `[/scrolly-section]`, every `[pull-quote` has a matching `[/pull-quote]`.
- [ ] **Commit to user repo**
```bash
git -C user add docs/demo/trips/italy-2025/04.stories/
git -C user commit -m "docs: add three Tuscany demo stories (gallery-led, scrollytelling-led, mood-fragment)"
```
---
### Task 2: Makefile update + end-to-end verification
**Files:**
- Modify: `Makefile` (main repo — no `-C user`)
**Interfaces:**
- Consumes: `user/docs/demo/trips/italy-2025/04.stories/` from Task 1
- Produces: `make demo-load` copies all three stories into pages; stories listing shows 3 cards; each story page renders shortcode HTML
- [ ] **Add the stories copy line to `demo-load`**
In `Makefile`, find this line:
```makefile
cp user/docs/demo/trips/italy-2025/stories.md user/pages/01.trips/italy-2025/04.stories/stories.md 2>/dev/null || true
```
Add the following line immediately after it:
```makefile
cp -r user/docs/demo/trips/italy-2025/04.stories/. user/pages/01.trips/italy-2025/04.stories/ 2>/dev/null || true
```
Note: use `04.stories/.` (trailing slash-dot) to copy the **contents** of the folder into the existing `04.stories/` directory (which already contains `stories.md`), rather than creating a nested `04.stories/04.stories/` structure.
- [ ] **Run `make demo-load` and clear cache**
```bash
make demo-load
```
Expected output ends with Grav cache cleared.
- [ ] **Verify stories listing shows 3 cards**
```bash
curl -s http://localhost:8081/trips/italy-2025/stories | grep -c 'story-card'
```
Expected: `3` (one card per story).
- [ ] **Verify Story 1 renders both snap-galleries and text-only pull-quote**
```bash
curl -s http://localhost:8081/trips/italy-2025/stories/val-dorcia-dawn | grep -c 'pgallery\|pull-quote'
```
Expected: at least `3` (2 pgallery divs + 1 pull-quote).
Also verify the text-only pull-quote (no background image div):
```bash
curl -s http://localhost:8081/trips/italy-2025/stories/val-dorcia-dawn | grep 'pull-quote__inner--no-image'
```
Expected: one match (the text-only pull-quote variant).
- [ ] **Verify Story 2 renders two scrolly-sections**
```bash
curl -s http://localhost:8081/trips/italy-2025/stories/long-climb-montalcino | grep -c 'class="scrolly"'
```
Expected: `2` (two scrolly-section blocks).
Also verify pull-quote with image (should NOT have `--no-image` class):
```bash
curl -s http://localhost:8081/trips/italy-2025/stories/long-climb-montalcino | grep 'pull-quote__bg'
```
Expected: one match (the background image div for the pull-quote).
- [ ] **Verify Story 3 renders pull-quote as opener and closer**
```bash
curl -s http://localhost:8081/trips/italy-2025/stories/one-evening-siena | grep -c 'pull-quote'
```
Expected: at least `4` (two pull-quote elements × ~2 class references each).
Verify the mid-story snap-gallery:
```bash
curl -s http://localhost:8081/trips/italy-2025/stories/one-evening-siena | grep -c 'pgallery'
```
Expected: at least `1`.
- [ ] **Run `make demo-reset` and verify cleanup**
```bash
make demo-reset
```
Verify Italy stories are gone:
```bash
ls user/pages/01.trips/italy-2025/ 2>/dev/null || echo "italy-2025 removed"
```
Expected: `italy-2025 removed` (the entire italy-2025 folder is removed by `demo-reset`).
- [ ] **Commit Makefile to main repo**
```bash
git add Makefile
git commit -m "build: add Italy 2025 stories folder to demo-load target"
```