Merge branch 'main' into feat/post-location-override

Brings the branch up to user/main, which was ahead on both content and
theme fixes. Notably e17a5dc ("block submit on unfinished photo uploads;
un-squeeze EXIF portraits in lightbox") — the branch point predated it, and
its absence is why UG1, UG2 and LD1 failed here: the upload gate and the
oriented-derivative slide dims those specs assert simply were not on this
branch. Also picks up denmark-2026 `published: true`, so the local testing
flip is no longer needed.

js/src/post-form.js auto-merged cleanly, keeping both main's upload gate and
this branch's location-override panel + lazy maplibre CSS link. The only
conflict was js/post/post-form.js, a generated bundle — resolved by
rebuilding via make build-assets rather than hand-merging minified output.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-24 23:36:41 +02:00
co-authored by Claude Opus 5
62 changed files with 497908 additions and 41867 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 MiB

@@ -0,0 +1,29 @@
---
photos:
IMG_1959.jpg:
name: IMG_1959.jpg
type: image/jpeg
size: 4104001
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-10-08-20-the-start/IMG_1959.jpg
IMG_1958.jpg:
name: IMG_1958.jpg
type: image/jpeg
size: 4602898
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-10-08-20-the-start/IMG_1958.jpg
title: 'The start…. '
date: '2026-07-10 08:20'
lat: null
lng: null
location_city: Berlin
location_country: Germany
weather_desc: Cloudy
weather_temp_c: 20
transport_mode: train
edit_path: null
published: true
force_connect: false
featured: false
---
The start was surprisingly smooth - the real wake-up was the crowd of odd characters hanging around S Gesundbrunnen at 6am. Deutsche Bahn did surprisingly well: just a 10-minute delay and a platform change.
The adventure has started. Denmark, here I come!
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 MiB

@@ -0,0 +1,49 @@
---
photos:
IMG_1972.jpg:
name: IMG_1972.jpg
type: image/jpeg
size: 2638016
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-10-22-34-a-day-full-of-firsts/IMG_1972.jpg
IMG_1969.jpg:
name: IMG_1969.jpg
type: image/jpeg
size: 4379241
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-10-22-34-a-day-full-of-firsts/IMG_1969.jpg
IMG_1977.jpg:
name: IMG_1977.jpg
type: image/jpeg
size: 3095975
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-10-22-34-a-day-full-of-firsts/IMG_1977.jpg
IMG_1983.jpg:
name: IMG_1983.jpg
type: image/jpeg
size: 4693570
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-10-22-34-a-day-full-of-firsts/IMG_1983.jpg
IMG_1999.jpg:
name: IMG_1999.jpg
type: image/jpeg
size: 4133238
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-10-22-34-a-day-full-of-firsts/IMG_1999.jpg
IMG_1994.jpg:
name: IMG_1994.jpg
type: image/jpeg
size: 4979702
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-10-22-34-a-day-full-of-firsts/IMG_1994.jpg
title: 'A day full of firsts'
date: '2026-07-10 22:34'
lat: '55.394911'
lng: '8.712669'
location_city: Esbjerg
location_country: Denmark
weather_desc: Sunny
weather_temp_c: 18
transport_mode: bicycle
edit_path: null
published: true
force_connect: false
featured: false
---
So what did I actually do? I visited the northernmost point of the German mainland, then cycled across a border on an international trip—last year I took the ferry, lame huh? I saw Ribe, the oldest town in Denmark, and tried the Danish shelter system for the first time. Its awesome.
But the most important part: no daily destination. Just a rough idea and a shelter spot to sleep in when Im tired. No anxiety, no hotel needed—though probably no showers in the upcoming days either. :D
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 MiB

@@ -0,0 +1,24 @@
---
photos: ''
title: 'Internet too slow in Denmark…?'
date: '2026-07-11 20:35'
lat: '55.682921'
lng: '8.183712'
location_city: Varde
location_country: Denmark
weather_desc: Cloudy
weather_temp_c: 19
transport_mode: bicycle
edit_path: /trips/denmark-2026/dailies/2026-07-11-20-35-internet-too-slow-in-denmark/entry.md
published: true
force_connect: false
featured: false
---
Sometimes yes, Im writing this while lying in my tent: 98km done and Im knackered. Uploading pictures keeps failing...
A quick coffee break at a hip specialty coffee place in Esbjerg made the morning complete and injected the fuel for a special detour today l. Namely, to reach a special geographical spot—the most western point of Denmark. My goal is to visit all the corners, and this trip should complete that.
Id actually wanted to stop at 70km, since Id already hit my goal for the day. But a quick food stop got me some fuel - a hot dog and a Starbucks triple espresso - and with a bit of wind at my back, voilà, here we are. Funny enough, some of the same people from last nights shelter are here too.
Note to self: that starbucks triple espresso is great fuel, dont be ashamed.
@@ -0,0 +1,43 @@
---
photos:
IMG_2035.jpg:
name: IMG_2035.jpg
type: image/jpeg
size: 4025475
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-12-20-28-fairytale-landscapes-and-the-financial-reality-check/IMG_2035.jpg
IMG_2037.jpg:
name: IMG_2037.jpg
type: image/jpeg
size: 4355388
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-12-20-28-fairytale-landscapes-and-the-financial-reality-check/IMG_2037.jpg
IMG_2041.jpg:
name: IMG_2041.jpg
type: image/jpeg
size: 3848089
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-12-20-28-fairytale-landscapes-and-the-financial-reality-check/IMG_2041.jpg
IMG_2042.jpg:
name: IMG_2042.jpg
type: image/jpeg
size: 5405714
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-12-20-28-fairytale-landscapes-and-the-financial-reality-check/IMG_2042.jpg
title: 'Fairytale landscapes and the financial reality check'
date: '2026-07-12 20:28'
lat: '56.143163'
lng: '8.176442'
location_city: 'Ringkobing-Skjern Kommune'
location_country: Denmark
weather_desc: Sunny
weather_temp_c: 24
transport_mode: bicycle
edit_path: null
published: true
force_connect: false
featured: false
---
A day through the dunes: more offroad gravel than the gorgeous paved cycling paths Denmark is famous for - those are saved for Route 475. Route 1 is hardcore. Well, okay, its not all that crazy, but I was happy with my new 45mm tires. Smooth riding, and enough grip.
The route went through a kind of dunish desert, all grass and sand. Scattered all over were little houses - holiday homes for the Danes, I assume. Even though some of them
looked legit.
The addiction to gentrified coffee was too great, so I stopped at a hip place in a little surf town. Im glad my in-head currency conversion isnt very fast: €13.60 for a coffee and a cake. Denmark makes you feel poor - which makes the tent feel quite fitting.
@@ -0,0 +1,20 @@
---
photos: ''
title: 'Cold Hawaii…'
date: '2026-07-14 22:16'
lat: '57.033053'
lng: '8.479737'
location_city: Klittmøller
location_country: Denmark
weather_desc: Sunny
weather_temp_c: 22
transport_mode: bicycle
edit_path: /trips/denmark-2026/dailies/2026-07-14-22-16-cold-hawaii/entry.md
published: true
force_connect: false
featured: false
---
Today was a mandatory take-it-easy day. Ive reached 350km of the 620km in four days — pretty powerful, maybe also too much. Ive noticed that when youre on the bike, youre in bike mode: I take a picture here and there, but you cant stop every 10km either. Too many breaks can be devastating.
So I arrived in Klitmøller, aka Cold Hawaii, because — guess what — you can surf here. I assumed it would just be downwind stuff, but apparently there can be some decent waves. Thats the vibe of this town, same as Hvide Sande: laid back, calm, and lots of people with surfboard carriers on their bikes. Danes on bikes can be as impressive as the Dutch — weve found our counterpart!
With just 38km today I planned a relaxing afternoon: laundry in a proper machine, a warm shower (first since I left home), and some bike maintenance and cleaning. But… my anti-mosquito spray had a surprise for me. All the shaking had worked the cap loose, and the DEET leaked slowly into a plastic bag — which it promptly dissolved, leaving gooey, sticky plastic all over my stuff. A challenge too great for a relaxing afternoon. I did minimal damage control, then had dinner and a beer with a view of the sea.
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

@@ -0,0 +1,51 @@
---
photos:
IMG_2123.jpg:
name: IMG_2123.jpg
type: image/jpeg
size: 2867530
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-15-20-35-a-fresh-feeling/IMG_2123.jpg
IMG_2098.jpg:
name: IMG_2098.jpg
type: image/jpeg
size: 3141614
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-15-20-35-a-fresh-feeling/IMG_2098.jpg
IMG_2099.jpg:
name: IMG_2099.jpg
type: image/jpeg
size: 3609643
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-15-20-35-a-fresh-feeling/IMG_2099.jpg
IMG_2103.jpg:
name: IMG_2103.jpg
type: image/jpeg
size: 4732533
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-15-20-35-a-fresh-feeling/IMG_2103.jpg
IMG_2107.jpg:
name: IMG_2107.jpg
type: image/jpeg
size: 3166448
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-15-20-35-a-fresh-feeling/IMG_2107.jpg
IMG_2108.jpg:
name: IMG_2108.jpg
type: image/jpeg
size: 4289987
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-15-20-35-a-fresh-feeling/IMG_2108.jpg
title: 'A fresh feeling'
date: '2026-07-15 20:35'
lat: '57.136715'
lng: '9.327441'
location_city: Abybro
location_country: Denmark
weather_desc: Sunny
weather_temp_c: 22
transport_mode: bicycle
edit_path: null
published: true
force_connect: false
featured: false
---
Do you think showering twice in one day counts as pre-showering for the days ahead? Ill let you know in a couple of days. But the morning started clean — freshness and mist in the air, and my body fully recovered after being pushed hard. Another 80km, which leaves about 140km to go.
Goal change: finish the route early and carry on down the east coast. My train back leaves from Aalborg (not the far north anyway), and I dont mind more of Denmark.
The legs felt rested and just kept plowing through. I glanced at the navigation and 50km was already done — Id even cycled past Bulbjerg. Too far to turn back, alas. I powered up with another triple-shot canned espresso (I feel genuinely bad for liking this stuff as a coffee aficionado, but it works), and before I knew it I was at my home for the night.
Then: my first dinner ever cooked on my little camp stove. Tonights menu — first course, pan-fried tomatoes with herbes de Provence and smoky salt: honestly delish, well worth bringing back for a dinner party at home. Main was a tuna pasta with herbs and smoky salt — that one was fine. And for dessert, gas-grilled marshmallows: my poor, not-so-outdoorsy, lazy mans version of a campfire roast. Three courses on one tiny burner. Now Im satisfied and heading to bed to charge up for tomorrow.
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

@@ -0,0 +1,46 @@
---
photos:
IMG_2153.jpg:
name: IMG_2153.jpg
type: image/jpeg
size: 2723140
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-17-15-30-the-lies-the-north-and-the-reward/IMG_2153.jpg
IMG_2155.jpg:
name: IMG_2155.jpg
type: image/jpeg
size: 3159543
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-17-15-30-the-lies-the-north-and-the-reward/IMG_2155.jpg
IMG_2159.jpg:
name: IMG_2159.jpg
type: image/jpeg
size: 3047815
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-17-15-30-the-lies-the-north-and-the-reward/IMG_2159.jpg
IMG_2157.jpg:
name: IMG_2157.jpg
type: image/jpeg
size: 5889404
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-17-15-30-the-lies-the-north-and-the-reward/IMG_2157.jpg
IMG_2158.jpg:
name: IMG_2158.jpg
type: image/jpeg
size: 2970861
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-17-15-30-the-lies-the-north-and-the-reward/IMG_2158.jpg
title: 'The lies, the north and the reward '
date: '2026-07-17 15:30'
lat: '57.725018'
lng: '10.596427'
location_city: Skagen
location_country: Denmark
weather_desc: 'Partly cloudy'
weather_temp_c: 26
transport_mode: bicycle
edit_path: null
published: true
force_connect: false
featured: false
---
Time flies when youve got a routine and youre just riding. Yesterdays post inspiration got lost at the Stranden shelter — two minutes from the beach, zero connectivity. Today was all about the goal. Must… reach… the north….
Yesterday I was pushing hard, telling myself each extra kilometer meant one less tomorrow. Then reality hit. My trusty Wahoo — which has navigated me without a single hiccup (knock on wood) — wasnt showing the true countdown. Turns out I had an extra 11km to reach the top. Whatever that means, Mr Wahoo.
Once I could smell success in the air, another painful decision: push my bike 1km through the sand, or leave it behind? Ill say nothing and let the pictures speak for themselves.
Now, a well-earned reward — an iskaffe and a lille citrontærte — and I start all over again? Not really. Ill continue down Route 1, then branch off onto number 5, the east coast route. Two days left before I have to catch my train, and cycling is cheaper than hovering around a Danish town for fun. Onwards to Aalborg!
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 MiB

@@ -0,0 +1,40 @@
---
photos:
IMG_2168.jpg:
name: IMG_2168.jpg
type: image/jpeg
size: 2125806
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-18-09-08-the-dunes-of-jerup/IMG_2168.jpg
IMG_2173.jpg:
name: IMG_2173.jpg
type: image/jpeg
size: 3497959
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-18-09-08-the-dunes-of-jerup/IMG_2173.jpg
IMG_2175.jpg:
name: IMG_2175.jpg
type: image/jpeg
size: 2672034
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-18-09-08-the-dunes-of-jerup/IMG_2175.jpg
IMG_2178.jpg:
name: IMG_2178.jpg
type: image/jpeg
size: 6060397
path: user/pages/01.trips/denmark-2026/01.dailies/2026-07-18-09-08-the-dunes-of-jerup/IMG_2178.jpg
title: 'The dunes of Jerup'
date: '2026-07-18 09:08'
lat: 57.54421
lng: 10.43837
location_city: Jerup
location_country: Denmark
weather_desc: Cloudy
weather_temp_c: 18
transport_mode: bicycle
published: true
force_connect: false
featured: false
---
After my reward I continued the route on the east coast, and while looking for a shelter I stumbled upon Jerup Shelterplads — the closest one to the beach Id seen on the whole trip. The east coast probably isnt as wild as the west. Hidden in the dunes, I saw the wooden structures pop up, the outlines of half a dozen camper vans, and the lively sound of people chatting and children playing. No silent retreat in nature this night, and I was happy about it. The weather looked slightly dramatic — rain and lots of lightning — though fortunately, as is common in Denmark, it settled into light showers and some thunder around 02:00.
My neighbours were a jolly bunch of Danish-Indonesians, delighted to learn more about Indonesian people living in the Netherlands. They were from Aceh, practically the opposite end of the country from where most Indonesian-Dutch families come from: the Maluku islands. One of them also knew about the Javanese diaspora in Suriname, and we had a little conversation about that too. Unfortunately their limited English and my practically non-existent Bahasa Indonesia wouldnt let us go further into such an interesting subject.
Jerup beach was my favourite shelter so far — each tent could hide in its own little spot in the dunes, barely 20 meters from the water. A last coffee on the beach, and the forecast looked very rainy. It started as I was packing up the last bits of the tent.
From Tolne I took the train to Aalborg, where Ill slowly assimilate back into the urban setting after eight days away from it.
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -5,8 +5,8 @@ date: '2026-07-10'
date_start: '2026-07-10'
date_end: '2026-07-20'
cover_image: bikepacking_denmark.jpeg
tagline: '560 km up Denmark''s wild North Sea coast to where two seas meet'
published: false
tagline: "560 km up Denmark's wild North Sea coast to where two seas meet"
published: true
autoconnect: intelligent_gpx
---
File diff suppressed because it is too large Load Diff
+57
View File
@@ -791,8 +791,65 @@ body::after {
.feed-map-link:hover { color: var(--color-accent-hover); }
/* ── Feedback / notification messages ────────────────────────────────────────── */
/* Grav renders feedback two ways and the theme styled neither globally:
- Form/flash messages as <div class="notices success|error|warning green|red|yellow">
(Form plugin form-messages.html.twig; also markdown-notices output).
- Plain flash messages as #messages .toast .toast-error|success|warning (quark
partials/messages.html.twig, resolved since this theme has none of its own).
Without these rules they fell back to light admonition boxes that clash with the
dark theme (first noticed on /login). Kept on-theme with a status-coloured
left border. */
.notices,
#messages .toast {
padding: 1rem 1.1rem;
border-radius: var(--radius-md);
font-size: var(--text-base);
margin: 0 0 var(--space-5);
background: var(--color-canvas);
color: var(--color-ink);
border: 1px solid var(--color-border);
border-left: 4px solid var(--color-accent);
}
.notices p,
#messages .toast p { margin: 0; }
/* markdown-notices sets bright per-colour backgrounds on .notices.red / .yellow /
.green / .blue at (0,2,0). Override each variant at equal specificity (this
sheet loads later) so the dark canvas + cream text always win — only the
left-border colour signals status. */
.notices.error, .notices.red,
.notices.success, .notices.green,
.notices.warning, .notices.yellow,
.notices.blue,
#messages .toast-error,
#messages .toast-success,
#messages .toast-warning {
background: var(--color-canvas);
color: var(--color-ink);
border-left-width: 4px;
border-left-style: solid;
}
.notices.error, .notices.red,
#messages .toast-error { border-left-color: var(--color-error); }
.notices.success, .notices.green,
#messages .toast-success { border-left-color: var(--color-accent); }
.notices.warning, .notices.yellow,
#messages .toast-warning { border-left-color: #c98a2e; }
.notices.blue { border-left-color: var(--color-accent); }
/* ── Login form ─────────────────────────────────────────────────────────────── */
/* Neutralise the Login plugin's built-in white box (#grav-login in
plugin://login/css/login.css) so the wrapper matches the dark theme. */
#grav-login {
background: var(--color-canvas);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
color: var(--color-ink);
}
.login-form { max-width: 400px; margin: var(--space-8) auto; padding: 0 var(--space-4); }
.login-form .form-field { margin-bottom: var(--space-5); }
.login-form .form-label label { display: block; font-size: var(--text-sm); font-weight: 600; margin-bottom: var(--space-2); }
File diff suppressed because one or more lines are too long
+32
View File
@@ -243,6 +243,38 @@ function initPhotoConversion() {
}
}, true);
// Complete upload gate (BUG 2026-07-09: fast create submit lost the photo).
// The form plugin's own submit guard (filepond-handler.js) only blocks the
// PROCESSING / PROCESSING_QUEUED states. A file still being read (LOADING —
// the "too quick" click) or one whose upload FAILED (PROCESSING_ERROR)
// slips through it and the entry is saved without the photo — silently,
// because an errored thumbnail still satisfies the ≥1-photo count. Block
// submit unless every FilePond item reached PROCESSING_COMPLETE, and say
// which case blocked it.
form.addEventListener('submit', function (e) {
if (!orderPond) return;
var files = orderPond.getFiles();
if (!files.length) return; // the ≥1-photo rule is initValidation's job
var statuses = (window.FilePond && window.FilePond.FileStatus) || {};
var pending = 0;
var failed = 0;
files.forEach(function (f) {
if (f.status === statuses.PROCESSING_COMPLETE) return;
if (f.status === statuses.PROCESSING_ERROR || f.status === statuses.LOAD_ERROR) failed++;
else pending++; // LOADING, INIT, IDLE, QUEUED, PROCESSING, …
});
if (!pending && !failed) return;
e.preventDefault();
if (collapse) collapse.details.open = true; // reveal the item states
setStatus(failed
? 'A photo failed to upload — remove it (tap its ✕) and re-add it before posting.'
: 'Photos are still uploading — hang on a moment.', 'err');
var el = photoStatusEl();
if (el && typeof el.scrollIntoView === 'function') {
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
}, true);
// FilePond hook: reject a HEIC item, convert it to JPEG via the lazy heic-to
// chunk (KTD4), then re-add the JPEG through pond.addFile() so FilePond
// uploads and page-attaches it via its own (correct) contract.
@@ -30,6 +30,7 @@
{% if grav.user.authenticated %}
<a href="{{ base_url_absolute }}/post"{% if page.template == 'post-form' %} aria-current="page"{% endif %}>New Post</a>
<a href="{{ base_url_absolute }}/gpx-manager"{% if page.template == 'gpx-manager' %} aria-current="page"{% endif %}>GPX Manager</a>
<a href="{{ url(uri.addNonce((uri.path)|trim('/') ~ '/task' ~ config.system.param_sep ~ 'login.logout', 'logout-form', 'logout-nonce'))|e }}">Logout</a>
{% endif %}
</nav>
{% endblock %}
@@ -38,15 +38,32 @@
{% set images = entry.media.images %}
{% if images|length > 0 %}
{% set firstImg = images|first %}
{% set wrapRatio = firstImg.height > firstImg.width ? '4 / 5' : '4 / 3' %}
{#
Lightbox slides link to a 2000px fit-within DERIVATIVE, and the
data-pswp-* dims are measured from that derivative's saved file — never
from `img.width`/`img.height`, which are the ORIGINAL's raw stored pixels
with EXIF orientation ignored. Originals from iPhones are often stored
rotated (landscape pixels + EXIF "rotate 90°"), so raw dims disagree with
what the browser renders and PhotoSwipe squeezes portraits into landscape
boxes (BUG 2026-07-09, covered by tests/ui/post/lightbox-dims.spec.js).
The derivative is re-encoded (EXIF stripped, orientation baked in when
php-exif is available), so its measured dims always match its rendering.
Note: .path()/.url each finalize+reset the medium's operation queue,
hence the repeated cropResize() calls — the derivative file itself is
cached. path() needs explicit parens: Medium is ArrayAccess and carries a
'path' ITEM (the page folder), which shadows the method in Twig's
attribute resolution and hands getimagesize a directory.
#}
{% set firstDims = (images|first).cropResize(2000, 2000).path()|getimagesize %}
{% set wrapRatio = firstDims[1] > firstDims[0] ? '4 / 5' : '4 / 3' %}
<div class="journal-photo-wrap" style="aspect-ratio: {{ wrapRatio }}">
<div class="journal-photo-strip pswp-gallery" id="gallery-{{ entry.slug }}" data-slides="{{ images|length }}">
{% for img in images %}
{% set slideDims = img.cropResize(2000, 2000).path()|getimagesize %}
<a class="journal-photo-slide"
href="{{ img.url }}"
data-pswp-width="{{ img.width }}"
data-pswp-height="{{ img.height }}"
href="{{ img.cropResize(2000, 2000).url }}"
data-pswp-width="{{ slideDims[0] }}"
data-pswp-height="{{ slideDims[1] }}"
style="--thumb: url('{{ img.cropResize(900, 675).url }}')"
target="_blank">
<img src="{{ img.cropResize(900, 675).url }}" alt="{{ entry.title }}" loading="lazy">
@@ -23,12 +23,18 @@
#}
<div class="home-map-col">
<div class="home-map" id="{{ map_id }}">
{# Same gate as the init script below: without entries the map never
initialises and nothing wires the button's click handler, so on
mobile (the only viewport where it shows) it would float as a dead
control over an empty map area (home pre-departure state). #}
{% if entries|length > 0 %}
<button class="feed-map-fullscreen-btn" id="{{ map_id }}-fullscreen" aria-label="Expand map">
<svg class="feed-map-fs-open" aria-hidden="true" width="14" height="14" viewBox="0 0 14 14" fill="currentColor">
<path d="M0 0v4h1.5V1.5H4V0z M14 0H10v1.5h2.5V4H14z M0 14v-4h1.5v2.5H4V14z M14 14H10v-1.5h2.5V10H14z"/>
</svg>
<span class="feed-map-fs-close" aria-hidden="true">✕</span>
</button>
{% endif %}
</div>
</div>