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
- 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
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
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
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
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
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
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
Portrait entries (first image taller than wide) get a 4:5 container —
Instagram's proven cap that prevents single photos dominating the screen.
Landscape entries keep 4:3. Aspect-ratio moved from slide to wrap so the
strip inherits it via height:100%.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
- object-fit: contain + ::before blurred background fill on all slides
- dots moved inside photo-wrap, overlaid at bottom with shadow for contrast
- arrows hidden on touch devices via @media (hover: none)
- margin-bottom increased for breathing room below photo block
- trip.html.twig brought up to parity with dailies: same structure,
same PhotoSwipe init, same expand button, same dot overlay
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
Replaces the boolean toggle with a select field offering:
on — connect all consecutive entries (chronological line)
manual — force_connect entries only (user-controlled connections)
intelligent_gpx — suppress connectors where GPX covers both endpoints;
force_connect overrides (original smart logic, restored)
off — no connectors at all; force_connect also ignored
buildJourneySegments gains an optional trackpointsPerFile param used
only by intelligent_gpx mode. renderGpxJourney extracts trackpoints
only when connectMode is intelligent_gpx. dailies.html.twig falls
back from intelligent_gpx → on (mini-map has no GPX tracks to
suppress against).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
Adds two configurable toggles to the trip blueprint (Admin2 Trip tab):
- use_gpx: show/hide GPX tracks on all maps (default: enabled)
- autoconnect: draw connector lines between markers (default: enabled)
When use_gpx is off, GPX files are not fetched or rendered on any map
(home, map, trip, dailies). The stats panel in trip.html.twig still
reads GPX_URLS directly and is unaffected.
When autoconnect is off, buildJourneySegments suppresses all
auto-connectors; only entries with force_connect:true still draw a
line — making force_connect behaviour independent of both settings.
Also refactors the inline Promise.all in trip.html.twig to use the
shared renderGpxJourney utility (reducing duplication).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vgmzx8VTTTmCskSpQtsLTr
Both stats.html.twig and trip.html.twig previously flattened all GPX
trackpoints into a single masterPts array before computing haversine
distance, elevation, and moving time. This caused the junction between
file N's last point and file N+1's first point to be treated as a real
segment — e.g. Florence→coast (~79 km, ~42 h) for Italy's 3-file demo
data, overstating distance and moving time significantly.
Fix: compute all metrics within each file independently and sum the
results. fileResults collection and callback consumption are unchanged.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WPJztrVGbwic2xTG7G9fjM
Adds Twig computation for days on road, countries visited, and GPS
points; an expandable stats panel (hidden by default) with haversine
distance calculation; and toggle JS that activates the Stats button.
Added JavaScript to the trip.html.twig template that:
- Adds event listeners to filter buttons (.trip-filter-btn)
- Shows/hides article cards based on data-type attribute (journal/story)
- Manages active state of filter buttons
- Displays empty state message when no results match the filter
- Uses ES5 syntax (no arrow functions, const/let, or template literals)
Also added hidden feed-filter-empty element to display appropriate
empty messages for each filter type.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RB86BaJBG3eGiMdfhmHRrQ
Replace the old trip-nav links with a new filter bar component featuring:
- Three pill buttons for filtering (All content, Journal, Stories)
- "All content" button active by default with teal accent styling
- Separate Stats button with matching pill styling
- CSS for buttons with hover and active states
- Responsive flexbox layout that wraps on narrow screens
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RB86BaJBG3eGiMdfhmHRrQ
- Same home-layout (45% sticky map / 55% scrollable feed) on every trip page
- GPX route overlay loaded from trip page media
- Marker click scrolls to entry card (same as home page)
- Map sub-nav link removed (map is now embedded)
- Separate /map page remains accessible by URL but has no nav link
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RB86BaJBG3eGiMdfhmHRrQ
- Rename tracker.html.twig to dailies.html.twig; update dailies.md template key
- Fix map.html.twig and stats.html.twig: find dailies via page.parent().route
- Update base.html.twig nav to use config.site.active_trip for all hrefs
- Fix dailies.html.twig mini-map link to use page.parent().url/map
- Create trip.html.twig, trips.html.twig, stories.html.twig
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>