Bootstrapped during the 2026-06-06 BlockNinja consolidation. Was previously an unversioned directory inside ~/src/blockninja-themes/noir. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
88 lines
2.2 KiB
Plaintext
88 lines
2.2 KiB
Plaintext
package main
|
|
|
|
// lightboxGalleryComponent renders the gallery grid with lightbox triggers.
|
|
templ lightboxGalleryComponent(items []LightboxItem, cols int) {
|
|
<section data-block="noir:lightbox_gallery" class="py-12">
|
|
<div class="max-w-6xl mx-auto px-6">
|
|
if len(items) == 0 {
|
|
<div class="hairline p-12 text-center tracked-mono" style="color: hsl(var(--mutedForeground));">
|
|
Add photographs to populate the gallery.
|
|
</div>
|
|
} else {
|
|
<div class={ "grid gap-4", lightboxGridCols(cols) }>
|
|
for i, item := range items {
|
|
<figure class="noir-figure">
|
|
<button
|
|
type="button"
|
|
data-noir-lightbox-trigger
|
|
data-src={ item.Image }
|
|
data-alt={ item.Caption }
|
|
data-caption={ item.Caption }
|
|
class="block w-full p-0 m-0 cursor-zoom-in bg-transparent border-0"
|
|
style="background: transparent;"
|
|
aria-label={ lightboxAriaLabel(i, item.Caption) }
|
|
>
|
|
<img
|
|
src={ item.Image }
|
|
alt={ item.Caption }
|
|
loading="lazy"
|
|
class="w-full h-auto block"
|
|
/>
|
|
</button>
|
|
if item.Caption != "" {
|
|
<figcaption class="tracked-mono mt-2" style="color: hsl(var(--mutedForeground));">
|
|
{ item.Caption }
|
|
</figcaption>
|
|
}
|
|
</figure>
|
|
}
|
|
</div>
|
|
}
|
|
</div>
|
|
</section>
|
|
}
|
|
|
|
// lightboxGridCols returns Tailwind grid-template-columns utility for the requested columns.
|
|
func lightboxGridCols(cols int) string {
|
|
switch cols {
|
|
case 2:
|
|
return "grid-cols-1 md:grid-cols-2"
|
|
case 4:
|
|
return "grid-cols-1 md:grid-cols-2 lg:grid-cols-4"
|
|
default: // 3
|
|
return "grid-cols-1 md:grid-cols-2 lg:grid-cols-3"
|
|
}
|
|
}
|
|
|
|
// lightboxAriaLabel builds an accessible button label for each gallery entry.
|
|
func lightboxAriaLabel(index int, caption string) string {
|
|
if caption != "" {
|
|
return "Open photograph: " + caption
|
|
}
|
|
return "Open photograph " + intToString(index+1)
|
|
}
|
|
|
|
// intToString avoids importing strconv into a templ-generated file.
|
|
func intToString(n int) string {
|
|
if n == 0 {
|
|
return "0"
|
|
}
|
|
neg := false
|
|
if n < 0 {
|
|
neg = true
|
|
n = -n
|
|
}
|
|
var b [20]byte
|
|
i := len(b)
|
|
for n > 0 {
|
|
i--
|
|
b[i] = byte('0' + n%10)
|
|
n /= 10
|
|
}
|
|
if neg {
|
|
i--
|
|
b[i] = '-'
|
|
}
|
|
return string(b[i:])
|
|
}
|