Preserve chronological order in gapless gallery rows

This commit is contained in:
2026-09-26 19:10:42 +01:00
parent c864e781d7
commit 00fffe703d
4 changed files with 86 additions and 14 deletions
+47
View File
@@ -1,6 +1,53 @@
require 'nokogiri'
module GalleryItems
JPEG_START_OF_FRAME = [0xC0, 0xC1, 0xC2, 0xC3, 0xC5, 0xC6, 0xC7,
0xC9, 0xCA, 0xCB, 0xCD, 0xCE, 0xCF].freeze
# Read just the dimensions from a local JPEG. The rendered gallery needs
# aspect ratios to size each chronological pair without cropping either photo.
def jpeg_dimensions(path)
File.open(path, 'rb') do |file|
return nil unless file.read(2) == "\xFF\xD8".b
while (prefix = file.read(1))
next unless prefix.getbyte(0) == 0xFF
marker = file.read(1)&.getbyte(0)
break unless marker
next if marker == 0xFF || marker == 0x01 || (0xD0..0xD7).cover?(marker)
break if marker == 0xD9 || marker == 0xDA
size = file.read(2)&.unpack1('n')
break unless size && size >= 2
if JPEG_START_OF_FRAME.include?(marker)
dimensions = file.read(5)
return nil unless dimensions&.length == 5
height, width = dimensions.byteslice(1, 4).unpack('n2')
return [width, height] if width.positive? && height.positive?
return nil
end
file.seek(size - 2, IO::SEEK_CUR)
end
end
nil
rescue Errno::ENOENT, EOFError
nil
end
def gallery_image_ratio(content)
image = Nokogiri::HTML::DocumentFragment.parse(content).at_css('img')
source = image&.[]('src')
return 1.5 unless source&.start_with?('/img/arts/')
path = File.join(File.expand_path('..', __dir__), source.delete_prefix('/'))
width, height = jpeg_dimensions(path)
return 1.5 unless width && height
(width.to_f / height).round(4)
end
# Uploaded batches share one source document, but each photo is a gallery item.
# Keeping this at render time also fixes batches that have already been published.
def gallery_items(content)
+22 -10
View File
@@ -227,16 +227,22 @@ hr {
}
.art .post-list {
column-count: 2;
column-gap: $spacing-unit;
.gallery-row {
display: flex;
gap: $spacing-unit;
align-items: flex-start;
list-style: none;
margin: 0 0 $spacing-unit;
> li {
display: inline-block;
width: 100%;
margin-top: 0;
margin-bottom: $spacing-unit;
break-inside: avoid;
-webkit-column-break-inside: avoid;
flex: var(--photo-ratio) 1 0;
min-width: 0;
margin: 0;
}
> li:only-child {
flex: 0 0 calc((100% - #{$spacing-unit}) / 2);
}
}
.post-content > p:last-child {
@@ -249,11 +255,17 @@ hr {
height: auto;
margin: 0;
// Reserve space before lazy images load, then use their natural proportions.
aspect-ratio: auto 3 / 2;
aspect-ratio: auto var(--photo-ratio, 3 / 2);
}
@include media-query($on-palm) {
column-count: 1;
.gallery-row {
display: block;
> li {
margin-bottom: $spacing-unit;
}
}
}
}
+10 -3
View File
@@ -28,14 +28,17 @@ wide_gallery: true
</details>
</div>
<ul class="post-list">
<div class="post-list">
{% assign gallery_index = 0 %}
{% for post in site.art reversed %}
{% if post.published == false %}
{% continue %}
{% endif %}
{% assign items = post.content | markdownify | lazy_images | gallery_items %}
{% for item in items %}
<li class='lang-{% if post.lang %}{{ post.lang }}{% else %}en{% endif %}'>
{% assign row_position = gallery_index | modulo: 2 %}
{% if row_position == 0 %}<ul class="gallery-row">{% endif %}
<li class='lang-{% if post.lang %}{{ post.lang }}{% else %}en{% endif %}' style='--photo-ratio: {{ item | gallery_image_ratio }}'>
<article class='post-content'>
{% if post.anchor and forloop.first %}
<span id='{{ post.title }}'></span>
@@ -43,9 +46,13 @@ wide_gallery: true
{{ item }}
</article>
</li>
{% assign gallery_index = gallery_index | plus: 1 %}
{% assign row_position = gallery_index | modulo: 2 %}
{% if row_position == 0 %}</ul>{% endif %}
{% endfor %}
{% endfor %}
</ul>
{% if row_position == 1 %}</ul>{% endif %}
</div>
<p class="rss-subscribe">subscribe <a href="{{ "/feed.xml" | prepend: site.baseurl }}">via rss</a></p>
+6
View File
@@ -27,4 +27,10 @@ single = '<p><img src="/img/arts/uploads/batch/00.jpg"></p>'
raise 'Single photo changed' unless renderer.gallery_items(single) == [single]
legacy = '<p><img src="/img/old.jpg"></p><p>Existing artwork content</p>'
raise 'Legacy artwork changed' unless renderer.gallery_items(legacy) == [legacy]
portrait = '<img src="/img/arts/dresden-prague-iran-2024/Prague_000512360030.jpg">'
landscape = '<img src="/img/arts/uploads/5e085e7d10edc54172e7b5c47d22fe532edec19c879a8d566667d3c3c1bb3d96/00.jpg">'
raise 'Portrait ratio incorrect' unless renderer.gallery_image_ratio(portrait) < 1
raise 'Landscape ratio incorrect' unless renderer.gallery_image_ratio(landscape) > 1
raise 'Video fallback ratio incorrect' unless renderer.gallery_image_ratio('<video></video>') == 1.5
puts 'Gallery item regression checks passed'