tangled
alpha
login
or
join now
dunkirk.sh
/
zera
5
fork
atom
the home site for me: also iteration 3 or 4 of my site
5
fork
atom
overview
issues
pulls
pipelines
feat: add a lightbox implementation
dunkirk.sh
3 months ago
83a8f6cf
8b44fc5b
verified
This commit was signed with the committer's
known signature
.
dunkirk.sh
SSH Key Fingerprint:
SHA256:DqcG0RXYExE26KiWo3VxJnsxswN1QNfTBvB+bdSpk80=
+215
-8
7 changed files
expand all
collapse all
unified
split
sass
css
_lightbox.scss
main.scss
mods.css
static
lightbox.js
templates
head.html
shortcodes
img.html
imgs.html
+109
sass/css/_lightbox.scss
···
1
1
+
#lightbox {
2
2
+
display: none;
3
3
+
position: fixed;
4
4
+
top: 0;
5
5
+
left: 0;
6
6
+
width: 100%;
7
7
+
height: 100%;
8
8
+
background-color: rgba(0, 0, 0, 0.8);
9
9
+
z-index: 9999;
10
10
+
justify-content: center;
11
11
+
align-items: center;
12
12
+
}
13
13
+
14
14
+
.lightbox-content {
15
15
+
position: relative;
16
16
+
max-width: 90%;
17
17
+
max-height: 90%;
18
18
+
display: flex;
19
19
+
flex-direction: column;
20
20
+
align-items: center;
21
21
+
justify-content: center;
22
22
+
}
23
23
+
24
24
+
#lightbox-img {
25
25
+
max-width: 100%;
26
26
+
max-height: 80vh;
27
27
+
object-fit: contain;
28
28
+
border: none;
29
29
+
padding: 0;
30
30
+
margin: 0;
31
31
+
background: transparent;
32
32
+
border-radius: 0;
33
33
+
}
34
34
+
35
35
+
.lightbox-controls {
36
36
+
display: flex;
37
37
+
gap: 2rem;
38
38
+
margin-top: 1rem;
39
39
+
align-items: center;
40
40
+
}
41
41
+
42
42
+
.lightbox-close {
43
43
+
position: fixed;
44
44
+
top: 20px;
45
45
+
right: 20px;
46
46
+
font-size: 40px;
47
47
+
color: var(--text);
48
48
+
background: transparent !important;
49
49
+
border: none;
50
50
+
cursor: pointer;
51
51
+
padding: 0;
52
52
+
line-height: 1;
53
53
+
-webkit-tap-highlight-color: transparent;
54
54
+
transition: color 120ms ease, transform 300ms ease;
55
55
+
}
56
56
+
57
57
+
.lightbox-close:hover {
58
58
+
background: transparent !important;
59
59
+
color: var(--accent);
60
60
+
background-color: transparent !important;
61
61
+
transform: rotate(90deg);
62
62
+
}
63
63
+
64
64
+
.lightbox-close:focus {
65
65
+
background: transparent !important;
66
66
+
background-color: transparent !important;
67
67
+
}
68
68
+
69
69
+
.lightbox-prev,
70
70
+
.lightbox-next {
71
71
+
font-size: 30px;
72
72
+
color: var(--text);
73
73
+
background: transparent !important;
74
74
+
border: none;
75
75
+
cursor: pointer;
76
76
+
padding: 0.5rem 1rem;
77
77
+
user-select: none;
78
78
+
-webkit-tap-highlight-color: transparent;
79
79
+
transition: color 120ms ease;
80
80
+
}
81
81
+
82
82
+
.lightbox-prev:hover,
83
83
+
.lightbox-next:hover {
84
84
+
background: transparent !important;
85
85
+
color: var(--accent);
86
86
+
background-color: transparent !important;
87
87
+
}
88
88
+
89
89
+
.lightbox-prev:focus,
90
90
+
.lightbox-next:focus {
91
91
+
background: transparent !important;
92
92
+
background-color: transparent !important;
93
93
+
}
94
94
+
95
95
+
@media only screen and (max-width: 720px) {
96
96
+
.lightbox-close {
97
97
+
top: 10px;
98
98
+
right: 10px;
99
99
+
}
100
100
+
}
101
101
+
102
102
+
.img-container {
103
103
+
cursor: pointer;
104
104
+
transition: opacity 120ms ease;
105
105
+
}
106
106
+
107
107
+
.img-container:hover {
108
108
+
opacity: 0.9;
109
109
+
}
+1
sass/css/main.scss
···
7
7
@use "copy-button";
8
8
@use "view-transitions";
9
9
@use "emoji-inline";
10
10
+
@use "lightbox";
+3
-5
sass/css/mods.css
···
110
110
}
111
111
112
112
.center .img-container {
113
113
-
display: block;
114
113
margin: 1rem auto;
115
114
}
116
115
···
342
341
gap: 1rem;
343
342
max-width: 100%;
344
343
justify-content: center;
344
344
+
align-items: flex-start;
345
345
}
346
346
347
347
.img-group .img-container {
348
348
-
flex: 1;
349
349
-
min-width: 0;
350
348
background-color: var(--accent);
351
349
border-bottom: 4px solid var(--bg-light);
352
350
border-radius: 7px 7px 10px 10px;
353
351
padding: 0.35rem;
354
352
margin: 1rem 0;
353
353
+
line-height: 0;
355
354
}
356
355
357
356
.img-group img {
358
358
-
width: 100%;
357
357
+
max-width: 100%;
359
358
height: auto;
360
360
-
object-fit: contain;
361
359
border-radius: 0.35rem;
362
360
}
363
361
+92
static/lightbox.js
···
1
1
+
let currentLightboxImages = [];
2
2
+
let currentLightboxIndex = 0;
3
3
+
4
4
+
function openLightbox(src) {
5
5
+
currentLightboxImages = [src];
6
6
+
currentLightboxIndex = 0;
7
7
+
showLightbox();
8
8
+
}
9
9
+
10
10
+
function openLightboxGroup(element) {
11
11
+
const group = element.closest('.img-group');
12
12
+
const images = Array.from(group.querySelectorAll('img')).map(img => img.src);
13
13
+
const clickedImg = element.querySelector('img');
14
14
+
15
15
+
currentLightboxImages = images;
16
16
+
currentLightboxIndex = images.indexOf(clickedImg.src);
17
17
+
showLightbox();
18
18
+
}
19
19
+
20
20
+
function showLightbox() {
21
21
+
let lightbox = document.getElementById('lightbox');
22
22
+
23
23
+
if (!lightbox) {
24
24
+
lightbox = document.createElement('div');
25
25
+
lightbox.id = 'lightbox';
26
26
+
lightbox.innerHTML = `
27
27
+
<div class="lightbox-content">
28
28
+
<button class="lightbox-close" onclick="closeLightbox()">×</button>
29
29
+
<img id="lightbox-img" src="" alt="">
30
30
+
<div class="lightbox-controls">
31
31
+
<button class="lightbox-prev" onclick="prevImage()">←</button>
32
32
+
<button class="lightbox-next" onclick="nextImage()">→</button>
33
33
+
</div>
34
34
+
</div>
35
35
+
`;
36
36
+
document.body.appendChild(lightbox);
37
37
+
38
38
+
lightbox.addEventListener('click', (e) => {
39
39
+
if (e.target === lightbox) closeLightbox();
40
40
+
});
41
41
+
42
42
+
document.addEventListener('keydown', handleKeyPress);
43
43
+
}
44
44
+
45
45
+
updateLightboxImage();
46
46
+
lightbox.style.display = 'flex';
47
47
+
document.body.style.overflow = 'hidden';
48
48
+
}
49
49
+
50
50
+
function closeLightbox() {
51
51
+
const lightbox = document.getElementById('lightbox');
52
52
+
if (lightbox) {
53
53
+
lightbox.style.display = 'none';
54
54
+
document.body.style.overflow = '';
55
55
+
}
56
56
+
}
57
57
+
58
58
+
function updateLightboxImage() {
59
59
+
const img = document.getElementById('lightbox-img');
60
60
+
const controls = document.querySelector('.lightbox-controls');
61
61
+
62
62
+
img.src = currentLightboxImages[currentLightboxIndex];
63
63
+
64
64
+
if (currentLightboxImages.length === 1) {
65
65
+
controls.style.display = 'none';
66
66
+
} else {
67
67
+
controls.style.display = 'flex';
68
68
+
}
69
69
+
}
70
70
+
71
71
+
function prevImage() {
72
72
+
currentLightboxIndex = (currentLightboxIndex - 1 + currentLightboxImages.length) % currentLightboxImages.length;
73
73
+
updateLightboxImage();
74
74
+
}
75
75
+
76
76
+
function nextImage() {
77
77
+
currentLightboxIndex = (currentLightboxIndex + 1) % currentLightboxImages.length;
78
78
+
updateLightboxImage();
79
79
+
}
80
80
+
81
81
+
function handleKeyPress(e) {
82
82
+
const lightbox = document.getElementById('lightbox');
83
83
+
if (!lightbox || lightbox.style.display !== 'flex') return;
84
84
+
85
85
+
if (e.key === 'Escape') {
86
86
+
closeLightbox();
87
87
+
} else if (e.key === 'ArrowLeft') {
88
88
+
prevImage();
89
89
+
} else if (e.key === 'ArrowRight') {
90
90
+
nextImage();
91
91
+
}
92
92
+
}
+7
templates/head.html
···
93
93
defer
94
94
></script>
95
95
96
96
+
{% set lightboxJsHash = get_hash(path="lightbox.js", sha_type=256,
97
97
+
base64=true) %}
98
98
+
<script
99
99
+
src="{{ get_url(path='lightbox.js?' ~ lightboxJsHash, trailing_slash=false) | safe }}"
100
100
+
defer
101
101
+
></script>
102
102
+
96
103
<script type="speculationrules">
97
104
{
98
105
"prerender": [
+1
-1
templates/shortcodes/img.html
···
1
1
<figure {% if class %}class="{{class}}" {% else %}class="center" {% endif %}>
2
2
-
<div class="img-container">
2
2
+
<div class="img-container" onclick="openLightbox('{{id}}')">
3
3
<img src="{{id}}" {% if alt %}alt="{{alt}}" {% endif %} />
4
4
</div>
5
5
{% if caption %}
+2
-2
templates/shortcodes/imgs.html
···
1
1
<figure {% if class %}class="{{class}}" {% else %}class="center" {% endif %}>
2
2
-
<div class="img-group">
2
2
+
<div class="img-group" data-images="{{id}}" data-alts="{{alt | default(value='')}}">
3
3
{% set images = id | split(pat=",") %}
4
4
{% set alts = alt | default(value="") | split(pat=",") %}
5
5
{% for image in images %}
6
6
-
<div class="img-container">
6
6
+
<div class="img-container" onclick="openLightboxGroup(this)">
7
7
<img src="{{image | trim}}" {% if alts[loop.index0] %}alt="{{alts[loop.index0] | trim}}" {% endif %} />
8
8
</div>
9
9
{% endfor %}