Commit Graph

285 Commits

Author SHA1 Message Date
m038 ed25907545 fix: DOMContentLoaded wrapper + correct asset registration in map templates
- feed-map.html.twig: remove addCss/addJs calls (too late for <head>); merge
  two <script> blocks into one wrapped in DOMContentLoaded
- map.html.twig: move {% block map_assets %} above {% block content %} so
  map.css reaches <head>; add DOMContentLoaded around map init
- dailies.html.twig: add {% block map_assets %} override so map.css and
  map.js are registered for the feed-map partial

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-24 00:16:57 +02:00
m038 476c2c17ef fix: add whitespace-control to date-range macro declaration 2026-06-24 00:09:56 +02:00
m038 24ffa42499 refactor: extract date range macro; fix stories.html.twig asset registration
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-24 00:07:26 +02:00
m038 04bcab2d55 refactor: extract stats and cycling panels to Twig macros
Move stats computation and both panel HTML divs out of trip.html.twig
into dedicated macros/stats.html.twig and macros/cycling.html.twig.
trip.html.twig imports both at the top of {% block content %} and
calls them via stats_m.stats_panel() and cycling_m.cycling_panel().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-23 23:57:54 +02:00
m038 1458c24aa3 fix: remove duplicate inline sort handlers from dailies and stories templates
main.js now registers initSortButton for feed-sort-toggle on all pages;
inline IIFEs caused double-fire reversing to original order.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-23 09:36:49 +02:00
m038 ede5ce1914 fix: move map_assets block to <head> so map.css registers before assets.css() renders
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-23 09:20:33 +02:00
m038 0b73cf5048 fix: wrap map init in DOMContentLoaded — map.js loads at bottom via Asset Manager
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-23 09:06:33 +02:00
m038 10354a0760 refactor: remove CDN tags from feed-map, map, story templates
- feed-map.html.twig: removed MapLibre/toGeoJSON/maplibre-utils CDN tags; added {% do assets.addCss/addJs %} calls directly in partial
- map.html.twig: removed MapLibre/toGeoJSON/maplibre-utils CDN tags; added {% block map_assets %} with Asset Manager registrations
- story.html.twig: removed Scrollama CDN tag (now bundled in main.js as window.scrollama)

All map init and script logic remains unchanged. CDN requests eliminated.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-22 23:39:22 +02:00
m038 632a3028fa refactor: trip.html.twig — remove CDN tags, deduplicate JS, use MapUtils.parseGpxFiles
- Remove PhotoSwipe CSS CDN link (now in css-compiled/main.css via Asset Manager)
- Remove MapLibre GL, toGeoJSON, maplibre-utils CDN/local script tags
- Add {% block map_assets %} to register map.css and map.js via Asset Manager
- Remove filter bar IIFE (now initFilterBar in main.js)
- Remove sort toggle IIFE (now initSortButton in main.js)
- Remove local haversineKm and parseGpxFiles functions (now in MapUtils via map.js)
- Update parseGpxFiles call to MapUtils.parseGpxFiles
- Update haversineKm call to MapUtils.haversineKm in Mode B stats
- Remove makePanelToggle helper + calls (now initPanelToggles in main.js)
- Remove back-to-top DOMContentLoaded block (now initBackToTop in main.js)
- Remove PhotoSwipe <script type="module"> block (now initPhotoSwipe + initPhotoStrip in main.js)
2026-06-22 23:35:58 +02:00
m038 53d873b4c7 feat: register assets via Asset Manager, remove Google Fonts, remove inline photo strip script 2026-06-22 23:31:30 +02:00
m038 a640294e9b build: add map.js bundle — MapLibre GL, toGeoJSON, MapUtils
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-22 23:29:06 +02:00
m038 f8a6b9eb96 feat: add parseGpxFiles and export haversineKm from MapUtils 2026-06-22 23:22:48 +02:00
m038 5923ba431a build: add main.js bundle — fonts, PhotoSwipe, UI utilities
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-22 23:19:19 +02:00
m038 75aaa61640 build: add esbuild scaffolding and Docker build-assets target
package.json with esbuild ^0.21 and npm dependencies (maplibre-gl,
photoswipe, scrollama, fontsource). Placeholder src files and
compiled outputs committed. node_modules gitignored.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-22 23:11:25 +02:00
m038 21c1d22859 fix: PhotoSwipe bg doesn't cover bottom — add !important and pin bg to viewport 2026-06-22 09:11:52 +02:00
m038 68b328dabc feat: enrich Slovenia 2024 Piran entry with coords and weather 2026-06-22 09:07:17 +02:00
m038 817bd17959 feat: split Slovenia 2024 into its own trip
Move Piran entry out of us-canada-mex-2024 into a new slovenia-2024 trip.
Rename entry folder to match the post title convention.
Fix us-canada-mex-2024 date_start to 2024-07-21 (first actual US entry).
2026-06-22 09:06:00 +02:00
m038 77dd99ee2b feat(stories): add mini-map via shared partial, add story card IDs 2026-06-22 01:39:29 +02:00
m038 857f33be54 refactor(dailies): use shared feed-map partial 2026-06-22 01:37:33 +02:00
m038 320a98893a feat: add shared feed-map partial (dailies + stories) 2026-06-22 01:33:26 +02:00
m038 e07fb3a72a feat(map): exit fullscreen on marker click, then scroll to entry
When fullscreen is active, clicking a marker now triggers fsBtn.click()
to exit cleanly (handles class, body overflow, tripMap.resize + icon),
then waits 450ms for the exit animation before scrolling to the entry
and firing the highlight. Also fixes missing icon-swap CSS for
.home-map-col.is-fullscreen (was only targeting .feed-map-wrap).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-22 01:12:52 +02:00
m038 1bb588d1d2 fix(trip): switch panel animation to max-height (grid-template-rows broken)
grid-template-rows: 0fr fails to fully collapse when the direct grid
child has overflow:hidden (creates a BFC that prevents 0-height).
max-height: 0 → 600px with overflow:hidden is simpler and reliable.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-22 01:09:38 +02:00
m038 aa1cb7411c fix(map): collapse attribution on load; darken fullscreen button
Attribution: MapLibre v4 uses <details> and may open it after load
regardless of compact:true — remove the open attribute in the load
handler to guarantee collapsed state.

