From 28008da922fcba6701bf97ef05aea9e48a8adda8 Mon Sep 17 00:00:00 2001 From: Mischa Date: Sun, 21 Jun 2026 12:36:35 +0200 Subject: [PATCH 01/11] docs: restructure docs/ into guides/ reference/ working/ research/ --- docs/{posting-pipeline.md => guides/posting.md} | 0 docs/{ => working}/bugs-and-fixes.md | 0 docs/{superpowers => working}/plans/2026-06-18-grav2-upgrade.md | 0 docs/{superpowers => working}/plans/2026-06-19-dark-mode.md | 0 .../plans/2026-06-19-home-and-trip-pages.md | 0 .../plans/2026-06-19-maplibre-migration.md | 0 docs/{superpowers => working}/plans/2026-06-19-stats-redesign.md | 0 docs/{superpowers => working}/plans/2026-06-19-story-mode.md | 0 docs/{superpowers => working}/plans/2026-06-19-trip-entity.md | 0 .../plans/2026-06-19-trip-page-filter-bar.md | 0 .../plans/2026-06-19-tuscany-demo-stories.md | 0 .../plans/2026-06-20-accessibility-audit.md | 0 .../plans/2026-06-20-demo-data-redesign.md | 0 .../plans/2026-06-20-gpx-connector-logic.md | 0 .../plans/2026-06-20-inline-journal-feed.md | 0 docs/{superpowers => working}/plans/2026-06-20-pixelfed-import.md | 0 docs/{superpowers => working}/plans/2026-06-20-ui-ux-alignment.md | 0 .../plans/2026-06-21-documentation-restructure.md | 0 .../plans/2026-06-21-homepage-redesign.md | 0 docs/{ => working}/production-todo.md | 0 .../specs/2026-06-18-grav2-upgrade-design.md | 0 .../{superpowers => working}/specs/2026-06-19-dark-mode-design.md | 0 .../specs/2026-06-19-home-and-trip-pages-design.md | 0 docs/{superpowers => working}/specs/2026-06-19-stats-redesign.md | 0 .../specs/2026-06-19-trip-page-filter-bar-design.md | 0 .../specs/2026-06-19-tuscany-demo-stories-design.md | 0 .../specs/2026-06-20-accessibility-audit-design.md | 0 .../specs/2026-06-20-demo-data-redesign.md | 0 .../specs/2026-06-20-gpx-connector-logic-design.md | 0 .../specs/2026-06-20-inline-journal-feed-design.md | 0 .../specs/2026-06-20-pixelfed-import-design.md | 0 .../specs/2026-06-20-ui-ux-alignment-design.md | 0 .../specs/2026-06-21-documentation-restructure-design.md | 0 .../specs/2026-06-21-entry-enrichment-design.md | 0 .../specs/2026-06-21-homepage-redesign.md | 0 35 files changed, 0 insertions(+), 0 deletions(-) rename docs/{posting-pipeline.md => guides/posting.md} (100%) rename docs/{ => working}/bugs-and-fixes.md (100%) rename docs/{superpowers => working}/plans/2026-06-18-grav2-upgrade.md (100%) rename docs/{superpowers => working}/plans/2026-06-19-dark-mode.md (100%) rename docs/{superpowers => working}/plans/2026-06-19-home-and-trip-pages.md (100%) rename docs/{superpowers => working}/plans/2026-06-19-maplibre-migration.md (100%) rename docs/{superpowers => working}/plans/2026-06-19-stats-redesign.md (100%) rename docs/{superpowers => working}/plans/2026-06-19-story-mode.md (100%) rename docs/{superpowers => working}/plans/2026-06-19-trip-entity.md (100%) rename docs/{superpowers => working}/plans/2026-06-19-trip-page-filter-bar.md (100%) rename docs/{superpowers => working}/plans/2026-06-19-tuscany-demo-stories.md (100%) rename docs/{superpowers => working}/plans/2026-06-20-accessibility-audit.md (100%) rename docs/{superpowers => working}/plans/2026-06-20-demo-data-redesign.md (100%) rename docs/{superpowers => working}/plans/2026-06-20-gpx-connector-logic.md (100%) rename docs/{superpowers => working}/plans/2026-06-20-inline-journal-feed.md (100%) rename docs/{superpowers => working}/plans/2026-06-20-pixelfed-import.md (100%) rename docs/{superpowers => working}/plans/2026-06-20-ui-ux-alignment.md (100%) rename docs/{superpowers => working}/plans/2026-06-21-documentation-restructure.md (100%) rename docs/{superpowers => working}/plans/2026-06-21-homepage-redesign.md (100%) rename docs/{ => working}/production-todo.md (100%) rename docs/{superpowers => working}/specs/2026-06-18-grav2-upgrade-design.md (100%) rename docs/{superpowers => working}/specs/2026-06-19-dark-mode-design.md (100%) rename docs/{superpowers => working}/specs/2026-06-19-home-and-trip-pages-design.md (100%) rename docs/{superpowers => working}/specs/2026-06-19-stats-redesign.md (100%) rename docs/{superpowers => working}/specs/2026-06-19-trip-page-filter-bar-design.md (100%) rename docs/{superpowers => working}/specs/2026-06-19-tuscany-demo-stories-design.md (100%) rename docs/{superpowers => working}/specs/2026-06-20-accessibility-audit-design.md (100%) rename docs/{superpowers => working}/specs/2026-06-20-demo-data-redesign.md (100%) rename docs/{superpowers => working}/specs/2026-06-20-gpx-connector-logic-design.md (100%) rename docs/{superpowers => working}/specs/2026-06-20-inline-journal-feed-design.md (100%) rename docs/{superpowers => working}/specs/2026-06-20-pixelfed-import-design.md (100%) rename docs/{superpowers => working}/specs/2026-06-20-ui-ux-alignment-design.md (100%) rename docs/{superpowers => working}/specs/2026-06-21-documentation-restructure-design.md (100%) rename docs/{superpowers => working}/specs/2026-06-21-entry-enrichment-design.md (100%) rename docs/{superpowers => working}/specs/2026-06-21-homepage-redesign.md (100%) diff --git a/docs/posting-pipeline.md b/docs/guides/posting.md similarity index 100% rename from docs/posting-pipeline.md rename to docs/guides/posting.md diff --git a/docs/bugs-and-fixes.md b/docs/working/bugs-and-fixes.md similarity index 100% rename from docs/bugs-and-fixes.md rename to docs/working/bugs-and-fixes.md diff --git a/docs/superpowers/plans/2026-06-18-grav2-upgrade.md b/docs/working/plans/2026-06-18-grav2-upgrade.md similarity index 100% rename from docs/superpowers/plans/2026-06-18-grav2-upgrade.md rename to docs/working/plans/2026-06-18-grav2-upgrade.md diff --git a/docs/superpowers/plans/2026-06-19-dark-mode.md b/docs/working/plans/2026-06-19-dark-mode.md similarity index 100% rename from docs/superpowers/plans/2026-06-19-dark-mode.md rename to docs/working/plans/2026-06-19-dark-mode.md diff --git a/docs/superpowers/plans/2026-06-19-home-and-trip-pages.md b/docs/working/plans/2026-06-19-home-and-trip-pages.md similarity index 100% rename from docs/superpowers/plans/2026-06-19-home-and-trip-pages.md rename to docs/working/plans/2026-06-19-home-and-trip-pages.md diff --git a/docs/superpowers/plans/2026-06-19-maplibre-migration.md b/docs/working/plans/2026-06-19-maplibre-migration.md similarity index 100% rename from docs/superpowers/plans/2026-06-19-maplibre-migration.md rename to docs/working/plans/2026-06-19-maplibre-migration.md diff --git a/docs/superpowers/plans/2026-06-19-stats-redesign.md b/docs/working/plans/2026-06-19-stats-redesign.md similarity index 100% rename from docs/superpowers/plans/2026-06-19-stats-redesign.md rename to docs/working/plans/2026-06-19-stats-redesign.md diff --git a/docs/superpowers/plans/2026-06-19-story-mode.md b/docs/working/plans/2026-06-19-story-mode.md similarity index 100% rename from docs/superpowers/plans/2026-06-19-story-mode.md rename to docs/working/plans/2026-06-19-story-mode.md diff --git a/docs/superpowers/plans/2026-06-19-trip-entity.md b/docs/working/plans/2026-06-19-trip-entity.md similarity index 100% rename from docs/superpowers/plans/2026-06-19-trip-entity.md rename to docs/working/plans/2026-06-19-trip-entity.md diff --git a/docs/superpowers/plans/2026-06-19-trip-page-filter-bar.md b/docs/working/plans/2026-06-19-trip-page-filter-bar.md similarity index 100% rename from docs/superpowers/plans/2026-06-19-trip-page-filter-bar.md rename to docs/working/plans/2026-06-19-trip-page-filter-bar.md diff --git a/docs/superpowers/plans/2026-06-19-tuscany-demo-stories.md b/docs/working/plans/2026-06-19-tuscany-demo-stories.md similarity index 100% rename from docs/superpowers/plans/2026-06-19-tuscany-demo-stories.md rename to docs/working/plans/2026-06-19-tuscany-demo-stories.md diff --git a/docs/superpowers/plans/2026-06-20-accessibility-audit.md b/docs/working/plans/2026-06-20-accessibility-audit.md similarity index 100% rename from docs/superpowers/plans/2026-06-20-accessibility-audit.md rename to docs/working/plans/2026-06-20-accessibility-audit.md diff --git a/docs/superpowers/plans/2026-06-20-demo-data-redesign.md b/docs/working/plans/2026-06-20-demo-data-redesign.md similarity index 100% rename from docs/superpowers/plans/2026-06-20-demo-data-redesign.md rename to docs/working/plans/2026-06-20-demo-data-redesign.md diff --git a/docs/superpowers/plans/2026-06-20-gpx-connector-logic.md b/docs/working/plans/2026-06-20-gpx-connector-logic.md similarity index 100% rename from docs/superpowers/plans/2026-06-20-gpx-connector-logic.md rename to docs/working/plans/2026-06-20-gpx-connector-logic.md diff --git a/docs/superpowers/plans/2026-06-20-inline-journal-feed.md b/docs/working/plans/2026-06-20-inline-journal-feed.md similarity index 100% rename from docs/superpowers/plans/2026-06-20-inline-journal-feed.md rename to docs/working/plans/2026-06-20-inline-journal-feed.md diff --git a/docs/superpowers/plans/2026-06-20-pixelfed-import.md b/docs/working/plans/2026-06-20-pixelfed-import.md similarity index 100% rename from docs/superpowers/plans/2026-06-20-pixelfed-import.md rename to docs/working/plans/2026-06-20-pixelfed-import.md diff --git a/docs/superpowers/plans/2026-06-20-ui-ux-alignment.md b/docs/working/plans/2026-06-20-ui-ux-alignment.md similarity index 100% rename from docs/superpowers/plans/2026-06-20-ui-ux-alignment.md rename to docs/working/plans/2026-06-20-ui-ux-alignment.md diff --git a/docs/superpowers/plans/2026-06-21-documentation-restructure.md b/docs/working/plans/2026-06-21-documentation-restructure.md similarity index 100% rename from docs/superpowers/plans/2026-06-21-documentation-restructure.md rename to docs/working/plans/2026-06-21-documentation-restructure.md diff --git a/docs/superpowers/plans/2026-06-21-homepage-redesign.md b/docs/working/plans/2026-06-21-homepage-redesign.md similarity index 100% rename from docs/superpowers/plans/2026-06-21-homepage-redesign.md rename to docs/working/plans/2026-06-21-homepage-redesign.md diff --git a/docs/production-todo.md b/docs/working/production-todo.md similarity index 100% rename from docs/production-todo.md rename to docs/working/production-todo.md diff --git a/docs/superpowers/specs/2026-06-18-grav2-upgrade-design.md b/docs/working/specs/2026-06-18-grav2-upgrade-design.md similarity index 100% rename from docs/superpowers/specs/2026-06-18-grav2-upgrade-design.md rename to docs/working/specs/2026-06-18-grav2-upgrade-design.md diff --git a/docs/superpowers/specs/2026-06-19-dark-mode-design.md b/docs/working/specs/2026-06-19-dark-mode-design.md similarity index 100% rename from docs/superpowers/specs/2026-06-19-dark-mode-design.md rename to docs/working/specs/2026-06-19-dark-mode-design.md diff --git a/docs/superpowers/specs/2026-06-19-home-and-trip-pages-design.md b/docs/working/specs/2026-06-19-home-and-trip-pages-design.md similarity index 100% rename from docs/superpowers/specs/2026-06-19-home-and-trip-pages-design.md rename to docs/working/specs/2026-06-19-home-and-trip-pages-design.md diff --git a/docs/superpowers/specs/2026-06-19-stats-redesign.md b/docs/working/specs/2026-06-19-stats-redesign.md similarity index 100% rename from docs/superpowers/specs/2026-06-19-stats-redesign.md rename to docs/working/specs/2026-06-19-stats-redesign.md diff --git a/docs/superpowers/specs/2026-06-19-trip-page-filter-bar-design.md b/docs/working/specs/2026-06-19-trip-page-filter-bar-design.md similarity index 100% rename from docs/superpowers/specs/2026-06-19-trip-page-filter-bar-design.md rename to docs/working/specs/2026-06-19-trip-page-filter-bar-design.md diff --git a/docs/superpowers/specs/2026-06-19-tuscany-demo-stories-design.md b/docs/working/specs/2026-06-19-tuscany-demo-stories-design.md similarity index 100% rename from docs/superpowers/specs/2026-06-19-tuscany-demo-stories-design.md rename to docs/working/specs/2026-06-19-tuscany-demo-stories-design.md diff --git a/docs/superpowers/specs/2026-06-20-accessibility-audit-design.md b/docs/working/specs/2026-06-20-accessibility-audit-design.md similarity index 100% rename from docs/superpowers/specs/2026-06-20-accessibility-audit-design.md rename to docs/working/specs/2026-06-20-accessibility-audit-design.md diff --git a/docs/superpowers/specs/2026-06-20-demo-data-redesign.md b/docs/working/specs/2026-06-20-demo-data-redesign.md similarity index 100% rename from docs/superpowers/specs/2026-06-20-demo-data-redesign.md rename to docs/working/specs/2026-06-20-demo-data-redesign.md diff --git a/docs/superpowers/specs/2026-06-20-gpx-connector-logic-design.md b/docs/working/specs/2026-06-20-gpx-connector-logic-design.md similarity index 100% rename from docs/superpowers/specs/2026-06-20-gpx-connector-logic-design.md rename to docs/working/specs/2026-06-20-gpx-connector-logic-design.md diff --git a/docs/superpowers/specs/2026-06-20-inline-journal-feed-design.md b/docs/working/specs/2026-06-20-inline-journal-feed-design.md similarity index 100% rename from docs/superpowers/specs/2026-06-20-inline-journal-feed-design.md rename to docs/working/specs/2026-06-20-inline-journal-feed-design.md diff --git a/docs/superpowers/specs/2026-06-20-pixelfed-import-design.md b/docs/working/specs/2026-06-20-pixelfed-import-design.md similarity index 100% rename from docs/superpowers/specs/2026-06-20-pixelfed-import-design.md rename to docs/working/specs/2026-06-20-pixelfed-import-design.md diff --git a/docs/superpowers/specs/2026-06-20-ui-ux-alignment-design.md b/docs/working/specs/2026-06-20-ui-ux-alignment-design.md similarity index 100% rename from docs/superpowers/specs/2026-06-20-ui-ux-alignment-design.md rename to docs/working/specs/2026-06-20-ui-ux-alignment-design.md diff --git a/docs/superpowers/specs/2026-06-21-documentation-restructure-design.md b/docs/working/specs/2026-06-21-documentation-restructure-design.md similarity index 100% rename from docs/superpowers/specs/2026-06-21-documentation-restructure-design.md rename to docs/working/specs/2026-06-21-documentation-restructure-design.md diff --git a/docs/superpowers/specs/2026-06-21-entry-enrichment-design.md b/docs/working/specs/2026-06-21-entry-enrichment-design.md similarity index 100% rename from docs/superpowers/specs/2026-06-21-entry-enrichment-design.md rename to docs/working/specs/2026-06-21-entry-enrichment-design.md diff --git a/docs/superpowers/specs/2026-06-21-homepage-redesign.md b/docs/working/specs/2026-06-21-homepage-redesign.md similarity index 100% rename from docs/superpowers/specs/2026-06-21-homepage-redesign.md rename to docs/working/specs/2026-06-21-homepage-redesign.md From 5aad6a376005ba364ba713cfc166e753ae0b9630 Mon Sep 17 00:00:00 2001 From: Mischa Date: Sun, 21 Jun 2026 12:38:43 +0200 Subject: [PATCH 02/11] docs: move research-story-editing to research/story-editing.md --- docs/{research-story-editing.md => research/story-editing.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/{research-story-editing.md => research/story-editing.md} (100%) diff --git a/docs/research-story-editing.md b/docs/research/story-editing.md similarity index 100% rename from docs/research-story-editing.md rename to docs/research/story-editing.md From 05d65652bdf401ba435499c48dd9065a09372f29 Mon Sep 17 00:00:00 2001 From: Mischa Date: Sun, 21 Jun 2026 12:42:32 +0200 Subject: [PATCH 03/11] docs: move remaining untracked files to restructured locations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - milestone specs: docs/milestone-*-spec.md → docs/working/milestones/milestone-*.md - qa files: docs/qa-*.md → docs/working/qa/*.md - research files: docs/research-*.md → docs/research/*.md - design spec: docs/design/design-spec.md → docs/reference/design-system.md - backlog, pm-analysis, summary: moved to docs/working/ --- docs/reference/design-system.md | 368 +++++++++++++++ docs/research/findpenguins.md | 141 ++++++ docs/research/polarsteps.md | 137 ++++++ docs/working/backlog.md | 11 + docs/working/milestones/milestone-1.md | 193 ++++++++ docs/working/milestones/milestone-2.md | 166 +++++++ docs/working/milestones/milestone-3.md | 182 +++++++ docs/working/milestones/milestone-4.md | 91 ++++ docs/working/pm-analysis.md | 161 +++++++ docs/working/qa/results.md | 217 +++++++++ docs/working/qa/test-plan.md | 628 +++++++++++++++++++++++++ docs/working/summary.md | 89 ++++ 12 files changed, 2384 insertions(+) create mode 100644 docs/reference/design-system.md create mode 100644 docs/research/findpenguins.md create mode 100644 docs/research/polarsteps.md create mode 100644 docs/working/backlog.md create mode 100644 docs/working/milestones/milestone-1.md create mode 100644 docs/working/milestones/milestone-2.md create mode 100644 docs/working/milestones/milestone-3.md create mode 100644 docs/working/milestones/milestone-4.md create mode 100644 docs/working/pm-analysis.md create mode 100644 docs/working/qa/results.md create mode 100644 docs/working/qa/test-plan.md create mode 100644 docs/working/summary.md diff --git a/docs/reference/design-system.md b/docs/reference/design-system.md new file mode 100644 index 0000000..b6519d9 --- /dev/null +++ b/docs/reference/design-system.md @@ -0,0 +1,368 @@ +# Into the East — Design Spec + +**Date:** 2026-06-18 +**Status:** Approved for implementation + +--- + +## 1. Direction + +**The brief:** A personal travel journal, sole author, trip to East Asia. Three weeks to implement before departure. Audience is both friends/family and the occasional curious stranger. + +**The position:** Neither Polarsteps nor FindPenguins. Both optimize for social sharing of travel data. This site optimizes for **the story** — and should feel like reading a well-edited travel journal, not using an app. + +**What we steal from each:** +- Polarsteps: photography-first hierarchy, airy whitespace, map as the emotional spine of the trip +- FindPenguins: typography as brand identity, stats as trophy case, hierarchical trip → entry structure + +**What we do better than both:** +- Web-native: fast, linkable, no install, works on any browser +- Single author = pure editorial voice, no social noise +- Full CSS control = real typographic identity, not generic app chrome +- Editorial feel: more travel magazine, less productivity dashboard + +**Aesthetic direction:** Field notes. The kind of journal a thoughtful traveler would carry — clean, direct, lets the photography speak. Sophisticated without effort. + +**The one aesthetic risk:** Full-bleed hero photography with a translucent date+location overlay at the bottom of each card. The photo IS the entry card — not a thumbnail beside text. This is the single element that distinguishes this design from both reference apps and from typical blog layouts. + +--- + +## 2. Color System + +### Palette + +| Token | Hex | Usage | +|---|---|---| +| `--color-ink` | `#17171A` | Primary text (near-black with cool undertone, like ink) | +| `--color-ink-2` | `#4A4850` | Secondary text, body paragraphs | +| `--color-ink-muted` | `#9896A0` | Labels, timestamps, captions, placeholder text | +| `--color-paper` | `#F7F5F2` | Page background (warm paper white, not blue-white) | +| `--color-canvas` | `#FFFFFF` | Card backgrounds, modals, form surfaces | +| `--color-border` | `#E8E6E3` | Standard dividers, card borders | +| `--color-border-soft` | `#F0EDEA` | Subtle section dividers | +| `--color-accent` | `#1F6B5A` | Deep teal — brand color, links, CTAs, active states | +| `--color-accent-hover` | `#185647` | Darkened accent for hover/pressed states | +| `--color-accent-light` | `#EBF5F2` | Pale teal for highlight backgrounds | +| `--color-accent-on` | `#FFFFFF` | Text on accent-colored surfaces | + +### Rationale for accent color + +Deep teal `#1F6B5A` was chosen over: +- Blue (#0066cc current): too generic, too tech +- Orange/saffron: clichéd for "Asia" travel design +- Terracotta/cream: the most common default for lifestyle/travel blogs + +Teal evokes bamboo, celadon porcelain, ancient jade, the color of temple gardens — all without being literal or kitsch. It works cleanly against both the warm paper background and white card surfaces. + +--- + +## 3. Typography + +### Fonts + +| Role | Family | Fallback | Source | +|---|---|---|---| +| Display / Headings | DM Serif Display | Georgia, serif | Google Fonts | +| UI / Body / Labels | DM Sans | -apple-system, BlinkMacSystemFont, sans-serif | Google Fonts | + +**Google Fonts URL:** +``` +https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;1,9..40,400&family=DM+Serif+Display:ital@0;1&display=swap +``` + +**Why this pairing:** +DM Serif Display has a calligraphic quality — slightly editorial, authoritative but not stiff. Paired with DM Sans (its designed companion) the system is cohesive. DM Sans is neutral and highly legible at all sizes. Both are under-used relative to Inter/Lato/Playfair, so the combination has a distinctive voice without being trendy. + +### Type Scale + +| Token | Size | Line Height | Usage | +|---|---|---|---| +| `--text-xs` | 0.75rem (12px) | 1.5 | Badges, captions | +| `--text-sm` | 0.875rem (14px) | 1.5 | Meta, timestamps, labels | +| `--text-base` | 1rem (16px) | 1.65 | Body paragraphs | +| `--text-md` | 1.125rem (18px) | 1.55 | Lead text, intro paragraphs | +| `--text-lg` | 1.375rem (22px) | 1.35 | Subheadings, card titles (mobile) | +| `--text-xl` | 1.75rem (28px) | 1.25 | Entry card titles | +| `--text-2xl` | 2.25rem (36px) | 1.2 | Page headings, entry titles (desktop) | +| `--text-3xl` | 3rem (48px) | 1.1 | Hero entry title | + +### Usage rules + +- Entry titles: `--font-display`, `--text-xl` (mobile) / `--text-2xl` (desktop) +- Site title in header: `--font-display`, `--text-lg` +- All other UI text: `--font-ui` +- Body paragraphs: `--font-ui`, `--text-base`, `--leading-normal` +- Timestamps/badges: `--font-ui`, `--text-xs`, uppercase, `letter-spacing: 0.07em` + +--- + +## 4. Spacing & Layout + +### Spacing scale (4px base unit) + +| Token | Value | +|---|---| +| `--space-1` | 0.25rem (4px) | +| `--space-2` | 0.5rem (8px) | +| `--space-3` | 0.75rem (12px) | +| `--space-4` | 1rem (16px) | +| `--space-5` | 1.25rem (20px) | +| `--space-6` | 1.5rem (24px) | +| `--space-8` | 2rem (32px) | +| `--space-10` | 2.5rem (40px) | +| `--space-12` | 3rem (48px) | +| `--space-16` | 4rem (64px) | + +### Layout + +- Content max-width: `720px` (comfortable reading at any font size) +- Page horizontal padding: `1.25rem` (mobile), `1.5rem` (desktop ≥520px) +- Header height: `60px` (fixed, for JS offset calculations) +- Map page: full viewport, no content max-width constraint + +### Border radius + +| Token | Value | Usage | +|---|---|---| +| `--radius-sm` | 4px | Photo corners, small chips | +| `--radius-md` | 8px | Cards, buttons, inputs | +| `--radius-lg` | 12px | Large cards, modals | +| `--radius-full` | 9999px | Pills, badges | + +### Shadows + +| Token | Value | Usage | +|---|---|---| +| `--shadow-sm` | `0 1px 3px rgba(0,0,0,0.08)` | Stat blocks, subtle elevation | +| `--shadow-md` | `0 4px 12px rgba(0,0,0,0.10)` | Cards on hover, dropdowns | +| `--shadow-lg` | `0 8px 24px rgba(0,0,0,0.14)` | Lightbox, modals | + +--- + +## 5. Component Inventory + +### 5.1 Site Header + +``` +[ into the east ] [ Journal Map Stats ] +← accent bar across top (3px) ─────────────────────────────── +``` + +- Top border: `3px solid var(--color-accent)` — thin accent bar signals the brand color without decorating +- Site title: DM Serif Display, `--text-lg`, no decoration +- Nav links: DM Sans, `--text-sm`, weight 500, `--color-ink-2` +- Active nav link: `--color-accent`, weight 600 +- Mobile: same layout, title slightly smaller, nav links compact +- Background: `--color-canvas` (white), bottom border `1px solid var(--color-border)` + +### 5.2 Entry Feed Card — With Photo + +``` +┌─────────────────────────────────────┐ +│ │ +│ [photo] │ ← full-width, 16:9, rounded corners +│ │ +│ 18 JUN · 📍 Kyoto, Japan │ ← overlaid at bottom, gradient mask +└─────────────────────────────────────┘ + Arrived in Tokyo ← DM Serif Display, --text-xl + After 14 hours of flying I finally ← body excerpt, --color-ink-2 + set foot on Japanese soil... + Read entry → ← --color-accent, --text-sm +``` + +- Photo: `aspect-ratio: 16/9`, `object-fit: cover`, `border-radius: var(--radius-md)` +- Photo has a `linear-gradient(to top, rgba(0,0,0,0.55), transparent)` overlay at the bottom 40% +- Date + location sit on top of gradient in white text (`rgba(255,255,255,0.92)`) +- On hover: photo scales to 1.03 (subtle zoom, 0.4s ease) +- Title below photo: DM Serif Display, hover turns `--color-accent` +- Card separation: `padding-bottom: var(--space-12)` + `border-bottom: 1px solid var(--color-border)` + +### 5.3 Entry Feed Card — No Photo + +When no photo is available, fall back to a text-only layout: + +``` + 18 JUN 2026 · 📍 Kyoto, Japan ← meta row, --text-sm, --color-ink-muted + + Arrived in Tokyo ← DM Serif Display, --text-xl + After 14 hours of flying... + Read entry → +``` + +- No photo container +- Meta (date + location) on one line above title, small + muted + +### 5.4 Single Entry Page + +``` + Wednesday, 18 June 2026 ← --text-sm, --color-ink-muted, uppercase + 📍 Kyoto, Japan · ⛅ Partly cloudy · 22°C + + Arrived in Tokyo ← DM Serif Display, --text-2xl / --text-3xl + ───────────────────────────────────── + Body text content... ← --font-ui, --text-base/md + + [Photo gallery — 2 or 3 col grid] + + ← Back to journal +``` + +- The entry title uses `--font-display` at largest scale +- A thin `--color-border` rule separates the header from the body +- Body text is `--text-md` (18px) for comfortable long-form reading +- Full-bleed hero option: if a `hero_image` is set, it spans the full content width with a bottom margin + +### 5.5 Post Form (Author View) + +``` + New Entry + + Title * [________________________] + Date & Time [2026-06-18 14:30 ] + What happened [ ] + today? [ ] + [ ] + + Photos [ + Add photos (max 4) ] + + City [________________________] + Country [________________________] + + [ 📍 Get Location ] [ 🌤 Get Weather ] + ✓ Location captured: Kyoto, Japan ← status line + + [ Post Entry ] +``` + +UX changes from current: +- Lat/lng inputs **hidden from the UI** (remain in the form as `display:none` for data capture, filled by JS) +- Location status shows captured city/country + coordinates in a single line (not separate status paragraphs) +- Photo upload area: larger touch target, visual indication of count +- "Post Entry" button: `--color-accent` background, full-width on mobile, `min-height: 52px` +- Form fields: `--radius-md` corners, `--color-border` border, focus ring in `--color-accent` +- Section spacing: generous vertical rhythm on mobile + +### 5.6 Stats Page + +``` + ┌────────────┐ ┌────────────┐ + │ 42 │ │ 18 │ + │ days on │ │ entries │ + │ the road │ │ posted │ + └────────────┘ └────────────┘ + ┌────────────┐ ┌────────────┐ + │ 6 │ │ ~14,200 │ + │ countries │ │ km │ + │ visited │ │ traveled │ + └────────────┘ └────────────┘ + + Countries visited + Japan · South Korea · Mongolia · Russia · Finland · Estonia +``` + +- Numbers: `--font-display`, `--text-3xl`, `--color-accent` +- Labels: `--font-ui`, `--text-xs`, uppercase, `--color-ink-muted` +- Cards: white, `--shadow-sm`, `--radius-md`, centered + +### 5.7 Map Page + +Minimal changes — the map itself is good. Style improvements: +- Leaflet popups: match the new design (DM Sans, `--radius-md`, `--shadow-md`) +- Markers: keep current circle style, update color to `--color-accent` +- Feed mini-map wrapper: match `--radius-md`, `--border` + +--- + +## 6. UX Flows + +### 6.1 Reader — First Visit + +1. Land on `/tracker` (journal feed) +2. See mini-map above fold (if entries exist) — route tells the geographic story at a glance +3. First entry card: full-bleed hero photo with date/location overlay — immediate emotional pull +4. Scroll through chronological entries +5. Tap/click entry → entry detail page +6. Navigate back via "← Back to journal" + +**Key principle:** The reader should understand the journey spatially (mini-map) and emotionally (hero photo) before reading a single word. + +### 6.2 Reader — Navigation + +- Journal: primary destination, the feed +- Map: geographic exploration mode +- Stats: quick numbers, satisfying progress indicator +- No account required, no social friction, no login prompt for readers + +### 6.3 Author — Posting from Mobile + +1. Navigate to `/post` (bookmark on home screen) +2. Already logged in (Grav session persists) — form loads directly +3. **Title**: tap → type (autofocused) +4. **Date & Time**: auto-filled to now, adjust if needed +5. **Content**: write what happened +6. **Photos**: tap "Add photos" → camera or gallery → select up to 4 +7. **Location**: tap "📍 Get Location" → GPS fires → status shows "Kyoto, Japan · 34.985, 135.758" in one line +8. **Weather**: tap "🌤 Get Weather" (works only if location was captured) → status shows "Partly cloudy · 22°C" +9. **City/Country**: auto-populated from GPS is a nice-to-have for v2; in v1 type manually if needed +10. Tap "Post Entry" → success message → 2-second pause → redirect to /tracker (new entry visible at top) + +**Key principles:** +- One-thumb operation for all critical actions on mobile +- Location/weather are conveniences, not blockers — can skip both +- Visual feedback is immediate (status line updates on GPS response) +- After submit: don't leave author on a success message page; redirect to see their new post + +--- + +## 7. Mobile Specifics + +### Touch targets +- All interactive elements: `min-height: 44px`, `min-width: 44px` (Apple HIG standard) +- Form buttons: `min-height: 52px` on the post form (primary CTA) +- Nav links: `padding: 0.5rem 0.75rem` + +### Viewport concerns +- Map page: `height: calc(100vh - 60px)`, `touch-action: none` on map container — prevents scroll trap +- Photo lightbox: full viewport overlay, swipe-friendly (keyboard + click already implemented) +- Form on mobile: single-column, generous input padding `0.875rem 1rem`, `font-size: 1rem` (prevents iOS zoom on focus) + +### Performance +- Google Fonts: loaded with `preconnect` hints +- Images: `loading="lazy"` on all non-above-fold images (already in place) +- Leaflet: loaded from CDN, only on pages that need it +- No new JS frameworks — vanilla JS throughout + +--- + +## 8. Tech Stack Decision + +**Keep Grav CMS.** With a 3-week timeline, replacing it would consume all available time on migration rather than design improvements. + +| Layer | Decision | Rationale | +|---|---|---| +| Backend | Grav CMS (PHP, Twig) — unchanged | Works, flat-file, no DB | +| CSS | Vanilla CSS + custom properties (design tokens) | No build step, full control, ships as one file | +| JS | Vanilla JS — unchanged | Current JS is well-structured, scope doesn't justify a framework | +| Icons | Unicode + emoji (current) | No dependency, works everywhere | +| Fonts | Google Fonts via CDN | Two fonts, display-swap, negligible impact | +| Maps | Leaflet.js (current) | Already in use, no reason to change | +| Build | None — no build pipeline | Grav's asset pipeline handles minification if needed | + +**No Alpine.js, no TypeScript, no Tailwind.** The site has clean vanilla JS and CSS today; a redesign is about visual quality, not framework migration. Introducing a build pipeline on a 3-week timeline is a distraction. + +--- + +## 9. What Changes From Current Design + +| Area | Current | New | +|---|---|---| +| Typography | System sans-serif only | DM Serif Display for headings + DM Sans for UI | +| Accent color | `#0066cc` (generic blue) | `#1F6B5A` (deep teal) | +| Background | `#ffffff` (pure white) | `#F7F5F2` (warm paper) | +| Entry cards | Thumbnail + text below | Full-bleed 16:9 photo with overlay | +| Header | No visual identity | Accent top-border, typographic title | +| Design tokens | Hardcoded values throughout | CSS custom properties throughout | +| Post form | Lat/lng visible inputs | Lat/lng hidden, single status line | +| Font loading | None | Google Fonts DM pairing | +| Hover states | Minimal | Photo zoom, title color change | +| Stat numbers | `#0066cc` | `--color-accent` (#1F6B5A) | diff --git a/docs/research/findpenguins.md b/docs/research/findpenguins.md new file mode 100644 index 0000000..4c46449 --- /dev/null +++ b/docs/research/findpenguins.md @@ -0,0 +1,141 @@ +# FindPenguins — Feature Research + +*Researched June 2026. Source: findpenguins.com, App Store, support docs, reviews.* + +--- + +## Overview + +FindPenguins is a German travel tracking and community app. Core features are free; premium subscription ($4.99/month or $32.99/year) unlocks more photos per post and ebook exports. Revenue comes from subscriptions and printed photo books ($40–240). It leans more social than Polarsteps — discovery, community, and inspiring other travelers are central to its identity. + +--- + +## Core User Flow + +1. User creates a **Trip** (title, dates, cover) +2. App runs in background with **automatic GPS + flight detection tracking** +3. User creates **Footprints** — individual journal entries tied to a location and time +4. Each Footprint can contain: location, title, date, text story, photos, video, weather +5. Footprints appear in a **chronological timeline** per trip +6. Trip is shareable; social followers can view, comment, react +7. At the end, optionally order a printed **photo book** + +--- + +## Map Features + +- **Automatic route tracking**: GPS + flight detection, works offline +- **Interactive world map**: route lines drawn between footprints +- **3D flyover video**: auto-generated cinematic route visualization, free +- **Countries/continents highlighted**: on personal map +- **Visited places completion**: stats on what % of a country/region visited +- Battery usage: ~4% per day (comparable to Polarsteps) +- Route visualized as path on map, not just pins + +--- + +## Footprints (Journal Entries) + +Each "Footprint" is the core content unit: + +- **Location**: GPS-detected, shown as city/country; uses reverse geocoding (LocationIQ) +- **Title**: required, user-set +- **Date**: required, defaults to current time +- **Text story**: freeform journal text +- **Photos**: 6 (free) / 10 (premium) per footprint +- **Videos**: 1 (free) / 2 (premium) per footprint +- **Weather**: auto-populated at location + time; manually editable +- **Place name**: auto-detected city/neighborhood/country, editable +- **Selective sharing**: each footprint can be public, friends-only, or private +- **Delayed posting**: option to share location with a time delay (privacy feature) + +--- + +## Photo Handling + +- Up to 6 photos per footprint (free), 10 (premium) +- 1 video per footprint (free), 2 (premium) +- Photos displayed in carousel/grid within footprint +- High-res stored for photobook printing +- Cover photo selectable per trip + +--- + +## Statistics + +- Countries visited (count + list + % world) +- Continents visited +- Total distance traveled +- Number of footprints / trips +- Days on the road +- World coverage percentage +- Shown on profile and within photo books + +--- + +## Social & Discovery Features + +- **Follower system**: follow other travelers, see their public footprints +- **Comments**: friends/followers can comment on individual footprints +- **Reactions**: like/react to footprints +- **Discovery**: browse 10M+ travel experiences from other users by destination +- **Group trips**: invite co-travelers to add footprints to a shared trip (with known bug: co-travelers can delete each other's content) +- **Travel inspiration**: browse community trips to plan your own +- **Explore by destination**: search real traveler experiences for any city/country + +--- + +## Privacy Controls + +- Per-footprint visibility: public / friends / private +- **Delayed sharing**: share location with a configurable time delay (safety feature for solo travelers) +- Trip-level privacy: whole trip can be private or public +- Can hide real-time location from followers + +--- + +## Photo Book (Premium) + +- Printed book with maps, photos, text, statistics, and friend comments +- €40–€240 depending on size/format (hardcover or layflat) +- Free ebook version for premium subscribers +- 5% discount on books with premium + +--- + +## 3D Flyover Video + +- Free feature: auto-generates a cinematic 3D video of your route +- Shareable directly from the app +- No native app required for viewing (shareable link) + +--- + +## Offline Capability + +- Tracker works fully offline (GPS, flight detection) +- Footprints can be created and edited offline +- Syncs when connected + +--- + +## What Makes FindPenguins Distinctive + +1. **Flight detection**: auto-detects flights and logs them on the route +2. **3D flyover video**: compelling visual output, free +3. **Delayed sharing**: useful for solo travelers worried about broadcasting real-time location +4. **Richer social layer**: comments on individual footprints, community discovery +5. **Destination exploration**: browse real traveler posts for any place (like a user-generated travel guide) +6. **Premium photo books**: more polished physical product with friend comments included + +--- + +## Limitations (relevant to our context) + +- Requires native app for GPS/flight tracking — not reproducible in a web CMS +- Social discovery features irrelevant for a solo personal blog +- Group trip feature has a bug (co-travelers can delete your content) +- Premium paywall for basic things like more than 6 photos per post +- Community/social focus means the UX is designed around a social graph we don't have +- 3D flyover video requires proprietary rendering pipeline +- Real-time delayed sharing is a privacy feature for apps broadcasting live location — moot for a blog that posts after the fact diff --git a/docs/research/polarsteps.md b/docs/research/polarsteps.md new file mode 100644 index 0000000..1c62416 --- /dev/null +++ b/docs/research/polarsteps.md @@ -0,0 +1,137 @@ +# Polarsteps — Feature Research + +*Researched June 2026. Source: polarsteps.com, App Store, support docs, reviews.* + +--- + +## Overview + +Polarsteps is a travel tracking and journaling app used by 20M+ travelers. It is ad-free, primarily free to use, with paid travel books as the main revenue stream. It positions itself as "by travelers, for travelers" — clean, minimal, focused on personal memory-keeping and sharing with close friends/family rather than a social discovery platform. + +--- + +## Core User Flow + +1. User creates a **Trip** (name, start/end dates, cover photo) +2. App runs in background and **auto-tracks GPS route** continuously (dots on map) +3. App auto-generates **Step Suggestions** when you stay somewhere — a notification asks "Are you in [City]? Add a step?" +4. User accepts or manually creates a **Step**: a journal entry tied to a location +5. Each Step gets: title, text, photos/videos, date, and auto-populated metadata +6. Steps appear in a **timeline feed** ordered chronologically +7. Trip is shareable via link; friends/family can follow in real time + +--- + +## Map Features + +- **Route tracking**: GPS + WiFi + cell towers → white dots plotted on world map as you move +- **Offline tracking**: stores locally, syncs when connected +- **Travel Tracker steps**: actual route taken (not straight lines), with transport mode tagging (car, bus, train, taxi, walk, fly) +- **Route visualization**: colored line on map connecting all steps +- **Countries/continents visited**: highlighted on world map +- **Battery usage**: ~4% per day (very efficient) +- **World completion %**: gamified stat showing % of the globe visited +- Tracks distance, speed, and estimated travel time between steps + +--- + +## Steps (Journal Entries) + +Each "Step" is the core content unit: + +- **Location**: auto-detected city/country, adjustable +- **Title**: auto-suggested from location, editable +- **Date/time**: auto from GPS +- **Text**: rich freeform journal text +- **Photos**: unlimited (mobile app), displayed in a grid/carousel +- **Videos**: supported on mobile only, excluded from printed books +- **Weather**: auto-populated (temperature, conditions) at time of step +- **Altitude**: recorded from GPS +- **GPS coordinates**: stored and displayed +- **Transport**: mode of travel to reach this step (car/train/fly/etc.) + +--- + +## Photo Handling + +- Add photos directly from camera roll per step +- Choose cover photo for the trip +- Photos displayed in gallery within each step +- High-resolution stored for travel book printing +- No hard per-step photo limit mentioned (effectively unlimited) +- Videos supported on mobile, excluded from print + +--- + +## Statistics + +Displayed on trip and profile level: +- Total km/miles traveled +- Countries visited (count + list) +- Continents visited +- Number of steps/entries +- Days on the road +- World completion percentage +- Furthest point from home +- Number of followers / following + +--- + +## Sharing & Social Features + +- **Privacy**: "Only me", "Followers only", or "Public" +- **Shareable link**: send a URL to anyone to follow the trip live +- **Followers**: people can follow your profile and see all public trips +- **Reactions/comments**: followers can react and comment on steps +- **Social media sharing**: export to Facebook, Instagram, etc. +- **Travel Buddy**: invite friends to join and co-document a trip together +- **Editors' Choice**: curated featured trips for discovery (like a magazine) +- **Trip Reels**: auto-generated short video from photos/videos + visited places, shareable + +--- + +## Planning Features (2025 addition) + +- **AI Itinerary Builder**: generates multi-stop travel plan on the map, with transport modes +- **Accommodation import**: forward booking confirmation emails to plan@polarsteps.app → appears on map +- **Activity planning**: add stays, restaurants, activities to itinerary +- **Travel DNA**: personality-based personalization for AI suggestions + +--- + +## Travel Book + +- Print a hardback book of your trip (€30–80, 24–300 pages) +- Each step on its own page: photo, text, map thumbnail, metadata +- Statistics page at the end +- Designed, high-quality output — main revenue for Polarsteps + +--- + +## Offline Capability + +- Full offline posting (text, photos) +- GPS route tracking continues offline +- All data syncs when back online + +--- + +## What Makes Polarsteps Distinctive + +1. **Simplicity** — minimal UI, auto-everything, almost no friction to log a day +2. **Route tracking** — actually shows where you walked/drove, not just pins +3. **"Step suggestions"** — proactive nudges to journal without opening the app +4. **Printed book** — the premium product, excellent quality +5. **Ad-free** — rare among free travel apps +6. **Battery efficiency** — 4% per day, usable on long trips + +--- + +## Limitations (relevant to our context) + +- Requires native mobile app for GPS tracking (cannot do in browser) +- Videos excluded from print +- Social/discovery features add little value for a solo personal blog +- AI itinerary builder overkill for one-person blog +- Travel Buddy / follower system assumes a social graph we don't have +- Reels require the native app video processing pipeline diff --git a/docs/working/backlog.md b/docs/working/backlog.md new file mode 100644 index 0000000..393b1e0 --- /dev/null +++ b/docs/working/backlog.md @@ -0,0 +1,11 @@ +# Backlog + +Ideas and improvements not yet planned or scheduled. + +--- + +## GPX Manager (`/gpx-manager`) + +- [ ] **Polish the UI** — the current design is functional but bare; align with the Field Notes aesthetic, add better empty states, drag-and-drop upload area +- [ ] **Link from Admin2** — Admin2 is a compiled SPA so we can't inject a sidebar link; options: (1) add a link to the site's nav when logged in, (2) a bookmarklet, or (3) wait for Admin2 to support plugin-contributed sidebar entries +- [ ] **Komoot integration** — explore how to pull GPX routes directly from Komoot without a manual export step. Komoot has an API (`api.komoot.de`) that returns GPX for a tour given its ID. Could be: a field on the GPX manager where you paste a Komoot tour URL/ID and it fetches + saves server-side, or a script run via `make`. Worth researching auth requirements (public tours may not need auth). diff --git a/docs/working/milestones/milestone-1.md b/docs/working/milestones/milestone-1.md new file mode 100644 index 0000000..6413fff --- /dev/null +++ b/docs/working/milestones/milestone-1.md @@ -0,0 +1,193 @@ +# Milestone 1 Spec — Entry Enrichment + +**Goal:** Every entry is richer out of the box — location name shown, weather auto-captured, photos in a proper gallery, hero image visible on the feed. + +--- + +## User Stories + +- As a traveler (Mischa), when I submit the post form, I want my current weather conditions auto-filled so I don't have to look them up manually. +- As a traveler, I want to type my city and country once and have it appear on the entry and in the feed card, so readers know where I am without reading the whole post. +- As a reader, when I scan the feed, I want to see a thumbnail photo and location for each entry so I can quickly get a sense of where Mischa is and whether to read the full entry. +- As a reader, when I open an entry, I want to see all uploaded photos in a gallery I can browse, not a wall of raw images. +- As a traveler, when I submit a form without photos, the entry should still display cleanly with no broken image placeholders. + +--- + +## Feature Details + +### 1.1 — Location Name Field on Post Form + +**What:** Add two text fields to the post form: `location_city` and `location_country`. + +**Behavior:** +- Both are optional (GPS coordinates are also optional) +- Placeholder text: "e.g. Kyoto" and "e.g. Japan" +- Displayed below the lat/lng fields +- On submit, stored in entry frontmatter as `location_city` and `location_country` +- On the form, shown as a single labeled group "Location Name" with two side-by-side inputs on desktop, stacked on mobile + +**Edge cases:** +- If left blank: entry shows no location badge. No error, no broken UI. +- Long city names (e.g. "Ulaanbaatar") must not overflow card layout. +- Special characters (accents, non-Latin) must render correctly. + +**Mobile behavior:** Both fields full-width, stacked, 44px min touch targets. + +--- + +### 1.2 — Weather Auto-Fetch on Post Form + +**What:** A "Get Weather" button on the post form that calls the Open-Meteo free API (no API key) using the lat/lng already entered, and fills hidden weather fields. + +**Fields to fetch and store:** +- `weather_temp_c` — temperature in Celsius (integer) +- `weather_desc` — short description: one of: Sunny, Partly cloudy, Cloudy, Foggy, Drizzle, Rain, Snow, Thunderstorm (derived from WMO weather code) + +**WMO code mapping (Open-Meteo uses WMO codes):** +- 0 → Sunny +- 1,2 → Partly cloudy +- 3 → Cloudy +- 45,48 → Foggy +- 51,53,55,56,57 → Drizzle +- 61,63,65,66,67,80,81,82 → Rain +- 71,73,75,77,85,86 → Snow +- 95,96,99 → Thunderstorm + +**API call:** +``` +https://api.open-meteo.com/v1/forecast?latitude={lat}&longitude={lng}¤t=temperature_2m,weather_code&temperature_unit=celsius +``` + +**UX flow:** +1. User fills in lat/lng (manually or via "Get Location" button) +2. User taps "Get Weather" button +3. Button shows "Fetching…" while loading +4. On success: fills temp and desc fields (visible, editable text inputs) +5. On failure (no network, no lat/lng): shows inline error "Could not fetch weather — enter manually" + +**Edge cases:** +- If lat/lng not filled when button tapped: show inline error "Enter coordinates first" +- Weather fields are always editable manually (auto-fill is a convenience, not mandatory) +- If weather fields left blank: entry shows no weather badge. No broken UI. +- Open-Meteo returns current conditions, not historical — this is fine for posting in real time + +**Mobile behavior:** "Get Weather" button is full-width, 44px height, placed immediately below the lat/lng + location name fields. + +--- + +### 1.3 — Weather Display on Entry Page + +**What:** If `weather_temp_c` or `weather_desc` is present in frontmatter, display a weather badge on the entry page. + +**Display format:** `☀️ Sunny · 28°C` (icon + description + temperature) +- Icon chosen from a small set based on `weather_desc`: + - Sunny → ☀️ + - Partly cloudy → ⛅ + - Cloudy → ☁️ + - Foggy → 🌫️ + - Drizzle → 🌦️ + - Rain → 🌧️ + - Snow → ❄️ + - Thunderstorm → ⛈️ + +**Placement:** In the entry header, between the date and the body text. Same line as GPS coordinates if those are shown. + +**Edge cases:** +- Only temp, no desc → show temp only +- Only desc, no temp → show desc only +- Neither → hide weather section entirely +- Temperature should always be integer (round if float) + +--- + +### 1.4 — Location Badge on Feed Cards and Entry Page + +**What:** Display `location_city, location_country` as a small badge on tracker feed cards and at the top of entry pages. + +**Feed card:** Below the date, above the excerpt. Format: `📍 Kyoto, Japan` + +**Entry page:** In the header below the date, above the content. Format: `📍 Kyoto, Japan` + +**Edge cases:** +- Only city, no country → `📍 Kyoto` +- Only country, no city → `📍 Japan` +- Neither → location badge hidden entirely +- Long location names: truncate with ellipsis at 30 chars on cards (full text on entry page) + +--- + +### 1.5 — Photo Gallery on Entry Page + +**What:** Photos uploaded to an entry should display in a responsive grid gallery with lightbox (click to enlarge). + +**Implementation approach:** Use Grav's native media collection for the entry page. Each `.entry` folder contains its photos. Render them in a grid in `entry.html.twig`. Use a minimal vanilla JS lightbox — no external framework. + +**Gallery behavior:** +- Photos displayed in a 2-column grid on mobile, 3-column on desktop +- Each thumbnail is square-cropped, 150px on mobile +- Clicking/tapping a thumbnail opens a lightbox overlay +- Lightbox: dark overlay, full-size image centered, tap/click outside or press Escape to close +- Left/right navigation arrows in lightbox (swipe on mobile) +- No captions needed for v1 + +**Edge cases:** +- 0 photos: gallery section hidden entirely +- 1 photo: still uses grid (single item), lightbox works +- Many photos (>10): gallery still renders (no hard limit on display) +- Non-image files in the media folder: skip them (only render jpg, jpeg, png, webp, gif) + +--- + +### 1.6 — Hero Image on Tracker Feed Cards + +**What:** If an entry has photos, the first photo (or the one named in `hero_image` frontmatter) appears as a thumbnail on the tracker feed card. + +**Implementation:** In `tracker.html.twig`, for each entry: +1. If `entry.header.hero_image` is set, use `entry.media[entry.header.hero_image]` +2. Else, use the first image in `entry.media` sorted by name +3. Render as a 16:9 aspect-ratio thumbnail, full width of card, above the title + +**Edge cases:** +- No photos: card shows no image, just text. No broken `` tag. +- `hero_image` set but file missing: fall back to first media file, or no image +- Very tall/wide images: CSS `object-fit: cover` maintains card aspect ratio + +--- + +## Out of Scope (Milestone 1) + +- Map features (Milestone 2) +- Statistics page (Milestone 3) +- Video support +- Comments or reactions +- Automated reverse geocoding (city name comes from form input, not auto-detected) +- Altitude display (data may not be present) +- Historical weather (Open-Meteo current endpoint only) + +--- + +## Acceptance Criteria + +1. Post form has `location_city` and `location_country` fields that save to entry frontmatter +2. Post form has "Get Weather" button that fills `weather_temp_c` and `weather_desc` via Open-Meteo when lat/lng are provided +3. Entry page shows weather badge when weather fields are present; hidden when absent +4. Entry page shows location badge `📍 City, Country` when location fields are present; hidden when absent +5. Tracker feed card shows location badge when present +6. Tracker feed card shows a hero image when photos exist for an entry +7. Entry page shows a 2-col (mobile) / 3-col (desktop) photo grid +8. Clicking any photo opens a full-screen lightbox with prev/next navigation +9. Pressing Escape or clicking outside lightbox closes it +10. All fields are optional — empty values produce no broken UI elements +11. All interactive elements meet 44px minimum touch target on mobile +12. Form submits correctly with all new fields populated or all blank + +--- + +## Design Notes + +- Weather and location badges should be subtle — small text, muted color, not the visual focus +- Use emoji icons for weather — universal, no icon font dependency +- Gallery grid: `gap: 4px` between thumbs, no borders, square crops +- Lightbox: `background: rgba(0,0,0,0.92)`, image centered with `max-height: 90vh` +- Feed card image: `aspect-ratio: 16/9`, `object-fit: cover`, rounded top corners matching card diff --git a/docs/working/milestones/milestone-2.md b/docs/working/milestones/milestone-2.md new file mode 100644 index 0000000..2e7337b --- /dev/null +++ b/docs/working/milestones/milestone-2.md @@ -0,0 +1,166 @@ +# Milestone 2 Spec — Interactive Map + +**Goal:** A `/map` page shows all entries as markers on an interactive Leaflet.js map, connected by a chronological route line, with popups linking to entries. + +--- + +## User Stories + +- As a reader, I want to see a world map showing where Mischa has been so I can understand the journey at a glance without reading every entry. +- As a reader, I want to click a map marker and see the entry date, title, and a thumbnail — and be able to click through to the full entry. +- As a reader on mobile, I want to pan and pinch-zoom the map with my fingers without the page scrolling underneath. +- As a traveler (Mischa), I want the map to automatically include every entry that has lat/lng data — I should not need to do any manual map maintenance. +- As a reader, I want the map to show the route line connecting stops in the order they were visited, so the journey makes narrative sense. + +--- + +## Feature Details + +### 2.1 — Map Page + +**Route:** `/map` + +**Template:** `map.html.twig` — extends `partials/base.html.twig` + +**Page file:** `user/pages/03.map/map.md` + +**Content:** +- Full-viewport-height map container below the site header +- Leaflet.js loaded from CDN (jsDelivr): `https://cdn.jsdelivr.net/npm/leaflet@1.9.4/dist/leaflet.min.js` +- Leaflet CSS from same CDN +- Tile layer: OpenStreetMap (free, no API key): `https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png` +- Attribution: "© OpenStreetMap contributors" + +**Map initialization:** +- Default zoom: auto-fit to bounds of all markers (use `map.fitBounds()`) +- If no entries with GPS data: show world view, zoom 2, centered at 0,0 with a message "No locations yet" +- Min zoom: 2, Max zoom: 18 + +--- + +### 2.2 — Entry Data Serialization + +**How entries reach the map JS:** + +In `map.html.twig`, Grav's Twig will iterate all published entries under `/tracker` and serialize them to a JSON array embedded in a `