diff --git a/CLAUDE.md b/CLAUDE.md index 6f1f7d8..b05935b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -28,26 +28,13 @@ The Docker dev server runs at **http://localhost:8081** (mapped from container p ### Local dev commands -| Command | What it does | -|---|---| -| `make setup` | One-shot first run: `build` → `start` → `install-plugins` → `fix-perms` | -| `make start` / `make stop` | Bring the compose stack up / down (`start-grav` = Grav service only) | -| `make build` | Rebuild the custom Docker image (after `Dockerfile` changes) | -| `make build-assets` | Rebuild theme JS/CSS bundles in a `node:20-alpine` container | -| `make install-plugins` | GPM-install everything in `plugins.txt`, then re-apply local patches | -| `make fix-perms` | Fix ownership in the container after root-owned writes | +`make setup` for a first run (build → start → install-plugins → fix-perms); `make start` / `make stop` thereafter. Other targets are self-describing in the `Makefile`. -**`make build-assets` is mandatory after editing anything in `user/themes/intotheeast/js/src/`.** Sources live in `js/src/`; esbuild writes the committed bundles — `js/main.js`, `js/map.js`, `js/feed-actions.js`, `js/trip-publish.js`, `js/post/`, and the CSS extracted into `css-compiled/`. **Never hand-edit those.** By contrast `css/style.css` and `css/tokens.css` are hand-authored sources, not build outputs. `build-assets` runs as your host UID (`--user`) so the outputs in the bind-mounted `user/` tree are not root-owned. +**`make build-assets` is mandatory after editing anything in `user/themes/intotheeast/js/src/`** — esbuild writes the *committed* bundles `js/main.js`, `js/map.js`, `js/feed-actions.js`, `js/trip-publish.js`, `js/post/`, and `css-compiled/`. **Never hand-edit those.** By contrast `css/style.css` and `css/tokens.css` are hand-authored sources. ### Custom plugins -Three plugins are site-owned and tracked in the `user/` repo (everything else under `user/plugins/` is GPM-managed and git-ignored): - -| Plugin | Role | -|---|---| -| `cache-on-save` | Clears the page-tree cache on `new-entry` submits, and derives the write target from `site.active_trip` (`onFormValidationProcessed` → `setData('parent', …)`) | -| `story-blocks` | Storytelling shortcode blocks for long-form stories (depends on `shortcode-core`) | -| `entry-actions` | Owner-only, active-trip-scoped journal entry actions (delete) via the Grav API | +Three plugins are site-owned and tracked in the `user/` repo (everything else under `user/plugins/` is GPM-managed and git-ignored): **`cache-on-save`** (clears page-tree cache on `new-entry` submits + injects the write target from `site.active_trip`), **`story-blocks`** (story shortcodes), **`entry-actions`** (owner-only entry delete via the API). ### Local plugin patches @@ -66,96 +53,28 @@ The site is structured around Trip entities. Key facts: - `01.dailies/` and `04.stories/` are `routable:false` **data containers** — visiting `/trips//dailies` or `/stories` directly 404s/redirects; their children (entries/stories) render at their own detail URLs and are aggregated by the trip page - Site nav in `base.html.twig` has Home + Past Trips only — does not link to trip sub-sections - New journal entries are written to the active trip's `dailies` — the write target is derived from `site.active_trip` at submit time by the `cache-on-save` plugin (post-form.md no longer hardcodes `pageconfig.parent`) -- The trip page (`trip.html.twig`) uses a **client-side filter bar** (All content / Journal / Stories). The standalone `/dailies`, `/map`, `/stats`, `/stories` view pages no longer exist — do NOT try to re-create them or link to them. This filter bar + stats chrome is shared with the home active-trip view via the `trip-feed-col` partial (see "Shared trip-feed-col partial" below) +- The trip page (`trip.html.twig`) uses a **client-side filter bar** (All content / Journal / Stories). The standalone `/dailies`, `/map`, `/stats`, `/stories` view pages no longer exist — do NOT try to re-create them or link to them. This filter bar + stats chrome is shared with the home active-trip view via the `trip-feed-col` partial (see "Two shared partials" below) - Stats are shown inline on the trip page via a toggle (the standalone `/stats` view was removed) - GPX route files live as media on the trip page itself, parsed client-side via toGeoJSON (bundled into `js/map.js`) and drawn on the trip/home map -- Manage GPX files (view/upload/delete) at `/gpx-manager` — requires admin login; filenames are auto-slugified on upload -### One map path: `MapUtils.initEntryMap` + the `entry-map` partial +### Two shared partials — the rules -There is a **single** map code path on the site. The engine is `MapUtils.initEntryMap(opts)` in `js/src/maplibre-utils.js` (bundled into `js/map.js` via `make build-assets` — never hand-edit `js/map.js`). It builds the MapLibre map, places markers/popups, fits bounds, draws the GPX journey, and wires the fullscreen toggle. +Trip and home render the same map and feed chrome through **two** shared partials, both included with `{% include … with {…} only %}`. Full parameter contracts: [`docs/reference/architecture.md`](docs/reference/architecture.md) → "Shared partial contracts". The rules that must not be broken: -The map **markup + invocation** is shared via one partial: - -- **Partial:** `user/themes/intotheeast/templates/partials/entry-map.html.twig` -- **Used by:** `trip.html.twig` and the active branch of `home.html.twig` (both via `{% include ... with {...} only %}`) - -It renders the `.home-map-col` column (map div `#{{ map_id }}` + fullscreen button) and, when `entries` is non-empty, a thin `