@simple-photo-gallery/common 2.1.2 → 2.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.js CHANGED
@@ -289,11 +289,52 @@ var PhotoSwipeVideoPlugin = class {
289
289
  };
290
290
 
291
291
  // src/client/photoswipe/lightbox.ts
292
+ var CAPTION_SAMPLE_SIZE = 50;
293
+ var CAPTION_SAMPLE_HEIGHT_RATIO = 0.15;
294
+ var CAPTION_BG_DARK = { r: 255, g: 255, b: 255, a: 0.5 };
295
+ var CAPTION_BG_LIGHT = { r: 0, g: 0, b: 0, a: 0.8 };
296
+ function interpolateCaptionBg(brightness) {
297
+ const t = Math.min(1, Math.max(0, brightness / 255));
298
+ const r = Math.round(CAPTION_BG_DARK.r + (CAPTION_BG_LIGHT.r - CAPTION_BG_DARK.r) * t);
299
+ const g = Math.round(CAPTION_BG_DARK.g + (CAPTION_BG_LIGHT.g - CAPTION_BG_DARK.g) * t);
300
+ const b = Math.round(CAPTION_BG_DARK.b + (CAPTION_BG_LIGHT.b - CAPTION_BG_DARK.b) * t);
301
+ const a = +(CAPTION_BG_DARK.a + (CAPTION_BG_LIGHT.a - CAPTION_BG_DARK.a) * t).toFixed(3);
302
+ return `rgba(${r}, ${g}, ${b}, ${a})`;
303
+ }
304
+ function createCaptionBrightnessSampler() {
305
+ const canvas = document.createElement("canvas");
306
+ const ctx = canvas.getContext("2d", { willReadFrequently: true });
307
+ if (!ctx) return null;
308
+ canvas.width = CAPTION_SAMPLE_SIZE;
309
+ canvas.height = CAPTION_SAMPLE_SIZE;
310
+ return (img) => {
311
+ if (!img.complete || img.naturalWidth === 0 || img.naturalHeight === 0) return null;
312
+ const srcWidth = img.naturalWidth;
313
+ const srcHeight = img.naturalHeight;
314
+ const sampleHeight = Math.max(1, Math.round(srcHeight * CAPTION_SAMPLE_HEIGHT_RATIO));
315
+ const srcY = Math.max(0, srcHeight - sampleHeight);
316
+ try {
317
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
318
+ ctx.drawImage(img, 0, srcY, srcWidth, sampleHeight, 0, 0, canvas.width, canvas.height);
319
+ const { data } = ctx.getImageData(0, 0, canvas.width, canvas.height);
320
+ let sum = 0;
321
+ let count = 0;
322
+ for (let i = 0; i < data.length; i += 4) {
323
+ sum += 0.299 * data[i] + 0.587 * data[i + 1] + 0.114 * data[i + 2];
324
+ count++;
325
+ }
326
+ return count ? sum / count : null;
327
+ } catch {
328
+ return null;
329
+ }
330
+ };
331
+ }
292
332
  async function createGalleryLightbox(options = {}) {
293
333
  const photoswipeModule = await import('photoswipe');
294
334
  const PhotoSwipe = photoswipeModule.default;
295
335
  const lightboxModule = await import('photoswipe/lightbox');
296
336
  const PhotoSwipeLightboxModule = lightboxModule.default;
337
+ const sampleBrightness = createCaptionBrightnessSampler();
297
338
  const lightbox = new PhotoSwipeLightboxModule({
298
339
  gallery: options.gallerySelector ?? ".gallery-grid",
299
340
  children: options.childrenSelector ?? "a",
@@ -326,6 +367,23 @@ async function createGalleryLightbox(options = {}) {
326
367
  if (currSlideElement) {
327
368
  const caption = currSlideElement.dataset.pswpCaption;
328
369
  el.innerHTML = caption || currSlideElement.querySelector("img")?.alt || "";
370
+ if (sampleBrightness) {
371
+ const img = currSlideElement.querySelector("img");
372
+ const apply = () => {
373
+ if (!img) return;
374
+ const brightness = sampleBrightness(img);
375
+ if (brightness === null) {
376
+ el.style.removeProperty("--pswp-caption-bg");
377
+ } else {
378
+ el.style.setProperty("--pswp-caption-bg", interpolateCaptionBg(brightness));
379
+ }
380
+ };
381
+ if (img && (!img.complete || img.naturalWidth === 0)) {
382
+ img.addEventListener("load", apply, { once: true });
383
+ } else {
384
+ apply();
385
+ }
386
+ }
329
387
  }
330
388
  });
331
389
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client/blurhash.ts","../src/client/hero-fallback.ts","../src/client/photoswipe/video-plugin.ts","../src/client/photoswipe/lightbox.ts","../src/client/photoswipe/deep-linking.ts","../src/client/css-utils.ts"],"names":[],"mappings":";;;AASO,SAAS,sBAAA,CAAuB,MAAA,EAA2B,KAAA,GAAgB,EAAA,EAAI,SAAiB,EAAA,EAAU;AAC/G,EAAA,MAAM,aAAA,GAAgB,OAAO,OAAA,CAAQ,QAAA;AACrC,EAAA,IAAI,CAAC,aAAA,EAAe;AAEpB,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,aAAA,EAAe,KAAA,EAAO,MAAM,CAAA;AAClD,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,UAAA,CAAW,IAAI,CAAA;AAClC,EAAA,IAAI,UAAU,GAAA,EAAK;AACjB,IAAA,MAAM,SAAA,GAAY,IAAI,SAAA,CAAU,IAAI,kBAAkB,MAAM,CAAA,EAAG,OAAO,MAAM,CAAA;AAC5E,IAAA,GAAA,CAAI,YAAA,CAAa,SAAA,EAAW,CAAA,EAAG,CAAC,CAAA;AAAA,EAClC;AACF;AAUO,SAAS,oBACd,QAAA,GAAmB,wBAAA,EACnB,KAAA,GAAgB,EAAA,EAChB,SAAiB,EAAA,EACX;AACN,EAAA,MAAM,QAAA,GAAW,QAAA,CAAS,gBAAA,CAAoC,QAAQ,CAAA;AACtE,EAAA,KAAA,MAAW,UAAU,QAAA,EAAU;AAC7B,IAAA,sBAAA,CAAuB,MAAA,EAAQ,OAAO,MAAM,CAAA;AAAA,EAC9C;AACF;;;ACJO,SAAS,qBAAA,CAAsB,OAAA,GAAoC,EAAC,EAAS;AAClF,EAAA,MAAM;AAAA,IACJ,eAAA,GAAkB,kBAAA;AAAA,IAClB,WAAA,GAAc,kBAAA;AAAA,IACd,cAAA,GAAiB;AAAA,GACnB,GAAI,OAAA;AAEJ,EAAA,MAAM,OAAA,GAAU,QAAA,CAAS,aAAA,CAAkC,eAAe,CAAA;AAC1E,EAAA,MAAM,GAAA,GAAM,OAAA,EAAS,aAAA,CAAgC,WAAW,CAAA;AAChE,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,aAAA,CAAiC,cAAc,CAAA;AAEvE,EAAA,IAAI,CAAC,GAAA,EAAK;AAEV,EAAA,MAAM,WAAA,GAAc,GAAA,CAAI,YAAA,CAAa,KAAK,CAAA,IAAK,EAAA;AAC/C,EAAA,IAAI,WAAA,GAAc,KAAA;AAElB,EAAA,MAAM,eAAe,MAAM;AACzB,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,MAAA,CAAO,MAAM,OAAA,GAAU,MAAA;AAAA,IACzB;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,aAAa,MAAM;AACvB,IAAA,IAAI,WAAA,EAAa;AACjB,IAAA,WAAA,GAAc,IAAA;AAEd,IAAA,IAAI,OAAA,EAAS;AAEX,MAAA,KAAA,MAAW,QAAA,IAAY,OAAA,CAAQ,gBAAA,CAAiB,QAAQ,CAAA,EAAG;AACzD,QAAA,QAAA,CAAS,MAAA,EAAO;AAAA,MAClB;AAAA,IACF;AAGA,IAAA,MAAM,OAAA,GAAU,GAAA,CAAI,YAAA,CAAa,KAAK,CAAA,IAAK,EAAA;AAC3C,IAAA,GAAA,CAAI,YAAA,CAAa,OAAO,EAAE,CAAA;AAC1B,IAAA,GAAA,CAAI,YAAA,CAAa,KAAA,EAAO,WAAA,IAAe,OAAO,CAAA;AAG9C,IAAA,GAAA,CAAI,gBAAA;AAAA,MACF,OAAA;AAAA,MACA,MAAM;AAAA,MAEN,CAAA;AAAA,MACA,EAAE,MAAM,IAAA;AAAK,KACf;AAGA,IAAA,GAAA,CAAI,iBAAiB,MAAA,EAAQ,YAAA,EAAc,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA,EAC3D,CAAA;AAGA,EAAA,IAAI,IAAI,QAAA,EAAU;AAChB,IAAA,IAAI,GAAA,CAAI,iBAAiB,CAAA,EAAG;AAC1B,MAAA,UAAA,EAAW;AAAA,IACb,CAAA,MAAO;AACL,MAAA,YAAA,EAAa;AAAA,IACf;AAAA,EACF,CAAA,MAAO;AACL,IAAA,GAAA,CAAI,iBAAiB,MAAA,EAAQ,YAAA,EAAc,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA,EAC3D;AAEA,EAAA,GAAA,CAAI,iBAAiB,OAAA,EAAS,UAAA,EAAY,EAAE,IAAA,EAAM,MAAM,CAAA;AAC1D;;;AC7FA,IAAM,cAAA,GAAqC;AAAA,EACzC,iBAAiB,EAAE,QAAA,EAAU,IAAI,WAAA,EAAa,EAAA,EAAI,SAAS,MAAA,EAAO;AAAA,EAClE,QAAA,EAAU,IAAA;AAAA,EACV,iBAAA,EAAmB;AACrB,CAAA;AAKA,SAAS,eAAe,OAAA,EAAmC;AACzD,EAAA,OAAO,WAAW,MAAA,IAAU,OAAA,IAAW,QAAQ,IAAA,IAAQ,OAAA,CAAQ,KAAK,IAAA,KAAS,OAAA;AAC/E;AAEA,IAAM,oBAAN,MAAwB;AAAA,EAGtB,WAAA,CAAY,UAA8B,OAAA,EAA6B;AACrE,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AAEf,IAAA,IAAA,CAAK,mBAAmB,QAAQ,CAAA;AAChC,IAAA,QAAA,CAAS,EAAA,CAAG,QAAQ,MAAM;AACxB,MAAA,IAAI,SAAS,IAAA,EAAM;AACjB,QAAA,IAAA,CAAK,cAAA,CAAe,SAAS,IAAI,CAAA;AAAA,MACnC;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAAA,EAEQ,mBAAmB,QAAA,EAAoC;AAC7D,IAAA,QAAA,CAAS,GAAG,aAAA,EAAe,CAAC,SAAkB,IAAA,CAAK,aAAA,CAAc,IAAiB,CAAC,CAAA;AACnF,IAAA,QAAA,CAAS,GAAG,gBAAA,EAAkB,CAAC,SAAkB,IAAA,CAAK,gBAAA,CAAiB,IAA4B,CAAC,CAAA;AACpG,IAAA,QAAA,CAAS,GAAG,iBAAA,EAAmB,CAAC,SAAkB,IAAA,CAAK,iBAAA,CAAkB,IAA4B,CAAC,CAAA;AACtG,IAAA,QAAA,CAAS,GAAG,mBAAA,EAAqB,CAAC,SAAkB,IAAA,CAAK,mBAAA,CAAoB,IAA4B,CAAC,CAAA;AAC1G,IAAA,QAAA,CAAS,GAAG,eAAA,EAAiB,CAAC,SAAkB,IAAA,CAAK,eAAA,CAAgB,IAAiB,CAAC,CAAA;AACvF,IAAA,QAAA,CAAS,GAAG,eAAA,EAAiB,CAAC,SAAkB,IAAA,CAAK,eAAA,CAAgB,IAAiB,CAAC,CAAA;AAEvF,IAAA,QAAA,CAAS,SAAA;AAAA,MAAU,sBAAA;AAAA,MAAwB,CAAC,UAAmB,IAAA,KAC7D,IAAA,CAAK,qBAAqB,KAAA,EAAkB,IAAA,CAAK,CAAC,CAAY;AAAA,KAChE;AACA,IAAA,QAAA,CAAS,SAAA;AAAA,MAAU,mBAAA;AAAA,MAAqB,CAAC,UAAmB,IAAA,KAC1D,IAAA,CAAK,kBAAkB,KAAA,EAAkB,IAAA,CAAK,CAAC,CAAY;AAAA,KAC7D;AACA,IAAA,QAAA,CAAS,SAAA;AAAA,MAAU,uBAAA;AAAA,MAAyB,CAAC,UAAmB,IAAA,KAC9D,IAAA,CAAK,sBAAsB,KAAA,EAAkB,IAAA,CAAK,CAAC,CAAY;AAAA,KACjE;AAEA,IAAA,QAAA,CAAS,SAAA,CAAU,aAAA,EAAe,CAAC,KAAA,EAAA,GAAmB,IAAA,KAAoB;AACxE,MAAA,MAAM,QAAA,GAAW,KAAA;AACjB,MAAA,MAAM,MAAA,GAAS,KAAK,CAAC,CAAA;AAErB,MAAA,IAAI,QAAA,CAAS,IAAA,KAAS,OAAA,IAAW,MAAA,EAAQ;AACvC,QAAA,IAAI,MAAA,CAAO,QAAQ,gBAAA,EAAkB;AACnC,UAAA,QAAA,CAAS,YAAA,GAAe,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,QAAQ,gBAAgB,CAAA;AAAA,QACpE,CAAA,MAAA,IAAW,MAAA,CAAO,OAAA,CAAQ,YAAA,EAAc;AACtC,UAAA,QAAA,CAAS,QAAA,GAAW,OAAO,OAAA,CAAQ,YAAA;AAAA,QACrC,CAAA,MAAO;AACL,UAAA,QAAA,CAAS,WAAW,MAAA,CAAO,IAAA;AAAA,QAC7B;AAAA,MACF;AACA,MAAA,OAAO,QAAA;AAAA,IACT,CAAC,CAAA;AAAA,EACH;AAAA,EAEQ,eAAe,IAAA,EAAwB;AAE7C,IAAA,IAAA,CAAK,EAAA,CAAG,aAAA,EAAe,CAAC,IAAA,KAAkB;AACxC,MAAA,MAAM,CAAA,GAAI,IAAA;AACV,MAAA,MAAM,QAAQ,IAAA,CAAK,SAAA;AACnB,MAAA,IAAI,SAAS,cAAA,CAAe,KAAK,CAAA,IAAK,IAAA,CAAK,QAAQ,iBAAA,EAAmB;AACpE,QAAA,MAAM,YAAY,CAAA,CAAE,aAAA;AACpB,QAAA,IAAI,SAAA,IAAa,SAAA,CAAU,IAAA,KAAS,aAAA,EAAe;AACjD,UAAA,MAAM,cAAc,IAAA,CAAK,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,MAAM,aAAa,CAAA;AAChE,UAAA,MAAM,cAAA,GAAiB,WAAA,GAAc,KAAA,CAAM,MAAA,CAAO,MAAA,CAAO,CAAA;AACzD,UAAA,MAAM,WAAA,GAAc,SAAA,CAAU,KAAA,GAAQ,IAAA,CAAK,MAAA,CAAO,CAAA;AAClD,UAAA,IAAI,cAAc,cAAA,GAAiB,IAAA,CAAK,OAAA,CAAQ,iBAAA,IAAsB,cAAc,cAAA,EAAgB;AAClG,YAAA,CAAA,CAAE,cAAA,IAAiB;AAAA,UACrB;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC,CAAA;AAGD,IAAA,IAAA,CAAK,EAAA,CAAG,aAAA,EAAe,CAAC,IAAA,KAAkB;AACxC,MAAA,MAAM,CAAA,GAAI,IAAA;AACV,MAAA,IAAI,CAAA,CAAE,SAAS,cAAA,CAAe,CAAA,CAAE,KAAK,CAAA,IAAK,CAAC,CAAA,CAAE,KAAA,CAAM,QAAA,EAAU;AAC3D,QAAA,CAAA,CAAE,cAAA,IAAiB;AAAA,MACrB;AAAA,IACF,CAAC,CAAA;AAED,IAAA,IAAA,CAAK,EAAA,CAAG,SAAS,MAAM;AACrB,MAAA,MAAM,QAAQ,IAAA,CAAK,SAAA;AACnB,MAAA,IAAI,KAAA,IAAS,cAAA,CAAe,KAAA,CAAM,OAAO,CAAA,EAAG;AAG1C,QAAA,IAAI,CAAC,IAAA,CAAK,OAAA,CAAQ,yBAAyB,IAAA,CAAK,OAAA,CAAQ,0BAA0B,MAAA,EAAQ;AACxF,UAAA,IAAA,CAAK,QAAQ,qBAAA,GAAwB,MAAA;AAAA,QACvC;AAGA,QAAA,IAAA,CAAK,UAAA,CAAW,MAAM,OAAO,CAAA;AAAA,MAC/B;AAAA,IACF,CAAC,CAAA;AAAA,EACH;AAAA,EAEQ,gBAAA,CAAiB,EAAE,OAAA,EAAQ,EAA+B;AAChE,IAAA,IAAI,cAAA,CAAe,OAAO,CAAA,IAAK,OAAA,CAAQ,eAAA,EAAiB;AACtD,MAAA,MAAM,aAAa,MAAM;AACvB,QAAA,IAAI,QAAQ,eAAA,EAAiB;AAC3B,UAAA,OAAA,CAAQ,eAAA,CAAgB,mBAAA,CAAoB,OAAA,EAAS,WAAW,CAAA;AAAA,QAClE;AAAA,MACF,CAAA;AACA,MAAA,MAAM,cAAc,MAAM;AAAA,MAE1B,CAAA;AAEA,MAAA,OAAA,CAAQ,eAAA,CAAgB,gBAAA,CAAiB,MAAA,EAAQ,UAAU,CAAA;AAC3D,MAAA,OAAA,CAAQ,eAAA,CAAgB,gBAAA,CAAiB,OAAA,EAAS,WAAW,CAAA;AAC7D,MAAA,OAAA,CAAQ,eAAA,GAAkB,MAAA;AAAA,IAC5B;AAAA,EACF;AAAA,EAEQ,gBAAgB,CAAA,EAAoB;AAC1C,IAAA,IAAI,CAAA,CAAE,OAAA,IAAW,cAAA,CAAe,CAAA,CAAE,OAAO,CAAA,EAAG;AAC1C,MAAA,CAAA,CAAE,cAAA,IAAiB;AAEnB,MAAA,MAAM,QAAQ,CAAA,CAAE,KAAA;AAChB,MAAA,MAAM,SAAS,CAAA,CAAE,MAAA;AACjB,MAAA,MAAM,UAAU,CAAA,CAAE,OAAA;AAElB,MAAA,IAAI,QAAQ,OAAA,EAAS;AACnB,QAAA,OAAA,CAAQ,OAAA,CAAQ,KAAA,CAAM,KAAA,GAAQ,KAAA,GAAQ,IAAA;AACtC,QAAA,OAAA,CAAQ,OAAA,CAAQ,KAAA,CAAM,MAAA,GAAS,MAAA,GAAS,IAAA;AAAA,MAC1C;AAEA,MAAA,IAAI,OAAA,CAAQ,KAAA,IAAS,OAAA,CAAQ,KAAA,CAAM,WAAA,EAAa;AAE9C,QAAA,MAAM,kBAAA,GAAqB,OAAA,CAAQ,KAAA,CAAM,WAAA,CAAY,OAAA,CAAQ,KAAA;AAC7D,QAAA,kBAAA,CAAmB,SAAA,GAAY,MAAA;AAC/B,QAAA,kBAAA,CAAmB,QAAQ,KAAA,GAAQ,IAAA;AACnC,QAAA,kBAAA,CAAmB,SAAS,MAAA,GAAS,IAAA;AAAA,MACvC;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,oBAAA,CAAqB,YAAqB,OAAA,EAA2B;AAC3E,IAAA,IAAI,cAAA,CAAe,OAAO,CAAA,EAAG;AAC3B,MAAA,OAAO,KAAA;AAAA,IACT;AACA,IAAA,OAAO,UAAA;AAAA,EACT;AAAA,EAEQ,iBAAA,CAAkB,YAAqB,OAAA,EAA2B;AACxE,IAAA,IAAI,cAAA,CAAe,OAAO,CAAA,EAAG;AAC3B,MAAA,OAAO,KAAA;AAAA,IACT;AACA,IAAA,OAAO,UAAA;AAAA,EACT;AAAA,EAEQ,iBAAA,CAAkB,EAAE,OAAA,EAAQ,EAA+B;AACjE,IAAA,IAAI,cAAA,CAAe,OAAO,CAAA,IAAK,IAAA,CAAK,QAAQ,QAAA,EAAU;AACpD,MAAA,IAAA,CAAK,UAAU,OAAO,CAAA;AAAA,IACxB;AAAA,EACF;AAAA,EAEQ,mBAAA,CAAoB,EAAE,OAAA,EAAQ,EAA+B;AACnE,IAAA,IAAI,cAAA,CAAe,OAAO,CAAA,EAAG;AAC3B,MAAA,IAAA,CAAK,WAAW,OAAO,CAAA;AAAA,IACzB;AAAA,EACF;AAAA,EAEQ,gBAAgB,CAAA,EAAoB;AAC1C,IAAA,IAAI,CAAA,CAAE,OAAA,IAAW,cAAA,CAAe,CAAA,CAAE,OAAO,CAAA,EAAG;AAC1C,MAAA,CAAA,CAAE,cAAA,IAAiB;AACnB,MAAA,CAAA,CAAE,QAAQ,UAAA,GAAa,IAAA;AACvB,MAAA,CAAA,CAAE,QAAQ,WAAA,IAAc;AAAA,IAC1B;AAAA,EACF;AAAA,EAEQ,cAAc,CAAA,EAAoB;AACxC,IAAA,MAAM,UAAU,CAAA,CAAE,OAAA;AAElB,IAAA,IAAI,CAAC,cAAA,CAAe,OAAO,CAAA,EAAG;AAC5B,MAAA;AAAA,IACF;AAGA,IAAA,CAAA,CAAE,cAAA,IAAiB;AAEnB,IAAA,IAAI,QAAQ,OAAA,EAAS;AACnB,MAAA;AAAA,IACF;AAEA,IAAA,OAAA,CAAQ,KAAA,GAAQ,SAAA;AAChB,IAAA,OAAA,CAAQ,IAAA,GAAO,OAAA;AAEf,IAAA,OAAA,CAAQ,OAAA,GAAU,QAAA,CAAS,aAAA,CAAc,OAAO,CAAA;AAEhD,IAAA,IAAI,IAAA,CAAK,QAAQ,eAAA,EAAiB;AAChC,MAAA,KAAA,MAAW,GAAA,IAAO,IAAA,CAAK,OAAA,CAAQ,eAAA,EAAiB;AAC9C,QAAA,OAAA,CAAQ,OAAA,CAAQ,aAAa,GAAA,EAAK,IAAA,CAAK,QAAQ,eAAA,CAAgB,GAAG,KAAK,EAAE,CAAA;AAAA,MAC3E;AAAA,IACF;AAEA,IAAA,OAAA,CAAQ,QAAQ,YAAA,CAAa,QAAA,EAAU,OAAA,CAAQ,IAAA,CAAK,QAAQ,EAAE,CAAA;AAE9D,IAAA,IAAA,CAAK,kBAAA,CAAmB,OAAA,EAAS,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAA;AAElD,IAAA,OAAA,CAAQ,OAAA,CAAQ,MAAM,QAAA,GAAW,UAAA;AACjC,IAAA,OAAA,CAAQ,OAAA,CAAQ,MAAM,IAAA,GAAO,GAAA;AAC7B,IAAA,OAAA,CAAQ,OAAA,CAAQ,MAAM,GAAA,GAAM,GAAA;AAE5B,IAAA,IAAI,OAAA,CAAQ,KAAK,YAAA,EAAc;AAC7B,MAAA,KAAA,MAAW,MAAA,IAAU,OAAA,CAAQ,IAAA,CAAK,YAAA,EAAc;AAC9C,QAAA,MAAM,QAAA,GAAW,QAAA,CAAS,aAAA,CAAc,QAAQ,CAAA;AAChD,QAAA,QAAA,CAAS,MAAM,MAAA,CAAO,GAAA;AACtB,QAAA,QAAA,CAAS,OAAO,MAAA,CAAO,IAAA;AACvB,QAAA,OAAA,CAAQ,OAAA,CAAQ,OAAO,QAAQ,CAAA;AAAA,MACjC;AAAA,IACF,CAAA,MAAA,IAAW,OAAA,CAAQ,IAAA,CAAK,QAAA,EAAU;AAChC,MAAA,OAAA,CAAQ,OAAA,CAAQ,GAAA,GAAM,OAAA,CAAQ,IAAA,CAAK,QAAA;AAAA,IACrC;AAAA,EACF;AAAA,EAEQ,kBAAA,CAAmB,SAAkB,GAAA,EAAoB;AAC/D,IAAA,IAAI,CAAC,OAAA,CAAQ,eAAA,IAAmB,GAAA,EAAK;AACnC,MAAA,OAAA,CAAQ,eAAA,GAAkB,IAAI,KAAA,EAAM;AACpC,MAAA,OAAA,CAAQ,gBAAgB,GAAA,GAAM,GAAA;AAC9B,MAAA,IAAI,OAAA,CAAQ,gBAAgB,QAAA,EAAU;AACpC,QAAA,OAAA,CAAQ,QAAA,IAAW;AAAA,MACrB,CAAA,MAAO;AACL,QAAA,OAAA,CAAQ,eAAA,CAAgB,gBAAA,CAAiB,MAAA,EAAQ,MAAM;AACrD,UAAA,OAAA,CAAQ,QAAA,IAAW;AAAA,QACrB,CAAC,CAAA;AACD,QAAA,OAAA,CAAQ,eAAA,CAAgB,gBAAA,CAAiB,OAAA,EAAS,MAAM;AACtD,UAAA,OAAA,CAAQ,QAAA,IAAW;AAAA,QACrB,CAAC,CAAA;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,UAAU,OAAA,EAAwB;AACxC,IAAA,IAAI,QAAQ,OAAA,EAAS;AACnB,MAAC,OAAA,CAAQ,QAA6B,IAAA,EAAK;AAAA,IAC7C;AAAA,EACF;AAAA,EAEQ,WAAW,OAAA,EAAwB;AACzC,IAAA,IAAI,QAAQ,OAAA,EAAS;AACnB,MAAC,OAAA,CAAQ,QAA6B,KAAA,EAAM;AAAA,IAC9C;AAAA,EACF;AAAA,EAEQ,qBAAA,CAAsB,gBAAyB,OAAA,EAA2B;AAChF,IAAA,IAAI,cAAA,CAAe,OAAO,CAAA,EAAG;AAC3B,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,OAAO,cAAA;AAAA,EACT;AACF,CAAA;AAuBO,IAAM,wBAAN,MAA4B;AAAA,EACjC,WAAA,CAAY,QAAA,EAA8B,OAAA,GAA8B,EAAC,EAAG;AAC1E,IAAA,IAAI,kBAAkB,QAAA,EAAU;AAAA,MAC9B,GAAG,cAAA;AAAA,MACH,GAAG;AAAA,KACJ,CAAA;AAAA,EACH;AACF;;;ACxOA,eAAsB,qBAAA,CAAsB,OAAA,GAAkC,EAAC,EAAgC;AAC7G,EAAA,MAAM,gBAAA,GAAmB,MAAM,OAAO,YAAY,CAAA;AAClD,EAAA,MAAM,aAAa,gBAAA,CAAiB,OAAA;AACpC,EAAA,MAAM,cAAA,GAAiB,MAAM,OAAO,qBAAqB,CAAA;AACzD,EAAA,MAAM,2BAA2B,cAAA,CAAe,OAAA;AAEhD,EAAA,MAAM,QAAA,GAAW,IAAI,wBAAA,CAAyB;AAAA,IAC5C,OAAA,EAAS,QAAQ,eAAA,IAAmB,eAAA;AAAA,IACpC,QAAA,EAAU,QAAQ,gBAAA,IAAoB,GAAA;AAAA,IACtC,UAAA,EAAY,UAAA;AAAA,IACZ,qBAAA,EAAuB,QAAQ,qBAAA,IAAyB,GAAA;AAAA,IACxD,qBAAA,EAAuB,QAAQ,qBAAA,IAAyB,GAAA;AAAA,IACxD,WAAA,EAAa,QAAQ,WAAA,IAAe,IAAA;AAAA,IACpC,IAAA,EAAM,QAAQ,IAAA,IAAQ,KAAA;AAAA,IACtB,SAAA,EAAW,QAAQ,SAAA,IAAa;AAAA,GACjC,CAAA;AAED,EAAA,IAAI,qBAAA,CAAsB,QAAA,EAAU,OAAA,CAAQ,kBAAkB,CAAA;AAG9D,EAAA,IAAI,OAAA,CAAQ,oBAAoB,KAAA,EAAO;AACrC,IAAA,QAAA,CAAS,EAAA,CAAG,mBAAA,EAAqB,CAAC,EAAE,SAAQ,KAA8C;AACxF,MAAA,OAAA,CAAQ,OAAA,EAAS,SAAA,CAAU,MAAA,CAAO,wBAAwB,CAAA;AAAA,IAC5D,CAAC,CAAA;AACD,IAAA,QAAA,CAAS,EAAA,CAAG,iBAAA,EAAmB,CAAC,EAAE,SAAQ,KAA8C;AACtF,MAAA,OAAA,CAAQ,OAAA,EAAS,SAAA,CAAU,GAAA,CAAI,wBAAwB,CAAA;AAAA,IACzD,CAAC,CAAA;AAAA,EACH;AAGA,EAAA,IAAI,OAAA,CAAQ,mBAAmB,KAAA,EAAO;AACpC,IAAA,QAAA,CAAS,EAAA,CAAG,cAAc,MAAM;AAC9B,MAAC,QAAA,CAAS,IAAA,EAAiC,EAAA,EAAI,eAAA,CAAgB;AAAA,QAC7D,IAAA,EAAM,gBAAA;AAAA,QACN,QAAA,EAAU,KAAA;AAAA,QACV,SAAA,EAAW,eAAA;AAAA,QACX,QAAA,EAAU,SAAA;AAAA,QACV,MAAA,EAAQ,CAAC,EAAA,KAAoB;AAC3B,UAAC,QAAA,CAAS,IAAA,EAAiC,EAAA,CAAG,QAAA,EAAU,MAAM;AAC5D,YAAA,MAAM,gBAAA,GAAoB,QAAA,CAAS,IAAA,EAAiC,SAAA,EAAW,IAAA,CAAK,OAAA;AAGpF,YAAA,IAAI,gBAAA,EAAkB;AACpB,cAAA,MAAM,OAAA,GAAW,iBAAiC,OAAA,CAAQ,WAAA;AAC1D,cAAA,EAAA,CAAG,YAAY,OAAA,IAAW,gBAAA,CAAiB,aAAA,CAAc,KAAK,GAAG,GAAA,IAAO,EAAA;AAAA,YAC1E;AAAA,UACF,CAAC,CAAA;AAAA,QACH;AAAA,OACD,CAAA;AAAA,IACH,CAAC,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,QAAA;AACT;;;AC9FO,SAAS,gBAAA,CAAiB,OAAA,EAAwB,SAAA,GAAoB,OAAA,EAAe;AAC1F,EAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,UAAA,CAAW,SAAS,IAAI,CAAA;AAC5C,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,GAAA,CAAI,YAAA,CAAa,GAAA,CAAI,SAAA,EAAW,OAAO,CAAA;AAAA,EACzC,CAAA,MAAO;AACL,IAAA,GAAA,CAAI,YAAA,CAAa,OAAO,SAAS,CAAA;AAAA,EACnC;AACA,EAAA,UAAA,CAAW,QAAQ,YAAA,CAAa,IAAI,EAAA,EAAI,GAAA,CAAI,UAAU,CAAA;AACxD;AAKO,SAAS,iBAAA,CAAkB,YAAoB,OAAA,EAAwB;AAC5E,EAAA,MAAM,MAAA,GAAS,IAAI,eAAA,CAAgB,UAAA,CAAW,SAAS,MAAM,CAAA;AAC7D,EAAA,OAAO,MAAA,CAAO,IAAI,SAAS,CAAA;AAC7B;AAQO,SAAS,aAAA,CAAc,QAAA,EAA8B,OAAA,EAAiB,OAAA,GAA8B,EAAC,EAAY;AACtH,EAAA,MAAM,eAAA,GAAkB,QAAQ,eAAA,IAAmB,eAAA;AACnD,EAAA,MAAM,YAAA,GAAe,QAAQ,YAAA,IAAgB,GAAA;AAE7C,EAAA,MAAM,SAAA,GAAY,QAAA,CAAS,gBAAA,CAAiB,eAAe,CAAA;AAC3D,EAAA,MAAM,WAA0B,EAAC;AAEjC,EAAA,KAAA,MAAW,WAAW,SAAA,EAAW;AAC/B,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,gBAAA,CAA8B,YAAY,CAAA;AAChE,IAAA,QAAA,CAAS,IAAA,CAAK,GAAG,KAAK,CAAA;AAAA,EACxB;AAEA,EAAA,KAAA,MAAW,CAAC,CAAA,EAAG,IAAI,CAAA,IAAK,QAAA,CAAS,SAAQ,EAAG;AAC1C,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,OAAA,IAAW,EAAA;AACvC,IAAA,IAAI,WAAW,OAAA,EAAS;AACtB,MAAA,QAAA,CAAS,YAAY,CAAC,CAAA;AACtB,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AACA,EAAA,OAAO,KAAA;AACT;AAcO,SAAS,gBAAA,CAAiB,QAAA,EAA8B,OAAA,GAA8B,EAAC,EAAS;AACrG,EAAA,MAAM,SAAA,GAAY,QAAQ,aAAA,IAAiB,OAAA;AAG3C,EAAA,QAAA,CAAS,EAAA,CAAG,UAAU,MAAM;AAC1B,IAAA,IAAI,SAAS,IAAA,EAAM;AACjB,MAAA,MAAM,gBAAA,GAAmB,QAAA,CAAS,IAAA,CAAK,SAAA,EAAW,IAAA,CAAK,OAAA;AACvD,MAAA,MAAM,OAAA,GAAU,gBAAA,EAAkB,OAAA,EAAS,OAAA,IAAW,IAAA;AACtD,MAAA,gBAAA,CAAiB,SAAS,SAAS,CAAA;AAAA,IACrC;AAAA,EACF,CAAC,CAAA;AAGD,EAAA,QAAA,CAAS,EAAA,CAAG,SAAS,MAAM;AACzB,IAAA,gBAAA,CAAiB,MAAM,SAAS,CAAA;AAAA,EAClC,CAAC,CAAA;AACH;AAeO,SAAS,cAAA,CAAe,QAAA,EAA8B,OAAA,GAA8B,EAAC,EAAS;AACnG,EAAA,MAAM,SAAA,GAAY,QAAQ,aAAA,IAAiB,OAAA;AAC3C,EAAA,MAAM,SAAA,GAAY,QAAQ,SAAA,IAAa,GAAA;AACvC,EAAA,MAAM,cAAA,GAAiB,kBAAkB,SAAS,CAAA;AAElD,EAAA,IAAI,cAAA,EAAgB;AAClB,IAAA,MAAM,OAAO,MAAM;AACjB,MAAA,UAAA,CAAW,MAAM,aAAA,CAAc,QAAA,EAAU,cAAA,EAAgB,OAAO,GAAG,SAAS,CAAA;AAAA,IAC9E,CAAA;AAEA,IAAA,IAAI,QAAA,CAAS,eAAe,SAAA,EAAW;AACrC,MAAA,QAAA,CAAS,gBAAA,CAAiB,oBAAoB,IAAI,CAAA;AAAA,IACpD,CAAA,MAAO;AACL,MAAA,IAAA,EAAK;AAAA,IACP;AAAA,EACF;AACF;;;AC/GO,SAAS,aAAa,GAAA,EAA4B;AACvD,EAAA,GAAA,GAAM,GAAA,CAAI,OAAA,CAAQ,GAAA,EAAK,EAAE,CAAA;AACzB,EAAA,IAAI,GAAA,CAAI,MAAA,KAAW,CAAA,EAAG,GAAA,GAAM,CAAC,GAAG,GAAG,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,GAAI,CAAC,CAAA,CAAE,KAAK,EAAE,CAAA;AAC9D,EAAA,OAAO,GAAA,CAAI,WAAW,CAAA,IAAK,kBAAA,CAAmB,KAAK,GAAG,CAAA,GAAI,CAAA,CAAA,EAAI,GAAG,CAAA,CAAA,GAAK,IAAA;AACxE;AAUO,SAAS,WAAW,UAAA,EAA0C;AACnE,EAAA,IAAI,CAAC,YAAY,OAAO,IAAA;AACxB,EAAA,MAAM,UAAA,GAAa,UAAA,CAAW,WAAA,EAAY,CAAE,IAAA,EAAK;AACjD,EAAA,IAAI,UAAA,KAAe,eAAe,OAAO,aAAA;AAEzC,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,aAAA,CAAc,KAAK,CAAA;AAC3C,EAAA,MAAA,CAAO,MAAM,KAAA,GAAQ,UAAA;AACrB,EAAA,IAAI,MAAA,CAAO,KAAA,CAAM,KAAA,EAAO,OAAO,UAAA;AAE/B,EAAA,OAAO,aAAa,UAAU,CAAA;AAChC;AAUO,SAAS,SAAA,CAAU,OAAA,EAAsB,IAAA,EAAc,KAAA,EAA4B;AACxF,EAAA,IAAI,KAAA,EAAO;AACT,IAAA,OAAA,CAAQ,KAAA,CAAM,WAAA,CAAY,IAAA,EAAM,KAAK,CAAA;AAAA,EACvC,CAAA,MAAO;AACL,IAAA,OAAA,CAAQ,KAAA,CAAM,eAAe,IAAI,CAAA;AAAA,EACnC;AACF;AAUO,SAAS,kBAAA,CAAmB,OAAe,OAAA,EAAyB;AACzE,EAAA,IAAI,KAAA,CAAM,UAAA,CAAW,MAAM,CAAA,EAAG;AAC5B,IAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,eAAA,EAAiB,CAAA,EAAA,EAAK,OAAO,CAAA,CAAA,CAAG,CAAA;AAAA,EACvD;AACA,EAAA,IAAI,KAAA,CAAM,UAAA,CAAW,KAAK,CAAA,EAAG;AAC3B,IAAA,OAAO,KAAA,CAAM,QAAQ,KAAA,EAAO,MAAM,EAAE,OAAA,CAAQ,GAAA,EAAK,CAAA,EAAA,EAAK,OAAO,CAAA,CAAA,CAAG,CAAA;AAAA,EAClE;AACA,EAAA,OAAO,KAAA;AACT","file":"client.js","sourcesContent":["import { decode } from 'blurhash';\n\n/**\n * Decode a single blurhash and draw it to a canvas element.\n *\n * @param canvas - The canvas element with a data-blur-hash attribute\n * @param width - The width to decode at (default: 32)\n * @param height - The height to decode at (default: 32)\n */\nexport function decodeBlurhashToCanvas(canvas: HTMLCanvasElement, width: number = 32, height: number = 32): void {\n const blurHashValue = canvas.dataset.blurHash;\n if (!blurHashValue) return;\n\n const pixels = decode(blurHashValue, width, height);\n const ctx = canvas.getContext('2d');\n if (pixels && ctx) {\n const imageData = new ImageData(new Uint8ClampedArray(pixels), width, height);\n ctx.putImageData(imageData, 0, 0);\n }\n}\n\n/**\n * Decode and render all blurhash canvases on the page.\n * Finds all canvas elements with data-blur-hash attribute and draws the decoded image.\n *\n * @param selector - CSS selector for canvas elements (default: 'canvas[data-blur-hash]')\n * @param width - The width to decode at (default: 32)\n * @param height - The height to decode at (default: 32)\n */\nexport function decodeAllBlurhashes(\n selector: string = 'canvas[data-blur-hash]',\n width: number = 32,\n height: number = 32,\n): void {\n const canvases = document.querySelectorAll<HTMLCanvasElement>(selector);\n for (const canvas of canvases) {\n decodeBlurhashToCanvas(canvas, width, height);\n }\n}\n","/** Options for the hero image fallback behavior */\nexport interface HeroImageFallbackOptions {\n /** CSS selector for the picture element (default: '#hero-bg-picture') */\n pictureSelector?: string;\n /** CSS selector for the img element within picture (default: 'img.hero__bg-img') */\n imgSelector?: string;\n /** CSS selector for the blurhash canvas element (default: 'canvas[data-blur-hash]') */\n canvasSelector?: string;\n}\n\n/**\n * Initialize hero image fallback behavior.\n * Handles:\n * - Hiding blurhash canvas when image loads successfully\n * - Removing source elements and retrying with fallback src on error\n * - Keeping blurhash visible if final fallback also fails\n *\n * @param options - Configuration options for selectors\n *\n * @example\n * ```typescript\n * import { initHeroImageFallback } from '@simple-photo-gallery/common/client';\n *\n * // Use default selectors\n * initHeroImageFallback();\n *\n * // Or with custom selectors\n * initHeroImageFallback({\n * pictureSelector: '#my-hero-picture',\n * imgSelector: 'img.my-hero-img',\n * canvasSelector: 'canvas.my-blurhash',\n * });\n * ```\n */\nexport function initHeroImageFallback(options: HeroImageFallbackOptions = {}): void {\n const {\n pictureSelector = '#hero-bg-picture',\n imgSelector = 'img.hero__bg-img',\n canvasSelector = 'canvas[data-blur-hash]',\n } = options;\n\n const picture = document.querySelector<HTMLPictureElement>(pictureSelector);\n const img = picture?.querySelector<HTMLImageElement>(imgSelector);\n const canvas = document.querySelector<HTMLCanvasElement>(canvasSelector);\n\n if (!img) return;\n\n const fallbackSrc = img.getAttribute('src') || '';\n let didFallback = false;\n\n const hideBlurhash = () => {\n if (canvas) {\n canvas.style.display = 'none';\n }\n };\n\n const doFallback = () => {\n if (didFallback) return;\n didFallback = true;\n\n if (picture) {\n // Remove all <source> elements so the browser does not retry them\n for (const sourceEl of picture.querySelectorAll('source')) {\n sourceEl.remove();\n }\n }\n\n // Force reload using the <img> src as the final fallback\n const current = img.getAttribute('src') || '';\n img.setAttribute('src', '');\n img.setAttribute('src', fallbackSrc || current);\n\n // If fallback also fails, keep blurhash visible\n img.addEventListener(\n 'error',\n () => {\n // Final fallback failed, blurhash stays visible\n },\n { once: true },\n );\n\n // If fallback succeeds, hide blurhash\n img.addEventListener('load', hideBlurhash, { once: true });\n };\n\n // Check if image already loaded or failed before script runs\n if (img.complete) {\n if (img.naturalWidth === 0) {\n doFallback();\n } else {\n hideBlurhash();\n }\n } else {\n img.addEventListener('load', hideBlurhash, { once: true });\n }\n\n img.addEventListener('error', doFallback, { once: true });\n}\n","import type { Content, EventData, Slide, VideoPluginOptions } from './types';\nimport type PhotoSwipe from 'photoswipe';\nimport type PhotoSwipeLightbox from 'photoswipe/lightbox';\n\nconst defaultOptions: VideoPluginOptions = {\n videoAttributes: { controls: '', playsinline: '', preload: 'auto' },\n autoplay: true,\n preventDragOffset: 40,\n};\n\n/**\n * Check if slide has video content\n */\nfunction isVideoContent(content: Content | Slide): boolean {\n return content && 'data' in content && content.data && content.data.type === 'video';\n}\n\nclass VideoContentSetup {\n private options: VideoPluginOptions;\n\n constructor(lightbox: PhotoSwipeLightbox, options: VideoPluginOptions) {\n this.options = options;\n\n this.initLightboxEvents(lightbox);\n lightbox.on('init', () => {\n if (lightbox.pswp) {\n this.initPswpEvents(lightbox.pswp);\n }\n });\n }\n\n private initLightboxEvents(lightbox: PhotoSwipeLightbox): void {\n lightbox.on('contentLoad', (data: unknown) => this.onContentLoad(data as EventData));\n lightbox.on('contentDestroy', (data: unknown) => this.onContentDestroy(data as { content: Content }));\n lightbox.on('contentActivate', (data: unknown) => this.onContentActivate(data as { content: Content }));\n lightbox.on('contentDeactivate', (data: unknown) => this.onContentDeactivate(data as { content: Content }));\n lightbox.on('contentAppend', (data: unknown) => this.onContentAppend(data as EventData));\n lightbox.on('contentResize', (data: unknown) => this.onContentResize(data as EventData));\n\n lightbox.addFilter('isKeepingPlaceholder', (value: unknown, ...args: unknown[]) =>\n this.isKeepingPlaceholder(value as boolean, args[0] as Content),\n );\n lightbox.addFilter('isContentZoomable', (value: unknown, ...args: unknown[]) =>\n this.isContentZoomable(value as boolean, args[0] as Content),\n );\n lightbox.addFilter('useContentPlaceholder', (value: unknown, ...args: unknown[]) =>\n this.useContentPlaceholder(value as boolean, args[0] as Content),\n );\n\n lightbox.addFilter('domItemData', (value: unknown, ...args: unknown[]) => {\n const itemData = value as Record<string, unknown>;\n const linkEl = args[1] as HTMLAnchorElement;\n\n if (itemData.type === 'video' && linkEl) {\n if (linkEl.dataset.pswpVideoSources) {\n itemData.videoSources = JSON.parse(linkEl.dataset.pswpVideoSources);\n } else if (linkEl.dataset.pswpVideoSrc) {\n itemData.videoSrc = linkEl.dataset.pswpVideoSrc;\n } else {\n itemData.videoSrc = linkEl.href;\n }\n }\n return itemData;\n });\n }\n\n private initPswpEvents(pswp: PhotoSwipe): void {\n // Prevent dragging when pointer is in bottom part of the video\n pswp.on('pointerDown', (data: unknown) => {\n const e = data as EventData;\n const slide = pswp.currSlide as Slide | undefined;\n if (slide && isVideoContent(slide) && this.options.preventDragOffset) {\n const origEvent = e.originalEvent;\n if (origEvent && origEvent.type === 'pointerdown') {\n const videoHeight = Math.ceil(slide.height * slide.currZoomLevel);\n const verticalEnding = videoHeight + slide.bounds.center.y;\n const pointerYPos = origEvent.pageY - pswp.offset.y;\n if (pointerYPos > verticalEnding - this.options.preventDragOffset! && pointerYPos < verticalEnding) {\n e.preventDefault?.();\n }\n }\n }\n });\n\n // do not append video on nearby slides\n pswp.on('appendHeavy', (data: unknown) => {\n const e = data as EventData;\n if (e.slide && isVideoContent(e.slide) && !e.slide.isActive) {\n e.preventDefault?.();\n }\n });\n\n pswp.on('close', () => {\n const slide = pswp.currSlide as Slide | undefined;\n if (slide && isVideoContent(slide.content)) {\n // Switch from zoom to fade closing transition,\n // as zoom transition is choppy for videos\n if (!pswp.options.showHideAnimationType || pswp.options.showHideAnimationType === 'zoom') {\n pswp.options.showHideAnimationType = 'fade';\n }\n\n // pause video when closing\n this.pauseVideo(slide.content);\n }\n });\n }\n\n private onContentDestroy({ content }: { content: Content }): void {\n if (isVideoContent(content) && content._videoPosterImg) {\n const handleLoad = () => {\n if (content._videoPosterImg) {\n content._videoPosterImg.removeEventListener('error', handleError);\n }\n };\n const handleError = () => {\n // Error handler\n };\n\n content._videoPosterImg.addEventListener('load', handleLoad);\n content._videoPosterImg.addEventListener('error', handleError);\n content._videoPosterImg = undefined;\n }\n }\n\n private onContentResize(e: EventData): void {\n if (e.content && isVideoContent(e.content)) {\n e.preventDefault?.();\n\n const width = e.width!;\n const height = e.height!;\n const content = e.content;\n\n if (content.element) {\n content.element.style.width = width + 'px';\n content.element.style.height = height + 'px';\n }\n\n if (content.slide && content.slide.placeholder) {\n // override placeholder size, so it more accurately matches the video\n const placeholderElStyle = content.slide.placeholder.element.style;\n placeholderElStyle.transform = 'none';\n placeholderElStyle.width = width + 'px';\n placeholderElStyle.height = height + 'px';\n }\n }\n }\n\n private isKeepingPlaceholder(isZoomable: boolean, content: Content): boolean {\n if (isVideoContent(content)) {\n return false;\n }\n return isZoomable;\n }\n\n private isContentZoomable(isZoomable: boolean, content: Content): boolean {\n if (isVideoContent(content)) {\n return false;\n }\n return isZoomable;\n }\n\n private onContentActivate({ content }: { content: Content }): void {\n if (isVideoContent(content) && this.options.autoplay) {\n this.playVideo(content);\n }\n }\n\n private onContentDeactivate({ content }: { content: Content }): void {\n if (isVideoContent(content)) {\n this.pauseVideo(content);\n }\n }\n\n private onContentAppend(e: EventData): void {\n if (e.content && isVideoContent(e.content)) {\n e.preventDefault?.();\n e.content.isAttached = true;\n e.content.appendImage?.();\n }\n }\n\n private onContentLoad(e: EventData): void {\n const content = e.content!;\n\n if (!isVideoContent(content)) {\n return;\n }\n\n // stop default content load\n e.preventDefault?.();\n\n if (content.element) {\n return;\n }\n\n content.state = 'loading';\n content.type = 'video';\n\n content.element = document.createElement('video');\n\n if (this.options.videoAttributes) {\n for (const key in this.options.videoAttributes) {\n content.element.setAttribute(key, this.options.videoAttributes[key] || '');\n }\n }\n\n content.element.setAttribute('poster', content.data.msrc || '');\n\n this.preloadVideoPoster(content, content.data.msrc);\n\n content.element.style.position = 'absolute';\n content.element.style.left = '0';\n content.element.style.top = '0';\n\n if (content.data.videoSources) {\n for (const source of content.data.videoSources) {\n const sourceEl = document.createElement('source');\n sourceEl.src = source.src;\n sourceEl.type = source.type;\n content.element.append(sourceEl);\n }\n } else if (content.data.videoSrc) {\n content.element.src = content.data.videoSrc;\n }\n }\n\n private preloadVideoPoster(content: Content, src?: string): void {\n if (!content._videoPosterImg && src) {\n content._videoPosterImg = new Image();\n content._videoPosterImg.src = src;\n if (content._videoPosterImg.complete) {\n content.onLoaded?.();\n } else {\n content._videoPosterImg.addEventListener('load', () => {\n content.onLoaded?.();\n });\n content._videoPosterImg.addEventListener('error', () => {\n content.onLoaded?.();\n });\n }\n }\n }\n\n private playVideo(content: Content): void {\n if (content.element) {\n (content.element as HTMLVideoElement).play();\n }\n }\n\n private pauseVideo(content: Content): void {\n if (content.element) {\n (content.element as HTMLVideoElement).pause();\n }\n }\n\n private useContentPlaceholder(usePlaceholder: boolean, content: Content): boolean {\n if (isVideoContent(content)) {\n return true;\n }\n return usePlaceholder;\n }\n}\n\n/**\n * PhotoSwipe plugin that adds video support to the lightbox.\n * Videos are automatically detected by the `data-pswp-type=\"video\"` attribute\n * on gallery links.\n *\n * @example\n * ```typescript\n * import PhotoSwipe from 'photoswipe';\n * import PhotoSwipeLightbox from 'photoswipe/lightbox';\n * import { PhotoSwipeVideoPlugin } from '@simple-photo-gallery/common/client';\n *\n * const lightbox = new PhotoSwipeLightbox({\n * gallery: '.gallery',\n * children: 'a',\n * pswpModule: PhotoSwipe,\n * });\n *\n * new PhotoSwipeVideoPlugin(lightbox);\n * lightbox.init();\n * ```\n */\nexport class PhotoSwipeVideoPlugin {\n constructor(lightbox: PhotoSwipeLightbox, options: VideoPluginOptions = {}) {\n new VideoContentSetup(lightbox, {\n ...defaultOptions,\n ...options,\n });\n }\n}\n","import { PhotoSwipeVideoPlugin } from './video-plugin';\n\nimport type { VideoPluginOptions } from './types';\nimport type PhotoSwipe from 'photoswipe';\nimport type PhotoSwipeLightbox from 'photoswipe/lightbox';\n\n/** Options for creating a gallery lightbox */\nexport interface GalleryLightboxOptions {\n /** CSS selector for gallery container (default: '.gallery-grid') */\n gallerySelector?: string;\n /** CSS selector for gallery items within container (default: 'a') */\n childrenSelector?: string;\n /** Animation duration when opening in ms (default: 300) */\n showAnimationDuration?: number;\n /** Animation duration when closing in ms (default: 300) */\n hideAnimationDuration?: number;\n /** Enable mouse wheel zoom (default: true) */\n wheelToZoom?: boolean;\n /** Loop back to first image after last (default: false) */\n loop?: boolean;\n /** Background opacity 0-1 (default: 1) */\n bgOpacity?: number;\n /** Options for the video plugin */\n videoPluginOptions?: VideoPluginOptions;\n /** Enable slide-in animations when changing slides (default: true) */\n slideAnimations?: boolean;\n /** Enable custom caption UI from data-pswp-caption attribute (default: true) */\n enableCaptions?: boolean;\n}\n\n/**\n * Create a PhotoSwipe lightbox with sensible defaults and video support.\n * Returns the lightbox instance for further customization before calling init().\n *\n * IMPORTANT: You must import the PhotoSwipe CSS files for the lightbox to work properly:\n * - `import 'photoswipe/style.css'` - Base PhotoSwipe styles\n * - `import '@simple-photo-gallery/common/styles/photoswipe'` - SPG enhancement styles\n *\n * @example\n * ```typescript\n * import { createGalleryLightbox } from '@simple-photo-gallery/common/client';\n * import 'photoswipe/style.css';\n * import '@simple-photo-gallery/common/styles/photoswipe';\n *\n * // Basic usage\n * const lightbox = await createGalleryLightbox();\n * lightbox.init();\n *\n * // With custom options\n * const lightbox = await createGalleryLightbox({\n * gallerySelector: '.my-gallery',\n * loop: true,\n * });\n *\n * // Add custom event handlers before init\n * lightbox.on('change', () => console.log('slide changed'));\n * lightbox.init();\n * ```\n */\nexport async function createGalleryLightbox(options: GalleryLightboxOptions = {}): Promise<PhotoSwipeLightbox> {\n const photoswipeModule = await import('photoswipe');\n const PhotoSwipe = photoswipeModule.default;\n const lightboxModule = await import('photoswipe/lightbox');\n const PhotoSwipeLightboxModule = lightboxModule.default;\n\n const lightbox = new PhotoSwipeLightboxModule({\n gallery: options.gallerySelector ?? '.gallery-grid',\n children: options.childrenSelector ?? 'a',\n pswpModule: PhotoSwipe,\n showAnimationDuration: options.showAnimationDuration ?? 300,\n hideAnimationDuration: options.hideAnimationDuration ?? 300,\n wheelToZoom: options.wheelToZoom ?? true,\n loop: options.loop ?? false,\n bgOpacity: options.bgOpacity ?? 1,\n });\n\n new PhotoSwipeVideoPlugin(lightbox, options.videoPluginOptions);\n\n // Slide animations (enabled by default)\n if (options.slideAnimations !== false) {\n lightbox.on('contentDeactivate', ({ content }: { content: { element?: HTMLElement } }) => {\n content.element?.classList.remove('pswp__img--in-viewport');\n });\n lightbox.on('contentActivate', ({ content }: { content: { element?: HTMLElement } }) => {\n content.element?.classList.add('pswp__img--in-viewport');\n });\n }\n\n // Custom caption UI (enabled by default)\n if (options.enableCaptions !== false) {\n lightbox.on('uiRegister', () => {\n (lightbox.pswp as PhotoSwipe | undefined)?.ui?.registerElement({\n name: 'custom-caption',\n isButton: false,\n className: 'pswp__caption',\n appendTo: 'wrapper',\n onInit: (el: HTMLElement) => {\n (lightbox.pswp as PhotoSwipe | undefined)?.on('change', () => {\n const currSlideElement = (lightbox.pswp as PhotoSwipe | undefined)?.currSlide?.data.element as\n | HTMLElement\n | undefined;\n if (currSlideElement) {\n const caption = (currSlideElement as HTMLElement).dataset.pswpCaption;\n el.innerHTML = caption || currSlideElement.querySelector('img')?.alt || '';\n }\n });\n },\n });\n });\n }\n\n return lightbox;\n}\n","import type PhotoSwipeLightbox from 'photoswipe/lightbox';\n\n/** Options for URL deep-linking functionality */\nexport interface DeepLinkingOptions {\n /** CSS selector for galleries (default: '.gallery-grid') */\n gallerySelector?: string;\n /** CSS selector for gallery items (default: 'a') */\n itemSelector?: string;\n /** URL parameter name for image ID (default: 'image') */\n parameterName?: string;\n /** Delay in ms before opening image on page load (default: 100) */\n openDelay?: number;\n}\n\n/**\n * Updates browser URL with current image ID.\n * Uses History API to replace state without page reload.\n */\nexport function updateGalleryURL(imageId: string | null, paramName: string = 'image'): void {\n const url = new URL(globalThis.location.href);\n if (imageId) {\n url.searchParams.set(paramName, imageId);\n } else {\n url.searchParams.delete(paramName);\n }\n globalThis.history.replaceState({}, '', url.toString());\n}\n\n/**\n * Extracts image ID from URL parameters.\n */\nexport function getImageIdFromURL(paramName: string = 'image'): string | null {\n const params = new URLSearchParams(globalThis.location.search);\n return params.get(paramName);\n}\n\n/**\n * Opens a specific image by ID within a gallery.\n * Searches through all gallery items and opens matching image in lightbox.\n *\n * @returns true if image was found and opened, false otherwise\n */\nexport function openImageById(lightbox: PhotoSwipeLightbox, imageId: string, options: DeepLinkingOptions = {}): boolean {\n const gallerySelector = options.gallerySelector ?? '.gallery-grid';\n const itemSelector = options.itemSelector ?? 'a';\n\n const galleries = document.querySelectorAll(gallerySelector);\n const allItems: HTMLElement[] = [];\n\n for (const gallery of galleries) {\n const items = gallery.querySelectorAll<HTMLElement>(itemSelector);\n allItems.push(...items);\n }\n\n for (const [i, item] of allItems.entries()) {\n const itemId = item.dataset.imageId || '';\n if (itemId === imageId) {\n lightbox.loadAndOpen(i);\n return true;\n }\n }\n return false;\n}\n\n/**\n * Sets up automatic URL updates when lightbox changes.\n * Call after creating lightbox but before init().\n *\n * @example\n * ```typescript\n * const lightbox = await createGalleryLightbox();\n * setupDeepLinking(lightbox);\n * lightbox.init();\n * restoreFromURL(lightbox);\n * ```\n */\nexport function setupDeepLinking(lightbox: PhotoSwipeLightbox, options: DeepLinkingOptions = {}): void {\n const paramName = options.parameterName ?? 'image';\n\n // Update URL when slide changes\n lightbox.on('change', () => {\n if (lightbox.pswp) {\n const currSlideElement = lightbox.pswp.currSlide?.data.element as HTMLElement | undefined;\n const imageId = currSlideElement?.dataset?.imageId ?? null;\n updateGalleryURL(imageId, paramName);\n }\n });\n\n // Clear URL parameter when lightbox closes\n lightbox.on('close', () => {\n updateGalleryURL(null, paramName);\n });\n}\n\n/**\n * Restores gallery state from URL on page load.\n * Automatically opens image if specified in URL parameters.\n * Call after lightbox.init().\n *\n * @example\n * ```typescript\n * const lightbox = await createGalleryLightbox();\n * setupDeepLinking(lightbox);\n * lightbox.init();\n * restoreFromURL(lightbox);\n * ```\n */\nexport function restoreFromURL(lightbox: PhotoSwipeLightbox, options: DeepLinkingOptions = {}): void {\n const paramName = options.parameterName ?? 'image';\n const openDelay = options.openDelay ?? 100;\n const imageIdFromURL = getImageIdFromURL(paramName);\n\n if (imageIdFromURL) {\n const open = () => {\n setTimeout(() => openImageById(lightbox, imageIdFromURL, options), openDelay);\n };\n\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', open);\n } else {\n open();\n }\n }\n}\n","/**\n * CSS utility functions for client-side theming and color manipulation.\n * These utilities are browser-only and require DOM access.\n */\n\n/**\n * Normalizes hex color values to 6-digit format (e.g., #abc -> #aabbcc).\n * Returns null if the hex value is invalid.\n *\n * @param hex - The hex color value to normalize (with or without #)\n * @returns The normalized 6-digit hex color with # prefix, or null if invalid\n */\nexport function normalizeHex(hex: string): string | null {\n hex = hex.replace('#', '');\n if (hex.length === 3) hex = [...hex].map((c) => c + c).join('');\n return hex.length === 6 && /^[0-9A-Fa-f]{6}$/.test(hex) ? `#${hex}` : null;\n}\n\n/**\n * Parses and validates a color value.\n * Supports CSS color names, hex values, rgb/rgba, and 'transparent'.\n * Returns null if the color is invalid.\n *\n * @param colorParam - The color string to parse\n * @returns The validated color string, or null if invalid\n */\nexport function parseColor(colorParam: string | null): string | null {\n if (!colorParam) return null;\n const normalized = colorParam.toLowerCase().trim();\n if (normalized === 'transparent') return 'transparent';\n\n const testEl = document.createElement('div');\n testEl.style.color = normalized;\n if (testEl.style.color) return normalized;\n\n return normalizeHex(colorParam);\n}\n\n/**\n * Sets or removes a CSS custom property (variable) on an element.\n * Removes the property if value is null.\n *\n * @param element - The HTML element to modify\n * @param name - The CSS variable name (e.g., '--my-color')\n * @param value - The value to set, or null to remove\n */\nexport function setCSSVar(element: HTMLElement, name: string, value: string | null): void {\n if (value) {\n element.style.setProperty(name, value);\n } else {\n element.style.removeProperty(name);\n }\n}\n\n/**\n * Derives a color with adjusted opacity from an existing color.\n * Converts rgb to rgba if needed, or adjusts existing rgba opacity.\n *\n * @param color - The source color (rgb, rgba, or other CSS color)\n * @param opacity - The target opacity (0-1)\n * @returns The color with adjusted opacity, or original if not rgb/rgba\n */\nexport function deriveOpacityColor(color: string, opacity: number): string {\n if (color.startsWith('rgba')) {\n return color.replace(/,\\s*[\\d.]+\\)$/, `, ${opacity})`);\n }\n if (color.startsWith('rgb')) {\n return color.replace('rgb', 'rgba').replace(')', `, ${opacity})`);\n }\n return color;\n}\n"]}
1
+ {"version":3,"sources":["../src/client/blurhash.ts","../src/client/hero-fallback.ts","../src/client/photoswipe/video-plugin.ts","../src/client/photoswipe/lightbox.ts","../src/client/photoswipe/deep-linking.ts","../src/client/css-utils.ts"],"names":[],"mappings":"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","file":"client.js","sourcesContent":["import { decode } from 'blurhash';\n\n/**\n * Decode a single blurhash and draw it to a canvas element.\n *\n * @param canvas - The canvas element with a data-blur-hash attribute\n * @param width - The width to decode at (default: 32)\n * @param height - The height to decode at (default: 32)\n */\nexport function decodeBlurhashToCanvas(canvas: HTMLCanvasElement, width: number = 32, height: number = 32): void {\n const blurHashValue = canvas.dataset.blurHash;\n if (!blurHashValue) return;\n\n const pixels = decode(blurHashValue, width, height);\n const ctx = canvas.getContext('2d');\n if (pixels && ctx) {\n const imageData = new ImageData(new Uint8ClampedArray(pixels), width, height);\n ctx.putImageData(imageData, 0, 0);\n }\n}\n\n/**\n * Decode and render all blurhash canvases on the page.\n * Finds all canvas elements with data-blur-hash attribute and draws the decoded image.\n *\n * @param selector - CSS selector for canvas elements (default: 'canvas[data-blur-hash]')\n * @param width - The width to decode at (default: 32)\n * @param height - The height to decode at (default: 32)\n */\nexport function decodeAllBlurhashes(\n selector: string = 'canvas[data-blur-hash]',\n width: number = 32,\n height: number = 32,\n): void {\n const canvases = document.querySelectorAll<HTMLCanvasElement>(selector);\n for (const canvas of canvases) {\n decodeBlurhashToCanvas(canvas, width, height);\n }\n}\n","/** Options for the hero image fallback behavior */\nexport interface HeroImageFallbackOptions {\n /** CSS selector for the picture element (default: '#hero-bg-picture') */\n pictureSelector?: string;\n /** CSS selector for the img element within picture (default: 'img.hero__bg-img') */\n imgSelector?: string;\n /** CSS selector for the blurhash canvas element (default: 'canvas[data-blur-hash]') */\n canvasSelector?: string;\n}\n\n/**\n * Initialize hero image fallback behavior.\n * Handles:\n * - Hiding blurhash canvas when image loads successfully\n * - Removing source elements and retrying with fallback src on error\n * - Keeping blurhash visible if final fallback also fails\n *\n * @param options - Configuration options for selectors\n *\n * @example\n * ```typescript\n * import { initHeroImageFallback } from '@simple-photo-gallery/common/client';\n *\n * // Use default selectors\n * initHeroImageFallback();\n *\n * // Or with custom selectors\n * initHeroImageFallback({\n * pictureSelector: '#my-hero-picture',\n * imgSelector: 'img.my-hero-img',\n * canvasSelector: 'canvas.my-blurhash',\n * });\n * ```\n */\nexport function initHeroImageFallback(options: HeroImageFallbackOptions = {}): void {\n const {\n pictureSelector = '#hero-bg-picture',\n imgSelector = 'img.hero__bg-img',\n canvasSelector = 'canvas[data-blur-hash]',\n } = options;\n\n const picture = document.querySelector<HTMLPictureElement>(pictureSelector);\n const img = picture?.querySelector<HTMLImageElement>(imgSelector);\n const canvas = document.querySelector<HTMLCanvasElement>(canvasSelector);\n\n if (!img) return;\n\n const fallbackSrc = img.getAttribute('src') || '';\n let didFallback = false;\n\n const hideBlurhash = () => {\n if (canvas) {\n canvas.style.display = 'none';\n }\n };\n\n const doFallback = () => {\n if (didFallback) return;\n didFallback = true;\n\n if (picture) {\n // Remove all <source> elements so the browser does not retry them\n for (const sourceEl of picture.querySelectorAll('source')) {\n sourceEl.remove();\n }\n }\n\n // Force reload using the <img> src as the final fallback\n const current = img.getAttribute('src') || '';\n img.setAttribute('src', '');\n img.setAttribute('src', fallbackSrc || current);\n\n // If fallback also fails, keep blurhash visible\n img.addEventListener(\n 'error',\n () => {\n // Final fallback failed, blurhash stays visible\n },\n { once: true },\n );\n\n // If fallback succeeds, hide blurhash\n img.addEventListener('load', hideBlurhash, { once: true });\n };\n\n // Check if image already loaded or failed before script runs\n if (img.complete) {\n if (img.naturalWidth === 0) {\n doFallback();\n } else {\n hideBlurhash();\n }\n } else {\n img.addEventListener('load', hideBlurhash, { once: true });\n }\n\n img.addEventListener('error', doFallback, { once: true });\n}\n","import type { Content, EventData, Slide, VideoPluginOptions } from './types';\nimport type PhotoSwipe from 'photoswipe';\nimport type PhotoSwipeLightbox from 'photoswipe/lightbox';\n\nconst defaultOptions: VideoPluginOptions = {\n videoAttributes: { controls: '', playsinline: '', preload: 'auto' },\n autoplay: true,\n preventDragOffset: 40,\n};\n\n/**\n * Check if slide has video content\n */\nfunction isVideoContent(content: Content | Slide): boolean {\n return content && 'data' in content && content.data && content.data.type === 'video';\n}\n\nclass VideoContentSetup {\n private options: VideoPluginOptions;\n\n constructor(lightbox: PhotoSwipeLightbox, options: VideoPluginOptions) {\n this.options = options;\n\n this.initLightboxEvents(lightbox);\n lightbox.on('init', () => {\n if (lightbox.pswp) {\n this.initPswpEvents(lightbox.pswp);\n }\n });\n }\n\n private initLightboxEvents(lightbox: PhotoSwipeLightbox): void {\n lightbox.on('contentLoad', (data: unknown) => this.onContentLoad(data as EventData));\n lightbox.on('contentDestroy', (data: unknown) => this.onContentDestroy(data as { content: Content }));\n lightbox.on('contentActivate', (data: unknown) => this.onContentActivate(data as { content: Content }));\n lightbox.on('contentDeactivate', (data: unknown) => this.onContentDeactivate(data as { content: Content }));\n lightbox.on('contentAppend', (data: unknown) => this.onContentAppend(data as EventData));\n lightbox.on('contentResize', (data: unknown) => this.onContentResize(data as EventData));\n\n lightbox.addFilter('isKeepingPlaceholder', (value: unknown, ...args: unknown[]) =>\n this.isKeepingPlaceholder(value as boolean, args[0] as Content),\n );\n lightbox.addFilter('isContentZoomable', (value: unknown, ...args: unknown[]) =>\n this.isContentZoomable(value as boolean, args[0] as Content),\n );\n lightbox.addFilter('useContentPlaceholder', (value: unknown, ...args: unknown[]) =>\n this.useContentPlaceholder(value as boolean, args[0] as Content),\n );\n\n lightbox.addFilter('domItemData', (value: unknown, ...args: unknown[]) => {\n const itemData = value as Record<string, unknown>;\n const linkEl = args[1] as HTMLAnchorElement;\n\n if (itemData.type === 'video' && linkEl) {\n if (linkEl.dataset.pswpVideoSources) {\n itemData.videoSources = JSON.parse(linkEl.dataset.pswpVideoSources);\n } else if (linkEl.dataset.pswpVideoSrc) {\n itemData.videoSrc = linkEl.dataset.pswpVideoSrc;\n } else {\n itemData.videoSrc = linkEl.href;\n }\n }\n return itemData;\n });\n }\n\n private initPswpEvents(pswp: PhotoSwipe): void {\n // Prevent dragging when pointer is in bottom part of the video\n pswp.on('pointerDown', (data: unknown) => {\n const e = data as EventData;\n const slide = pswp.currSlide as Slide | undefined;\n if (slide && isVideoContent(slide) && this.options.preventDragOffset) {\n const origEvent = e.originalEvent;\n if (origEvent && origEvent.type === 'pointerdown') {\n const videoHeight = Math.ceil(slide.height * slide.currZoomLevel);\n const verticalEnding = videoHeight + slide.bounds.center.y;\n const pointerYPos = origEvent.pageY - pswp.offset.y;\n if (pointerYPos > verticalEnding - this.options.preventDragOffset! && pointerYPos < verticalEnding) {\n e.preventDefault?.();\n }\n }\n }\n });\n\n // do not append video on nearby slides\n pswp.on('appendHeavy', (data: unknown) => {\n const e = data as EventData;\n if (e.slide && isVideoContent(e.slide) && !e.slide.isActive) {\n e.preventDefault?.();\n }\n });\n\n pswp.on('close', () => {\n const slide = pswp.currSlide as Slide | undefined;\n if (slide && isVideoContent(slide.content)) {\n // Switch from zoom to fade closing transition,\n // as zoom transition is choppy for videos\n if (!pswp.options.showHideAnimationType || pswp.options.showHideAnimationType === 'zoom') {\n pswp.options.showHideAnimationType = 'fade';\n }\n\n // pause video when closing\n this.pauseVideo(slide.content);\n }\n });\n }\n\n private onContentDestroy({ content }: { content: Content }): void {\n if (isVideoContent(content) && content._videoPosterImg) {\n const handleLoad = () => {\n if (content._videoPosterImg) {\n content._videoPosterImg.removeEventListener('error', handleError);\n }\n };\n const handleError = () => {\n // Error handler\n };\n\n content._videoPosterImg.addEventListener('load', handleLoad);\n content._videoPosterImg.addEventListener('error', handleError);\n content._videoPosterImg = undefined;\n }\n }\n\n private onContentResize(e: EventData): void {\n if (e.content && isVideoContent(e.content)) {\n e.preventDefault?.();\n\n const width = e.width!;\n const height = e.height!;\n const content = e.content;\n\n if (content.element) {\n content.element.style.width = width + 'px';\n content.element.style.height = height + 'px';\n }\n\n if (content.slide && content.slide.placeholder) {\n // override placeholder size, so it more accurately matches the video\n const placeholderElStyle = content.slide.placeholder.element.style;\n placeholderElStyle.transform = 'none';\n placeholderElStyle.width = width + 'px';\n placeholderElStyle.height = height + 'px';\n }\n }\n }\n\n private isKeepingPlaceholder(isZoomable: boolean, content: Content): boolean {\n if (isVideoContent(content)) {\n return false;\n }\n return isZoomable;\n }\n\n private isContentZoomable(isZoomable: boolean, content: Content): boolean {\n if (isVideoContent(content)) {\n return false;\n }\n return isZoomable;\n }\n\n private onContentActivate({ content }: { content: Content }): void {\n if (isVideoContent(content) && this.options.autoplay) {\n this.playVideo(content);\n }\n }\n\n private onContentDeactivate({ content }: { content: Content }): void {\n if (isVideoContent(content)) {\n this.pauseVideo(content);\n }\n }\n\n private onContentAppend(e: EventData): void {\n if (e.content && isVideoContent(e.content)) {\n e.preventDefault?.();\n e.content.isAttached = true;\n e.content.appendImage?.();\n }\n }\n\n private onContentLoad(e: EventData): void {\n const content = e.content!;\n\n if (!isVideoContent(content)) {\n return;\n }\n\n // stop default content load\n e.preventDefault?.();\n\n if (content.element) {\n return;\n }\n\n content.state = 'loading';\n content.type = 'video';\n\n content.element = document.createElement('video');\n\n if (this.options.videoAttributes) {\n for (const key in this.options.videoAttributes) {\n content.element.setAttribute(key, this.options.videoAttributes[key] || '');\n }\n }\n\n content.element.setAttribute('poster', content.data.msrc || '');\n\n this.preloadVideoPoster(content, content.data.msrc);\n\n content.element.style.position = 'absolute';\n content.element.style.left = '0';\n content.element.style.top = '0';\n\n if (content.data.videoSources) {\n for (const source of content.data.videoSources) {\n const sourceEl = document.createElement('source');\n sourceEl.src = source.src;\n sourceEl.type = source.type;\n content.element.append(sourceEl);\n }\n } else if (content.data.videoSrc) {\n content.element.src = content.data.videoSrc;\n }\n }\n\n private preloadVideoPoster(content: Content, src?: string): void {\n if (!content._videoPosterImg && src) {\n content._videoPosterImg = new Image();\n content._videoPosterImg.src = src;\n if (content._videoPosterImg.complete) {\n content.onLoaded?.();\n } else {\n content._videoPosterImg.addEventListener('load', () => {\n content.onLoaded?.();\n });\n content._videoPosterImg.addEventListener('error', () => {\n content.onLoaded?.();\n });\n }\n }\n }\n\n private playVideo(content: Content): void {\n if (content.element) {\n (content.element as HTMLVideoElement).play();\n }\n }\n\n private pauseVideo(content: Content): void {\n if (content.element) {\n (content.element as HTMLVideoElement).pause();\n }\n }\n\n private useContentPlaceholder(usePlaceholder: boolean, content: Content): boolean {\n if (isVideoContent(content)) {\n return true;\n }\n return usePlaceholder;\n }\n}\n\n/**\n * PhotoSwipe plugin that adds video support to the lightbox.\n * Videos are automatically detected by the `data-pswp-type=\"video\"` attribute\n * on gallery links.\n *\n * @example\n * ```typescript\n * import PhotoSwipe from 'photoswipe';\n * import PhotoSwipeLightbox from 'photoswipe/lightbox';\n * import { PhotoSwipeVideoPlugin } from '@simple-photo-gallery/common/client';\n *\n * const lightbox = new PhotoSwipeLightbox({\n * gallery: '.gallery',\n * children: 'a',\n * pswpModule: PhotoSwipe,\n * });\n *\n * new PhotoSwipeVideoPlugin(lightbox);\n * lightbox.init();\n * ```\n */\nexport class PhotoSwipeVideoPlugin {\n constructor(lightbox: PhotoSwipeLightbox, options: VideoPluginOptions = {}) {\n new VideoContentSetup(lightbox, {\n ...defaultOptions,\n ...options,\n });\n }\n}\n","import { PhotoSwipeVideoPlugin } from './video-plugin';\n\nimport type { VideoPluginOptions } from './types';\nimport type PhotoSwipe from 'photoswipe';\nimport type PhotoSwipeLightbox from 'photoswipe/lightbox';\n\n/** Options for creating a gallery lightbox */\nexport interface GalleryLightboxOptions {\n /** CSS selector for gallery container (default: '.gallery-grid') */\n gallerySelector?: string;\n /** CSS selector for gallery items within container (default: 'a') */\n childrenSelector?: string;\n /** Animation duration when opening in ms (default: 300) */\n showAnimationDuration?: number;\n /** Animation duration when closing in ms (default: 300) */\n hideAnimationDuration?: number;\n /** Enable mouse wheel zoom (default: true) */\n wheelToZoom?: boolean;\n /** Loop back to first image after last (default: false) */\n loop?: boolean;\n /** Background opacity 0-1 (default: 1) */\n bgOpacity?: number;\n /** Options for the video plugin */\n videoPluginOptions?: VideoPluginOptions;\n /** Enable slide-in animations when changing slides (default: true) */\n slideAnimations?: boolean;\n /** Enable custom caption UI from data-pswp-caption attribute (default: true) */\n enableCaptions?: boolean;\n}\n\nconst CAPTION_SAMPLE_SIZE = 50;\nconst CAPTION_SAMPLE_HEIGHT_RATIO = 0.15;\n\n/* Caption background endpoints for brightness interpolation (0=dark image, 1=light image) */\nconst CAPTION_BG_DARK = { r: 255, g: 255, b: 255, a: 0.5 }; // white frost on dark images\nconst CAPTION_BG_LIGHT = { r: 0, g: 0, b: 0, a: 0.8 }; // dark frost on light images\n\nfunction interpolateCaptionBg(brightness: number): string {\n const t = Math.min(1, Math.max(0, brightness / 255));\n const r = Math.round(CAPTION_BG_DARK.r + (CAPTION_BG_LIGHT.r - CAPTION_BG_DARK.r) * t);\n const g = Math.round(CAPTION_BG_DARK.g + (CAPTION_BG_LIGHT.g - CAPTION_BG_DARK.g) * t);\n const b = Math.round(CAPTION_BG_DARK.b + (CAPTION_BG_LIGHT.b - CAPTION_BG_DARK.b) * t);\n const a = +(CAPTION_BG_DARK.a + (CAPTION_BG_LIGHT.a - CAPTION_BG_DARK.a) * t).toFixed(3);\n return `rgba(${r}, ${g}, ${b}, ${a})`;\n}\n\n/**\n * Creates a reusable function that samples the average brightness\n * of the bottom strip of an image using an offscreen canvas.\n */\nfunction createCaptionBrightnessSampler() {\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d', { willReadFrequently: true });\n if (!ctx) return null;\n\n canvas.width = CAPTION_SAMPLE_SIZE;\n canvas.height = CAPTION_SAMPLE_SIZE;\n\n return (img: HTMLImageElement): number | null => {\n if (!img.complete || img.naturalWidth === 0 || img.naturalHeight === 0) return null;\n\n const srcWidth = img.naturalWidth;\n const srcHeight = img.naturalHeight;\n const sampleHeight = Math.max(1, Math.round(srcHeight * CAPTION_SAMPLE_HEIGHT_RATIO));\n const srcY = Math.max(0, srcHeight - sampleHeight);\n\n try {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n ctx.drawImage(img, 0, srcY, srcWidth, sampleHeight, 0, 0, canvas.width, canvas.height);\n\n const { data } = ctx.getImageData(0, 0, canvas.width, canvas.height);\n let sum = 0;\n let count = 0;\n for (let i = 0; i < data.length; i += 4) {\n sum += 0.299 * data[i] + 0.587 * data[i + 1] + 0.114 * data[i + 2];\n count++;\n }\n\n return count ? sum / count : null;\n } catch {\n return null;\n }\n };\n}\n\n/**\n * Create a PhotoSwipe lightbox with sensible defaults and video support.\n * Returns the lightbox instance for further customization before calling init().\n *\n * IMPORTANT: You must import the PhotoSwipe CSS files for the lightbox to work properly:\n * - `import 'photoswipe/style.css'` - Base PhotoSwipe styles\n * - `import '@simple-photo-gallery/common/styles/photoswipe'` - SPG enhancement styles\n *\n * @example\n * ```typescript\n * import { createGalleryLightbox } from '@simple-photo-gallery/common/client';\n * import 'photoswipe/style.css';\n * import '@simple-photo-gallery/common/styles/photoswipe';\n *\n * // Basic usage\n * const lightbox = await createGalleryLightbox();\n * lightbox.init();\n *\n * // With custom options\n * const lightbox = await createGalleryLightbox({\n * gallerySelector: '.my-gallery',\n * loop: true,\n * });\n *\n * // Add custom event handlers before init\n * lightbox.on('change', () => console.log('slide changed'));\n * lightbox.init();\n * ```\n */\nexport async function createGalleryLightbox(options: GalleryLightboxOptions = {}): Promise<PhotoSwipeLightbox> {\n const photoswipeModule = await import('photoswipe');\n const PhotoSwipe = photoswipeModule.default;\n const lightboxModule = await import('photoswipe/lightbox');\n const PhotoSwipeLightboxModule = lightboxModule.default;\n const sampleBrightness = createCaptionBrightnessSampler();\n\n const lightbox = new PhotoSwipeLightboxModule({\n gallery: options.gallerySelector ?? '.gallery-grid',\n children: options.childrenSelector ?? 'a',\n pswpModule: PhotoSwipe,\n showAnimationDuration: options.showAnimationDuration ?? 300,\n hideAnimationDuration: options.hideAnimationDuration ?? 300,\n wheelToZoom: options.wheelToZoom ?? true,\n loop: options.loop ?? false,\n bgOpacity: options.bgOpacity ?? 1,\n });\n\n new PhotoSwipeVideoPlugin(lightbox, options.videoPluginOptions);\n\n // Slide animations (enabled by default)\n if (options.slideAnimations !== false) {\n lightbox.on('contentDeactivate', ({ content }: { content: { element?: HTMLElement } }) => {\n content.element?.classList.remove('pswp__img--in-viewport');\n });\n lightbox.on('contentActivate', ({ content }: { content: { element?: HTMLElement } }) => {\n content.element?.classList.add('pswp__img--in-viewport');\n });\n }\n\n // Custom caption UI (enabled by default)\n if (options.enableCaptions !== false) {\n lightbox.on('uiRegister', () => {\n (lightbox.pswp as PhotoSwipe | undefined)?.ui?.registerElement({\n name: 'custom-caption',\n isButton: false,\n className: 'pswp__caption',\n appendTo: 'wrapper',\n onInit: (el: HTMLElement) => {\n (lightbox.pswp as PhotoSwipe | undefined)?.on('change', () => {\n const currSlideElement = (lightbox.pswp as PhotoSwipe | undefined)?.currSlide?.data.element as\n | HTMLElement\n | undefined;\n if (currSlideElement) {\n const caption = (currSlideElement as HTMLElement).dataset.pswpCaption;\n el.innerHTML = caption || currSlideElement.querySelector('img')?.alt || '';\n\n // Adapt caption background based on image brightness\n if (sampleBrightness) {\n const img = currSlideElement.querySelector('img');\n const apply = () => {\n if (!img) return;\n const brightness = sampleBrightness(img);\n if (brightness === null) {\n el.style.removeProperty('--pswp-caption-bg');\n } else {\n el.style.setProperty('--pswp-caption-bg', interpolateCaptionBg(brightness));\n }\n };\n\n if (img && (!img.complete || img.naturalWidth === 0)) {\n img.addEventListener('load', apply, { once: true });\n } else {\n apply();\n }\n }\n }\n });\n },\n });\n });\n }\n\n return lightbox;\n}\n","import type PhotoSwipeLightbox from 'photoswipe/lightbox';\n\n/** Options for URL deep-linking functionality */\nexport interface DeepLinkingOptions {\n /** CSS selector for galleries (default: '.gallery-grid') */\n gallerySelector?: string;\n /** CSS selector for gallery items (default: 'a') */\n itemSelector?: string;\n /** URL parameter name for image ID (default: 'image') */\n parameterName?: string;\n /** Delay in ms before opening image on page load (default: 100) */\n openDelay?: number;\n}\n\n/**\n * Updates browser URL with current image ID.\n * Uses History API to replace state without page reload.\n */\nexport function updateGalleryURL(imageId: string | null, paramName: string = 'image'): void {\n const url = new URL(globalThis.location.href);\n if (imageId) {\n url.searchParams.set(paramName, imageId);\n } else {\n url.searchParams.delete(paramName);\n }\n globalThis.history.replaceState({}, '', url.toString());\n}\n\n/**\n * Extracts image ID from URL parameters.\n */\nexport function getImageIdFromURL(paramName: string = 'image'): string | null {\n const params = new URLSearchParams(globalThis.location.search);\n return params.get(paramName);\n}\n\n/**\n * Opens a specific image by ID within a gallery.\n * Searches through all gallery items and opens matching image in lightbox.\n *\n * @returns true if image was found and opened, false otherwise\n */\nexport function openImageById(lightbox: PhotoSwipeLightbox, imageId: string, options: DeepLinkingOptions = {}): boolean {\n const gallerySelector = options.gallerySelector ?? '.gallery-grid';\n const itemSelector = options.itemSelector ?? 'a';\n\n const galleries = document.querySelectorAll(gallerySelector);\n const allItems: HTMLElement[] = [];\n\n for (const gallery of galleries) {\n const items = gallery.querySelectorAll<HTMLElement>(itemSelector);\n allItems.push(...items);\n }\n\n for (const [i, item] of allItems.entries()) {\n const itemId = item.dataset.imageId || '';\n if (itemId === imageId) {\n lightbox.loadAndOpen(i);\n return true;\n }\n }\n return false;\n}\n\n/**\n * Sets up automatic URL updates when lightbox changes.\n * Call after creating lightbox but before init().\n *\n * @example\n * ```typescript\n * const lightbox = await createGalleryLightbox();\n * setupDeepLinking(lightbox);\n * lightbox.init();\n * restoreFromURL(lightbox);\n * ```\n */\nexport function setupDeepLinking(lightbox: PhotoSwipeLightbox, options: DeepLinkingOptions = {}): void {\n const paramName = options.parameterName ?? 'image';\n\n // Update URL when slide changes\n lightbox.on('change', () => {\n if (lightbox.pswp) {\n const currSlideElement = lightbox.pswp.currSlide?.data.element as HTMLElement | undefined;\n const imageId = currSlideElement?.dataset?.imageId ?? null;\n updateGalleryURL(imageId, paramName);\n }\n });\n\n // Clear URL parameter when lightbox closes\n lightbox.on('close', () => {\n updateGalleryURL(null, paramName);\n });\n}\n\n/**\n * Restores gallery state from URL on page load.\n * Automatically opens image if specified in URL parameters.\n * Call after lightbox.init().\n *\n * @example\n * ```typescript\n * const lightbox = await createGalleryLightbox();\n * setupDeepLinking(lightbox);\n * lightbox.init();\n * restoreFromURL(lightbox);\n * ```\n */\nexport function restoreFromURL(lightbox: PhotoSwipeLightbox, options: DeepLinkingOptions = {}): void {\n const paramName = options.parameterName ?? 'image';\n const openDelay = options.openDelay ?? 100;\n const imageIdFromURL = getImageIdFromURL(paramName);\n\n if (imageIdFromURL) {\n const open = () => {\n setTimeout(() => openImageById(lightbox, imageIdFromURL, options), openDelay);\n };\n\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', open);\n } else {\n open();\n }\n }\n}\n","/**\n * CSS utility functions for client-side theming and color manipulation.\n * These utilities are browser-only and require DOM access.\n */\n\n/**\n * Normalizes hex color values to 6-digit format (e.g., #abc -> #aabbcc).\n * Returns null if the hex value is invalid.\n *\n * @param hex - The hex color value to normalize (with or without #)\n * @returns The normalized 6-digit hex color with # prefix, or null if invalid\n */\nexport function normalizeHex(hex: string): string | null {\n hex = hex.replace('#', '');\n if (hex.length === 3) hex = [...hex].map((c) => c + c).join('');\n return hex.length === 6 && /^[0-9A-Fa-f]{6}$/.test(hex) ? `#${hex}` : null;\n}\n\n/**\n * Parses and validates a color value.\n * Supports CSS color names, hex values, rgb/rgba, and 'transparent'.\n * Returns null if the color is invalid.\n *\n * @param colorParam - The color string to parse\n * @returns The validated color string, or null if invalid\n */\nexport function parseColor(colorParam: string | null): string | null {\n if (!colorParam) return null;\n const normalized = colorParam.toLowerCase().trim();\n if (normalized === 'transparent') return 'transparent';\n\n const testEl = document.createElement('div');\n testEl.style.color = normalized;\n if (testEl.style.color) return normalized;\n\n return normalizeHex(colorParam);\n}\n\n/**\n * Sets or removes a CSS custom property (variable) on an element.\n * Removes the property if value is null.\n *\n * @param element - The HTML element to modify\n * @param name - The CSS variable name (e.g., '--my-color')\n * @param value - The value to set, or null to remove\n */\nexport function setCSSVar(element: HTMLElement, name: string, value: string | null): void {\n if (value) {\n element.style.setProperty(name, value);\n } else {\n element.style.removeProperty(name);\n }\n}\n\n/**\n * Derives a color with adjusted opacity from an existing color.\n * Converts rgb to rgba if needed, or adjusts existing rgba opacity.\n *\n * @param color - The source color (rgb, rgba, or other CSS color)\n * @param opacity - The target opacity (0-1)\n * @returns The color with adjusted opacity, or original if not rgb/rgba\n */\nexport function deriveOpacityColor(color: string, opacity: number): string {\n if (color.startsWith('rgba')) {\n return color.replace(/,\\s*[\\d.]+\\)$/, `, ${opacity})`);\n }\n if (color.startsWith('rgb')) {\n return color.replace('rgb', 'rgba').replace(')', `, ${opacity})`);\n }\n return color;\n}\n"]}
package/dist/gallery.cjs CHANGED
@@ -102,6 +102,7 @@ var GalleryDataSchema = zod.z.object({
102
102
  thumbsBaseUrl: zod.z.string().optional(),
103
103
  analyticsScript: zod.z.string().optional(),
104
104
  ctaBanner: zod.z.boolean().optional(),
105
+ customStyles: zod.z.record(zod.z.string(), zod.z.string()).optional(),
105
106
  sections: zod.z.array(GallerySectionSchema),
106
107
  subGalleries: zod.z.object({ title: zod.z.string(), galleries: zod.z.array(SubGallerySchema) })
107
108
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/gallery/schemas.ts"],"names":["z"],"mappings":"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","file":"gallery.cjs","sourcesContent":["import { z } from 'zod';\n\n/** Zod schema for thumbnail metadata including path and dimensions */\nexport const ThumbnailSchema = z.object({\n baseUrl: z.string().optional(),\n path: z.string(),\n pathRetina: z.string(),\n width: z.number(),\n height: z.number(),\n blurHash: z.string().optional(),\n});\n\n/** Zod schema for media file metadata including type, dimensions, and thumbnail info */\nexport const MediaFileSchema = z.object({\n type: z.enum(['image', 'video']),\n filename: z.string(),\n url: z.string().optional(),\n alt: z.string().optional(),\n width: z.number(),\n height: z.number(),\n thumbnail: ThumbnailSchema.optional(),\n lastMediaTimestamp: z.string().optional(),\n});\n\n/**\n * Zod schema for media file with path.\n * @deprecated Use MediaFileSchema instead which uses 'filename' instead of 'path'.\n */\nexport const MediaFileDeprecatedSchema = z.object({\n type: z.enum(['image', 'video']),\n path: z.string(),\n alt: z.string().optional(),\n width: z.number(),\n height: z.number(),\n thumbnail: ThumbnailSchema.optional(),\n lastMediaTimestamp: z.string().optional(),\n});\n\n/** Zod schema for a gallery section containing title, description, and media files */\nexport const GallerySectionSchema = z.object({\n title: z.string().optional(),\n description: z.string().optional(),\n images: z.array(MediaFileSchema),\n});\n\n/**\n * Zod schema for a gallery section containing title, description, and media files.\n * @deprecated Use GallerySectionSchema instead which uses MediaFileSchema.\n */\nexport const GallerySectionDeprecatedSchema = z.object({\n title: z.string().optional(),\n description: z.string().optional(),\n images: z.array(MediaFileDeprecatedSchema),\n});\n\n/** Zod schema for sub-gallery metadata including title, header image, and path */\nexport const SubGallerySchema = z.object({\n title: z.string(),\n headerImage: z.string(),\n path: z.string(),\n});\n\n/** Zod schema for portrait image size variants */\nconst PortraitSizesSchema = z.object({\n 360: z.string().optional(),\n 480: z.string().optional(),\n 720: z.string().optional(),\n 1080: z.string().optional(),\n});\n\n/** Zod schema for landscape image size variants */\nconst LandscapeSizesSchema = z.object({\n 640: z.string().optional(),\n 960: z.string().optional(),\n 1280: z.string().optional(),\n 1920: z.string().optional(),\n 2560: z.string().optional(),\n 3840: z.string().optional(),\n});\n\n/** Zod schema for header image variants allowing explicit specification of responsive hero images */\nexport const HeaderImageVariantsSchema = z.object({\n portrait: z\n .object({\n avif: PortraitSizesSchema.optional(),\n jpg: PortraitSizesSchema.optional(),\n })\n .optional(),\n landscape: z\n .object({\n avif: LandscapeSizesSchema.optional(),\n jpg: LandscapeSizesSchema.optional(),\n })\n .optional(),\n});\n\n/** Zod schema for complete gallery data including metadata, sections, and sub-galleries */\nexport const GalleryMetadataSchema = z.object({\n image: z.string().optional(),\n imageWidth: z.number().optional(),\n imageHeight: z.number().optional(),\n ogUrl: z.string().optional(),\n ogType: z.string().optional(),\n ogSiteName: z.string().optional(),\n twitterSite: z.string().optional(),\n twitterCreator: z.string().optional(),\n author: z.string().optional(),\n keywords: z.string().optional(),\n canonicalUrl: z.string().optional(),\n language: z.string().optional(),\n robots: z.string().optional(),\n});\n\n/** Zod schema for complete gallery data including metadata, sections, and sub-galleries */\nexport const GalleryDataSchema = z.object({\n title: z.string(),\n description: z.string(),\n mediaBasePath: z.string().optional(),\n url: z.string().optional(),\n headerImage: z.string(),\n headerImageBlurHash: z.string().optional(),\n headerImageVariants: HeaderImageVariantsSchema.optional(),\n theme: z.string().optional(),\n thumbnails: z\n .object({\n size: z.number().optional(),\n edge: z.enum(['auto', 'width', 'height']).optional(),\n })\n .optional(),\n metadata: GalleryMetadataSchema,\n mediaBaseUrl: z.string().optional(),\n thumbsBaseUrl: z.string().optional(),\n analyticsScript: z.string().optional(),\n ctaBanner: z.boolean().optional(),\n sections: z.array(GallerySectionSchema),\n subGalleries: z.object({ title: z.string(), galleries: z.array(SubGallerySchema) }),\n});\n\n/**\n * Zod schema for complete gallery data without mediaBasePath.\n * @deprecated Use GalleryDataSchema instead which includes mediaBasePath and headerImageVariants.\n */\nexport const GalleryDataDeprecatedSchema = z.object({\n title: z.string(),\n description: z.string(),\n url: z.string().optional(),\n headerImage: z.string(),\n thumbnailSize: z.number().optional(),\n metadata: GalleryMetadataSchema,\n mediaBaseUrl: z.string().optional(),\n analyticsScript: z.string().optional(),\n sections: z.array(GallerySectionDeprecatedSchema),\n subGalleries: z.object({ title: z.string(), galleries: z.array(SubGallerySchema) }),\n});\n"]}
1
+ {"version":3,"sources":["../src/gallery/schemas.ts"],"names":["z"],"mappings":"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","file":"gallery.cjs","sourcesContent":["import { z } from 'zod';\n\n/** Zod schema for thumbnail metadata including path and dimensions */\nexport const ThumbnailSchema = z.object({\n baseUrl: z.string().optional(),\n path: z.string(),\n pathRetina: z.string(),\n width: z.number(),\n height: z.number(),\n blurHash: z.string().optional(),\n});\n\n/** Zod schema for media file metadata including type, dimensions, and thumbnail info */\nexport const MediaFileSchema = z.object({\n type: z.enum(['image', 'video']),\n filename: z.string(),\n url: z.string().optional(),\n alt: z.string().optional(),\n width: z.number(),\n height: z.number(),\n thumbnail: ThumbnailSchema.optional(),\n lastMediaTimestamp: z.string().optional(),\n});\n\n/**\n * Zod schema for media file with path.\n * @deprecated Use MediaFileSchema instead which uses 'filename' instead of 'path'.\n */\nexport const MediaFileDeprecatedSchema = z.object({\n type: z.enum(['image', 'video']),\n path: z.string(),\n alt: z.string().optional(),\n width: z.number(),\n height: z.number(),\n thumbnail: ThumbnailSchema.optional(),\n lastMediaTimestamp: z.string().optional(),\n});\n\n/** Zod schema for a gallery section containing title, description, and media files */\nexport const GallerySectionSchema = z.object({\n title: z.string().optional(),\n description: z.string().optional(),\n images: z.array(MediaFileSchema),\n});\n\n/**\n * Zod schema for a gallery section containing title, description, and media files.\n * @deprecated Use GallerySectionSchema instead which uses MediaFileSchema.\n */\nexport const GallerySectionDeprecatedSchema = z.object({\n title: z.string().optional(),\n description: z.string().optional(),\n images: z.array(MediaFileDeprecatedSchema),\n});\n\n/** Zod schema for sub-gallery metadata including title, header image, and path */\nexport const SubGallerySchema = z.object({\n title: z.string(),\n headerImage: z.string(),\n path: z.string(),\n});\n\n/** Zod schema for portrait image size variants */\nconst PortraitSizesSchema = z.object({\n 360: z.string().optional(),\n 480: z.string().optional(),\n 720: z.string().optional(),\n 1080: z.string().optional(),\n});\n\n/** Zod schema for landscape image size variants */\nconst LandscapeSizesSchema = z.object({\n 640: z.string().optional(),\n 960: z.string().optional(),\n 1280: z.string().optional(),\n 1920: z.string().optional(),\n 2560: z.string().optional(),\n 3840: z.string().optional(),\n});\n\n/** Zod schema for header image variants allowing explicit specification of responsive hero images */\nexport const HeaderImageVariantsSchema = z.object({\n portrait: z\n .object({\n avif: PortraitSizesSchema.optional(),\n jpg: PortraitSizesSchema.optional(),\n })\n .optional(),\n landscape: z\n .object({\n avif: LandscapeSizesSchema.optional(),\n jpg: LandscapeSizesSchema.optional(),\n })\n .optional(),\n});\n\n/** Zod schema for complete gallery data including metadata, sections, and sub-galleries */\nexport const GalleryMetadataSchema = z.object({\n image: z.string().optional(),\n imageWidth: z.number().optional(),\n imageHeight: z.number().optional(),\n ogUrl: z.string().optional(),\n ogType: z.string().optional(),\n ogSiteName: z.string().optional(),\n twitterSite: z.string().optional(),\n twitterCreator: z.string().optional(),\n author: z.string().optional(),\n keywords: z.string().optional(),\n canonicalUrl: z.string().optional(),\n language: z.string().optional(),\n robots: z.string().optional(),\n});\n\n/** Zod schema for complete gallery data including metadata, sections, and sub-galleries */\nexport const GalleryDataSchema = z.object({\n title: z.string(),\n description: z.string(),\n mediaBasePath: z.string().optional(),\n url: z.string().optional(),\n headerImage: z.string(),\n headerImageBlurHash: z.string().optional(),\n headerImageVariants: HeaderImageVariantsSchema.optional(),\n theme: z.string().optional(),\n thumbnails: z\n .object({\n size: z.number().optional(),\n edge: z.enum(['auto', 'width', 'height']).optional(),\n })\n .optional(),\n metadata: GalleryMetadataSchema,\n mediaBaseUrl: z.string().optional(),\n thumbsBaseUrl: z.string().optional(),\n analyticsScript: z.string().optional(),\n ctaBanner: z.boolean().optional(),\n customStyles: z.record(z.string(), z.string()).optional(),\n sections: z.array(GallerySectionSchema),\n subGalleries: z.object({ title: z.string(), galleries: z.array(SubGallerySchema) }),\n});\n\n/**\n * Zod schema for complete gallery data without mediaBasePath.\n * @deprecated Use GalleryDataSchema instead which includes mediaBasePath and headerImageVariants.\n */\nexport const GalleryDataDeprecatedSchema = z.object({\n title: z.string(),\n description: z.string(),\n url: z.string().optional(),\n headerImage: z.string(),\n thumbnailSize: z.number().optional(),\n metadata: GalleryMetadataSchema,\n mediaBaseUrl: z.string().optional(),\n analyticsScript: z.string().optional(),\n sections: z.array(GallerySectionDeprecatedSchema),\n subGalleries: z.object({ title: z.string(), galleries: z.array(SubGallerySchema) }),\n});\n"]}
@@ -232,6 +232,7 @@ declare const GalleryDataSchema: z.ZodObject<{
232
232
  thumbsBaseUrl: z.ZodOptional<z.ZodString>;
233
233
  analyticsScript: z.ZodOptional<z.ZodString>;
234
234
  ctaBanner: z.ZodOptional<z.ZodBoolean>;
235
+ customStyles: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
235
236
  sections: z.ZodArray<z.ZodObject<{
236
237
  title: z.ZodOptional<z.ZodString>;
237
238
  description: z.ZodOptional<z.ZodString>;
package/dist/gallery.d.ts CHANGED
@@ -232,6 +232,7 @@ declare const GalleryDataSchema: z.ZodObject<{
232
232
  thumbsBaseUrl: z.ZodOptional<z.ZodString>;
233
233
  analyticsScript: z.ZodOptional<z.ZodString>;
234
234
  ctaBanner: z.ZodOptional<z.ZodBoolean>;
235
+ customStyles: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
235
236
  sections: z.ZodArray<z.ZodObject<{
236
237
  title: z.ZodOptional<z.ZodString>;
237
238
  description: z.ZodOptional<z.ZodString>;
package/dist/gallery.js CHANGED
@@ -100,6 +100,7 @@ var GalleryDataSchema = z.object({
100
100
  thumbsBaseUrl: z.string().optional(),
101
101
  analyticsScript: z.string().optional(),
102
102
  ctaBanner: z.boolean().optional(),
103
+ customStyles: z.record(z.string(), z.string()).optional(),
103
104
  sections: z.array(GallerySectionSchema),
104
105
  subGalleries: z.object({ title: z.string(), galleries: z.array(SubGallerySchema) })
105
106
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/gallery/schemas.ts"],"names":[],"mappings":"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","file":"gallery.js","sourcesContent":["import { z } from 'zod';\n\n/** Zod schema for thumbnail metadata including path and dimensions */\nexport const ThumbnailSchema = z.object({\n baseUrl: z.string().optional(),\n path: z.string(),\n pathRetina: z.string(),\n width: z.number(),\n height: z.number(),\n blurHash: z.string().optional(),\n});\n\n/** Zod schema for media file metadata including type, dimensions, and thumbnail info */\nexport const MediaFileSchema = z.object({\n type: z.enum(['image', 'video']),\n filename: z.string(),\n url: z.string().optional(),\n alt: z.string().optional(),\n width: z.number(),\n height: z.number(),\n thumbnail: ThumbnailSchema.optional(),\n lastMediaTimestamp: z.string().optional(),\n});\n\n/**\n * Zod schema for media file with path.\n * @deprecated Use MediaFileSchema instead which uses 'filename' instead of 'path'.\n */\nexport const MediaFileDeprecatedSchema = z.object({\n type: z.enum(['image', 'video']),\n path: z.string(),\n alt: z.string().optional(),\n width: z.number(),\n height: z.number(),\n thumbnail: ThumbnailSchema.optional(),\n lastMediaTimestamp: z.string().optional(),\n});\n\n/** Zod schema for a gallery section containing title, description, and media files */\nexport const GallerySectionSchema = z.object({\n title: z.string().optional(),\n description: z.string().optional(),\n images: z.array(MediaFileSchema),\n});\n\n/**\n * Zod schema for a gallery section containing title, description, and media files.\n * @deprecated Use GallerySectionSchema instead which uses MediaFileSchema.\n */\nexport const GallerySectionDeprecatedSchema = z.object({\n title: z.string().optional(),\n description: z.string().optional(),\n images: z.array(MediaFileDeprecatedSchema),\n});\n\n/** Zod schema for sub-gallery metadata including title, header image, and path */\nexport const SubGallerySchema = z.object({\n title: z.string(),\n headerImage: z.string(),\n path: z.string(),\n});\n\n/** Zod schema for portrait image size variants */\nconst PortraitSizesSchema = z.object({\n 360: z.string().optional(),\n 480: z.string().optional(),\n 720: z.string().optional(),\n 1080: z.string().optional(),\n});\n\n/** Zod schema for landscape image size variants */\nconst LandscapeSizesSchema = z.object({\n 640: z.string().optional(),\n 960: z.string().optional(),\n 1280: z.string().optional(),\n 1920: z.string().optional(),\n 2560: z.string().optional(),\n 3840: z.string().optional(),\n});\n\n/** Zod schema for header image variants allowing explicit specification of responsive hero images */\nexport const HeaderImageVariantsSchema = z.object({\n portrait: z\n .object({\n avif: PortraitSizesSchema.optional(),\n jpg: PortraitSizesSchema.optional(),\n })\n .optional(),\n landscape: z\n .object({\n avif: LandscapeSizesSchema.optional(),\n jpg: LandscapeSizesSchema.optional(),\n })\n .optional(),\n});\n\n/** Zod schema for complete gallery data including metadata, sections, and sub-galleries */\nexport const GalleryMetadataSchema = z.object({\n image: z.string().optional(),\n imageWidth: z.number().optional(),\n imageHeight: z.number().optional(),\n ogUrl: z.string().optional(),\n ogType: z.string().optional(),\n ogSiteName: z.string().optional(),\n twitterSite: z.string().optional(),\n twitterCreator: z.string().optional(),\n author: z.string().optional(),\n keywords: z.string().optional(),\n canonicalUrl: z.string().optional(),\n language: z.string().optional(),\n robots: z.string().optional(),\n});\n\n/** Zod schema for complete gallery data including metadata, sections, and sub-galleries */\nexport const GalleryDataSchema = z.object({\n title: z.string(),\n description: z.string(),\n mediaBasePath: z.string().optional(),\n url: z.string().optional(),\n headerImage: z.string(),\n headerImageBlurHash: z.string().optional(),\n headerImageVariants: HeaderImageVariantsSchema.optional(),\n theme: z.string().optional(),\n thumbnails: z\n .object({\n size: z.number().optional(),\n edge: z.enum(['auto', 'width', 'height']).optional(),\n })\n .optional(),\n metadata: GalleryMetadataSchema,\n mediaBaseUrl: z.string().optional(),\n thumbsBaseUrl: z.string().optional(),\n analyticsScript: z.string().optional(),\n ctaBanner: z.boolean().optional(),\n sections: z.array(GallerySectionSchema),\n subGalleries: z.object({ title: z.string(), galleries: z.array(SubGallerySchema) }),\n});\n\n/**\n * Zod schema for complete gallery data without mediaBasePath.\n * @deprecated Use GalleryDataSchema instead which includes mediaBasePath and headerImageVariants.\n */\nexport const GalleryDataDeprecatedSchema = z.object({\n title: z.string(),\n description: z.string(),\n url: z.string().optional(),\n headerImage: z.string(),\n thumbnailSize: z.number().optional(),\n metadata: GalleryMetadataSchema,\n mediaBaseUrl: z.string().optional(),\n analyticsScript: z.string().optional(),\n sections: z.array(GallerySectionDeprecatedSchema),\n subGalleries: z.object({ title: z.string(), galleries: z.array(SubGallerySchema) }),\n});\n"]}
1
+ {"version":3,"sources":["../src/gallery/schemas.ts"],"names":[],"mappings":"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","file":"gallery.js","sourcesContent":["import { z } from 'zod';\n\n/** Zod schema for thumbnail metadata including path and dimensions */\nexport const ThumbnailSchema = z.object({\n baseUrl: z.string().optional(),\n path: z.string(),\n pathRetina: z.string(),\n width: z.number(),\n height: z.number(),\n blurHash: z.string().optional(),\n});\n\n/** Zod schema for media file metadata including type, dimensions, and thumbnail info */\nexport const MediaFileSchema = z.object({\n type: z.enum(['image', 'video']),\n filename: z.string(),\n url: z.string().optional(),\n alt: z.string().optional(),\n width: z.number(),\n height: z.number(),\n thumbnail: ThumbnailSchema.optional(),\n lastMediaTimestamp: z.string().optional(),\n});\n\n/**\n * Zod schema for media file with path.\n * @deprecated Use MediaFileSchema instead which uses 'filename' instead of 'path'.\n */\nexport const MediaFileDeprecatedSchema = z.object({\n type: z.enum(['image', 'video']),\n path: z.string(),\n alt: z.string().optional(),\n width: z.number(),\n height: z.number(),\n thumbnail: ThumbnailSchema.optional(),\n lastMediaTimestamp: z.string().optional(),\n});\n\n/** Zod schema for a gallery section containing title, description, and media files */\nexport const GallerySectionSchema = z.object({\n title: z.string().optional(),\n description: z.string().optional(),\n images: z.array(MediaFileSchema),\n});\n\n/**\n * Zod schema for a gallery section containing title, description, and media files.\n * @deprecated Use GallerySectionSchema instead which uses MediaFileSchema.\n */\nexport const GallerySectionDeprecatedSchema = z.object({\n title: z.string().optional(),\n description: z.string().optional(),\n images: z.array(MediaFileDeprecatedSchema),\n});\n\n/** Zod schema for sub-gallery metadata including title, header image, and path */\nexport const SubGallerySchema = z.object({\n title: z.string(),\n headerImage: z.string(),\n path: z.string(),\n});\n\n/** Zod schema for portrait image size variants */\nconst PortraitSizesSchema = z.object({\n 360: z.string().optional(),\n 480: z.string().optional(),\n 720: z.string().optional(),\n 1080: z.string().optional(),\n});\n\n/** Zod schema for landscape image size variants */\nconst LandscapeSizesSchema = z.object({\n 640: z.string().optional(),\n 960: z.string().optional(),\n 1280: z.string().optional(),\n 1920: z.string().optional(),\n 2560: z.string().optional(),\n 3840: z.string().optional(),\n});\n\n/** Zod schema for header image variants allowing explicit specification of responsive hero images */\nexport const HeaderImageVariantsSchema = z.object({\n portrait: z\n .object({\n avif: PortraitSizesSchema.optional(),\n jpg: PortraitSizesSchema.optional(),\n })\n .optional(),\n landscape: z\n .object({\n avif: LandscapeSizesSchema.optional(),\n jpg: LandscapeSizesSchema.optional(),\n })\n .optional(),\n});\n\n/** Zod schema for complete gallery data including metadata, sections, and sub-galleries */\nexport const GalleryMetadataSchema = z.object({\n image: z.string().optional(),\n imageWidth: z.number().optional(),\n imageHeight: z.number().optional(),\n ogUrl: z.string().optional(),\n ogType: z.string().optional(),\n ogSiteName: z.string().optional(),\n twitterSite: z.string().optional(),\n twitterCreator: z.string().optional(),\n author: z.string().optional(),\n keywords: z.string().optional(),\n canonicalUrl: z.string().optional(),\n language: z.string().optional(),\n robots: z.string().optional(),\n});\n\n/** Zod schema for complete gallery data including metadata, sections, and sub-galleries */\nexport const GalleryDataSchema = z.object({\n title: z.string(),\n description: z.string(),\n mediaBasePath: z.string().optional(),\n url: z.string().optional(),\n headerImage: z.string(),\n headerImageBlurHash: z.string().optional(),\n headerImageVariants: HeaderImageVariantsSchema.optional(),\n theme: z.string().optional(),\n thumbnails: z\n .object({\n size: z.number().optional(),\n edge: z.enum(['auto', 'width', 'height']).optional(),\n })\n .optional(),\n metadata: GalleryMetadataSchema,\n mediaBaseUrl: z.string().optional(),\n thumbsBaseUrl: z.string().optional(),\n analyticsScript: z.string().optional(),\n ctaBanner: z.boolean().optional(),\n customStyles: z.record(z.string(), z.string()).optional(),\n sections: z.array(GallerySectionSchema),\n subGalleries: z.object({ title: z.string(), galleries: z.array(SubGallerySchema) }),\n});\n\n/**\n * Zod schema for complete gallery data without mediaBasePath.\n * @deprecated Use GalleryDataSchema instead which includes mediaBasePath and headerImageVariants.\n */\nexport const GalleryDataDeprecatedSchema = z.object({\n title: z.string(),\n description: z.string(),\n url: z.string().optional(),\n headerImage: z.string(),\n thumbnailSize: z.number().optional(),\n metadata: GalleryMetadataSchema,\n mediaBaseUrl: z.string().optional(),\n analyticsScript: z.string().optional(),\n sections: z.array(GallerySectionDeprecatedSchema),\n subGalleries: z.object({ title: z.string(), galleries: z.array(SubGallerySchema) }),\n});\n"]}
@@ -13,7 +13,7 @@
13
13
  --pswp-counter-font-size: 1rem;
14
14
 
15
15
  /* Caption container */
16
- --pswp-caption-bg: rgba(128, 128, 128, 0.3);
16
+ --pswp-caption-bg: rgba(128, 128, 128, 0.35);
17
17
  --pswp-caption-blur: 8px;
18
18
  --pswp-caption-color: white;
19
19
  --pswp-caption-padding: 16px;
@@ -79,6 +79,7 @@
79
79
  border-radius: var(--pswp-caption-radius);
80
80
  margin: var(--pswp-caption-margin);
81
81
  box-shadow: var(--pswp-caption-shadow);
82
+ transition: background 0.3s ease;
82
83
  }
83
84
 
84
85
  @media (max-width: 768px) {
@@ -99,14 +100,14 @@
99
100
  font-size: var(--pswp-caption-title-size);
100
101
  font-weight: var(--pswp-caption-title-weight);
101
102
  margin-bottom: 0.5rem;
102
- text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
103
+ text-shadow: 0 2px 4px rgba(0, 0, 0, 0.6);
103
104
  }
104
105
 
105
106
  .pswp__caption p {
106
107
  font-size: var(--pswp-caption-text-size);
107
108
  opacity: 0.95;
108
109
  line-height: 1.6;
109
- text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
110
+ text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
110
111
  font-weight: 400;
111
112
  }
112
113
 
package/dist/theme.d.ts CHANGED
@@ -121,6 +121,7 @@ declare const GalleryDataSchema: z.ZodObject<{
121
121
  thumbsBaseUrl: z.ZodOptional<z.ZodString>;
122
122
  analyticsScript: z.ZodOptional<z.ZodString>;
123
123
  ctaBanner: z.ZodOptional<z.ZodBoolean>;
124
+ customStyles: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
124
125
  sections: z.ZodArray<z.ZodObject<{
125
126
  title: z.ZodOptional<z.ZodString>;
126
127
  description: z.ZodOptional<z.ZodString>;
@@ -278,6 +279,8 @@ interface ResolvedGalleryData {
278
279
  * Themes should use this for display sizing (e.g., row-height for modern theme).
279
280
  */
280
281
  thumbnails?: Required<ThumbnailConfig>;
282
+ /** Custom CSS variable overrides from gallery.json, passed through for theme injection. */
283
+ customStyles?: Record<string, string>;
281
284
  }
282
285
 
283
286
  /** Portrait image sizes for responsive hero images */
package/dist/theme.js CHANGED
@@ -185,6 +185,7 @@ var GalleryDataSchema = z.object({
185
185
  thumbsBaseUrl: z.string().optional(),
186
186
  analyticsScript: z.string().optional(),
187
187
  ctaBanner: z.boolean().optional(),
188
+ customStyles: z.record(z.string(), z.string()).optional(),
188
189
  sections: z.array(GallerySectionSchema),
189
190
  subGalleries: z.object({ title: z.string(), galleries: z.array(SubGallerySchema) })
190
191
  });
@@ -356,7 +357,8 @@ async function resolveGalleryData(gallery, options) {
356
357
  subGalleries: resolvedSubGalleries,
357
358
  mediaBaseUrl,
358
359
  thumbsBaseUrl,
359
- thumbnails
360
+ thumbnails,
361
+ customStyles: gallery.customStyles
360
362
  };
361
363
  }
362
364
  function preventEmptyContentFiles() {
package/dist/theme.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/theme/config.ts","../src/theme/constants.ts","../src/theme/markdown.ts","../src/theme/paths.ts","../src/gallery/schemas.ts","../src/theme/loader.ts","../src/theme/resolver.ts","../src/theme/astro.ts"],"names":["z","path","fs"],"mappings":"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","file":"theme.js","sourcesContent":["import { z } from 'zod';\n\n/** Zod schema for thumbnail configuration */\nexport const ThumbnailConfigSchema = z.object({\n size: z.number().min(50).max(4000).optional(),\n edge: z.enum(['auto', 'width', 'height']).optional(),\n});\n\n/** Zod schema for theme configuration file (themeConfig.json) */\nexport const ThemeConfigSchema = z.object({\n thumbnails: ThumbnailConfigSchema.optional(),\n});\n\n/** TypeScript type for thumbnail configuration */\nexport type ThumbnailConfig = z.infer<typeof ThumbnailConfigSchema>;\n\n/** TypeScript type for theme configuration */\nexport type ThemeConfig = z.infer<typeof ThemeConfigSchema>;\n\n/** Default thumbnail configuration values */\nexport const DEFAULT_THUMBNAIL_CONFIG: Required<ThumbnailConfig> = {\n size: 300,\n edge: 'auto',\n};\n\n/**\n * Extracts thumbnail config from gallery data.\n * @param gallery - The gallery data object\n * @returns ThumbnailConfig with values from gallery data\n */\nexport function extractThumbnailConfigFromGallery(gallery: { thumbnails?: ThumbnailConfig }): ThumbnailConfig {\n return {\n size: gallery.thumbnails?.size,\n edge: gallery.thumbnails?.edge,\n };\n}\n\n/**\n * Merges thumbnail configurations with hierarchy:\n * 1. CLI flags (highest precedence)\n * 2. gallery.json settings\n * 3. themeConfig.json (theme defaults)\n * 4. Built-in defaults (lowest)\n *\n * @param cliConfig - Config from CLI flags (optional)\n * @param galleryConfig - Config from gallery.json (optional)\n * @param themeConfig - Config from themeConfig.json (optional)\n * @returns Merged thumbnail configuration with all values resolved\n */\nexport function mergeThumbnailConfig(\n cliConfig?: ThumbnailConfig,\n galleryConfig?: ThumbnailConfig,\n themeConfig?: ThumbnailConfig,\n): Required<ThumbnailConfig> {\n return {\n size: cliConfig?.size ?? galleryConfig?.size ?? themeConfig?.size ?? DEFAULT_THUMBNAIL_CONFIG.size,\n edge: cliConfig?.edge ?? galleryConfig?.edge ?? themeConfig?.edge ?? DEFAULT_THUMBNAIL_CONFIG.edge,\n };\n}\n","/** Portrait image sizes for responsive hero images */\nexport const PORTRAIT_SIZES = [360, 480, 720, 1080] as const;\n\n/** Landscape image sizes for responsive hero images */\nexport const LANDSCAPE_SIZES = [640, 960, 1280, 1920, 2560, 3840] as const;\n","import { marked } from 'marked';\n\n// Configure marked to only allow specific formatting options\nconst renderer = new marked.Renderer();\n\n// Disable headings by rendering them as paragraphs\nrenderer.heading = ({ text }: { text: string }) => {\n return '<p>' + text + '</p>\\n';\n};\n\n// Disable images\nrenderer.image = () => '';\n\n// Disable HTML\nrenderer.html = () => '';\n\n// Disable tables\nrenderer.table = () => '';\nrenderer.tablerow = () => '';\nrenderer.tablecell = () => '';\n\n// Configure marked options\nmarked.use({\n renderer: renderer,\n breaks: true,\n gfm: true,\n});\n\n/**\n * Renders markdown with limited formatting options.\n * Supported: paragraphs, bold, italic, lists, code blocks, blockquotes, links\n * Disabled: headings (rendered as paragraphs), images, HTML, tables\n */\nexport async function renderMarkdown(markdown: string): Promise<string> {\n if (!markdown) return '';\n return await marked.parse(markdown);\n}\n","import path from 'node:path';\n\n/**\n * Normalizes resource paths to be relative to the gallery root directory.\n *\n * @param resourcePath - The resource path (file or directory), typically relative to the gallery.json file\n * @param galleryJsonPath - Path to the gallery.json file used to resolve relative paths\n * @returns The normalized path relative to the gallery root directory\n */\nexport function getRelativePath(resourcePath: string, galleryJsonPath: string): string {\n const galleryConfigPath = path.resolve(galleryJsonPath);\n const galleryConfigDir = path.dirname(galleryConfigPath);\n\n const absoluteResourcePath = path.resolve(path.join(galleryConfigDir, resourcePath));\n const baseDir = path.dirname(galleryConfigDir);\n\n return path.relative(baseDir, absoluteResourcePath);\n}\n\n/**\n * Get the path to a thumbnail that is relative to the gallery root directory or the thumbnails base URL.\n *\n * @param resourcePath - The resource path (file or directory), typically relative to the gallery.json file\n * @param thumbsBaseUrl - The base URL for the thumbnails (gallery-level)\n * @param thumbnailBaseUrl - Optional thumbnail-specific base URL that overrides thumbsBaseUrl if provided\n * @returns The normalized path relative to the gallery root directory or the thumbnails base URL\n */\nexport function getThumbnailPath(resourcePath: string, thumbsBaseUrl?: string, thumbnailBaseUrl?: string): string {\n // If thumbnail-specific baseUrl is provided, use it and combine with the path\n if (thumbnailBaseUrl) {\n return `${thumbnailBaseUrl}/${resourcePath}`;\n }\n // Otherwise, use the gallery-level thumbsBaseUrl if provided\n return thumbsBaseUrl ? `${thumbsBaseUrl}/${resourcePath}` : `gallery/images/${path.basename(resourcePath)}`;\n}\n\n/**\n * Get the path to a photo that is always in the gallery root directory.\n *\n * @param filename - The filename to get the path for\n * @param mediaBaseUrl - The base URL for the media\n * @param url - Optional URL that, if provided, will be used directly regardless of base URL or path\n * @returns The normalized path relative to the gallery root directory, or the provided URL\n */\nexport function getPhotoPath(filename: string, mediaBaseUrl?: string, url?: string): string {\n // If url is provided, always use it regardless of base URL or path\n if (url) {\n return url;\n }\n\n return mediaBaseUrl ? `${mediaBaseUrl}/${filename}` : filename;\n}\n\n/**\n * Get the path to a subgallery thumbnail that is always in the subgallery directory.\n *\n * @param subgalleryHeaderImagePath - The path to the subgallery header image on the hard disk\n * @returns The normalized path relative to the subgallery directory\n */\nexport function getSubgalleryThumbnailPath(subgalleryHeaderImagePath: string): string {\n const photoBasename = path.basename(subgalleryHeaderImagePath);\n const subgalleryFolderName = path.basename(path.dirname(subgalleryHeaderImagePath));\n\n return path.join(subgalleryFolderName, 'gallery', 'thumbnails', photoBasename);\n}\n\n/**\n * Build a srcset string for responsive images.\n * Uses custom paths from variants when provided, otherwise generates default paths.\n *\n * @param variants - Optional record mapping sizes to custom URLs\n * @param sizes - Array of image widths to include\n * @param thumbnailBasePath - Base path for generated thumbnails\n * @param imgBasename - Image basename for generated paths\n * @param orientation - 'portrait' or 'landscape'\n * @param format - Image format ('avif' or 'jpg')\n * @param useDefaultPaths - Whether to use generated paths when no custom variant exists\n * @returns Comma-separated srcset string\n */\nexport function buildHeroSrcset(\n variants: Record<number, string | undefined> | undefined,\n sizes: readonly number[],\n thumbnailBasePath: string,\n imgBasename: string,\n orientation: 'portrait' | 'landscape',\n format: 'avif' | 'jpg',\n useDefaultPaths: boolean,\n): string {\n return sizes\n .map((size) => {\n const customPath = variants?.[size];\n if (customPath) {\n return `${customPath} ${size}w`;\n }\n if (useDefaultPaths) {\n return `${thumbnailBasePath}/${imgBasename}_${orientation}_${size}.${format} ${size}w`;\n }\n return null;\n })\n .filter(Boolean)\n .join(', ');\n}\n","import { z } from 'zod';\n\n/** Zod schema for thumbnail metadata including path and dimensions */\nexport const ThumbnailSchema = z.object({\n baseUrl: z.string().optional(),\n path: z.string(),\n pathRetina: z.string(),\n width: z.number(),\n height: z.number(),\n blurHash: z.string().optional(),\n});\n\n/** Zod schema for media file metadata including type, dimensions, and thumbnail info */\nexport const MediaFileSchema = z.object({\n type: z.enum(['image', 'video']),\n filename: z.string(),\n url: z.string().optional(),\n alt: z.string().optional(),\n width: z.number(),\n height: z.number(),\n thumbnail: ThumbnailSchema.optional(),\n lastMediaTimestamp: z.string().optional(),\n});\n\n/**\n * Zod schema for media file with path.\n * @deprecated Use MediaFileSchema instead which uses 'filename' instead of 'path'.\n */\nexport const MediaFileDeprecatedSchema = z.object({\n type: z.enum(['image', 'video']),\n path: z.string(),\n alt: z.string().optional(),\n width: z.number(),\n height: z.number(),\n thumbnail: ThumbnailSchema.optional(),\n lastMediaTimestamp: z.string().optional(),\n});\n\n/** Zod schema for a gallery section containing title, description, and media files */\nexport const GallerySectionSchema = z.object({\n title: z.string().optional(),\n description: z.string().optional(),\n images: z.array(MediaFileSchema),\n});\n\n/**\n * Zod schema for a gallery section containing title, description, and media files.\n * @deprecated Use GallerySectionSchema instead which uses MediaFileSchema.\n */\nexport const GallerySectionDeprecatedSchema = z.object({\n title: z.string().optional(),\n description: z.string().optional(),\n images: z.array(MediaFileDeprecatedSchema),\n});\n\n/** Zod schema for sub-gallery metadata including title, header image, and path */\nexport const SubGallerySchema = z.object({\n title: z.string(),\n headerImage: z.string(),\n path: z.string(),\n});\n\n/** Zod schema for portrait image size variants */\nconst PortraitSizesSchema = z.object({\n 360: z.string().optional(),\n 480: z.string().optional(),\n 720: z.string().optional(),\n 1080: z.string().optional(),\n});\n\n/** Zod schema for landscape image size variants */\nconst LandscapeSizesSchema = z.object({\n 640: z.string().optional(),\n 960: z.string().optional(),\n 1280: z.string().optional(),\n 1920: z.string().optional(),\n 2560: z.string().optional(),\n 3840: z.string().optional(),\n});\n\n/** Zod schema for header image variants allowing explicit specification of responsive hero images */\nexport const HeaderImageVariantsSchema = z.object({\n portrait: z\n .object({\n avif: PortraitSizesSchema.optional(),\n jpg: PortraitSizesSchema.optional(),\n })\n .optional(),\n landscape: z\n .object({\n avif: LandscapeSizesSchema.optional(),\n jpg: LandscapeSizesSchema.optional(),\n })\n .optional(),\n});\n\n/** Zod schema for complete gallery data including metadata, sections, and sub-galleries */\nexport const GalleryMetadataSchema = z.object({\n image: z.string().optional(),\n imageWidth: z.number().optional(),\n imageHeight: z.number().optional(),\n ogUrl: z.string().optional(),\n ogType: z.string().optional(),\n ogSiteName: z.string().optional(),\n twitterSite: z.string().optional(),\n twitterCreator: z.string().optional(),\n author: z.string().optional(),\n keywords: z.string().optional(),\n canonicalUrl: z.string().optional(),\n language: z.string().optional(),\n robots: z.string().optional(),\n});\n\n/** Zod schema for complete gallery data including metadata, sections, and sub-galleries */\nexport const GalleryDataSchema = z.object({\n title: z.string(),\n description: z.string(),\n mediaBasePath: z.string().optional(),\n url: z.string().optional(),\n headerImage: z.string(),\n headerImageBlurHash: z.string().optional(),\n headerImageVariants: HeaderImageVariantsSchema.optional(),\n theme: z.string().optional(),\n thumbnails: z\n .object({\n size: z.number().optional(),\n edge: z.enum(['auto', 'width', 'height']).optional(),\n })\n .optional(),\n metadata: GalleryMetadataSchema,\n mediaBaseUrl: z.string().optional(),\n thumbsBaseUrl: z.string().optional(),\n analyticsScript: z.string().optional(),\n ctaBanner: z.boolean().optional(),\n sections: z.array(GallerySectionSchema),\n subGalleries: z.object({ title: z.string(), galleries: z.array(SubGallerySchema) }),\n});\n\n/**\n * Zod schema for complete gallery data without mediaBasePath.\n * @deprecated Use GalleryDataSchema instead which includes mediaBasePath and headerImageVariants.\n */\nexport const GalleryDataDeprecatedSchema = z.object({\n title: z.string(),\n description: z.string(),\n url: z.string().optional(),\n headerImage: z.string(),\n thumbnailSize: z.number().optional(),\n metadata: GalleryMetadataSchema,\n mediaBaseUrl: z.string().optional(),\n analyticsScript: z.string().optional(),\n sections: z.array(GallerySectionDeprecatedSchema),\n subGalleries: z.object({ title: z.string(), galleries: z.array(SubGallerySchema) }),\n});\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport process from 'node:process';\n\nimport { ThemeConfigSchema, type ThumbnailConfig } from './config';\n\nimport { GalleryDataSchema, type GalleryData } from '../gallery';\n\nexport interface LoadGalleryDataOptions {\n /**\n * When true, validates the loaded JSON against the GalleryData schema.\n * Throws a descriptive error if validation fails.\n * @default false\n */\n validate?: boolean;\n}\n\n/**\n * Load theme configuration from themeConfig.json file.\n *\n * Searches for themeConfig.json in the following locations (in priority order):\n * 1. Current working directory (process.cwd()) - checked first\n * 2. Provided themePath parameter - checked second\n *\n * The first valid configuration found is returned. This means a themeConfig.json\n * in the project root will take precedence over the theme's built-in configuration,\n * allowing users to override theme defaults without modifying the theme itself.\n *\n * **Note for theme authors:** Your theme's themeConfig.json provides sensible defaults,\n * but users can override these by placing their own themeConfig.json in their project root.\n *\n * @param themePath - Optional path to the theme directory\n * @returns The thumbnail configuration from the theme, or undefined if not found\n *\n * @example\n * ```typescript\n * // Load from theme directory\n * const themeConfig = loadThemeConfig('/path/to/theme');\n *\n * // Load from current directory\n * const themeConfig = loadThemeConfig();\n * ```\n */\nexport function loadThemeConfig(themePath?: string): ThumbnailConfig | undefined {\n const themeConfigPaths: string[] = [path.resolve(process.cwd(), 'themeConfig.json')];\n\n if (themePath) {\n themeConfigPaths.push(path.resolve(themePath, 'themeConfig.json'));\n }\n\n for (const configPath of themeConfigPaths) {\n if (fs.existsSync(configPath)) {\n try {\n const configData = JSON.parse(fs.readFileSync(configPath, 'utf8'));\n const parsed = ThemeConfigSchema.safeParse(configData);\n if (parsed.success) {\n return parsed.data.thumbnails;\n }\n // Log validation errors for debugging\n if (process.env.DEBUG || process.env.VERBOSE) {\n console.warn(`Failed to validate themeConfig at ${configPath}:`, parsed.error.message);\n }\n } catch (error) {\n // Log parse errors for debugging\n if (process.env.DEBUG || process.env.VERBOSE) {\n console.warn(`Failed to parse themeConfig at ${configPath}:`, error);\n }\n }\n }\n }\n\n return undefined;\n}\n\n/**\n * Load gallery data from a JSON file.\n *\n * @param galleryJsonPath - Path to the gallery.json file. Defaults to './gallery.json'.\n * @param options - Optional settings for loading behavior.\n * @returns The parsed gallery data\n * @throws Error if file cannot be read, parsed, or fails validation\n *\n * @example\n * ```typescript\n * // Basic usage (no validation)\n * const gallery = loadGalleryData('./gallery.json');\n *\n * // With schema validation\n * const gallery = loadGalleryData('./gallery.json', { validate: true });\n * ```\n */\nexport function loadGalleryData(galleryJsonPath = './gallery.json', options?: LoadGalleryDataOptions): GalleryData {\n const galleryData = JSON.parse(fs.readFileSync(galleryJsonPath, 'utf8'));\n\n if (options?.validate) {\n const result = GalleryDataSchema.safeParse(galleryData);\n if (!result.success) {\n throw new Error(`Invalid gallery.json at ${galleryJsonPath}: ${result.error.message}`);\n }\n return result.data;\n }\n\n return galleryData as GalleryData;\n}\n","import path from 'node:path';\n\nimport { extractThumbnailConfigFromGallery, mergeThumbnailConfig, type ThumbnailConfig } from './config';\nimport { LANDSCAPE_SIZES, PORTRAIT_SIZES } from './constants';\nimport { renderMarkdown } from './markdown';\nimport { buildHeroSrcset, getPhotoPath, getRelativePath, getSubgalleryThumbnailPath, getThumbnailPath } from './paths';\n\nimport type { GalleryData, GallerySection, MediaFile, SubGallery } from '../gallery';\nimport type { ResolvedGalleryData, ResolvedHero, ResolvedImage, ResolvedSection, ResolvedSubGallery } from './types';\n\n/**\n * Resolve a single image with all paths computed.\n */\nfunction resolveImage(image: MediaFile, mediaBaseUrl?: string, thumbsBaseUrl?: string): ResolvedImage {\n const imagePath = getPhotoPath(image.filename, mediaBaseUrl, image.url);\n const thumbnailPath = image.thumbnail\n ? getThumbnailPath(image.thumbnail.path, thumbsBaseUrl, image.thumbnail.baseUrl)\n : imagePath;\n\n const thumbnailSrcSet = image.thumbnail\n ? getThumbnailPath(image.thumbnail.path, thumbsBaseUrl, image.thumbnail.baseUrl) +\n ' 1x, ' +\n getThumbnailPath(image.thumbnail.pathRetina, thumbsBaseUrl, image.thumbnail.baseUrl) +\n ' 2x'\n : undefined;\n\n return {\n type: image.type,\n filename: image.filename,\n alt: image.alt,\n width: image.width,\n height: image.height,\n imagePath,\n thumbnailPath,\n thumbnailSrcSet,\n thumbnailWidth: image.thumbnail?.width,\n thumbnailHeight: image.thumbnail?.height,\n blurHash: image.thumbnail?.blurHash,\n };\n}\n\n/**\n * Resolve a section with parsed markdown and resolved image paths.\n */\nasync function resolveSection(\n section: GallerySection,\n mediaBaseUrl?: string,\n thumbsBaseUrl?: string,\n): Promise<ResolvedSection> {\n const parsedDescription = section.description ? await renderMarkdown(section.description) : '';\n\n return {\n title: section.title,\n description: section.description,\n parsedDescription,\n images: section.images.map((img) => resolveImage(img, mediaBaseUrl, thumbsBaseUrl)),\n };\n}\n\n/**\n * Resolve a sub-gallery with computed thumbnail path and optional resolved path.\n */\nfunction resolveSubGallery(subGallery: SubGallery, galleryJsonPath?: string): ResolvedSubGallery {\n return {\n title: subGallery.title,\n headerImage: subGallery.headerImage,\n path: subGallery.path,\n thumbnailPath: getSubgalleryThumbnailPath(subGallery.headerImage),\n resolvedPath: galleryJsonPath ? getRelativePath(subGallery.path, galleryJsonPath) : undefined,\n };\n}\n\n/**\n * Resolve hero data with all paths computed and srcsets built.\n */\nasync function resolveHero(gallery: GalleryData): Promise<ResolvedHero> {\n const { title, description, headerImage, headerImageBlurHash, headerImageVariants, mediaBaseUrl, thumbsBaseUrl } = gallery;\n\n const parsedDescription = description ? await renderMarkdown(description) : '';\n const imgBasename = headerImage ? path.basename(headerImage, path.extname(headerImage)) : 'header';\n const thumbnailBasePath = thumbsBaseUrl || 'gallery/images';\n const headerPhotoPath = getPhotoPath(headerImage || '', mediaBaseUrl);\n\n // Determine which sources to show based on headerImageVariants\n // If headerImageVariants is not set, use all generated paths (default behavior)\n const useDefaultPaths = !headerImageVariants;\n\n const srcsets = {\n portraitAvif: buildHeroSrcset(\n headerImageVariants?.portrait?.avif,\n PORTRAIT_SIZES,\n thumbnailBasePath,\n imgBasename,\n 'portrait',\n 'avif',\n useDefaultPaths,\n ),\n portraitJpg: buildHeroSrcset(\n headerImageVariants?.portrait?.jpg,\n PORTRAIT_SIZES,\n thumbnailBasePath,\n imgBasename,\n 'portrait',\n 'jpg',\n useDefaultPaths,\n ),\n landscapeAvif: buildHeroSrcset(\n headerImageVariants?.landscape?.avif,\n LANDSCAPE_SIZES,\n thumbnailBasePath,\n imgBasename,\n 'landscape',\n 'avif',\n useDefaultPaths,\n ),\n landscapeJpg: buildHeroSrcset(\n headerImageVariants?.landscape?.jpg,\n LANDSCAPE_SIZES,\n thumbnailBasePath,\n imgBasename,\n 'landscape',\n 'jpg',\n useDefaultPaths,\n ),\n };\n\n return {\n title,\n description,\n parsedDescription,\n headerImage,\n headerPhotoPath,\n headerImageBlurHash,\n headerImageVariants,\n thumbnailBasePath,\n imgBasename,\n srcsets,\n };\n}\n\n/**\n * Options for resolving gallery data.\n */\nexport interface ResolveGalleryDataOptions {\n /**\n * Path to the gallery.json file. When provided, enables resolution of\n * relative paths for sub-galleries (resolvedPath field).\n */\n galleryJsonPath?: string;\n /**\n * Theme-specific thumbnail configuration from themeConfig.json.\n * Used as fallback when gallery.json doesn't specify thumbnail settings.\n */\n themeConfig?: ThumbnailConfig;\n /**\n * CLI-specified thumbnail configuration (highest priority).\n * Overrides both gallery.json and theme config settings.\n */\n cliConfig?: ThumbnailConfig;\n}\n\n/**\n * Transform raw gallery data into a fully resolved structure with all paths\n * computed and markdown parsed. This is the main API for themes.\n *\n * @param gallery - Raw gallery data from loadGalleryData()\n * @param options - Optional configuration for path resolution\n * @returns Fully resolved gallery data ready for rendering\n */\nexport async function resolveGalleryData(\n gallery: GalleryData,\n options?: ResolveGalleryDataOptions,\n): Promise<ResolvedGalleryData> {\n const { mediaBaseUrl, thumbsBaseUrl, subGalleries } = gallery;\n const { galleryJsonPath, themeConfig, cliConfig } = options ?? {};\n\n const hero = await resolveHero(gallery);\n const sections = await Promise.all(\n gallery.sections.map((section) => resolveSection(section, mediaBaseUrl, thumbsBaseUrl)),\n );\n\n const resolvedSubGalleries = subGalleries?.galleries?.length\n ? {\n title: subGalleries.title,\n galleries: subGalleries.galleries.map((sg) => resolveSubGallery(sg, galleryJsonPath)),\n }\n : undefined;\n\n // Merge thumbnail config: CLI > gallery.json > themeConfig > defaults\n const galleryThumbnailConfig = extractThumbnailConfigFromGallery(gallery);\n const thumbnails = mergeThumbnailConfig(cliConfig, galleryThumbnailConfig, themeConfig);\n\n return {\n title: gallery.title,\n url: gallery.url,\n metadata: gallery.metadata,\n analyticsScript: gallery.analyticsScript,\n ctaBanner: gallery.ctaBanner,\n hero,\n sections,\n subGalleries: resolvedSubGalleries,\n mediaBaseUrl,\n thumbsBaseUrl,\n thumbnails,\n };\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\n\n/** Astro integration type (simplified to avoid astro dependency in common) */\ninterface AstroIntegration {\n name: string;\n hooks: {\n 'astro:build:done': (options: { dir: URL }) => void;\n };\n}\n\n/**\n * Astro integration to prevent empty content collection files from being generated.\n * Removes empty content-assets.mjs and content-modules.mjs files after build.\n */\nexport function preventEmptyContentFiles(): AstroIntegration {\n return {\n name: 'prevent-empty-content-files',\n hooks: {\n 'astro:build:done': ({ dir }) => {\n const filesToRemove = ['content-assets.mjs', 'content-modules.mjs'];\n for (const fileName of filesToRemove) {\n const filePath = path.join(dir.pathname, fileName);\n if (fs.existsSync(filePath)) {\n try {\n const content = fs.readFileSync(filePath, 'utf8');\n if (content.trim() === 'export default new Map();' || content.trim() === '') {\n fs.unlinkSync(filePath);\n }\n } catch {\n // Silently ignore errors\n }\n }\n }\n },\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/theme/config.ts","../src/theme/constants.ts","../src/theme/markdown.ts","../src/theme/paths.ts","../src/gallery/schemas.ts","../src/theme/loader.ts","../src/theme/resolver.ts","../src/theme/astro.ts"],"names":["z","path","fs"],"mappings":"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","file":"theme.js","sourcesContent":["import { z } from 'zod';\n\n/** Zod schema for thumbnail configuration */\nexport const ThumbnailConfigSchema = z.object({\n size: z.number().min(50).max(4000).optional(),\n edge: z.enum(['auto', 'width', 'height']).optional(),\n});\n\n/** Zod schema for theme configuration file (themeConfig.json) */\nexport const ThemeConfigSchema = z.object({\n thumbnails: ThumbnailConfigSchema.optional(),\n});\n\n/** TypeScript type for thumbnail configuration */\nexport type ThumbnailConfig = z.infer<typeof ThumbnailConfigSchema>;\n\n/** TypeScript type for theme configuration */\nexport type ThemeConfig = z.infer<typeof ThemeConfigSchema>;\n\n/** Default thumbnail configuration values */\nexport const DEFAULT_THUMBNAIL_CONFIG: Required<ThumbnailConfig> = {\n size: 300,\n edge: 'auto',\n};\n\n/**\n * Extracts thumbnail config from gallery data.\n * @param gallery - The gallery data object\n * @returns ThumbnailConfig with values from gallery data\n */\nexport function extractThumbnailConfigFromGallery(gallery: { thumbnails?: ThumbnailConfig }): ThumbnailConfig {\n return {\n size: gallery.thumbnails?.size,\n edge: gallery.thumbnails?.edge,\n };\n}\n\n/**\n * Merges thumbnail configurations with hierarchy:\n * 1. CLI flags (highest precedence)\n * 2. gallery.json settings\n * 3. themeConfig.json (theme defaults)\n * 4. Built-in defaults (lowest)\n *\n * @param cliConfig - Config from CLI flags (optional)\n * @param galleryConfig - Config from gallery.json (optional)\n * @param themeConfig - Config from themeConfig.json (optional)\n * @returns Merged thumbnail configuration with all values resolved\n */\nexport function mergeThumbnailConfig(\n cliConfig?: ThumbnailConfig,\n galleryConfig?: ThumbnailConfig,\n themeConfig?: ThumbnailConfig,\n): Required<ThumbnailConfig> {\n return {\n size: cliConfig?.size ?? galleryConfig?.size ?? themeConfig?.size ?? DEFAULT_THUMBNAIL_CONFIG.size,\n edge: cliConfig?.edge ?? galleryConfig?.edge ?? themeConfig?.edge ?? DEFAULT_THUMBNAIL_CONFIG.edge,\n };\n}\n","/** Portrait image sizes for responsive hero images */\nexport const PORTRAIT_SIZES = [360, 480, 720, 1080] as const;\n\n/** Landscape image sizes for responsive hero images */\nexport const LANDSCAPE_SIZES = [640, 960, 1280, 1920, 2560, 3840] as const;\n","import { marked } from 'marked';\n\n// Configure marked to only allow specific formatting options\nconst renderer = new marked.Renderer();\n\n// Disable headings by rendering them as paragraphs\nrenderer.heading = ({ text }: { text: string }) => {\n return '<p>' + text + '</p>\\n';\n};\n\n// Disable images\nrenderer.image = () => '';\n\n// Disable HTML\nrenderer.html = () => '';\n\n// Disable tables\nrenderer.table = () => '';\nrenderer.tablerow = () => '';\nrenderer.tablecell = () => '';\n\n// Configure marked options\nmarked.use({\n renderer: renderer,\n breaks: true,\n gfm: true,\n});\n\n/**\n * Renders markdown with limited formatting options.\n * Supported: paragraphs, bold, italic, lists, code blocks, blockquotes, links\n * Disabled: headings (rendered as paragraphs), images, HTML, tables\n */\nexport async function renderMarkdown(markdown: string): Promise<string> {\n if (!markdown) return '';\n return await marked.parse(markdown);\n}\n","import path from 'node:path';\n\n/**\n * Normalizes resource paths to be relative to the gallery root directory.\n *\n * @param resourcePath - The resource path (file or directory), typically relative to the gallery.json file\n * @param galleryJsonPath - Path to the gallery.json file used to resolve relative paths\n * @returns The normalized path relative to the gallery root directory\n */\nexport function getRelativePath(resourcePath: string, galleryJsonPath: string): string {\n const galleryConfigPath = path.resolve(galleryJsonPath);\n const galleryConfigDir = path.dirname(galleryConfigPath);\n\n const absoluteResourcePath = path.resolve(path.join(galleryConfigDir, resourcePath));\n const baseDir = path.dirname(galleryConfigDir);\n\n return path.relative(baseDir, absoluteResourcePath);\n}\n\n/**\n * Get the path to a thumbnail that is relative to the gallery root directory or the thumbnails base URL.\n *\n * @param resourcePath - The resource path (file or directory), typically relative to the gallery.json file\n * @param thumbsBaseUrl - The base URL for the thumbnails (gallery-level)\n * @param thumbnailBaseUrl - Optional thumbnail-specific base URL that overrides thumbsBaseUrl if provided\n * @returns The normalized path relative to the gallery root directory or the thumbnails base URL\n */\nexport function getThumbnailPath(resourcePath: string, thumbsBaseUrl?: string, thumbnailBaseUrl?: string): string {\n // If thumbnail-specific baseUrl is provided, use it and combine with the path\n if (thumbnailBaseUrl) {\n return `${thumbnailBaseUrl}/${resourcePath}`;\n }\n // Otherwise, use the gallery-level thumbsBaseUrl if provided\n return thumbsBaseUrl ? `${thumbsBaseUrl}/${resourcePath}` : `gallery/images/${path.basename(resourcePath)}`;\n}\n\n/**\n * Get the path to a photo that is always in the gallery root directory.\n *\n * @param filename - The filename to get the path for\n * @param mediaBaseUrl - The base URL for the media\n * @param url - Optional URL that, if provided, will be used directly regardless of base URL or path\n * @returns The normalized path relative to the gallery root directory, or the provided URL\n */\nexport function getPhotoPath(filename: string, mediaBaseUrl?: string, url?: string): string {\n // If url is provided, always use it regardless of base URL or path\n if (url) {\n return url;\n }\n\n return mediaBaseUrl ? `${mediaBaseUrl}/${filename}` : filename;\n}\n\n/**\n * Get the path to a subgallery thumbnail that is always in the subgallery directory.\n *\n * @param subgalleryHeaderImagePath - The path to the subgallery header image on the hard disk\n * @returns The normalized path relative to the subgallery directory\n */\nexport function getSubgalleryThumbnailPath(subgalleryHeaderImagePath: string): string {\n const photoBasename = path.basename(subgalleryHeaderImagePath);\n const subgalleryFolderName = path.basename(path.dirname(subgalleryHeaderImagePath));\n\n return path.join(subgalleryFolderName, 'gallery', 'thumbnails', photoBasename);\n}\n\n/**\n * Build a srcset string for responsive images.\n * Uses custom paths from variants when provided, otherwise generates default paths.\n *\n * @param variants - Optional record mapping sizes to custom URLs\n * @param sizes - Array of image widths to include\n * @param thumbnailBasePath - Base path for generated thumbnails\n * @param imgBasename - Image basename for generated paths\n * @param orientation - 'portrait' or 'landscape'\n * @param format - Image format ('avif' or 'jpg')\n * @param useDefaultPaths - Whether to use generated paths when no custom variant exists\n * @returns Comma-separated srcset string\n */\nexport function buildHeroSrcset(\n variants: Record<number, string | undefined> | undefined,\n sizes: readonly number[],\n thumbnailBasePath: string,\n imgBasename: string,\n orientation: 'portrait' | 'landscape',\n format: 'avif' | 'jpg',\n useDefaultPaths: boolean,\n): string {\n return sizes\n .map((size) => {\n const customPath = variants?.[size];\n if (customPath) {\n return `${customPath} ${size}w`;\n }\n if (useDefaultPaths) {\n return `${thumbnailBasePath}/${imgBasename}_${orientation}_${size}.${format} ${size}w`;\n }\n return null;\n })\n .filter(Boolean)\n .join(', ');\n}\n","import { z } from 'zod';\n\n/** Zod schema for thumbnail metadata including path and dimensions */\nexport const ThumbnailSchema = z.object({\n baseUrl: z.string().optional(),\n path: z.string(),\n pathRetina: z.string(),\n width: z.number(),\n height: z.number(),\n blurHash: z.string().optional(),\n});\n\n/** Zod schema for media file metadata including type, dimensions, and thumbnail info */\nexport const MediaFileSchema = z.object({\n type: z.enum(['image', 'video']),\n filename: z.string(),\n url: z.string().optional(),\n alt: z.string().optional(),\n width: z.number(),\n height: z.number(),\n thumbnail: ThumbnailSchema.optional(),\n lastMediaTimestamp: z.string().optional(),\n});\n\n/**\n * Zod schema for media file with path.\n * @deprecated Use MediaFileSchema instead which uses 'filename' instead of 'path'.\n */\nexport const MediaFileDeprecatedSchema = z.object({\n type: z.enum(['image', 'video']),\n path: z.string(),\n alt: z.string().optional(),\n width: z.number(),\n height: z.number(),\n thumbnail: ThumbnailSchema.optional(),\n lastMediaTimestamp: z.string().optional(),\n});\n\n/** Zod schema for a gallery section containing title, description, and media files */\nexport const GallerySectionSchema = z.object({\n title: z.string().optional(),\n description: z.string().optional(),\n images: z.array(MediaFileSchema),\n});\n\n/**\n * Zod schema for a gallery section containing title, description, and media files.\n * @deprecated Use GallerySectionSchema instead which uses MediaFileSchema.\n */\nexport const GallerySectionDeprecatedSchema = z.object({\n title: z.string().optional(),\n description: z.string().optional(),\n images: z.array(MediaFileDeprecatedSchema),\n});\n\n/** Zod schema for sub-gallery metadata including title, header image, and path */\nexport const SubGallerySchema = z.object({\n title: z.string(),\n headerImage: z.string(),\n path: z.string(),\n});\n\n/** Zod schema for portrait image size variants */\nconst PortraitSizesSchema = z.object({\n 360: z.string().optional(),\n 480: z.string().optional(),\n 720: z.string().optional(),\n 1080: z.string().optional(),\n});\n\n/** Zod schema for landscape image size variants */\nconst LandscapeSizesSchema = z.object({\n 640: z.string().optional(),\n 960: z.string().optional(),\n 1280: z.string().optional(),\n 1920: z.string().optional(),\n 2560: z.string().optional(),\n 3840: z.string().optional(),\n});\n\n/** Zod schema for header image variants allowing explicit specification of responsive hero images */\nexport const HeaderImageVariantsSchema = z.object({\n portrait: z\n .object({\n avif: PortraitSizesSchema.optional(),\n jpg: PortraitSizesSchema.optional(),\n })\n .optional(),\n landscape: z\n .object({\n avif: LandscapeSizesSchema.optional(),\n jpg: LandscapeSizesSchema.optional(),\n })\n .optional(),\n});\n\n/** Zod schema for complete gallery data including metadata, sections, and sub-galleries */\nexport const GalleryMetadataSchema = z.object({\n image: z.string().optional(),\n imageWidth: z.number().optional(),\n imageHeight: z.number().optional(),\n ogUrl: z.string().optional(),\n ogType: z.string().optional(),\n ogSiteName: z.string().optional(),\n twitterSite: z.string().optional(),\n twitterCreator: z.string().optional(),\n author: z.string().optional(),\n keywords: z.string().optional(),\n canonicalUrl: z.string().optional(),\n language: z.string().optional(),\n robots: z.string().optional(),\n});\n\n/** Zod schema for complete gallery data including metadata, sections, and sub-galleries */\nexport const GalleryDataSchema = z.object({\n title: z.string(),\n description: z.string(),\n mediaBasePath: z.string().optional(),\n url: z.string().optional(),\n headerImage: z.string(),\n headerImageBlurHash: z.string().optional(),\n headerImageVariants: HeaderImageVariantsSchema.optional(),\n theme: z.string().optional(),\n thumbnails: z\n .object({\n size: z.number().optional(),\n edge: z.enum(['auto', 'width', 'height']).optional(),\n })\n .optional(),\n metadata: GalleryMetadataSchema,\n mediaBaseUrl: z.string().optional(),\n thumbsBaseUrl: z.string().optional(),\n analyticsScript: z.string().optional(),\n ctaBanner: z.boolean().optional(),\n customStyles: z.record(z.string(), z.string()).optional(),\n sections: z.array(GallerySectionSchema),\n subGalleries: z.object({ title: z.string(), galleries: z.array(SubGallerySchema) }),\n});\n\n/**\n * Zod schema for complete gallery data without mediaBasePath.\n * @deprecated Use GalleryDataSchema instead which includes mediaBasePath and headerImageVariants.\n */\nexport const GalleryDataDeprecatedSchema = z.object({\n title: z.string(),\n description: z.string(),\n url: z.string().optional(),\n headerImage: z.string(),\n thumbnailSize: z.number().optional(),\n metadata: GalleryMetadataSchema,\n mediaBaseUrl: z.string().optional(),\n analyticsScript: z.string().optional(),\n sections: z.array(GallerySectionDeprecatedSchema),\n subGalleries: z.object({ title: z.string(), galleries: z.array(SubGallerySchema) }),\n});\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport process from 'node:process';\n\nimport { ThemeConfigSchema, type ThumbnailConfig } from './config';\n\nimport { GalleryDataSchema, type GalleryData } from '../gallery';\n\nexport interface LoadGalleryDataOptions {\n /**\n * When true, validates the loaded JSON against the GalleryData schema.\n * Throws a descriptive error if validation fails.\n * @default false\n */\n validate?: boolean;\n}\n\n/**\n * Load theme configuration from themeConfig.json file.\n *\n * Searches for themeConfig.json in the following locations (in priority order):\n * 1. Current working directory (process.cwd()) - checked first\n * 2. Provided themePath parameter - checked second\n *\n * The first valid configuration found is returned. This means a themeConfig.json\n * in the project root will take precedence over the theme's built-in configuration,\n * allowing users to override theme defaults without modifying the theme itself.\n *\n * **Note for theme authors:** Your theme's themeConfig.json provides sensible defaults,\n * but users can override these by placing their own themeConfig.json in their project root.\n *\n * @param themePath - Optional path to the theme directory\n * @returns The thumbnail configuration from the theme, or undefined if not found\n *\n * @example\n * ```typescript\n * // Load from theme directory\n * const themeConfig = loadThemeConfig('/path/to/theme');\n *\n * // Load from current directory\n * const themeConfig = loadThemeConfig();\n * ```\n */\nexport function loadThemeConfig(themePath?: string): ThumbnailConfig | undefined {\n const themeConfigPaths: string[] = [path.resolve(process.cwd(), 'themeConfig.json')];\n\n if (themePath) {\n themeConfigPaths.push(path.resolve(themePath, 'themeConfig.json'));\n }\n\n for (const configPath of themeConfigPaths) {\n if (fs.existsSync(configPath)) {\n try {\n const configData = JSON.parse(fs.readFileSync(configPath, 'utf8'));\n const parsed = ThemeConfigSchema.safeParse(configData);\n if (parsed.success) {\n return parsed.data.thumbnails;\n }\n // Log validation errors for debugging\n if (process.env.DEBUG || process.env.VERBOSE) {\n console.warn(`Failed to validate themeConfig at ${configPath}:`, parsed.error.message);\n }\n } catch (error) {\n // Log parse errors for debugging\n if (process.env.DEBUG || process.env.VERBOSE) {\n console.warn(`Failed to parse themeConfig at ${configPath}:`, error);\n }\n }\n }\n }\n\n return undefined;\n}\n\n/**\n * Load gallery data from a JSON file.\n *\n * @param galleryJsonPath - Path to the gallery.json file. Defaults to './gallery.json'.\n * @param options - Optional settings for loading behavior.\n * @returns The parsed gallery data\n * @throws Error if file cannot be read, parsed, or fails validation\n *\n * @example\n * ```typescript\n * // Basic usage (no validation)\n * const gallery = loadGalleryData('./gallery.json');\n *\n * // With schema validation\n * const gallery = loadGalleryData('./gallery.json', { validate: true });\n * ```\n */\nexport function loadGalleryData(galleryJsonPath = './gallery.json', options?: LoadGalleryDataOptions): GalleryData {\n const galleryData = JSON.parse(fs.readFileSync(galleryJsonPath, 'utf8'));\n\n if (options?.validate) {\n const result = GalleryDataSchema.safeParse(galleryData);\n if (!result.success) {\n throw new Error(`Invalid gallery.json at ${galleryJsonPath}: ${result.error.message}`);\n }\n return result.data;\n }\n\n return galleryData as GalleryData;\n}\n","import path from 'node:path';\n\nimport { extractThumbnailConfigFromGallery, mergeThumbnailConfig, type ThumbnailConfig } from './config';\nimport { LANDSCAPE_SIZES, PORTRAIT_SIZES } from './constants';\nimport { renderMarkdown } from './markdown';\nimport { buildHeroSrcset, getPhotoPath, getRelativePath, getSubgalleryThumbnailPath, getThumbnailPath } from './paths';\n\nimport type { GalleryData, GallerySection, MediaFile, SubGallery } from '../gallery';\nimport type { ResolvedGalleryData, ResolvedHero, ResolvedImage, ResolvedSection, ResolvedSubGallery } from './types';\n\n/**\n * Resolve a single image with all paths computed.\n */\nfunction resolveImage(image: MediaFile, mediaBaseUrl?: string, thumbsBaseUrl?: string): ResolvedImage {\n const imagePath = getPhotoPath(image.filename, mediaBaseUrl, image.url);\n const thumbnailPath = image.thumbnail\n ? getThumbnailPath(image.thumbnail.path, thumbsBaseUrl, image.thumbnail.baseUrl)\n : imagePath;\n\n const thumbnailSrcSet = image.thumbnail\n ? getThumbnailPath(image.thumbnail.path, thumbsBaseUrl, image.thumbnail.baseUrl) +\n ' 1x, ' +\n getThumbnailPath(image.thumbnail.pathRetina, thumbsBaseUrl, image.thumbnail.baseUrl) +\n ' 2x'\n : undefined;\n\n return {\n type: image.type,\n filename: image.filename,\n alt: image.alt,\n width: image.width,\n height: image.height,\n imagePath,\n thumbnailPath,\n thumbnailSrcSet,\n thumbnailWidth: image.thumbnail?.width,\n thumbnailHeight: image.thumbnail?.height,\n blurHash: image.thumbnail?.blurHash,\n };\n}\n\n/**\n * Resolve a section with parsed markdown and resolved image paths.\n */\nasync function resolveSection(\n section: GallerySection,\n mediaBaseUrl?: string,\n thumbsBaseUrl?: string,\n): Promise<ResolvedSection> {\n const parsedDescription = section.description ? await renderMarkdown(section.description) : '';\n\n return {\n title: section.title,\n description: section.description,\n parsedDescription,\n images: section.images.map((img) => resolveImage(img, mediaBaseUrl, thumbsBaseUrl)),\n };\n}\n\n/**\n * Resolve a sub-gallery with computed thumbnail path and optional resolved path.\n */\nfunction resolveSubGallery(subGallery: SubGallery, galleryJsonPath?: string): ResolvedSubGallery {\n return {\n title: subGallery.title,\n headerImage: subGallery.headerImage,\n path: subGallery.path,\n thumbnailPath: getSubgalleryThumbnailPath(subGallery.headerImage),\n resolvedPath: galleryJsonPath ? getRelativePath(subGallery.path, galleryJsonPath) : undefined,\n };\n}\n\n/**\n * Resolve hero data with all paths computed and srcsets built.\n */\nasync function resolveHero(gallery: GalleryData): Promise<ResolvedHero> {\n const { title, description, headerImage, headerImageBlurHash, headerImageVariants, mediaBaseUrl, thumbsBaseUrl } = gallery;\n\n const parsedDescription = description ? await renderMarkdown(description) : '';\n const imgBasename = headerImage ? path.basename(headerImage, path.extname(headerImage)) : 'header';\n const thumbnailBasePath = thumbsBaseUrl || 'gallery/images';\n const headerPhotoPath = getPhotoPath(headerImage || '', mediaBaseUrl);\n\n // Determine which sources to show based on headerImageVariants\n // If headerImageVariants is not set, use all generated paths (default behavior)\n const useDefaultPaths = !headerImageVariants;\n\n const srcsets = {\n portraitAvif: buildHeroSrcset(\n headerImageVariants?.portrait?.avif,\n PORTRAIT_SIZES,\n thumbnailBasePath,\n imgBasename,\n 'portrait',\n 'avif',\n useDefaultPaths,\n ),\n portraitJpg: buildHeroSrcset(\n headerImageVariants?.portrait?.jpg,\n PORTRAIT_SIZES,\n thumbnailBasePath,\n imgBasename,\n 'portrait',\n 'jpg',\n useDefaultPaths,\n ),\n landscapeAvif: buildHeroSrcset(\n headerImageVariants?.landscape?.avif,\n LANDSCAPE_SIZES,\n thumbnailBasePath,\n imgBasename,\n 'landscape',\n 'avif',\n useDefaultPaths,\n ),\n landscapeJpg: buildHeroSrcset(\n headerImageVariants?.landscape?.jpg,\n LANDSCAPE_SIZES,\n thumbnailBasePath,\n imgBasename,\n 'landscape',\n 'jpg',\n useDefaultPaths,\n ),\n };\n\n return {\n title,\n description,\n parsedDescription,\n headerImage,\n headerPhotoPath,\n headerImageBlurHash,\n headerImageVariants,\n thumbnailBasePath,\n imgBasename,\n srcsets,\n };\n}\n\n/**\n * Options for resolving gallery data.\n */\nexport interface ResolveGalleryDataOptions {\n /**\n * Path to the gallery.json file. When provided, enables resolution of\n * relative paths for sub-galleries (resolvedPath field).\n */\n galleryJsonPath?: string;\n /**\n * Theme-specific thumbnail configuration from themeConfig.json.\n * Used as fallback when gallery.json doesn't specify thumbnail settings.\n */\n themeConfig?: ThumbnailConfig;\n /**\n * CLI-specified thumbnail configuration (highest priority).\n * Overrides both gallery.json and theme config settings.\n */\n cliConfig?: ThumbnailConfig;\n}\n\n/**\n * Transform raw gallery data into a fully resolved structure with all paths\n * computed and markdown parsed. This is the main API for themes.\n *\n * @param gallery - Raw gallery data from loadGalleryData()\n * @param options - Optional configuration for path resolution\n * @returns Fully resolved gallery data ready for rendering\n */\nexport async function resolveGalleryData(\n gallery: GalleryData,\n options?: ResolveGalleryDataOptions,\n): Promise<ResolvedGalleryData> {\n const { mediaBaseUrl, thumbsBaseUrl, subGalleries } = gallery;\n const { galleryJsonPath, themeConfig, cliConfig } = options ?? {};\n\n const hero = await resolveHero(gallery);\n const sections = await Promise.all(\n gallery.sections.map((section) => resolveSection(section, mediaBaseUrl, thumbsBaseUrl)),\n );\n\n const resolvedSubGalleries = subGalleries?.galleries?.length\n ? {\n title: subGalleries.title,\n galleries: subGalleries.galleries.map((sg) => resolveSubGallery(sg, galleryJsonPath)),\n }\n : undefined;\n\n // Merge thumbnail config: CLI > gallery.json > themeConfig > defaults\n const galleryThumbnailConfig = extractThumbnailConfigFromGallery(gallery);\n const thumbnails = mergeThumbnailConfig(cliConfig, galleryThumbnailConfig, themeConfig);\n\n return {\n title: gallery.title,\n url: gallery.url,\n metadata: gallery.metadata,\n analyticsScript: gallery.analyticsScript,\n ctaBanner: gallery.ctaBanner,\n hero,\n sections,\n subGalleries: resolvedSubGalleries,\n mediaBaseUrl,\n thumbsBaseUrl,\n thumbnails,\n customStyles: gallery.customStyles,\n };\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\n\n/** Astro integration type (simplified to avoid astro dependency in common) */\ninterface AstroIntegration {\n name: string;\n hooks: {\n 'astro:build:done': (options: { dir: URL }) => void;\n };\n}\n\n/**\n * Astro integration to prevent empty content collection files from being generated.\n * Removes empty content-assets.mjs and content-modules.mjs files after build.\n */\nexport function preventEmptyContentFiles(): AstroIntegration {\n return {\n name: 'prevent-empty-content-files',\n hooks: {\n 'astro:build:done': ({ dir }) => {\n const filesToRemove = ['content-assets.mjs', 'content-modules.mjs'];\n for (const fileName of filesToRemove) {\n const filePath = path.join(dir.pathname, fileName);\n if (fs.existsSync(filePath)) {\n try {\n const content = fs.readFileSync(filePath, 'utf8');\n if (content.trim() === 'export default new Map();' || content.trim() === '') {\n fs.unlinkSync(filePath);\n }\n } catch {\n // Silently ignore errors\n }\n }\n }\n },\n },\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simple-photo-gallery/common",
3
- "version": "2.1.2",
3
+ "version": "2.1.3",
4
4
  "description": "Shared utilities and types for Simple Photo Gallery",
5
5
  "license": "MIT",
6
6
  "author": "Vladimir Haltakov, Tomasz Rusin",
@@ -77,4 +77,4 @@
77
77
  "typescript": "^5.9.0",
78
78
  "typescript-eslint": "^8.38.0"
79
79
  }
80
- }
80
+ }