docs: add trip entity implementation plan
This commit is contained in:
@@ -0,0 +1,538 @@
|
|||||||
|
# Trip Entity Implementation Plan
|
||||||
|
|
||||||
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use `superpowers:subagent-driven-development` to implement this plan task-by-task.
|
||||||
|
|
||||||
|
**Goal:** Restructure the site around a Trip entity — tracker/map/stats/stories become children of `/trips/japan-korea-2026/`, GPX route files live as media on the trip page, and `site.yaml` holds an `active_trip` slug so the nav can switch trips via config.
|
||||||
|
|
||||||
|
**Architecture:** Trip = a Grav page (`trip.html.twig`) at `/trips/<slug>/`. Map/stats templates find the tracker via `page.parent().route ~ '/tracker'` instead of the hardcoded `/tracker` path. Leaflet-gpx (CDN) loads all `*.gpx` media files from the trip page. A `trips.html.twig` listing page provides the multi-trip root. Stories is stubbed with a placeholder template.
|
||||||
|
|
||||||
|
**Tech Stack:** Grav CMS 1.7/2.0, Twig, Leaflet.js, leaflet-gpx (CDN, vanilla JS — consistent with existing inline JS pattern)
|
||||||
|
|
||||||
|
## Global Constraints
|
||||||
|
|
||||||
|
- All content/theme edits go in `user/` — commit with `git -C user`, not main-repo git
|
||||||
|
- Entry URLs change: `/tracker/<slug>` → `/trips/japan-korea-2026/tracker/<slug>` — acceptable pre-launch
|
||||||
|
- `make test-post` (6/6) and `make test-ui` (25/25) must pass after every task
|
||||||
|
- No new JS framework dependencies; leaflet-gpx is 3KB vanilla JS
|
||||||
|
- `user/config/media.yaml` must whitelist `.gpx` so Grav serves it as a file
|
||||||
|
- The `02.post/post-form.md` `pageconfig.parent` must stay in sync with the tracker path
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 1: Restructure pages under `/trips/`
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `user/pages/01.trips/trips.md`
|
||||||
|
- Create: `user/pages/01.trips/japan-korea-2026/trip.md`
|
||||||
|
- Create: `user/pages/01.trips/japan-korea-2026/01.tracker/tracker.md` (copy from `user/pages/01.tracker/tracker.md`, no content change)
|
||||||
|
- Move: all `*.entry/` folders from `user/pages/01.tracker/` → `user/pages/01.trips/japan-korea-2026/01.tracker/`
|
||||||
|
- Create: `user/pages/01.trips/japan-korea-2026/02.map/map.md` (copy from `user/pages/03.map/map.md`)
|
||||||
|
- Create: `user/pages/01.trips/japan-korea-2026/03.stats/stats.md` (copy from `user/pages/04.stats/stats.md`)
|
||||||
|
- Create: `user/pages/01.trips/japan-korea-2026/04.stories/stories.md`
|
||||||
|
- Delete: `user/pages/01.tracker/`, `user/pages/03.map/`, `user/pages/04.stats/`
|
||||||
|
- Modify: `user/config/site.yaml` — add `active_trip: japan-korea-2026`
|
||||||
|
- Modify (create if absent): `user/config/media.yaml` — whitelist GPX
|
||||||
|
|
||||||
|
- [ ] **Step 1: Verify current structure before touching anything**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find user/pages -name "*.md" | sort
|
||||||
|
```
|
||||||
|
Expected: entries under `01.tracker/`, map at `03.map/map.md`, stats at `04.stats/stats.md`.
|
||||||
|
|
||||||
|
- [ ] **Step 2: Create trips hierarchy**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p user/pages/01.trips/japan-korea-2026/01.tracker
|
||||||
|
mkdir -p user/pages/01.trips/japan-korea-2026/02.map
|
||||||
|
mkdir -p user/pages/01.trips/japan-korea-2026/03.stats
|
||||||
|
mkdir -p user/pages/01.trips/japan-korea-2026/04.stories
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Write `trips.md`**
|
||||||
|
|
||||||
|
`user/pages/01.trips/trips.md`:
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
title: Trips
|
||||||
|
template: trips
|
||||||
|
content:
|
||||||
|
items: '@self.children'
|
||||||
|
order:
|
||||||
|
by: date
|
||||||
|
dir: desc
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 4: Write `trip.md`**
|
||||||
|
|
||||||
|
`user/pages/01.trips/japan-korea-2026/trip.md`:
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
title: 'Japan & Korea 2026'
|
||||||
|
template: trip
|
||||||
|
date: '2026-06-17'
|
||||||
|
date_start: '2026-06-17'
|
||||||
|
date_end: ''
|
||||||
|
cover_image: ''
|
||||||
|
content:
|
||||||
|
items: '@self.children'
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 5: Copy tracker.md, move entries**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp user/pages/01.tracker/tracker.md user/pages/01.trips/japan-korea-2026/01.tracker/tracker.md
|
||||||
|
mv user/pages/01.tracker/*.entry user/pages/01.trips/japan-korea-2026/01.tracker/
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 6: Copy map.md and stats.md**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp user/pages/03.map/map.md user/pages/01.trips/japan-korea-2026/02.map/map.md
|
||||||
|
cp user/pages/04.stats/stats.md user/pages/01.trips/japan-korea-2026/03.stats/stats.md
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 7: Write stories stub**
|
||||||
|
|
||||||
|
`user/pages/01.trips/japan-korea-2026/04.stories/stories.md`:
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
title: Stories
|
||||||
|
template: stories
|
||||||
|
published: true
|
||||||
|
---
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 8: Delete old top-level pages**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
rm -rf user/pages/01.tracker user/pages/03.map user/pages/04.stats
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 9: Add `active_trip` to site.yaml**
|
||||||
|
|
||||||
|
Add to `user/config/site.yaml`:
|
||||||
|
```yaml
|
||||||
|
active_trip: japan-korea-2026
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 10: Whitelist GPX in media.yaml**
|
||||||
|
|
||||||
|
`user/config/media.yaml` (create if absent):
|
||||||
|
```yaml
|
||||||
|
gpx:
|
||||||
|
type: file
|
||||||
|
extensions: ['gpx']
|
||||||
|
mime: application/gpx+xml
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 11: Verify pages load at new URLs**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s -o /dev/null -w "%{http_code}" http://localhost:8081/trips/japan-korea-2026/tracker
|
||||||
|
# Expected: 200
|
||||||
|
curl -s -o /dev/null -w "%{http_code}" http://localhost:8081/trips/japan-korea-2026/map
|
||||||
|
# Expected: 200
|
||||||
|
curl -s -o /dev/null -w "%{http_code}" http://localhost:8081/trips/japan-korea-2026/stats
|
||||||
|
# Expected: 200
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 12: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git -C user add pages/01.trips config/site.yaml config/media.yaml
|
||||||
|
git -C user rm -r --cached pages/01.tracker pages/03.map pages/04.stats
|
||||||
|
git -C user commit -m "feat: restructure pages under trips/japan-korea-2026 entity"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 2: Update templates for trip-relative paths + new trip/trips/stories templates
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `user/themes/intotheeast/templates/map.html.twig` — change hardcoded `/tracker` path
|
||||||
|
- Modify: `user/themes/intotheeast/templates/stats.html.twig` — same
|
||||||
|
- Modify: `user/themes/intotheeast/templates/partials/base.html.twig` — nav uses `active_trip`
|
||||||
|
- Create: `user/themes/intotheeast/templates/trip.html.twig`
|
||||||
|
- Create: `user/themes/intotheeast/templates/trips.html.twig`
|
||||||
|
- Create: `user/themes/intotheeast/templates/stories.html.twig`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: `config.site.active_trip` from site.yaml (set in Task 1)
|
||||||
|
- Produces: map/stats find entries via `page.parent().route ~ '/tracker'`
|
||||||
|
|
||||||
|
- [ ] **Step 1: Fix `map.html.twig` — tracker path**
|
||||||
|
|
||||||
|
Replace:
|
||||||
|
```twig
|
||||||
|
{% set tracker_page = grav.pages.find('/tracker') %}
|
||||||
|
{% set all_entries = tracker_page ? tracker_page.children.published() : [] %}
|
||||||
|
```
|
||||||
|
With:
|
||||||
|
```twig
|
||||||
|
{% set tracker_page = grav.pages.find(page.parent().route ~ '/tracker') %}
|
||||||
|
{% set all_entries = tracker_page ? tracker_page.children.published() : [] %}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Fix `stats.html.twig` — tracker path**
|
||||||
|
|
||||||
|
Same replacement as Step 1 (identical pattern in stats.html.twig).
|
||||||
|
|
||||||
|
- [ ] **Step 3: Update `base.html.twig` nav**
|
||||||
|
|
||||||
|
Replace hardcoded nav href values with `active_trip`-driven paths. The pattern in base.html.twig currently sets hrefs to `/tracker`, `/map`, `/stats`. Replace with:
|
||||||
|
|
||||||
|
```twig
|
||||||
|
{% set active_trip = config.site.active_trip %}
|
||||||
|
{% set trip_base = '/trips/' ~ active_trip %}
|
||||||
|
```
|
||||||
|
|
||||||
|
Nav links become:
|
||||||
|
- Journal: `{{ trip_base }}/tracker`
|
||||||
|
- Map: `{{ trip_base }}/map`
|
||||||
|
- Stats: `{{ trip_base }}/stats`
|
||||||
|
|
||||||
|
Active state detection: replace `page.url starts with '/tracker'` checks with `page.url starts with trip_base ~ '/tracker'` (and similarly for map/stats).
|
||||||
|
|
||||||
|
- [ ] **Step 4: Create `trip.html.twig`**
|
||||||
|
|
||||||
|
`user/themes/intotheeast/templates/trip.html.twig`:
|
||||||
|
```twig
|
||||||
|
{% extends 'partials/base.html.twig' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% set tracker_page = grav.pages.find(page.route ~ '/tracker') %}
|
||||||
|
{% set entries = tracker_page ? tracker_page.children.published() : [] %}
|
||||||
|
|
||||||
|
<div class="trip-hero">
|
||||||
|
<h1>{{ page.title }}</h1>
|
||||||
|
{% if page.header.date_start %}
|
||||||
|
<p class="trip-dates">
|
||||||
|
{{ page.header.date_start|date('d M Y') }}
|
||||||
|
{% if page.header.date_end %} — {{ page.header.date_end|date('d M Y') }}{% endif %}
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<nav class="trip-nav">
|
||||||
|
<a href="{{ page.route }}/tracker">Journal</a>
|
||||||
|
<a href="{{ page.route }}/map">Map</a>
|
||||||
|
<a href="{{ page.route }}/stats">Stats</a>
|
||||||
|
<a href="{{ page.route }}/stories">Stories</a>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
{% if entries|length > 0 %}
|
||||||
|
<section class="trip-recent">
|
||||||
|
<h2>Recent entries</h2>
|
||||||
|
{% for entry in entries|slice(0, 3) %}
|
||||||
|
<a href="{{ entry.url }}">
|
||||||
|
<span>{{ entry.date|date('d M Y') }}</span>
|
||||||
|
{{ entry.title }}
|
||||||
|
{% if entry.header.location_city %} · {{ entry.header.location_city }}{% endif %}
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</section>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 5: Create `trips.html.twig`**
|
||||||
|
|
||||||
|
`user/themes/intotheeast/templates/trips.html.twig`:
|
||||||
|
```twig
|
||||||
|
{% extends 'partials/base.html.twig' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>{{ page.title }}</h1>
|
||||||
|
{% set trips = page.children.published() %}
|
||||||
|
{% if trips|length == 0 %}
|
||||||
|
<p>No trips yet.</p>
|
||||||
|
{% else %}
|
||||||
|
<ul class="trips-list">
|
||||||
|
{% for trip in trips %}
|
||||||
|
<li>
|
||||||
|
<a href="{{ trip.url }}">
|
||||||
|
<strong>{{ trip.title }}</strong>
|
||||||
|
{% if trip.header.date_start %}
|
||||||
|
<span>{{ trip.header.date_start|date('d M Y') }}</span>
|
||||||
|
{% endif %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 6: Create `stories.html.twig` stub**
|
||||||
|
|
||||||
|
`user/themes/intotheeast/templates/stories.html.twig`:
|
||||||
|
```twig
|
||||||
|
{% extends 'partials/base.html.twig' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>{{ page.title }}</h1>
|
||||||
|
<p>Stories coming soon.</p>
|
||||||
|
{% endblock %}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 7: Verify templates render**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s -o /dev/null -w "%{http_code}" http://localhost:8081/trips/japan-korea-2026
|
||||||
|
# Expected: 200
|
||||||
|
curl -s -o /dev/null -w "%{http_code}" http://localhost:8081/trips
|
||||||
|
# Expected: 200
|
||||||
|
curl -s -o /dev/null -w "%{http_code}" http://localhost:8081/trips/japan-korea-2026/stories
|
||||||
|
# Expected: 200
|
||||||
|
```
|
||||||
|
|
||||||
|
Check nav links resolve correctly on tracker/map/stats pages.
|
||||||
|
|
||||||
|
- [ ] **Step 8: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git -C user add themes/intotheeast/templates/
|
||||||
|
git -C user commit -m "feat: add trip/trips/stories templates, update nav and map/stats to use trip-relative paths"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 3: Add GPX route support to map template
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `user/themes/intotheeast/templates/map.html.twig`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Consumes: `*.gpx` files uploaded as media to the trip page (`page.parent()`)
|
||||||
|
- Produces: GPX tracks rendered as colored polylines on the Leaflet map, underneath entry pins
|
||||||
|
|
||||||
|
- [ ] **Step 1: Add leaflet-gpx script tag**
|
||||||
|
|
||||||
|
In `map.html.twig`, after the existing Leaflet script tag, add:
|
||||||
|
```html
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/leaflet-gpx@2.1.2/gpx.min.js"></script>
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Collect GPX URLs from trip media**
|
||||||
|
|
||||||
|
After the `{% set trip_page = page.parent() %}` line (add this at the top of the template, alongside the tracker_page lookup), add:
|
||||||
|
|
||||||
|
```twig
|
||||||
|
{% set gpx_urls = [] %}
|
||||||
|
{% for name, media in trip_page.media.all %}
|
||||||
|
{% if name|split('.')|last == 'gpx' %}
|
||||||
|
{% set gpx_urls = gpx_urls|merge([media.url]) %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Pass GPX URLs to JavaScript**
|
||||||
|
|
||||||
|
In the `<script>` block, after the map is initialized and before the entry markers loop, add:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// GPX route tracks
|
||||||
|
const gpxUrls = {{ gpx_urls|json_encode|raw }};
|
||||||
|
gpxUrls.forEach(url => {
|
||||||
|
new L.GPX(url, {
|
||||||
|
async: true,
|
||||||
|
polyline_options: { color: '#1F6B5A', weight: 2, opacity: 0.7 },
|
||||||
|
marker_options: { startIconUrl: null, endIconUrl: null, shadowUrl: null }
|
||||||
|
}).addTo(map);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Disabling start/end markers keeps the map clean — the entry pins already mark key stops.
|
||||||
|
|
||||||
|
- [ ] **Step 4: Test with a sample GPX**
|
||||||
|
|
||||||
|
Create a minimal 3-point GPX file to test without a real Komoot export:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<gpx version="1.1" creator="test">
|
||||||
|
<trk><trkseg>
|
||||||
|
<trkpt lat="35.6762" lon="139.6503"><time>2026-03-25T10:00:00Z</time></trkpt>
|
||||||
|
<trkpt lat="35.0116" lon="135.7681"><time>2026-03-27T10:00:00Z</time></trkpt>
|
||||||
|
<trkpt lat="37.5665" lon="126.9780"><time>2026-04-01T10:00:00Z</time></trkpt>
|
||||||
|
</trkseg></trk>
|
||||||
|
</gpx>
|
||||||
|
```
|
||||||
|
|
||||||
|
Upload via Grav Admin to the trip page media, then verify the map at `/trips/japan-korea-2026/map` renders the polyline. Remove the test file after verification.
|
||||||
|
|
||||||
|
- [ ] **Step 5: Verify map still works without GPX**
|
||||||
|
|
||||||
|
Confirm map renders normally when no `.gpx` files are present (gpxUrls = []).
|
||||||
|
|
||||||
|
- [ ] **Step 6: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git -C user add themes/intotheeast/templates/map.html.twig
|
||||||
|
git -C user commit -m "feat: add GPX route rendering to trip map via leaflet-gpx"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 4: Update post form, Makefile, demo content, and tests
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Modify: `user/pages/02.post/post-form.md` — `pageconfig.parent`
|
||||||
|
- Modify: `Makefile` — `demo-load` and `demo-reset` paths
|
||||||
|
- Modify: `scripts/test-post.sh` — `TRACKER` variable
|
||||||
|
- Modify: `scripts/test-form-config.sh` — expected parent value
|
||||||
|
- Modify: `tests/ui/tracker.spec.js` — any hardcoded `/tracker` URL references
|
||||||
|
- Modify: `user/docs/demo/` — move demo entries to new path structure
|
||||||
|
|
||||||
|
- [ ] **Step 1: Update post form parent**
|
||||||
|
|
||||||
|
In `user/pages/02.post/post-form.md`, change:
|
||||||
|
```yaml
|
||||||
|
pageconfig:
|
||||||
|
parent: '/tracker'
|
||||||
|
```
|
||||||
|
To:
|
||||||
|
```yaml
|
||||||
|
pageconfig:
|
||||||
|
parent: '/trips/japan-korea-2026/tracker'
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Update demo content structure**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p user/docs/demo/trips/japan-korea-2026/tracker
|
||||||
|
mv user/docs/demo/tracker/* user/docs/demo/trips/japan-korea-2026/tracker/
|
||||||
|
rmdir user/docs/demo/tracker
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 3: Update Makefile demo targets**
|
||||||
|
|
||||||
|
In `Makefile`, update `demo-load` and `demo-reset`:
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
demo-load:
|
||||||
|
cp -r user/docs/demo/trips/japan-korea-2026/tracker/. user/pages/01.trips/japan-korea-2026/01.tracker/
|
||||||
|
docker exec intotheeast_grav bash -c "cd /var/www/html && php bin/grav clearcache"
|
||||||
|
|
||||||
|
demo-reset:
|
||||||
|
@for dir in user/docs/demo/trips/japan-korea-2026/tracker/*/; do \
|
||||||
|
folder=$$(basename "$$dir"); \
|
||||||
|
rm -rf "user/pages/01.trips/japan-korea-2026/01.tracker/$$folder"; \
|
||||||
|
done
|
||||||
|
docker exec intotheeast_grav bash -c "cd /var/www/html && php bin/grav clearcache"
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 4: Update `test-post.sh` TRACKER path**
|
||||||
|
|
||||||
|
Find the line setting `TRACKER=` in `scripts/test-post.sh` and change it to:
|
||||||
|
```bash
|
||||||
|
TRACKER="user/pages/01.trips/japan-korea-2026/01.tracker"
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 5: Update `test-form-config.sh` expected parent**
|
||||||
|
|
||||||
|
Find the assertion that checks `parent: '/tracker'` and update to check for `parent: '/trips/japan-korea-2026/tracker'`.
|
||||||
|
|
||||||
|
- [ ] **Step 6: Check Playwright tests for hardcoded paths**
|
||||||
|
|
||||||
|
Search `tests/ui/` for any hardcoded `/tracker` URL references:
|
||||||
|
```bash
|
||||||
|
grep -rn "tracker\|/map\|/stats" tests/ui/
|
||||||
|
```
|
||||||
|
|
||||||
|
Update any that reference the old paths to use the new trip-scoped paths.
|
||||||
|
|
||||||
|
- [ ] **Step 7: Run full test suite**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make test-config && make test-post && make test-ui
|
||||||
|
```
|
||||||
|
Expected: all pass (14/14, 6/6, 25/25).
|
||||||
|
|
||||||
|
- [ ] **Step 8: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Main repo changes (Makefile + test scripts)
|
||||||
|
git add Makefile scripts/test-post.sh scripts/test-form-config.sh tests/
|
||||||
|
git commit -m "fix: update paths for trips/japan-korea-2026 restructure"
|
||||||
|
|
||||||
|
# User repo changes
|
||||||
|
git -C user add pages/02.post/post-form.md docs/demo/
|
||||||
|
git -C user commit -m "fix: update post form parent and demo content paths for trip structure"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Task 5: Admin blueprint for trip page type
|
||||||
|
|
||||||
|
**Files:**
|
||||||
|
- Create: `user/themes/intotheeast/blueprints/trip.yaml`
|
||||||
|
|
||||||
|
**Interfaces:**
|
||||||
|
- Produces: "Trip" tab in Grav Admin when editing the trip page, with date range and cover image fields
|
||||||
|
|
||||||
|
- [ ] **Step 1: Create `trip.yaml` blueprint**
|
||||||
|
|
||||||
|
`user/themes/intotheeast/blueprints/trip.yaml`:
|
||||||
|
```yaml
|
||||||
|
title: 'Trip'
|
||||||
|
'@extends':
|
||||||
|
type: default
|
||||||
|
context: blueprints://pages
|
||||||
|
|
||||||
|
form:
|
||||||
|
fields:
|
||||||
|
tabs:
|
||||||
|
type: tabs
|
||||||
|
active: 1
|
||||||
|
fields:
|
||||||
|
trip:
|
||||||
|
type: tab
|
||||||
|
title: Trip
|
||||||
|
fields:
|
||||||
|
header.date_start:
|
||||||
|
type: date
|
||||||
|
label: 'Start Date'
|
||||||
|
placeholder: '2026-06-17'
|
||||||
|
help: 'First day of the trip'
|
||||||
|
|
||||||
|
header.date_end:
|
||||||
|
type: date
|
||||||
|
label: 'End Date'
|
||||||
|
placeholder: ''
|
||||||
|
help: 'Leave blank if trip is ongoing'
|
||||||
|
|
||||||
|
header.cover_image:
|
||||||
|
type: text
|
||||||
|
label: 'Cover Image Filename'
|
||||||
|
placeholder: 'cover.jpg'
|
||||||
|
help: 'Used in the trips listing page'
|
||||||
|
```
|
||||||
|
|
||||||
|
- [ ] **Step 2: Verify blueprint appears in Admin**
|
||||||
|
|
||||||
|
Open Grav Admin → Pages → Trips → Japan & Korea 2026 → Edit. Confirm the "Trip" tab appears with start date, end date, cover image fields.
|
||||||
|
|
||||||
|
- [ ] **Step 3: Commit**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git -C user add themes/intotheeast/blueprints/trip.yaml
|
||||||
|
git -C user commit -m "feat: add Admin blueprint for trip page type"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
After all tasks, run end-to-end check:
|
||||||
|
|
||||||
|
1. `make test-config && make test-post && make test-ui` — all must pass
|
||||||
|
2. Navigate to `http://localhost:8081/trips/japan-korea-2026/tracker` — entries display in date order
|
||||||
|
3. Navigate to `http://localhost:8081/trips/japan-korea-2026/map` — entry pins render, GPX polyline renders if a `.gpx` file is present on the trip page
|
||||||
|
4. Navigate to `http://localhost:8081/trips/japan-korea-2026/stats` — stats compute correctly
|
||||||
|
5. Navigate to `http://localhost:8081/trips` — trip listing shows Japan & Korea 2026
|
||||||
|
6. Submit a post via `/post` — new entry appears under `/trips/japan-korea-2026/tracker`
|
||||||
|
7. Grav Admin: edit the trip page → "Trip" tab visible with date fields
|
||||||
Reference in New Issue
Block a user