yefeme 0.8.9 → 0.8.10

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bbce7b62320b843aa7f3d3bf7b7d733a2ad22b2dfe02127673a7bd5f09ff6d7c
4
- data.tar.gz: 7a6707abaefe1bf323fb5200204bcf03f0aa97d5c03504cbb376087540a93144
3
+ metadata.gz: '080bfd44d21f6f9ffe2dc4f171bb50fce8ce032d3feed441444c2c30ecb77bbe'
4
+ data.tar.gz: 48af270410eec82cf3953c2640978f7bcf47cb4c97a09f435d7d179d3c857dde
5
5
  SHA512:
6
- metadata.gz: 75afa28eb150f953b963149929cb45f24a319a5435b4663d5e95adc0ed8de5b95a191f884a7b02ff6c032423ed689283453d93291340fee4f90b0f1de21b640d
7
- data.tar.gz: 4f19e3f39202e576af151846dbb4c835c4f229b811bd9073183dde773e4b491f21e61ed9209eb1956a625872f80af11f928ae3f23f749aa32f0501e7f8ed46b9
6
+ metadata.gz: 4af6f45d6b415ee0a22b58c268573d3d9cca92b9008e6d26b26105e566af40bfb8fa3f2bc0e5e5763d029473fae8a685a802c630350cd9a4aa2dabc679c634d8
7
+ data.tar.gz: 491e1b847b25567d437ef9b7a479c0979b553c57aecffb562e88b08e57975effafb09424bed2fe2c31dff048ed72e343316fa8f8e93804a32c7805f41ba089c0
data/README.md CHANGED
@@ -80,7 +80,7 @@ images:
80
80
 
81
81
  The optional `cover` field selects the Cloudflare image ID used for the shoot's link preview (`og:image`). It defaults to the first image and uses the configured `xl` variant.
82
82
 
83
- The theme decodes each BlurHash in the browser and displays it as an immediate placeholder behind the full thumbnail. Selecting a thumbnail opens the shoot in a full-screen lightbox with button, keyboard, horizontal swipe, and native pinch-to-zoom navigation. Scalar image IDs remain supported for existing sites, but do not provide intrinsic sizing or placeholder information.
83
+ The theme decodes each BlurHash in the browser and displays it as an immediate placeholder behind the full thumbnail. Selecting a thumbnail opens the shoot in a full-screen lightbox with button, keyboard, and horizontal swipe navigation. Tap the backdrop or drag vertically to close; double-tap or pinch an image to zoom, then drag to pan. Scalar image IDs remain supported for existing sites, but do not provide intrinsic sizing or placeholder information.
84
84
 
85
85
  ## Contributing
86
86
 
@@ -92,6 +92,8 @@ To set up your environment to develop this theme, run `bundle install`.
92
92
 
93
93
  Check cover metadata with `bundle exec ruby test_cover.rb`.
94
94
 
95
+ Check lightbox gesture handling with `node --test test_lightbox.js`.
96
+
95
97
  Your theme is setup just like a normal Jekyll site! To test your theme, run `bundle exec jekyll serve` and open your browser at `http://localhost:4000`. This starts a Jekyll server using your theme. Add pages, documents, data, etc. like normal to test your theme's contents. As you make modifications to your theme and to your content, your site will regenerate and you should see the changes in the browser after a refresh, just like normal.
96
98
 
97
99
  Gem releases are built from a clean checkout and include the tracked theme layouts, includes, Sass, and browser assets selected by `yefeme.gemspec`. The release workflow verifies the package and rejects site content from `_posts` or `_shoots`.
@@ -37,10 +37,17 @@
37
37
  justify-content: center;
38
38
  padding: 0;
39
39
  position: relative;
40
+ transition: opacity 0.25s, visibility 0.25s;
40
41
  width: 2rem;
41
42
  z-index: 2;
42
43
  }
43
44
 
45
+ .modal.zoomed button {
46
+ opacity: 0;
47
+ pointer-events: none;
48
+ visibility: hidden;
49
+ }
50
+
44
51
  button svg {
45
52
  display: block;
46
53
  fill: none;
@@ -91,8 +98,15 @@
91
98
  display: flex;
92
99
  flex: 0 0 100%;
93
100
  justify-content: center;
101
+ opacity: var(--drag-opacity, 1);
94
102
  position: relative;
95
103
  scroll-snap-align: center;
104
+ transition: opacity 0.33s ease;
105
+ }
106
+
107
+ .slide.zooming,
108
+ .slide.zooming img {
109
+ touch-action: none;
96
110
  }
