diff --git a/Makefile b/Makefile index 8c05c89..7e17d88 100644 --- a/Makefile +++ b/Makefile @@ -64,6 +64,26 @@ calendar: setup-python @$(PYTHON) generate_calendar.py @echo "Calendar generated successfully!" +# Optional responsive copies; originals remain the source of truth. +event-images: + @command -v convert >/dev/null && command -v identify >/dev/null || \ + { echo "Install ImageMagick to generate responsive event images."; exit 1; } + @mkdir -p images/events/responsive + @set -e; for image in images/events/*.jpg; do \ + name=$$(basename "$$image" .jpg); \ + width=$$(identify -ping -format '%w' "$$image"); \ + for size in 480 960 1440; do \ + target="images/events/responsive/$$name-$$size.webp"; \ + if [ "$$width" -ge "$$size" ]; then \ + if [ ! -f "$$target" ] || [ "$$image" -nt "$$target" ]; then \ + convert "$$image" -auto-orient -resize "$${size}x" -strip -quality 80 "$$target"; \ + fi; \ + else \ + rm -f "$$target"; \ + fi; \ + done; \ + done + # Setup Python environment for calendar generation setup-python: $(VENV)/.requirements-installed @@ -76,5 +96,4 @@ $(VENV)/.requirements-installed: requirements.txt @touch $@ @echo "Python environment ready!" -.PHONY: all build lint test check serve serve-livereload serve-windows calendar setup-python run clean install - +.PHONY: all build lint test check serve serve-livereload serve-windows calendar event-images setup-python run clean install diff --git a/README.md b/README.md index 72d0893..a085505 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ This repository includes common shortcuts in [`makefile`](makefile): - `serve-windows`: Live reload with force polling - `clean`: Remove build and cache artifacts - `calendar`: Generate `calendar.ics` from event data +- `event-images`: Generate optional responsive WebP copies of event banners (requires ImageMagick) Examples: @@ -80,7 +81,8 @@ Keep filenames lowercase and use the `.jpg` extension. No additional image field is needed in the event data. Upcoming event cards, past event cards, and event detail pages all use the same -local banner. Separate `-550.jpg` thumbnails are not required. If an image is +local banner. Upcoming cards and detail pages prefer an optional `-teaser.jpg` +when present. Separate `-550.jpg` thumbnails are not required. If an image is missing, the site displays `images/cloudnativelinz-banner.png` as a fallback. Add new banners directly to `images/events/`, not the generated `_site/` @@ -92,6 +94,19 @@ automatically. When creating or updating an event, commit the corresponding `images/events/.jpg` if a new or updated banner is needed. Changes to event data do not regenerate existing banners. +After adding or replacing a banner or teaser, run `make event-images` with +ImageMagick installed (on Ubuntu: `sudo apt-get install imagemagick`). Commit the +generated `images/events/responsive/-480.webp`, `-960.webp`, and `-1440.webp` +alongside the original. Copies preserve the aspect ratio, strip metadata, and are +only generated at widths no larger than the original; unchanged files are skipped. +When deleting or renaming an original, remove its responsive copies too. + +The shared `_includes/event-image.html` advertises only existing copies through +`picture`, `srcset`, and layout-specific `sizes`. Browsers select a suitable +download for the display width and pixel density. Originals still work when no +copies exist or WebP is unsupported, and failed image loads retain the common +fallback. Generation is optional and is not required for a normal Jekyll build. + ## Event URL Redirects Event pages use stable slugs to avoid broken links when titles change. @@ -138,4 +153,3 @@ Contributions are welcome. 2. Make your changes 3. Build locally and verify 4. Open a pull request - diff --git a/_includes/event-image.html b/_includes/event-image.html new file mode 100644 index 0000000..c8e6119 --- /dev/null +++ b/_includes/event-image.html @@ -0,0 +1,24 @@ +{%- assign image_name = include.path | split: '/' | last | remove: '.jpg' -%} +{%- assign image_widths = '480,960,1440' | split: ',' -%} +{%- assign image_srcset = '' -%} +{%- for image_width in image_widths -%} + {%- assign variant_path = '/images/events/responsive/' | append: image_name | append: '-' | append: image_width | append: '.webp' -%} + {%- assign variant_file = site.static_files | where: 'path', variant_path | first -%} + {%- if variant_file -%} + {%- unless image_srcset == '' -%} + {%- assign image_srcset = image_srcset | append: ', ' -%} + {%- endunless -%} + {%- assign variant_url = variant_path | relative_url -%} + {%- assign image_srcset = image_srcset | append: variant_url | append: ' ' | append: image_width | append: 'w' -%} + {%- endif -%} +{%- endfor -%} + + {% unless image_srcset == '' %} + + {% endunless %} + {{ include.alt | escape }} + diff --git a/_includes/meta.html b/_includes/meta.html index 9b069c5..0ad0e64 100644 --- a/_includes/meta.html +++ b/_includes/meta.html @@ -1,6 +1,6 @@ - + {% if page.excerpt %} diff --git a/_includes/upcoming-events.html b/_includes/upcoming-events.html index e0a0125..db8fc63 100644 --- a/_includes/upcoming-events.html +++ b/_includes/upcoming-events.html @@ -31,12 +31,7 @@
- {{ event.title }} + {% include event-image.html path=event_image_path alt=event.title class=event_image_class %}
diff --git a/_layouts/default.html b/_layouts/default.html index b48a6f3..c6273ed 100644 --- a/_layouts/default.html +++ b/_layouts/default.html @@ -26,7 +26,6 @@ - {% include analytics_head.html %} @@ -49,14 +48,14 @@ - -