fix(trip-cover): crop-to-fill cover strip + all-or-nothing retina
Banners/cards used cropResize (fit-inside), so a portrait fallback source was handed back as a narrow sliver that object-fit:cover then upscaled into a blur (reported on us-canada-mex-2024). Switch to cropZoom (crop-to-fill) so the derivative is a real w×h cover strip. Emit the 2x srcset descriptor only when the source is genuinely >=2w wide (cover.width >= 2w), else 1x-only — no upscaling, no odd intermediate widths. Imported pixelfed photos cap at ~1440px wide, so auto-picked covers are usually 1x-only (see backlog: full-res reimport). Also drop the no-photos-demo test fixture — it surfaced as stray demo content in the trip list; AE4 (no cover + no images -> no banner) is a trivial else-branch of the shared macro's cover guard, covered by construction alongside the R7/AE3 fallback tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RDS6t8wcpbwKvvrxykVQ5K
This commit is contained in:
@@ -1,18 +0,0 @@
|
|||||||
---
|
|
||||||
title: 'First Light on the Road'
|
|
||||||
date: '2027-01-10 10:00'
|
|
||||||
template: entry
|
|
||||||
published: true
|
|
||||||
hero_image: ''
|
|
||||||
lat: 60.17
|
|
||||||
lng: 24.94
|
|
||||||
location_city: Helsinki
|
|
||||||
location_country: Finland
|
|
||||||
weather_temp_c: -6
|
|
||||||
weather_desc: Clear
|
|
||||||
---
|
|
||||||
|
|
||||||
The bus left before dawn and the city was still under snow. I wrote most of
|
|
||||||
this by the window with a cold coffee, watching the harbour lights slide past.
|
|
||||||
No photographs today — the light was flat and grey and would not have kept
|
|
||||||
anyway. Some mornings the notebook is the only camera worth carrying.
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
title: Journal
|
|
||||||
template: default
|
|
||||||
routable: false
|
|
||||||
visible: false
|
|
||||||
content:
|
|
||||||
items: '@self.children'
|
|
||||||
order:
|
|
||||||
by: date
|
|
||||||
dir: desc
|
|
||||||
filter:
|
|
||||||
published: true
|
|
||||||
---
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
title: Stories
|
|
||||||
template: default
|
|
||||||
routable: false
|
|
||||||
visible: false
|
|
||||||
content:
|
|
||||||
items: '@self.children'
|
|
||||||
order:
|
|
||||||
by: date
|
|
||||||
dir: desc
|
|
||||||
filter:
|
|
||||||
published: true
|
|
||||||
---
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
---
|
|
||||||
title: 'Notes from the Road 2027'
|
|
||||||
template: trip
|
|
||||||
date: '2027-01-10'
|
|
||||||
date_start: '2027-01-10'
|
|
||||||
date_end: '2027-01-14'
|
|
||||||
cover_image: ''
|
|
||||||
tagline: 'A text-only journal, written before the photos catch up'
|
|
||||||
---
|
|
||||||
|
|
||||||
A short winter trip recorded in words only — no camera this time, just a
|
|
||||||
notebook and whatever the road turned up. The entries stand on their own until
|
|
||||||
the film comes back from the lab, so this one is a deliberate test of how the
|
|
||||||
trip page reads with nothing but text to show.
|
|
||||||
@@ -20,8 +20,17 @@
|
|||||||
wrapper + retina <img> when a cover exists, and nothing at all when none
|
wrapper + retina <img> when a cover exists, and nothing at all when none
|
||||||
does (which gives R9/AE4 a clean text-only header for free).
|
does (which gives R9/AE4 a clean text-only header for free).
|
||||||
|
|
||||||
Retina (R6 / R14): two explicit cropResize derivatives (1x at w×h, 2x at
|
Rendering (R6 / R14): cropZoom crops-to-fill (cover), so the 1x derivative is
|
||||||
2w×2h) as an explicit `srcset` with w-descriptors; `alt` is the trip title.
|
an actual w×h strip matching the banner/card aspect — NOT cropResize, which
|
||||||
|
fits-inside and would hand a portrait source back as a narrow sliver that the
|
||||||
|
wrapper's object-fit:cover then upscales into a blur. `alt` is the trip title.
|
||||||
|
|
||||||
|
Retina, all-or-nothing: a 2x derivative (2w×2h) is added to the `srcset` only
|
||||||
|
when the source is genuinely wide enough to supply it without upscaling
|
||||||
|
(`cover.width >= 2w`); otherwise the srcset is 1x only — no blurry, re-encoded
|
||||||
|
upscale, and no odd intermediate widths. Note most imported phone photos are
|
||||||
|
≤1440px wide, so an auto-picked fallback cover is usually 1x-only; the 2x
|
||||||
|
kicks in mainly for an explicitly-set wide landscape `cover_image`.
|
||||||
#}
|
#}
|
||||||
{% macro render(trip_page, alt, w, h, wrapper_class, sizes) %}
|
{% macro render(trip_page, alt, w, h, wrapper_class, sizes) %}
|
||||||
{%- set cover = null -%}
|
{%- set cover = null -%}
|
||||||
@@ -38,8 +47,8 @@
|
|||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
{%- if cover -%}
|
{%- if cover -%}
|
||||||
<div class="{{ wrapper_class }}">
|
<div class="{{ wrapper_class }}">
|
||||||
<img src="{{ cover.cropResize(w, h).url }}"
|
<img src="{{ cover.cropZoom(w, h).url }}"
|
||||||
srcset="{{ cover.cropResize(w, h).url }} {{ w }}w, {{ cover.cropResize(w * 2, h * 2).url }} {{ (w * 2) }}w"
|
srcset="{{ cover.cropZoom(w, h).url }} {{ w }}w{% if cover.width >= (w * 2) %}, {{ cover.cropZoom(w * 2, h * 2).url }} {{ (w * 2) }}w{% endif %}"
|
||||||
sizes="{{ sizes|default('100vw') }}"
|
sizes="{{ sizes|default('100vw') }}"
|
||||||
alt="{{ alt }}"
|
alt="{{ alt }}"
|
||||||
loading="lazy">
|
loading="lazy">
|
||||||
|
|||||||
Reference in New Issue
Block a user