Button: switch from teal to --color-canvas (#22201B) so it sits quietly
against the dark map; icon reads in --color-ink (warm cream).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-22 01:05:12 +02:00
m038 5fe8c015f1 fix(map): theme fullscreen button with accent colour
Replace plain white with --color-accent/--color-accent-on so the button
reads as a site control rather than a stray MapLibre element.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-22 01:00:50 +02:00
m038 6f9538053c feat(map): mobile fullscreen button on trip page map
Button in bottom-right of #trip-map (z-index:1000), hidden ≥769px.
Attribution moved to bottom-left to free the corner. Clicking toggles
.is-fullscreen on .home-map-col (position:fixed, 100dvh), locks body
scroll, and calls tripMap.resize() for MapLibre to re-render.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-22 00:56:57 +02:00
m038 5e503cf3a5 fix(map): fullscreen btn inside map div, attribution moved to bottom-left
Button is back inside #feed-map with z-index:1000 to clear all MapLibre
layers. Attribution control disabled in constructor and re-added to
bottom-left so bottom-right is free for the fullscreen button.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-22 00:20:23 +02:00
m038 ce860cfef9 fix(map): move fullscreen button outside feed-map div, top-right corner
MapLibre's attribution button occupies bottom-right of the container.
Moving our button out of the map div avoids MapLibre's DOM entirely,
and top-right is clear of all default MapLibre controls.
Position anchor moves to feed-map-wrap (position:relative).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 23:54:13 +02:00
m038 989755d33c feat(map): mobile fullscreen button for feed mini-map
Button in the bottom-right corner of the map, hidden ≥769px. Clicking
it toggles .is-fullscreen on .feed-map-wrap (position:fixed, full
viewport), locks body scroll, and calls feedMap.resize() so MapLibre
re-renders at the new size. Icon swaps between expand SVG and ✕.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 23:44:09 +02:00
m038 9ddf52c635 fix(trip): raise stat-value clamp floor to 2rem (32px)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 23:35:32 +02:00
m038 9b62f79301 fix(trip): raise stat-value clamp floor to --text-xl (1.75rem)
22px floor was too close to the preferred at 375px (6vw=22.5px), so
values were pinned near the minimum. 28px floor makes values pop more
on small screens while long values like ~12,366 still wrap gracefully.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 23:33:06 +02:00
m038 64aa9ec023 revert(trip): restore stat-label to --text-xs
Small label is intentional — the contrast with the larger value is the
visual hierarchy. Revert the sm bump from the previous commit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 23:30:24 +02:00
m038 9bfd96af2c fix(trip): bump stat-label to --text-sm, widen stat-value fluid range
Label: xs (12px) → sm (14px) for clearer hierarchy below the value.
Value preferred: 5.5vw → 6vw so short values stay bold on mid phones.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 23:28:42 +02:00
m038 000af6934f fix(trip): raise stat-value clamp floor to --text-lg for visual hierarchy
14px floor was too close to the 12px label size. 1.375rem keeps the
value visually dominant over the label even at minimum size.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 23:23:39 +02:00
m038 c94e36a861 fix(trip): fluid stat-value font size with clamp()
Replaces fixed 3rem with clamp(--text-sm, 5.5vw, --text-3xl) so long
values like "4:32:15" scale down on mobile instead of overflowing.
Desktop (≥870px viewport) is unchanged at 3rem.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 23:21:58 +02:00
m038 2c831628b2 fix(trip): fix cycling stats mobile grid — span lone last card full width
7 cycling stat blocks in a 2-col mobile grid leaves a lone card in the
last row's left column with empty space on the right. Using
:last-child:nth-child(odd) + grid-column: 1/-1 spans that card across
both columns. Also minmax(0,1fr) on both grids for strictly equal widths.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 23:18:09 +02:00
m038 02fc666661 feat(trip): pill radius on panel toggles, slide animation, mobile close button
- Radius: trip-panel-toggle now uses --radius-full, consistent with filter pills
- Animation: stats/cycling blocks use CSS grid-template-rows 0fr→1fr transition
  (inner trip-panel-inner div carries decoration so border/padding don't peek
  out when collapsed; display:none removed)
- Close button: ↑ Close stats / ↑ Close cycling at bottom of each panel,
  hidden ≥769px, triggers the header toggle via data-toggle attribute

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 23:09:52 +02:00
m038 c3cb224402 style(trip): give Stats/Cycling panel toggles a square bordered style
Border + 4px radius instead of borderless text, matching the visual
weight of the filter pills without the full pill roundness.
Active state gets teal border + accent-light background like other active controls.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 23:03:56 +02:00
m038 2b8ea1963b refactor(trip): declutter filter bar — move Stats/Cycling to panel toggles
Filter bar now has one job: content type (All/Journal/Stories) + sort icon (↑/↓).
Stats and Cycling move to a lean text-button row below the bar with a
rotating ▾ caret — CSS handles expand/collapse state via .is-active,
no JS changes needed for the caret animation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 22:58:28 +02:00
m038 f94880e758 feat: add sort toggle to dailies and stories pages
dailies: reverse Twig output to ascending (matching trip default),
add feed-sort-bar above feed, add sort JS using [data-type] + appendChild.

stories: wrap heading in flex header row with sort button inline,
add sort JS targeting .story-card children of .stories-grid.

CSS: feed-sort-bar (right-aligned button above feed),
stories-listing__header (flex row, baseline-aligned), heading margin moved to header.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 22:27:11 +02:00
m038 b6142cee44 feat(trip): add ascending/descending sort toggle button
Button sits in the right filter group alongside Stats/Cycling.
Default state: ascending (↑ Oldest first, no highlight).
Toggled state: descending (↓ Newest first, is-active pill style).
DOM reversal uses insertBefore against the anchored #feed-filter-empty
so the empty-state message stays last regardless of sort direction.
Interacts safely with the type filter (show/hide by data-type).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 22:21:55 +02:00
m038 53bfe5955d fix(photoswipe): target currSlide.container not currSlide.el
pswp.currSlide is a Slide instance whose DOM element is stored as
.container (.pswp__zoom-wrap). The .el property belongs to the
itemHolder wrapper, not the Slide — so currSlide.el was always
undefined, the null-guard exited early, and no animation played.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 21:45:22 +02:00
m038 9f503c011d fix(photoswipe): keyboard arrow animation via CSS keyframes
Previous approach (CSS transition + reflow trick) is unreliable in
Firefox. New approach: PhotoSwipe emits 'change' synchronously before
painting; we add a direction-aware CSS keyframe animation to the
incoming slide element, with animation-fill-mode:both so there is no
flash before the animation starts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 21:36:48 +02:00
m038 415d95ed47 feat(photoswipe): animate keyboard arrow navigation in lightbox
PhotoSwipe's goTo() moves slides instantly (no spring animation unlike
swipe). Intercepts keydown in capture phase, sets a CSS transition and
forces a reflow before PhotoSwipe moves the container, so the browser
animates from the old position to the new one. Cleans up on close.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 21:29:06 +02:00
m038 e787544a2b feat(strip): smooth scroll animation on arrow button clicks
scroll-behavior: smooth on the strip element ensures programmatic
scrollBy calls animate consistently, cooperating with scroll-snap.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 21:22:42 +02:00
m038 9f94164c61 fix(arrows): insert strip-controls after wrap, not inside it
Dots moved inside journal-photo-wrap (overflow:hidden) earlier, so
controls were being clipped. Now inserts after the wrap element.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 21:13:43 +02:00
m038 608ccfdecd fix(partial): restore data-slides on photo strip
Missing data-slides caused base.html.twig arrow script to read
slideCount as 1 and bail before creating prev/next controls.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 21:10:48 +02:00
m038 933652fd57 refactor(templates): extract entry markup into shared partials
Creates partials/entry-journal.html.twig and partials/entry-story.html.twig
so trip, dailies, and home all use the same up-to-date markup. Home page
gains PhotoSwipe, blurred fill, adaptive aspect ratio, and hash-based
marker scroll. Future changes only need to happen in one place.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 21:07:12 +02:00
m038 fdaed1033a fix(ios): use 100dvh for PhotoSwipe to fix dynamic viewport
iOS Safari freezes 100vh at the initial viewport height (address bar
visible). 100dvh tracks the live viewport as browser chrome shows/hides.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 20:48:13 +02:00
m038 bc77baca2e fix(scroll): clear URL hash when back-to-top is clicked
Uses history.pushState to strip the stale #entry-slug without
triggering a page jump, then smooth-scrolls to the top.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 20:41:41 +02:00
m038 7c9a55224a fix(scroll): use hash navigation for marker clicks
Browser handles scroll natively via window.location.hash, respecting
scroll-margin-top. Updates URL for shareability and screen reader
compatibility. Added html { scroll-behavior: smooth } for smooth
hash navigation globally.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
2026-06-21 20:40:15 +02:00