From 5e864b0c031f4f1911d4f66c43d78eb9597103d2 Mon Sep 17 00:00:00 2001 From: Mischa Date: Fri, 19 Jun 2026 21:24:19 +0200 Subject: [PATCH] docs: add trip page filter bar implementation plan --- .../plans/2026-06-19-trip-page-filter-bar.md | 472 ++++++++++++++++++ 1 file changed, 472 insertions(+) create mode 100644 docs/superpowers/plans/2026-06-19-trip-page-filter-bar.md diff --git a/docs/superpowers/plans/2026-06-19-trip-page-filter-bar.md b/docs/superpowers/plans/2026-06-19-trip-page-filter-bar.md new file mode 100644 index 0000000..245a454 --- /dev/null +++ b/docs/superpowers/plans/2026-06-19-trip-page-filter-bar.md @@ -0,0 +1,472 @@ +# Trip Page Filter Bar — 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:** Replace the three unstyled nav links on the trip page with an in-page filter bar (All content / Journal / Stories) and an inline Stats toggle — no page navigation needed. + +**Architecture:** Pure client-side. `data-type` attributes on article cards let vanilla JS show/hide by content type. Stats computation is inlined into `trip.html.twig` from `stats.html.twig`. No new files, no Grav config changes, no page navigation. + +**Tech Stack:** Twig (Grav 2.0), vanilla JS (ES5), CSS custom properties + +## Global Constraints + +- CSS variables only — no raw hex values; use tokens from `tokens.css` +- ES5 JS — no arrow functions, no `const`/`let`, no template literals (inline script in Twig) +- Touch the minimum: only `trip.html.twig` and `style.css` +- Do not modify `stats.html.twig`, `dailies.html.twig`, or any sub-page template + +--- + +### Task 1: Story card border + data-type attributes + +**Files:** +- Modify: `user/themes/intotheeast/templates/trip.html.twig:77,119` +- Modify: `user/themes/intotheeast/css/style.css:816-819` + +**Interfaces:** +- Produces: `data-type="journal"` and `data-type="story"` attributes on all article cards — consumed by Tasks 3 and 4 + +- [ ] **Step 1: Add data-type to journal article (trip.html.twig line 77)** + +Find this line: +```twig +
+``` +Replace with: +```twig +
+``` + +- [ ] **Step 2: Add data-type to story article (trip.html.twig line 119)** + +Find this line: +```twig +
+``` +Replace with: +```twig +
+``` + +- [ ] **Step 3: Replace story card border in style.css** + +Find the existing `.entry-card--story` rule (around line 816): +```css +.entry-card--story { + border-left: 3px solid var(--color-accent); + padding-left: var(--space-5); +} +``` +Replace with: +```css +.entry-card--story { + border: 2px solid var(--color-accent); + border-radius: var(--radius-md); + padding: var(--space-6); + background: var(--color-canvas); +} +``` + +- [ ] **Step 4: Verify visually** + +Open the trip page in the browser. In DevTools: +- Select a journal article → confirm it has `data-type="journal"` +- Select a story article → confirm it has `data-type="story"` +- Story cards should now appear as a boxed card with a full teal border and rounded corners instead of a left-only bar + +- [ ] **Step 5: Commit** + +```bash +git add user/themes/intotheeast/templates/trip.html.twig user/themes/intotheeast/css/style.css +git commit -m "feat: add data-type attributes to feed cards; restyle story card with full border" +``` + +--- + +### Task 2: Filter bar markup + CSS (static, no JS yet) + +**Files:** +- Modify: `user/themes/intotheeast/templates/trip.html.twig:58-62` +- Modify: `user/themes/intotheeast/css/style.css` (append after `.home-trip-counts` block, around line 694) + +**Interfaces:** +- Consumes: nothing from prior tasks (static HTML) +- Produces: `.trip-filter-bar`, `.trip-filter-btn`, `.trip-stats-btn` CSS classes consumed by Task 3 + +- [ ] **Step 1: Replace nav with filter bar in trip.html.twig** + +Find the existing nav block (lines 58–62): +```twig + +``` +Replace with: +```twig +
+
+ + + +
+ +
+``` + +- [ ] **Step 2: Add filter bar CSS to style.css** + +After the `.home-trip-counts` rule (around line 694), append: +```css +/* ── Trip page filter bar ────────────────────────────────────────────────────── */ + +.trip-filter-bar { + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--space-3); + margin-top: var(--space-4); + flex-wrap: wrap; +} + +.trip-filter-group { + display: flex; + gap: var(--space-2); + flex-wrap: wrap; +} + +.trip-filter-btn, +.trip-stats-btn { + font-family: var(--font-ui); + font-size: var(--text-sm); + font-weight: 500; + color: var(--color-ink-muted); + background: transparent; + border: 1px solid var(--color-border); + border-radius: var(--radius-full); + padding: var(--space-1) var(--space-4); + cursor: pointer; + transition: color 0.15s, border-color 0.15s, background 0.15s; +} + +.trip-filter-btn:hover, +.trip-stats-btn:hover { + color: var(--color-ink); + border-color: var(--color-ink-muted); +} + +.trip-filter-btn.is-active, +.trip-stats-btn.is-active { + color: var(--color-accent); + border-color: var(--color-accent); + background: var(--color-accent-light); +} +``` + +- [ ] **Step 3: Verify visually** + +Open the trip page. Confirm: +- Three filter pills (All content / Journal / Stories) and a Stats button appear below the trip title +- "All content" pill has teal active styling +- Other pills are muted/bordered +- Clicking the buttons does nothing yet (no JS) + +- [ ] **Step 4: Commit** + +```bash +git add user/themes/intotheeast/templates/trip.html.twig user/themes/intotheeast/css/style.css +git commit -m "feat: add filter bar markup and pill button styles to trip page" +``` + +--- + +### Task 3: Filter JS (show/hide cards by type) + +**Files:** +- Modify: `user/themes/intotheeast/templates/trip.html.twig` (append to the existing ``) + +**Interfaces:** +- Consumes: `data-type` on articles (Task 1); `.trip-filter-btn`, `data-filter` (Task 2) +- Produces: working filter interaction + +- [ ] **Step 1: Add an empty-state element to the feed** + +In `trip.html.twig`, find the closing `` of the `.feed` block (after the `{% else %}` empty message). Add a hidden filter-empty message right before ``: +```twig + + +``` + +The full `.feed` block close should look like: +```twig + {% else %} +