97
111
 
98
112
  .slide img {
@@ -106,20 +120,53 @@
106
120
  opacity: var(--resolution-opacity, 1);
107
121
  position: absolute;
108
122
  top: 50%;
109
- touch-action: manipulation;
110
- transform: translate(-50%, calc(-50% - 1.5rem));
111
- transition: opacity 0.3s ease;
123
+ touch-action: pan-x;
124
+ transform:
125
+ translate(-50%, calc(-50% - 1.5rem))
126
+ translateY(var(--drag-y, 0px));
127
+ transition: opacity 0.3s ease, transform 0.33s ease;
112
128
  user-select: none;
113
129
  width: auto;
114
130
  -webkit-user-drag: none;
115
131
  }
116
132
 
133
+ .slide.dragging,
134
+ .slide.dragging img {
135
+ transition: none;
136
+ }
137
+
138
+ .slide.settling {
139
+ transition: opacity 0.33s ease-out;
140
+ }
141
+
142
+ .slide.settling img {
143
+ transition: opacity 0.3s ease, transform 0.33s ease-out;
144
+ }
145
+
146
+ .slide.zooming img {
147
+ transform:
148
+ translate(-50%, calc(-50% - 1.5rem))
149
+ translate(var(--pan-x, 0px), var(--pan-y, 0px))
150
+ scale(var(--scale, 1));
151
+ transition: none;
152
+ }
153
+
154
+ .slide.zooming.zooming-paused img {
155
+ transition: opacity 0.3s ease, transform 0.33s ease;
156
+ }
157
+
158
+ .slide.zooming.panning img {
159
+ transition: none;
160
+ }
161
+
117
162
  .slide img.high-resolution {
118
163
  --resolution-opacity: 0;
164
+ pointer-events: none;
119
165
  }
120
166
 
121
167
  .slide img.high-resolution.loaded {
122
168
  --resolution-opacity: 1;
169
+ pointer-events: auto;
123
170
  }
124
171
 
125
172
  .status {
@@ -143,7 +190,16 @@
143
190
  max-height: 98dvh;
144
191
  max-width: calc(98vw - 6rem);
145
192
  max-width: calc(98dvw - 6rem);
146
- transform: translate(-50%, -50%);
193
+ transform:
194
+ translate(-50%, -50%)
195
+ translateY(var(--drag-y, 0px));
196
+ }
197
+
198
+ .slide.zooming img {
199
+ transform:
200
+ translate(-50%, -50%)
201
+ translate(var(--pan-x, 0px), var(--pan-y, 0px))
202
+ scale(var(--scale, 1));
147
203
  }
148
204
  }
149
205
 
@@ -164,6 +220,7 @@
164
220
 
