Add glightbox and use it in horizontal-scroller

This commit is contained in:
Kuba Orlik 2026-01-01 19:16:02 +01:00
parent f227889876
commit 99c6494fb2
7 changed files with 155 additions and 13 deletions

11
package-lock.json generated
View File

@ -30,6 +30,7 @@
"dotenv": "^16.4.5",
"escape-goat": "^4.0.0",
"get-port": "^7.0.0",
"glightbox": "^3.3.1",
"glob": "^11.0.3",
"js-convert-case": "^4.2.0",
"koa-mount": "^4.2.0",
@ -6064,6 +6065,11 @@
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="
},
"node_modules/glightbox": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/glightbox/-/glightbox-3.3.1.tgz",
"integrity": "sha512-nXoKfJRnQTDaAFAw5799hjpfAAHx5aLvOLG0SIGudeMCwtHgO3P2/avNYapJ+SL4UEZxO2YNBPtq6pzMhSx42g=="
},
"node_modules/glob": {
"version": "11.0.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz",
@ -19515,6 +19521,11 @@
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="
},
"glightbox": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/glightbox/-/glightbox-3.3.1.tgz",
"integrity": "sha512-nXoKfJRnQTDaAFAw5799hjpfAAHx5aLvOLG0SIGudeMCwtHgO3P2/avNYapJ+SL4UEZxO2YNBPtq6pzMhSx42g=="
},
"glob": {
"version": "11.0.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz",

View File

@ -82,6 +82,10 @@
{
"from": "node_modules/@sealcode/sealcodemirror/mode/javascript/javascript.js",
"to": "dist/codemirror-javascript-mode.js"
},
{
"from": "node_modules/glightbox/dist",
"to": "dist/glightbox"
}
]
},
@ -109,6 +113,7 @@
"dotenv": "^16.4.5",
"escape-goat": "^4.0.0",
"get-port": "^7.0.0",
"glightbox": "^3.3.1",
"glob": "^11.0.3",
"js-convert-case": "^4.2.0",
"koa-mount": "^4.2.0",

View File

@ -69,6 +69,13 @@
max-width: 100cqw;
align-items: center;
& > span {
display: grid;
max-height: min(75vh, 700px);
grid-template-rows: 1fr min-content;
height: 100%;
}
&,
picture,
img {
@ -80,10 +87,50 @@
); /* at just 100cqw it breaks the scroller when the images are very horizontal */
}
picture {
height: auto;
width: 100% !important;
background-image: none !important;
.caption {
font-style: italic;
text-align: justify;
grid-row: 2/3;
grid-column: 1/2;
z-index: 1;
padding: 8px;
background-color: color-mix(
in srgb,
var(--color-brand-text-bg) 70%,
transparent
);
backdrop-filter: blur(5px);
will-change: backdrop-filter background-color;
&:hover {
background-color: color-mix(
in srgb,
var(--color-brand-text-bg) 90%,
transparent
);
backdrop-filter: blur(10px);
}
}
.image-wrapper {
grid-row: 1/3;
grid-column: 1/2;
display: flex;
flex-flow: row;
align-items: center;
cursor: pointer;
&:has(picture:hover) + .caption:not(:hover) {
opacity: 0.1;
}
picture {
height: auto;
width: 100% !important;
background-image: none !important;
}
}
}
}

View File

@ -7,13 +7,15 @@ import type {
} from "@sealcode/jdd";
import { Component, ComponentArguments, insert_nbsp } from "@sealcode/jdd";
import { horizontalScroller } from "../../routes/common/horizontal-scroller/horizontal-scroller.js";
import { htmlEscape } from "escape-goat";
const component_arguments = {
title: new ComponentArguments.ShortText(),
images: new ComponentArguments.List(
new ComponentArguments.Structured({
image: new ComponentArguments.Image(),
alt: new ComponentArguments.ShortText(),
alt: new ComponentArguments.ShortText().setExampleValues([""]),
caption: new ComponentArguments.ShortText().setExampleValues([""]),
})
),
} as const;
@ -40,15 +42,33 @@ export class HorizontalGallery extends Component<typeof component_arguments> {
<div
class={["horizontal-gallery", ...classes]}
style={`--jdd-index: ${index}`}
data-controller="glightbox"
>
{horizontalScroller({
elements: (images || []).map((image) =>
render_image(image.image, {
sizesAttr: "100vw",
container: { width: 800, height: 500, objectFit: "contain" },
alt: image.alt,
})
),
elements: (images || []).map((image) => (
<>
<div
class="image-wrapper"
data-glightbox-target="pictureWrapper"
data-glightbox-caption={htmlEscape(image.caption)}
>
{render_image(image.image, {
sizesAttr: "100vw",
container: {
width: 800,
height: 500,
objectFit: "contain",
},
alt: image.alt,
})}
</div>
{image.caption.trim() ? (
<div class="caption">{image.caption}</div>
) : (
""
)}
</>
)),
render: async ({ scroller, markers }) => (
<div>
<div class="horizontal-gallery__top-bar">

View File

@ -16,6 +16,9 @@ application.register("map-with-pins", MapWithPins);
import { default as HorizontalScroller } from "./../back/routes/common/horizontal-scroller/horizontal-scroller.stimulus.js";
application.register("horizontal-scroller", HorizontalScroller);
import { default as Glightbox } from "./controllers/glightbox.stimulus.js";
application.register("glightbox", Glightbox);
import { default as AutogrowTextarea } from "./../../node_modules/@sealcode/jdd-editor/src/controllers/autogrow-textarea.stimulus.js";
application.register("autogrow-textarea", AutogrowTextarea);

View File

@ -0,0 +1,55 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any */
/* ^ necessary until https://github.com/biati-digital/glightbox/pull/577 waits for merge */
import { Controller } from "stimulus";
import { addCSS, addJS } from "@sealcode/add-to-head";
import type { default as GL } from "glightbox";
declare global {
interface Window {
GLightbox: typeof GL;
}
}
const settings = { touchNavigation: true };
export default class GlightboxController extends Controller {
static targets = ["pictureWrapper"];
id: string;
gallery: ReturnType<typeof GL>;
declare pictureWrapperTargets: HTMLDivElement[];
async connect() {
await this.initGallery();
}
async initGallery() {
await Promise.all([
addJS("/dist/glightbox/js/glightbox.min.js"),
addCSS("/dist/glightbox/css/glightbox.min.css"),
]);
this.gallery?.destroy();
this.gallery = window.GLightbox({
elements: this.pictureWrapperTargets.map((e) => {
const img = e.querySelector("img");
return {
type: "image",
href: img.getAttribute("src"),
description: e.getAttribute("data-glightbox-caption"),
alt: img.getAttribute("alt") || "",
};
}) as any,
...settings,
});
this.pictureWrapperTargets.map((e, index) => {
e.addEventListener("click", () => {
this.gallery.openAt(index);
});
});
}
async pictureWrapperTargetConnected() {
await this.initGallery();
}
}

View File

@ -6,7 +6,8 @@
"lib": ["dom", "es2021"],
"skipLibCheck": true,
"esModuleInterop": true,
"noUncheckedIndexedAccess": true
"noUncheckedIndexedAccess": true,
"allowSyntheticDefaultImports": true
},
"include": ["./src/front", "./src/**/*.stimulus.ts"]
}