No entries yet. The journey is about to begin.

+ {% endif %} + + +``` + +- [ ] **Step 2: Append filter JS to the existing script block** + +In `trip.html.twig`, find the closing `` tag at the bottom. Insert before it: +```javascript +(function() { + var filterBtns = document.querySelectorAll('.trip-filter-btn'); + var cards = document.querySelectorAll('[data-type]'); + var filterEmpty = document.getElementById('feed-filter-empty'); + + filterBtns.forEach(function(btn) { + btn.addEventListener('click', function() { + filterBtns.forEach(function(b) { b.classList.remove('is-active'); }); + btn.classList.add('is-active'); + + var filter = btn.getAttribute('data-filter'); + var visible = 0; + + cards.forEach(function(card) { + var show = filter === 'all' || card.getAttribute('data-type') === filter; + card.style.display = show ? '' : 'none'; + if (show) visible++; + }); + + if (filterEmpty) { + if (visible === 0) { + filterEmpty.textContent = filter === 'story' + ? 'No stories yet for this trip.' + : 'No entries yet.'; + filterEmpty.style.display = ''; + } else { + filterEmpty.style.display = 'none'; + } + } + }); + }); +})(); +``` + +- [ ] **Step 3: Verify filter behavior** + +Open the trip page. With demo entries loaded (run `make demo-load` if needed): +- Click **Journal** → only journal cards visible, story cards hidden +- Click **Stories** → only story cards visible, journal cards hidden +- Click **All content** → all cards visible again +- If no stories exist, clicking Stories shows "No stories yet for this trip." +- "All content" pill always has active state after clicking it + +- [ ] **Step 4: Commit** + +```bash +git add user/themes/intotheeast/templates/trip.html.twig +git commit -m "feat: wire up feed filter — All content / Journal / Stories" +``` + +--- + +### Task 4: Inline stats block (Twig computation + HTML + toggle JS) + +**Files:** +- Modify: `user/themes/intotheeast/templates/trip.html.twig` +- Modify: `user/themes/intotheeast/css/style.css` (append after filter bar CSS from Task 2) + +**Interfaces:** +- Consumes: `.trip-stats-btn#trip-stats-toggle` (Task 2); `journal_entries` variable already set at top of template +- Produces: expandable stats block; `STATS_GPS` JS variable for haversine distance + +- [ ] **Step 1: Add stats Twig computation at the top of the template** + +In `trip.html.twig`, after line 19 (`{% set story_count = story_entries|length %}`), add: +```twig +{# Stats computation #} +{% set days_on_road = 0 %} +{% set first_ts = null %} +{% for entry in journal_entries %} + {% set ts = entry.date|date('U') %} + {% if first_ts is null or ts < first_ts %} + {% set first_ts = ts %} + {% endif %} +{% endfor %} +{% if first_ts is not null %} + {% set now_ts = "now"|date('U') %} + {% set diff_seconds = now_ts - first_ts %} + {% set days_raw = (diff_seconds / 86400)|round(0, 'floor') %} + {% set days_on_road = days_raw < 1 ? 1 : days_raw %} +{% endif %} + +{% set seen_lower = [] %} +{% set country_display = [] %} +{% for entry in journal_entries %} + {% if entry.header.location_country is not empty %} + {% set lower = entry.header.location_country|trim|lower %} + {% if lower not in seen_lower %} + {% set seen_lower = seen_lower|merge([lower]) %} + {% set country_display = country_display|merge([entry.header.location_country|trim]) %} + {% endif %} + {% endif %} +{% endfor %} + +{% set gps_points = [] %} +{% for entry in journal_entries %} + {% if entry.header.lat is not empty and entry.header.lng is not empty %} + {% set gps_points = gps_points|merge([[entry.header.lat, entry.header.lng]]) %} + {% endif %} +{% endfor %} +``` + +- [ ] **Step 2: Add stats block HTML between filter bar and feed** + +In `trip.html.twig`, find the `
` line and insert the stats block immediately before it: +```twig + +``` + +- [ ] **Step 3: Add stats block CSS to style.css** + +Append after the filter bar CSS added in Task 2: +```css +/* ── Trip page inline stats block ───────────────────────────────────────────── */ + +.trip-stats-block { + background: var(--color-canvas); + border: 1px solid var(--color-border); + border-radius: var(--radius-md); + padding: var(--space-6); + margin-bottom: var(--space-6); +} + +.trip-stats-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: var(--space-4); + margin-bottom: var(--space-4); +} + +@media (max-width: 600px) { + .trip-stats-grid { grid-template-columns: repeat(2, 1fr); } +} + +.trip-stats-countries { + font-size: var(--text-sm); + color: var(--color-ink-2); + margin-bottom: var(--space-2); +} + +.trip-stats-note { + font-size: var(--text-xs); + color: var(--color-ink-muted); +} +``` + +Note: `.stat-block`, `.stat-value`, `.stat-label` are reused from `stats.html.twig` and already have CSS defined. Do not add duplicate rules. + +- [ ] **Step 4: Verify those existing CSS classes exist** + +Run: +```bash +grep -n "\.stat-block\|\.stat-value\|\.stat-label" user/themes/intotheeast/css/style.css +``` +Expected: at least 3 matches. If not found, copy from `stats.html.twig`'s inline `