165
221
  @media (prefers-reduced-motion: reduce) {
166
222
  .modal,
223
+ .slide,
167
224
  .slide img {
168
225
  transition: none;
169
226
  }
data/assets/lightbox.js CHANGED
@@ -1,12 +1,21 @@
1
1
  (function () {
2
2
  "use strict";
3
3
 
4
+ var DOUBLE_TAP_MAX_MS = 300;
5
+ var DOUBLE_TAP_MAX_DISTANCE = 30;
6
+ var DOUBLE_TAP_ZOOM_SCALE = 2;
7
+ var TAP_MAX_DISTANCE = 10;
8
+
4
9
  if (!window.customElements || window.customElements.get("shoot-lightbox")) return;
5
10
 
6
11
  function getImage(photo) {
7
12
  return photo.querySelector("img");
8
13
  }
9
14
 
15
+ function distanceBetween(first, second) {
16
+ return Math.hypot(second.clientX - first.clientX, second.clientY - first.clientY);
17
+ }
18
+
10
19
  class ShootLightbox extends HTMLElement {
11
20
  constructor() {
12
21
  super();
@@ -25,6 +34,14 @@
25
34
  if (!this.photos.length) return;
26
35
 
27
36
  this.currentPhoto = 0;
37
+ this.maxTouches = 0;
38
+ this.touchStarts = [];
39
+ this.zoomScale = 1;
40
+ this.panX = 0;
41
+ this.panY = 0;
42
+ this.startPan = { x: null, y: null };
43
+ this.lastTap = null;
44
+
28
45
  this.modal = this.shadowRoot.querySelector(".modal");
29
46
  this.track = this.shadowRoot.querySelector(".track");
30
47
  this.previousButton = this.shadowRoot.querySelector(".previous");
@@ -49,7 +66,7 @@
49
66
  image.loading = "eager";
50
67
  image.decoding = "async";
51
68
  image.draggable = false;
52
- image.addEventListener("click", (event) => event.stopPropagation());
69
+ this.bindImageEvents(image);
53
70
 
54
71
  slide.appendChild(image);
55
72
  this.track.appendChild(slide);
@@ -58,6 +75,14 @@
58
75
  this.slides = Array.from(this.track.querySelectorAll(".slide"));
59
76
  }
60
77
 
78
+ bindImageEvents(image) {
79
+ image.addEventListener("click", (event) => event.stopPropagation());
80
+ image.addEventListener("touchstart", this.onTouchStart, { passive: false });
81
+ image.addEventListener("touchmove", this.onTouchMove, { passive: false });
82
+ image.addEventListener("touchend", this.onTouchEnd, { passive: false });
83
+ image.addEventListener("touchcancel", this.onTouchCancel, { passive: false });
84
+ }
85
+
61
86
  loadHighResolutionImage(slide, photo) {
62
87
  if (!slide || !photo.href || slide.dataset.highResolutionRequested) return;
63
88
 
@@ -80,7 +105,7 @@
80
105
  image.loading = "eager";
81
106
  image.decoding = "async";
82
107
  image.draggable = false;
83
- image.addEventListener("click", (event) => event.stopPropagation());
108
+ this.bindImageEvents(image);
84
109
 
85
110
  var reveal = () => {
86
111
  if (revealed) return;
@@ -111,6 +136,7 @@
111
136
  this.previousButton.addEventListener("click", this.previous);
112
137
  this.nextButton.addEventListener("click", this.next);
113
138
  this.closeButton.addEventListener("click", this.close);
139
+ this.modal.addEventListener("click", this.close);
114
140
  this.track.addEventListener("scroll", this.onScroll, { passive: true });
115
141
  document.addEventListener("keydown", this.onKeydown);
116
142
  window.addEventListener("resize", this.onResize, { passive: true });
@@ -134,11 +160,20 @@
134
160
  event.stopPropagation();
135
161
  }
136
162
 
137
- if (this.modal.classList.contains("hidden")) return;
163
+ if (this.modal.classList.contains("hidden") || this.zoomScale !== 1) return;
164
+
165
+ var slide = this.getCurrentSlide();
138
166
 
139
167
  this.modal.classList.add("hidden");
140
168
  this.modal.setAttribute("aria-hidden", "true");
141
169
  document.documentElement.classList.remove("lightbox-open");
170
+ this.lastTap = null;
171
+
172
+ if (slide && slide.classList.contains("settling")) {
173
+ this.scheduleGestureReset(slide);
174
+ } else {
175
+ this.resetGestureState(slide);
176
+ }
142
177
 
143
178
  if (this.previouslyFocused) this.previouslyFocused.focus({ preventScroll: true });
144
179
  };
@@ -163,7 +198,18 @@
163
198
  return this.currentPhoto >= this.photos.length - 1;
164
199
  }
165
200
 
201
+ getCurrentSlide() {
202
+ return this.slides[this.currentPhoto];
203
+ }
204
+
205
+ getCurrentImage() {
206
+ var slide = this.getCurrentSlide();
207
+ return slide && (slide.querySelector(".high-resolution.loaded") || slide.querySelector("img"));
208
+ }
209
+
166
210
  updateCurrentPhoto(index, behavior) {
211
+ if (this.zoomScale !== 1) this.resetZoomState(this.getCurrentSlide());
212
+
167
213
  this.currentPhoto = Math.max(0, Math.min(this.photos.length - 1, index));
168
214
  this.track.scrollTo({
169
215
  left: this.currentPhoto * this.track.clientWidth,
@@ -180,7 +226,7 @@
180
226
  }
181
227
 
182
228
  onKeydown = (event) => {
183
- if (this.modal.classList.contains("hidden")) return;
229
+ if (this.modal.classList.contains("hidden") || this.zoomScale !== 1) return;
184
230
 
185
231
  if (event.key === "ArrowLeft") this.previous(event);
186
232
  if (event.key === "ArrowRight") this.next(event);
@@ -191,10 +237,16 @@
191
237
  window.clearTimeout(this.scrollSyncTimeout);
192
238
  this.scrollSyncTimeout = window.setTimeout(() => {
193
239
  var width = this.track.clientWidth || window.innerWidth;
194
- this.currentPhoto = Math.max(
240
+ var nextPhoto = Math.max(
195
241
  0,
196
242
  Math.min(this.photos.length - 1, Math.round(this.track.scrollLeft / width))
197
243
  );
244
+
245
+ if (nextPhoto !== this.currentPhoto && this.zoomScale !== 1) {
246
+ this.resetZoomState(this.getCurrentSlide());
247
+ }
248
+
249
+ this.currentPhoto = nextPhoto;
198
250
  this.updateControls();
199
251
  this.loadHighResolutionImage(this.slides[this.currentPhoto], this.photos[this.currentPhoto]);
200
252
  }, 100);
@@ -204,6 +256,256 @@
204
256
  if (this.modal.classList.contains("hidden")) return;
205
257
  this.updateCurrentPhoto(this.currentPhoto, "auto");
206
258
  };
259
+
260
+ onTouchStart = (event) => {
261
+ if (this.getCurrentSlide().classList.contains("settling")) this.resetGestureState();
262
+
263
+ this.touchStarts = Array.from(event.targetTouches);
264
+ this.maxTouches = Math.max(this.maxTouches, event.targetTouches.length);
265
+ this.startPan = { x: null, y: null };
266
+
267
+ if (this.touchStarts.length === 1) this.gestureDirection = undefined;
268
+ };
269
+
270
+ onTouchMove = (event) => {
271
+ this.maxTouches = Math.max(this.maxTouches, event.targetTouches.length);
272
+
273
+ if (this.maxTouches >= 2) {
274
+ this.pinchToZoom(event);
275
+ } else if (this.zoomScale === 1) {
276
+ this.maybeApplyVerticalDrag(event);
277
+ } else {
278
+ this.panZoomedImage(event);
279
+ }
280
+ };
281
+
282
+ onTouchEnd = (event) => {
283
+ if (event.targetTouches.length !== 0) return;
284
+
285
+ var slide = this.getCurrentSlide();
286
+
287
+ if (this.isDoubleTap(event)) {
288
+ if (this.zoomScale === 1) {
289
+ this.doubleTapZoomIn(event);
290
+ } else {
291
+ this.resetZoomState(slide);
292
+ }
293
+ } else if (this.zoomScale === 1) {
294
+ if (this.maxTouches === 1) this.finishVerticalDrag(event);
295
+ if (this.maxTouches >= 2) this.resetZoomState(slide);
296
+ } else if (this.maxTouches === 1) {
297
+ this.finishPanning();
298
+ } else if (this.maxTouches >= 2) {
299
+ this.pauseZooming();
300
+ }
301
+
302
+ this.maxTouches = 0;
303
+ };
304
+
305
+ onTouchCancel = () => {
306
+ this.lastTap = null;
307
+ this.maxTouches = 0;
308
+
309
+ if (this.zoomScale === 1) {
310
+ this.resetGestureState();
311
+ } else {
312
+ this.pauseZooming();
313
+ }
314
+ };
315
+
316
+ isDoubleTap(event) {
317
+ var touch = event.changedTouches[0];
318
+ var startedAsTap = touch &&
319
+ this.maxTouches === 1 &&
320
+ !this.gestureDirection &&
321
+ this.touchStarts[0] &&
322
+ distanceBetween(this.touchStarts[0], touch) < TAP_MAX_DISTANCE;
323
+
324
+ if (!startedAsTap) {
325
+ this.lastTap = null;
326
+ return false;
327
+ }
328
+
329
+ var isDoubleTap = this.lastTap &&
330
+ event.timeStamp - this.lastTap.time < DOUBLE_TAP_MAX_MS &&
331
+ distanceBetween(this.lastTap.touch, touch) < DOUBLE_TAP_MAX_DISTANCE;
332
+
333
+ this.lastTap = isDoubleTap ? null : { time: event.timeStamp, touch: touch };
334
+ return Boolean(isDoubleTap);
335
+ }
336
+
337
+ doubleTapZoomIn(event) {
338
+ this.resetGestureState();
339
+
340
+ var slide = this.getCurrentSlide();
341
+ var image = this.getCurrentImage();
342
+ var rect = image.getBoundingClientRect();
343
+
344
+ this.zoomScale = DOUBLE_TAP_ZOOM_SCALE;
345
+ this.panX = (1 - DOUBLE_TAP_ZOOM_SCALE) *
346
+ ((event.changedTouches[0].clientX - rect.left) - image.offsetWidth / 2);
347
+ this.panY = (1 - DOUBLE_TAP_ZOOM_SCALE) *
348
+ ((event.changedTouches[0].clientY - rect.top) - image.offsetHeight / 2);
349
+
350
+ slide.classList.add("zooming", "zooming-paused");
351
+ this.modal.classList.add("zoomed");
352
+ this.applyZoomStyles(slide);
353
+ }
354
+
355
+ pinchToZoom(event) {
356
+ var slide = this.getCurrentSlide();
357
+ if (slide.classList.contains("dragging") || event.targetTouches.length < 2) return;
358
+
359
+ var image = this.getCurrentImage();
360
+ var rect = image.getBoundingClientRect();
361
+ var firstTouch = event.targetTouches[0];
362
+ var secondTouch = event.targetTouches[1];
363
+ var distance = distanceBetween(firstTouch, secondTouch);
364
+ var previousScale = this.zoomScale;
365
+
366
+ event.preventDefault();
367
+ slide.classList.add("zooming");
368
+ slide.classList.remove("zooming-paused");
369
+ this.modal.classList.add("zoomed");
370
+
371
+ if (this.startDistance == null) {
372
+ this.startDistance = distanceBetween(this.touchStarts[0], this.touchStarts[1]);
373
+ this.startScale = this.zoomScale;
374
+ this.zoomAnchorPhotoX = ((firstTouch.clientX + secondTouch.clientX) / 2 - rect.left) / previousScale;
375
+ this.zoomAnchorPhotoY = ((firstTouch.clientY + secondTouch.clientY) / 2 - rect.top) / previousScale;
376
+ }
377
+
378
+ this.zoomScale = Math.max(1, this.startScale * (distance / this.startDistance));
379
+
380
+ var midpointX = (firstTouch.clientX + secondTouch.clientX) / 2;
381
+ var midpointY = (firstTouch.clientY + secondTouch.clientY) / 2;
382
+
383
+ this.panX += (midpointX - rect.left) - this.zoomScale * this.zoomAnchorPhotoX +
384
+ (image.offsetWidth / 2) * (this.zoomScale - previousScale);
385
+ this.panY += (midpointY - rect.top) - this.zoomScale * this.zoomAnchorPhotoY +
386
+ (image.offsetHeight / 2) * (this.zoomScale - previousScale);
387
+
388
+ this.applyZoomStyles(slide);
389
+ }
390
+
391
+ panZoomedImage(event) {
392
+ event.preventDefault();
393
+
394
+ var slide = this.getCurrentSlide();
395
+ var image = this.getCurrentImage();
396
+ var rect = image.getBoundingClientRect();
397
+ var touch = event.targetTouches[0];
398
+
399
+ if (this.startPan.x == null || this.startPan.y == null) {
400
+ slide.classList.add("panning");
401
+ this.startPan = {
402
+ x: (touch.clientX - rect.left) / this.zoomScale,
403
+ y: (touch.clientY - rect.top) / this.zoomScale
404
+ };
405
+ }
406
+
407
+ this.panX += (touch.clientX - rect.left) - this.startPan.x * this.zoomScale;
408
+ this.panY += (touch.clientY - rect.top) - this.startPan.y * this.zoomScale;
409
+ this.applyZoomStyles(slide);
410
+ }
411
+
412
+ applyZoomStyles(slide) {
413
+ slide.style.setProperty("--scale", this.zoomScale);
414
+ slide.style.setProperty("--pan-x", this.panX + "px");
415
+ slide.style.setProperty("--pan-y", this.panY + "px");
416
+ }
417
+
418
+ maybeApplyVerticalDrag(event) {
419
+ var touch = event.targetTouches[0];
420
+ if (!touch || !this.touchStarts[0]) return;
421
+
422
+ if (!this.gestureDirection && distanceBetween(this.touchStarts[0], touch) >= TAP_MAX_DISTANCE) {
423
+ this.gestureDirection = Math.abs(touch.clientX - this.touchStarts[0].clientX) >
424
+ Math.abs(touch.clientY - this.touchStarts[0].clientY) ? "horizontal" : "vertical";
425
+ }
426
+
427
+ if (this.gestureDirection !== "vertical") return;
428
+
429
+ event.preventDefault();
430
+ this.track.style.scrollSnapType = "none";
431
+ this.track.style.overflowX = "hidden";
432
+ this.applyVerticalDrag(touch.clientY - this.touchStarts[0].clientY);
433
+ }
434
+
435
+ applyVerticalDrag(distance) {
436
+ var slide = this.getCurrentSlide();
437
+ var maxDrag = window.innerHeight * 0.5;
438
+ var opacity = Math.max(0, Math.min(1, 1 - Math.abs(distance) / maxDrag));
439
+
440
+ slide.classList.add("dragging");
441
+ slide.style.setProperty("--drag-y", distance + "px");
442
+ slide.style.setProperty("--drag-opacity", opacity);
443
+ }
444
+
445
+ finishVerticalDrag(event) {
446
+ if (this.gestureDirection !== "vertical") return;
447
+
448
+ var slide = this.getCurrentSlide();
449
+ var distance = event.changedTouches[0].clientY - this.touchStarts[0].clientY;
450
+ var threshold = Math.min(window.innerHeight * 0.3, 150);
451
+
452
+ slide.classList.add("settling");
453
+
454
+ if (Math.abs(distance) < threshold) {
455
+ slide.style.setProperty("--drag-y", "0px");
456
+ slide.style.setProperty("--drag-opacity", "1");
457
+ this.scheduleGestureReset(slide);
458
+ return;
459
+ }
460
+
461
+ slide.style.setProperty("--drag-y", (distance > 0 ? distance + 200 : distance - 200) + "px");
462
+ slide.style.setProperty("--drag-opacity", "0");
463
+ this.close();
464
+ }
465
+
466
+ finishPanning() {
467
+ this.startPan = { x: null, y: null };
468
+ this.getCurrentSlide().classList.remove("panning");
469
+ }
470
+
471
+ pauseZooming() {
472
+ this.startDistance = null;
473
+ this.getCurrentSlide().classList.add("zooming-paused");
474
+ }
475
+
476
+ resetZoomState(slide) {
477
+ if (!slide) return;
478
+
479
+ this.resetGestureState(slide);
480
+ slide.classList.remove("zooming", "zooming-paused", "panning");
481
+ slide.style.removeProperty("--scale");
482
+ slide.style.removeProperty("--pan-x");
483
+ slide.style.removeProperty("--pan-y");
484
+ this.modal.classList.remove("zoomed");
485
+ this.zoomScale = 1;
486
+ this.panX = 0;
487
+ this.panY = 0;
488
+ }
489
+
490
+ scheduleGestureReset(slide) {
491
+ window.clearTimeout(this.gestureResetTimeout);
492
+ this.gestureResetTimeout = window.setTimeout(() => this.resetGestureState(slide), 350);
493
+ }
494
+
495
+ resetGestureState = (slide) => {
496
+ slide = slide || this.getCurrentSlide();
497
+ if (!slide) return;
498
+
499
+ window.clearTimeout(this.gestureResetTimeout);
500
+ slide.classList.remove("dragging", "settling");
501
+ slide.style.removeProperty("--drag-y");
502
+ slide.style.removeProperty("--drag-opacity");
503
+ this.track.style.scrollSnapType = "";
504
+ this.track.style.overflowX = "";
505
+ this.maxTouches = 0;
506
+ this.startDistance = null;
507
+ this.gestureDirection = undefined;
508
+ };
207
509
  }
208
510
 
209
511
  window.customElements.define("shoot-lightbox", ShootLightbox);
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yefeme
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.9
4
+ version: 0.8.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yefim Vedernikoff
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-14 00:00:00.000000000 Z
11
+ date: 2026-10-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jekyll