yefeme 0.8.5 → 0.8.7
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 +4 -4
- data/README.md +5 -5
- data/_includes/light-box.html +194 -0
- data/_layouts/shoot.html +4 -1
- data/_sass/yefeme.scss +6 -0
- data/assets/lightbox.js +211 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3c7317716ec9a0aebf898f16c054534d4d1600bdc9965e5c2876fdee545461ea
|
|
4
|
+
data.tar.gz: 43baa2e2347b94d9fe6cd6db04ce537faa7dfc2b8ac7074d99edf0cd6a4b4af2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 398591c9a678dd1269ff117014dc7cfab2616cb66c7a09db706ebe4978365dfdb129a45201eaffcf55703edc94c12842b54c5f72298d948170c057cef8569816
|
|
7
|
+
data.tar.gz: c3364c44ad14960d18d85c64d6c7ee7bbc2734b83701295d7edb2ee7af6acf28788b9f9cee2e7d1aabf1d328c76e4f92ca6432ceb81d4a37a40ca7fe66477e58
|
data/README.md
CHANGED
|
@@ -77,7 +77,7 @@ images:
|
|
|
77
77
|
---
|
|
78
78
|
```
|
|
79
79
|
|
|
80
|
-
The theme decodes each BlurHash in the browser and displays it as an immediate placeholder behind the full thumbnail. Scalar image IDs remain supported for existing sites, but do not provide intrinsic sizing or placeholder information.
|
|
80
|
+
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.
|
|
81
81
|
|
|
82
82
|
## Contributing
|
|
83
83
|
|
|
@@ -89,11 +89,11 @@ To set up your environment to develop this theme, run `bundle install`.
|
|
|
89
89
|
|
|
90
90
|
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.
|
|
91
91
|
|
|
92
|
-
|
|
92
|
+
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`.
|
|
93
93
|
|
|
94
94
|
## Releasing
|
|
95
95
|
|
|
96
|
-
Gem releases are published by GitHub Actions using RubyGems Trusted Publishing.
|
|
96
|
+
Gem releases are published by the [`Release gem`](.github/workflows/release.yml) GitHub Actions workflow using RubyGems Trusted Publishing. Publishing uses short-lived credentials, so the repository does not need a `RUBYGEMS_API_KEY` secret.
|
|
97
97
|
|
|
98
98
|
1. Update the version in `yefeme.gemspec` and merge the change to `master`.
|
|
99
99
|
2. Create and push the matching version tag, for example:
|
|
@@ -103,9 +103,9 @@ Gem releases are published by GitHub Actions using RubyGems Trusted Publishing.
|
|
|
103
103
|
git push origin v0.8.5
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
-
The release workflow verifies that the tag matches the gemspec, builds and inspects the package from a clean checkout, publishes it to RubyGems, and waits
|
|
106
|
+
The release workflow verifies that the tag matches the gemspec, builds and inspects the package from a clean checkout, publishes it to RubyGems, and waits until the release is available from RubyGems indexes.
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
Trusted Publishing is configured for `yefim/yefeme`, the `release.yml` workflow, and the `release` GitHub environment. Configure required reviewers on that environment if releases should retain a manual approval gate.
|
|
109
109
|
|
|
110
110
|
## License
|
|
111
111
|
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
<template id="shoot-lightbox-template">
|
|
2
|
+
<style>
|
|
3
|
+
* {
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.modal {
|
|
8
|
+
align-items: flex-end;
|
|
9
|
+
background: #fff;
|
|
10
|
+
display: flex;
|
|
11
|
+
gap: 1rem;
|
|
12
|
+
height: 100%;
|
|
13
|
+
inset: 0;
|
|
14
|
+
justify-content: center;
|
|
15
|
+
padding: 1rem;
|
|
16
|
+
position: fixed;
|
|
17
|
+
transition: opacity 0.25s, visibility 0.25s;
|
|
18
|
+
width: 100%;
|
|
19
|
+
z-index: 1000;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.modal.hidden {
|
|
23
|
+
opacity: 0;
|
|
24
|
+
pointer-events: none;
|
|
25
|
+
visibility: hidden;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
button {
|
|
29
|
+
align-items: center;
|
|
30
|
+
background: #999;
|
|
31
|
+
border: 0;
|
|
32
|
+
border-radius: 50%;
|
|
33
|
+
color: #fff;
|
|
34
|
+
cursor: pointer;
|
|
35
|
+
display: flex;
|
|
36
|
+
height: 2rem;
|
|
37
|
+
justify-content: center;
|
|
38
|
+
padding: 0;
|
|
39
|
+
position: relative;
|
|
40
|
+
width: 2rem;
|
|
41
|
+
z-index: 2;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
button svg {
|
|
45
|
+
display: block;
|
|
46
|
+
fill: none;
|
|
47
|
+
height: 1.125rem;
|
|
48
|
+
shape-rendering: geometricPrecision;
|
|
49
|
+
stroke: currentColor;
|
|
50
|
+
stroke-linecap: round;
|
|
51
|
+
stroke-linejoin: round;
|
|
52
|
+
stroke-width: 2.25;
|
|
53
|
+
width: 1.125rem;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
button:focus-visible {
|
|
57
|
+
outline: 2px solid currentColor;
|
|
58
|
+
outline-offset: 3px;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
button[disabled] {
|
|
62
|
+
background: #eee;
|
|
63
|
+
cursor: default;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.close {
|
|
67
|
+
position: absolute;
|
|
68
|
+
right: max(1rem, env(safe-area-inset-right));
|
|
69
|
+
top: max(1rem, env(safe-area-inset-top));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.track {
|
|
73
|
+
display: flex;
|
|
74
|
+
height: 100%;
|
|
75
|
+
inset: 0;
|
|
76
|
+
overflow-x: auto;
|
|
77
|
+
overflow-y: hidden;
|
|
78
|
+
position: absolute;
|
|
79
|
+
scroll-snap-type: x mandatory;
|
|
80
|
+
scrollbar-width: none;
|
|
81
|
+
width: 100%;
|
|
82
|
+
-webkit-overflow-scrolling: touch;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.track::-webkit-scrollbar {
|
|
86
|
+
display: none;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.slide {
|
|
90
|
+
align-items: center;
|
|
91
|
+
display: flex;
|
|
92
|
+
flex: 0 0 100%;
|
|
93
|
+
justify-content: center;
|
|
94
|
+
position: relative;
|
|
95
|
+
scroll-snap-align: center;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.slide img {
|
|
99
|
+
height: auto;
|
|
100
|
+
left: 50%;
|
|
101
|
+
max-height: calc(100vh - 5rem);
|
|
102
|
+
max-height: calc(100dvh - 5rem);
|
|
103
|
+
max-width: 98vw;
|
|
104
|
+
max-width: 98dvw;
|
|
105
|
+
object-fit: contain;
|
|
106
|
+
opacity: var(--resolution-opacity, 1);
|
|
107
|
+
position: absolute;
|
|
108
|
+
top: 50%;
|
|
109
|
+
touch-action: manipulation;
|
|
110
|
+
transform: translate(-50%, calc(-50% - 1.5rem));
|
|
111
|
+
transition: opacity 0.3s ease;
|
|
112
|
+
user-select: none;
|
|
113
|
+
width: auto;
|
|
114
|
+
-webkit-user-drag: none;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.slide img.high-resolution {
|
|
118
|
+
--resolution-opacity: 0;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.slide img.high-resolution.loaded {
|
|
122
|
+
--resolution-opacity: 1;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.status {
|
|
126
|
+
clip: rect(0 0 0 0);
|
|
127
|
+
clip-path: inset(50%);
|
|
128
|
+
height: 1px;
|
|
129
|
+
overflow: hidden;
|
|
130
|
+
position: absolute;
|
|
131
|
+
white-space: nowrap;
|
|
132
|
+
width: 1px;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
@media (orientation: landscape) {
|
|
136
|
+
.modal {
|
|
137
|
+
align-items: center;
|
|
138
|
+
justify-content: space-between;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.slide img {
|
|
142
|
+
max-height: 98vh;
|
|
143
|
+
max-height: 98dvh;
|
|
144
|
+
max-width: calc(98vw - 6rem);
|
|
145
|
+
max-width: calc(98dvw - 6rem);
|
|
146
|
+
transform: translate(-50%, -50%);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
@media (prefers-color-scheme: dark) {
|
|
151
|
+
.modal {
|
|
152
|
+
background: #000;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
button {
|
|
156
|
+
background: #666;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
button[disabled] {
|
|
160
|
+
background: #333;
|
|
161
|
+
color: #000;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
@media (prefers-reduced-motion: reduce) {
|
|
166
|
+
.modal,
|
|
167
|
+
.slide img {
|
|
168
|
+
transition: none;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
</style>
|
|
172
|
+
|
|
173
|
+
<div class="modal hidden" role="dialog" aria-label="Photo viewer" aria-hidden="true" tabindex="-1">
|
|
174
|
+
<div class="track"></div>
|
|
175
|
+
<button class="previous" type="button" aria-label="Previous photo">
|
|
176
|
+
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
|
|
177
|
+
<path d="M15 18l-6-6 6-6"></path>
|
|
178
|
+
</svg>
|
|
179
|
+
</button>
|
|
180
|
+
<button class="next" type="button" aria-label="Next photo">
|
|
181
|
+
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
|
|
182
|
+
<path d="M9 6l6 6-6 6"></path>
|
|
183
|
+
</svg>
|
|
184
|
+
</button>
|
|
185
|
+
<button class="close" type="button" aria-label="Close photo viewer">
|
|
186
|
+
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
|
|
187
|
+
<path d="M6 6l12 12M18 6L6 18"></path>
|
|
188
|
+
</svg>
|
|
189
|
+
</button>
|
|
190
|
+
<p class="status" aria-live="polite"></p>
|
|
191
|
+
</div>
|
|
192
|
+
</template>
|
|
193
|
+
|
|
194
|
+
<shoot-lightbox></shoot-lightbox>
|
data/_layouts/shoot.html
CHANGED
|
@@ -10,7 +10,7 @@ layout: entry
|
|
|
10
10
|
{% for image in page.images %}
|
|
11
11
|
{% assign image_id = image["id"] | default: image %}
|
|
12
12
|
{% assign base = "https://imagedelivery.net/" | append: site.cf_images_account_hash | append: "/" | append: image_id | append: "/" %}
|
|
13
|
-
<a class="tile" href="{{ base }}{{ xl }}"
|
|
13
|
+
<a class="tile" href="{{ base }}{{ xl }}">
|
|
14
14
|
<img
|
|
15
15
|
src="{{ base }}{{ thumb }}"
|
|
16
16
|
{% if image["width"] and image["height"] %}
|
|
@@ -28,3 +28,6 @@ layout: entry
|
|
|
28
28
|
{% endfor %}
|
|
29
29
|
</div>
|
|
30
30
|
</main>
|
|
31
|
+
|
|
32
|
+
{% include light-box.html %}
|
|
33
|
+
<script defer src="{{ "/assets/lightbox.js" | relative_url }}"></script>
|
data/_sass/yefeme.scss
CHANGED
|
@@ -24,6 +24,11 @@ body {
|
|
|
24
24
|
font-family: "Libre Baskerville", serif;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
html.lightbox-open,
|
|
28
|
+
html.lightbox-open body {
|
|
29
|
+
overflow: hidden;
|
|
30
|
+
}
|
|
31
|
+
|
|
27
32
|
li,
|
|
28
33
|
ol,
|
|
29
34
|
ul {
|
|
@@ -367,6 +372,7 @@ article {
|
|
|
367
372
|
background: #f6f6f6;
|
|
368
373
|
border-radius: 8px;
|
|
369
374
|
break-inside: avoid;
|
|
375
|
+
cursor: zoom-in;
|
|
370
376
|
display: block;
|
|
371
377
|
margin-bottom: 12px;
|
|
372
378
|
overflow: hidden;
|
data/assets/lightbox.js
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
(function () {
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
if (!window.customElements || window.customElements.get("shoot-lightbox")) return;
|
|
5
|
+
|
|
6
|
+
function getImage(photo) {
|
|
7
|
+
return photo.querySelector("img");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
class ShootLightbox extends HTMLElement {
|
|
11
|
+
constructor() {
|
|
12
|
+
super();
|
|
13
|
+
|
|
14
|
+
var template = document.getElementById("shoot-lightbox-template");
|
|
15
|
+
if (!template) return;
|
|
16
|
+
|
|
17
|
+
this.attachShadow({ mode: "open" });
|
|
18
|
+
this.shadowRoot.appendChild(template.content.cloneNode(true));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
connectedCallback() {
|
|
22
|
+
if (!this.shadowRoot) return;
|
|
23
|
+
|
|
24
|
+
this.photos = Array.from(document.querySelectorAll(".portfolio-day .tile"));
|
|
25
|
+
if (!this.photos.length) return;
|
|
26
|
+
|
|
27
|
+
this.currentPhoto = 0;
|
|
28
|
+
this.modal = this.shadowRoot.querySelector(".modal");
|
|
29
|
+
this.track = this.shadowRoot.querySelector(".track");
|
|
30
|
+
this.previousButton = this.shadowRoot.querySelector(".previous");
|
|
31
|
+
this.nextButton = this.shadowRoot.querySelector(".next");
|
|
32
|
+
this.closeButton = this.shadowRoot.querySelector(".close");
|
|
33
|
+
this.status = this.shadowRoot.querySelector(".status");
|
|
34
|
+
|
|
35
|
+
this.buildSlides();
|
|
36
|
+
this.bindEvents();
|
|
37
|
+
this.updateControls();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
buildSlides() {
|
|
41
|
+
this.photos.forEach((photo) => {
|
|
42
|
+
var sourceImage = getImage(photo);
|
|
43
|
+
if (!sourceImage) return;
|
|
44
|
+
|
|
45
|
+
var slide = document.createElement("div");
|
|
46
|
+
var image = sourceImage.cloneNode(true);
|
|
47
|
+
|
|
48
|
+
slide.className = "slide";
|
|
49
|
+
image.loading = "eager";
|
|
50
|
+
image.decoding = "async";
|
|
51
|
+
image.draggable = false;
|
|
52
|
+
image.addEventListener("click", (event) => event.stopPropagation());
|
|
53
|
+
|
|
54
|
+
slide.appendChild(image);
|
|
55
|
+
this.track.appendChild(slide);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
this.slides = Array.from(this.track.querySelectorAll(".slide"));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
loadHighResolutionImage(slide, photo) {
|
|
62
|
+
if (!slide || !photo.href || slide.dataset.highResolutionRequested) return;
|
|
63
|
+
|
|
64
|
+
var preview = slide.querySelector("img");
|
|
65
|
+
if (!preview) return;
|
|
66
|
+
|
|
67
|
+
slide.dataset.highResolutionRequested = "true";
|
|
68
|
+
|
|
69
|
+
var image = preview.cloneNode(true);
|
|
70
|
+
var revealed = false;
|
|
71
|
+
|
|
72
|
+
image.classList.remove("blurhash-loaded");
|
|
73
|
+
image.classList.add("high-resolution");
|
|
74
|
+
image.removeAttribute("data-blurhash");
|
|
75
|
+
image.removeAttribute("style");
|
|
76
|
+
image.removeAttribute("srcset");
|
|
77
|
+
image.removeAttribute("sizes");
|
|
78
|
+
image.setAttribute("alt", "");
|
|
79
|
+
image.setAttribute("aria-hidden", "true");
|
|
80
|
+
image.loading = "eager";
|
|
81
|
+
image.decoding = "async";
|
|
82
|
+
image.draggable = false;
|
|
83
|
+
image.addEventListener("click", (event) => event.stopPropagation());
|
|
84
|
+
|
|
85
|
+
var reveal = () => {
|
|
86
|
+
if (revealed) return;
|
|
87
|
+
revealed = true;
|
|
88
|
+
|
|
89
|
+
var decoded = typeof image.decode === "function" ? image.decode().catch(() => {}) : Promise.resolve();
|
|
90
|
+
decoded.then(() => {
|
|
91
|
+
window.requestAnimationFrame(() => image.classList.add("loaded"));
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
image.addEventListener("load", reveal, { once: true });
|
|
96
|
+
image.addEventListener("error", () => {
|
|
97
|
+
delete slide.dataset.highResolutionRequested;
|
|
98
|
+
image.remove();
|
|
99
|
+
}, { once: true });
|
|
100
|
+
|
|
101
|
+
slide.appendChild(image);
|
|
102
|
+
image.src = photo.href;
|
|
103
|
+
if (image.complete && image.naturalWidth) reveal();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
bindEvents() {
|
|
107
|
+
this.photos.forEach((photo, index) => {
|
|
108
|
+
photo.addEventListener("click", (event) => this.open(event, index));
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
this.previousButton.addEventListener("click", this.previous);
|
|
112
|
+
this.nextButton.addEventListener("click", this.next);
|
|
113
|
+
this.closeButton.addEventListener("click", this.close);
|
|
114
|
+
this.modal.addEventListener("click", this.close);
|
|
115
|
+
this.track.addEventListener("scroll", this.onScroll, { passive: true });
|
|
116
|
+
document.addEventListener("keydown", this.onKeydown);
|
|
117
|
+
window.addEventListener("resize", this.onResize, { passive: true });
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
open(event, index) {
|
|
121
|
+
event.preventDefault();
|
|
122
|
+
|
|
123
|
+
this.previouslyFocused = document.activeElement;
|
|
124
|
+
this.updateCurrentPhoto(index, "auto");
|
|
125
|
+
this.modal.classList.remove("hidden");
|
|
126
|
+
this.modal.setAttribute("aria-hidden", "false");
|
|
127
|
+
document.documentElement.classList.add("lightbox-open");
|
|
128
|
+
this.loadHighResolutionImage(this.slides[this.currentPhoto], this.photos[this.currentPhoto]);
|
|
129
|
+
this.modal.focus({ preventScroll: true });
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
close = (event) => {
|
|
133
|
+
if (event) {
|
|
134
|
+
event.preventDefault();
|
|
135
|
+
event.stopPropagation();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (this.modal.classList.contains("hidden")) return;
|
|
139
|
+
|
|
140
|
+
this.modal.classList.add("hidden");
|
|
141
|
+
this.modal.setAttribute("aria-hidden", "true");
|
|
142
|
+
document.documentElement.classList.remove("lightbox-open");
|
|
143
|
+
|
|
144
|
+
if (this.previouslyFocused) this.previouslyFocused.focus({ preventScroll: true });
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
next = (event) => {
|
|
148
|
+
event.preventDefault();
|
|
149
|
+
event.stopPropagation();
|
|
150
|
+
if (!this.isLastPhoto()) this.updateCurrentPhoto(this.currentPhoto + 1);
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
previous = (event) => {
|
|
154
|
+
event.preventDefault();
|
|
155
|
+
event.stopPropagation();
|
|
156
|
+
if (!this.isFirstPhoto()) this.updateCurrentPhoto(this.currentPhoto - 1);
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
isFirstPhoto() {
|
|
160
|
+
return this.currentPhoto <= 0;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
isLastPhoto() {
|
|
164
|
+
return this.currentPhoto >= this.photos.length - 1;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
updateCurrentPhoto(index, behavior) {
|
|
168
|
+
this.currentPhoto = Math.max(0, Math.min(this.photos.length - 1, index));
|
|
169
|
+
this.track.scrollTo({
|
|
170
|
+
left: this.currentPhoto * this.track.clientWidth,
|
|
171
|
+
behavior: behavior || "smooth"
|
|
172
|
+
});
|
|
173
|
+
this.updateControls();
|
|
174
|
+
this.loadHighResolutionImage(this.slides[this.currentPhoto], this.photos[this.currentPhoto]);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
updateControls() {
|
|
178
|
+
this.previousButton.disabled = this.isFirstPhoto();
|
|
179
|
+
this.nextButton.disabled = this.isLastPhoto();
|
|
180
|
+
this.status.textContent = "Photo " + (this.currentPhoto + 1) + " of " + this.photos.length;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
onKeydown = (event) => {
|
|
184
|
+
if (this.modal.classList.contains("hidden")) return;
|
|
185
|
+
|
|
186
|
+
if (event.key === "ArrowLeft") this.previous(event);
|
|
187
|
+
if (event.key === "ArrowRight") this.next(event);
|
|
188
|
+
if (event.key === "Escape") this.close(event);
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
onScroll = () => {
|
|
192
|
+
window.clearTimeout(this.scrollSyncTimeout);
|
|
193
|
+
this.scrollSyncTimeout = window.setTimeout(() => {
|
|
194
|
+
var width = this.track.clientWidth || window.innerWidth;
|
|
195
|
+
this.currentPhoto = Math.max(
|
|
196
|
+
0,
|
|
197
|
+
Math.min(this.photos.length - 1, Math.round(this.track.scrollLeft / width))
|
|
198
|
+
);
|
|
199
|
+
this.updateControls();
|
|
200
|
+
this.loadHighResolutionImage(this.slides[this.currentPhoto], this.photos[this.currentPhoto]);
|
|
201
|
+
}, 100);
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
onResize = () => {
|
|
205
|
+
if (this.modal.classList.contains("hidden")) return;
|
|
206
|
+
this.updateCurrentPhoto(this.currentPhoto, "auto");
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
window.customElements.define("shoot-lightbox", ShootLightbox);
|
|
211
|
+
}());
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: yefeme
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.8.
|
|
4
|
+
version: 0.8.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Yefim Vedernikoff
|
|
@@ -36,6 +36,7 @@ files:
|
|
|
36
36
|
- _includes/email.svg
|
|
37
37
|
- _includes/github.svg
|
|
38
38
|
- _includes/head.html
|
|
39
|
+
- _includes/light-box.html
|
|
39
40
|
- _includes/logo.svg
|
|
40
41
|
- _includes/twitter.svg
|
|
41
42
|
- _layouts/default.html
|
|
@@ -46,6 +47,7 @@ files:
|
|
|
46
47
|
- _sass/highlight.scss
|
|
47
48
|
- _sass/yefeme.scss
|
|
48
49
|
- assets/blurhash.js
|
|
50
|
+
- assets/lightbox.js
|
|
49
51
|
- assets/main.scss
|
|
50
52
|
- index.md
|
|
51
53
|
homepage: https://github.com/yefim/yefeme
|