Files
schreifuchs.ch/web/pages/gallery.templ
T

124 lines
3.6 KiB
Templ

package pages
import (
"fmt"
"git.schreifuchs.ch/schreifuchs/schreifuchs.ch/internal/components/gallery"
"git.schreifuchs.ch/schreifuchs/schreifuchs.ch/internal/pkg/templer"
"git.schreifuchs.ch/schreifuchs/schreifuchs.ch/web/components"
)
const detailsID = "imgs-details"
// detailsContentID is the inner element of the modal that htmx swaps into.
// It is defined by components.Modal and must not be the dialog itself.
const detailsContentID = detailsID + "-content"
templ GallerySet(g gallery.Set) {
<div class="p-5">
@components.Modal(detailsID) {
// Placeholder: only visible until the first image is swapped in.
// prev/next are nil because relative links would be resolved
// against the gallery index, not the image page.
if len(g.SM.Images) > 0 {
@GalleryImage(g.SM.Images[0].UID, nil, nil)
}
}
<div
class="grid gap-5 grid-cols-1 lg:hidden"
>
for _,img := range g.SM.Images {
<button
hx-get={ templer.RelativePath(ctx, "./"+img.UID) }
hx-target={ "#" + detailsContentID }
hx-swap="innerHTML"
class="block w-full cursor-pointer"
>
<img
src={ "/images/" + img.UID + "?w=600" }
loading="lazy"
class="w-full"
alt="Gallery item"
/>
</button>
}
</div>
<div class="hidden lg:block 3xl:hidden">
@Gallery(g.SM)
</div>
<div class="hidden 3xl:block 6xl:hidden">
@Gallery(g.LG)
</div>
<div class="hidden 6xl:block">
@Gallery(g.XLG)
</div>
</div>
}
templ GalleryImage(image string, next *gallery.Image, prev *gallery.Image) {
<div class="relative w-10/12 h-10/12 flex items-center justify-center overflow-hidden ">
<!-- 1. Preloaded Base Image (w=800) -->
<img
src={ "/images/" + image + "?w=800" }
alt=""
class="absolute inset-0 w-full h-full object-contain"
/>
<!-- 2. Responsive Image Layer (Overlaid on top) -->
<img
src={ "/images/" + image + "?w=800" }
srcset={ "/images/" + image + "?w=400 400w, /images/" + image + "?w=800 800w, /images/" + image + "?w=1200 1200w, /images/" + image + "?w=1600 1600w" }
sizes="(max-width: 600px) 400px, (max-width: 1200px) 800px, 1200px"
alt="Image description"
onload="this.classList.remove('opacity-0')"
class="absolute inset-0 w-full h-full object-contain transition-opacity duration-300"
/>
<!-- 3. Navigation Controls -->
if prev != nil {
<button
hx-get={ templer.RelativePath(ctx, "../"+prev.UID) }
hx-target={ "#" + detailsContentID }
hx-swap="innerHTML"
class="absolute left-4 top-1/2 -translate-y-1/2 z-10 p-2 text-white"
>
&lt;
</button>
}
if next != nil {
<button
hx-get={ templer.RelativePath(ctx, "../"+next.UID) }
hx-target={ "#" + detailsContentID }
hx-swap="innerHTML"
class="absolute right-4 top-1/2 -translate-y-1/2 z-10 p-2 text-white"
>
&gt;
</button>
}
</div>
}
templ Gallery(g gallery.Gallery) {
<div
class="grid gap-5"
style={ fmt.Sprintf("grid-template-columns: repeat(%d, 1fr); grid-template-rows: repeat(%d, auto);", g.GridWith, g.GridHeight) }
>
for _, img := range g.Images {
<div
style={ fmt.Sprintf("grid-column: %d / span %d; grid-row: %d / span %d;aspect-ratio: %d / %d;", img.X+1, img.Width, img.Y+1, img.Height, img.Width, img.Height) }
class="overflow-hidden shadow-sm"
>
<button
hx-get={ templer.RelativePath(ctx, "./"+img.UID) }
hx-target={ "#" + detailsContentID }
hx-swap="innerHTML"
>
<img
src={ "/images/" + img.UID + "?w=800" }
loading="lazy"
class="w-full h-full object-cover"
alt="Gallery item"
/>
</button>
</div>
}
</div>
}