leo861 commited on
Commit
3c1acd4
·
verified ·
1 Parent(s): 5f7dd89

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +594 -19
index.html CHANGED
@@ -1,19 +1,594 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
6
+ <title>Leo's Lens📸</title>
7
+ <style>
8
+ :root {
9
+ --bg-color: #000;
10
+ --text-color: white;
11
+ --accent-color: #fff;
12
+ --gap-size: 12px;
13
+ --transition-speed: 0.3s;
14
+ --shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
15
+ }
16
+
17
+ * {
18
+ box-sizing: border-box;
19
+ margin: 0;
20
+ padding: 0;
21
+ }
22
+
23
+ html, body {
24
+ background-color: var(--bg-color);
25
+ color: var(--text-color);
26
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
27
+ Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
28
+ min-height: 100vh;
29
+ overflow-x: hidden;
30
+ }
31
+
32
+ /* Top Navigation */
33
+ .top-bar {
34
+ position: sticky;
35
+ top: 0;
36
+ z-index: 100;
37
+ display: flex;
38
+ justify-content: space-between;
39
+ align-items: center;
40
+ padding: 16px;
41
+ background: var(--bg-color);
42
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
43
+ }
44
+
45
+ .nav-button {
46
+ font-size: 1.4rem;
47
+ cursor: pointer;
48
+ color: var(--accent-color);
49
+ transition: opacity var(--transition-speed);
50
+ }
51
+
52
+ .nav-button:hover {
53
+ opacity: 0.8;
54
+ }
55
+
56
+ /* Profile Section */
57
+ .profile-section {
58
+ display: flex;
59
+ flex-direction: column;
60
+ align-items: center;
61
+ padding: 20px 16px;
62
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
63
+ }
64
+
65
+ .profile-pic {
66
+ width: 80px;
67
+ height: 80px;
68
+ border-radius: 50%;
69
+ object-fit: cover;
70
+ margin-bottom: 12px;
71
+ border: 2px solid rgba(255, 255, 255, 0.1);
72
+ }
73
+
74
+ .profile-name {
75
+ font-size: 1.2rem;
76
+ font-weight: 500;
77
+ margin-bottom: 8px;
78
+ }
79
+
80
+ .profile-bio {
81
+ font-size: 0.9rem;
82
+ color: #ccc;
83
+ text-align: center;
84
+ max-width: 300px;
85
+ line-height: 1.4;
86
+ }
87
+
88
+ /* Gallery Layout */
89
+ .gallery {
90
+ display: flex;
91
+ gap: var(--gap-size);
92
+ padding: var(--gap-size);
93
+ }
94
+
95
+ .gallery-column {
96
+ flex: 1;
97
+ display: flex;
98
+ flex-direction: column;
99
+ gap: var(--gap-size);
100
+ }
101
+
102
+ /* Image Card */
103
+ .image-wrapper {
104
+ position: relative;
105
+ width: 100%;
106
+ overflow: hidden;
107
+ cursor: pointer;
108
+ border-radius: 12px;
109
+ transition: transform var(--transition-speed) ease;
110
+ box-shadow: var(--shadow);
111
+ aspect-ratio: 3/4;
112
+ }
113
+
114
+ .image-wrapper:hover {
115
+ transform: scale(0.98);
116
+ }
117
+
118
+ .image-wrapper img {
119
+ width: 100%;
120
+ height: 100%;
121
+ display: block;
122
+ object-fit: cover;
123
+ transition: transform var(--transition-speed) ease;
124
+ }
125
+
126
+ .image-wrapper:hover img {
127
+ transform: scale(1.05);
128
+ }
129
+
130
+ /* Shimmer animation for loading */
131
+ @keyframes shimmer {
132
+ 0% { background-position: -200% 0; }
133
+ 100% { background-position: 200% 0; }
134
+ }
135
+
136
+ /* Ripple Effect */
137
+ .ripple {
138
+ position: absolute;
139
+ width: 20px;
140
+ height: 20px;
141
+ background: rgba(255, 255, 255, 0.3);
142
+ border-radius: 50%;
143
+ transform: scale(0);
144
+ animation: ripple-effect 0.6s ease-out forwards;
145
+ }
146
+
147
+ @keyframes ripple-effect {
148
+ to {
149
+ transform: scale(10);
150
+ opacity: 0;
151
+ }
152
+ }
153
+
154
+ /* Single Image View */
155
+ .single-view {
156
+ display: none;
157
+ position: fixed;
158
+ top: 0;
159
+ left: 0;
160
+ width: 100vw;
161
+ height: 100vh;
162
+ background-color: var(--bg-color);
163
+ z-index: 999;
164
+ overflow-y: auto;
165
+ padding-top: 60px; /* Space for top bar */
166
+ }
167
+
168
+ .single-image {
169
+ display: flex;
170
+ flex-direction: column;
171
+ align-items: center;
172
+ padding: 0 16px;
173
+ }
174
+
175
+ .single-image img {
176
+ max-width: 100%;
177
+ max-height: 80vh;
178
+ object-fit: contain;
179
+ border-radius: 12px;
180
+ box-shadow: var(--shadow);
181
+ transition: transform var(--transition-speed);
182
+ }
183
+
184
+ .single-image img:hover {
185
+ transform: scale(1.02);
186
+ }
187
+
188
+ .caption-container {
189
+ padding: 24px 16px;
190
+ text-align: center;
191
+ font-size: 0.95rem;
192
+ color: #ccc;
193
+ opacity: 0.8;
194
+ border-top: 1px solid #222;
195
+ margin-top: 16px;
196
+ width: 100%;
197
+ max-width: 600px;
198
+ margin-left: auto;
199
+ margin-right: auto;
200
+ }
201
+
202
+ /* Carousel Navigation */
203
+ .carousel-nav {
204
+ position: fixed;
205
+ top: 50%;
206
+ transform: translateY(-50%);
207
+ width: 40px;
208
+ height: 40px;
209
+ background: rgba(0, 0, 0, 0.4);
210
+ border-radius: 50%;
211
+ display: flex;
212
+ align-items: center;
213
+ justify-content: center;
214
+ cursor: pointer;
215
+ z-index: 1001;
216
+ transition: background var(--transition-speed);
217
+ }
218
+
219
+ .carousel-nav:hover {
220
+ background: rgba(0, 0, 0, 0.6);
221
+ }
222
+
223
+ .carousel-left {
224
+ left: 20px;
225
+ }
226
+
227
+ .carousel-right {
228
+ right: 20px;
229
+ }
230
+
231
+ /* Close Button for Single View */
232
+ .close-button {
233
+ position: fixed;
234
+ top: 16px;
235
+ left: 16px;
236
+ z-index: 1002;
237
+ font-size: 1.8rem;
238
+ cursor: pointer;
239
+ color: var(--accent-color);
240
+ transition: opacity var(--transition-speed);
241
+ background: rgba(0, 0, 0, 0.4);
242
+ width: 40px;
243
+ height: 40px;
244
+ border-radius: 50%;
245
+ display: flex;
246
+ align-items: center;
247
+ justify-content: center;
248
+ }
249
+
250
+ .close-button:hover {
251
+ opacity: 0.8;
252
+ }
253
+
254
+ /* Responsive */
255
+ @media (max-width: 600px) {
256
+ .top-bar {
257
+ padding: 12px;
258
+ }
259
+
260
+ .profile-section {
261
+ padding: 16px;
262
+ }
263
+
264
+ .profile-pic {
265
+ width: 70px;
266
+ height: 70px;
267
+ }
268
+
269
+ .profile-name {
270
+ font-size: 1.1rem;
271
+ }
272
+
273
+ .profile-bio {
274
+ font-size: 0.85rem;
275
+ max-width: 90%;
276
+ }
277
+
278
+ .gallery {
279
+ padding: 8px;
280
+ gap: 8px;
281
+ }
282
+
283
+ .gallery-column {
284
+ gap: 8px;
285
+ }
286
+
287
+ .carousel-nav {
288
+ width: 36px;
289
+ height: 36px;
290
+ }
291
+
292
+ .carousel-left {
293
+ left: 10px;
294
+ }
295
+
296
+ .carousel-right {
297
+ right: 10px;
298
+ }
299
+ }
300
+ </style>
301
+ </head>
302
+ <body>
303
+ <!-- Top Navigation -->
304
+ <div class="top-bar">
305
+ <div class="nav-button" id="backBtn">←</div>
306
+ <div style="width: 24px;"></div> <!-- Empty space to keep alignment -->
307
+ </div>
308
+
309
+ <!-- Profile Section -->
310
+ <div class="profile-section">
311
+ <img src="pics/profile.jpg" alt="Profile" class="profile-pic">
312
+ <div class="profile-name">LEO JOSEPH</div>
313
+ <div class="profile-bio">
314
+ <div>𝖢𝖺𝗉𝗍𝗎𝗋𝗂𝗇𝗀 𝖼𝗈𝗅𝗈𝗋𝗌, 𝖾𝗆𝗈𝗍𝗂𝗈𝗇𝗌, 𝖺𝗇𝖽 𝗌𝗍𝗂𝗅𝗅𝗇𝖾𝗌𝗌</div>
315
+ <div>M𝗈𝗆𝖾𝗇𝗍𝗌 𝗍𝗁𝖺𝗍 𝗍𝖾𝗅𝗅 𝗌𝗍𝗈𝗋𝗂𝖾𝗌</div>
316
+ </div>
317
+ </div>
318
+
319
+ <!-- Gallery Grid -->
320
+ <div class="gallery" id="gallery">
321
+ <div class="gallery-column" id="leftColumn"></div>
322
+ <div class="gallery-column" id="rightColumn"></div>
323
+ </div>
324
+
325
+ <!-- Single Image View -->
326
+ <div class="single-view" id="singleView">
327
+ <!-- Close Button -->
328
+ <div class="close-button" id="closeBtn">×</div>
329
+
330
+ <!-- Carousel Navigation -->
331
+ <div class="carousel-nav carousel-left" id="prevBtn">←</div>
332
+ <div class="carousel-nav carousel-right" id="nextBtn">→</div>
333
+
334
+ <div class="single-image">
335
+ <img id="fullImage" src="" alt="">
336
+ <div class="caption-container" id="imageCaption"></div>
337
+ </div>
338
+ </div>
339
+
340
+ <script>
341
+ // Sample image data with fixed URLs
342
+ const imageData = [
343
+ {
344
+ id: 1,
345
+ url: 'pics/Snapseed (4).jpg',
346
+ caption: 'Timeless textures, rustic tones — a quiet story told without a single word. 🐪🇰🇼✨'
347
+ },
348
+ { id: 2, url: 'pics/Snapseed (3).jpg', caption: 'When elegance framed in gold meets dim-lit stories untold⚜📜🕯' },
349
+ { id: 3, url: 'pics/FullSizeRender (8).jpg', caption: 'Beneath a kaleidoscope ceiling, the fountain sings in silence. ✨🏛🌌' },
350
+ { id: 4, url: 'pics/FullSizeRender (7).jpg', caption: 'Renaissance vibes, reimagined in cyan. 🫧🗿🤎🎞' },
351
+ { id: 5, url: 'pics/Snapseed (2).jpg', caption: 'Faded tales through lenses, time rests on velvet and ink. 🕰🪞🥀📜✨' },
352
+ { id: 6, url: 'pics/Snapseed (1).jpg', caption: 'Golden dreams draped in art, blooms, and timeless elegance.⚜✨🥀' },
353
+ { id: 7, url: 'pics/FullSizeRender (6).jpg', caption: 'Chiseled by time, silent in thought — a marble mood eternal. 🍂🗿🖤' },
354
+ { id: 8, url: 'pics/FullSizeRender (9).jpg', caption: '6 scoops. 6 moods. summer melting into memories.🍦✨' },
355
+ { id: 9, url: 'pics/IMG_4624.JPG', caption: 'Every slice is a love letter to my taste buds. 🍕🤤' },
356
+ { id: 10, url: 'pics/FullSizeRender (3).jpg', caption: 'Where water whispers secrets only nature knows. 🌿✨' },
357
+ { id: 11, url: 'pics/IMG_4625.JPG', caption: 'Wildflowers bloom quietly as mountains fade into the mist.☁✨' },
358
+ { id: 12, url: 'pics/IMG_4623.JPG', caption: 'Where every embrace whispers love and safety. 🐒🤎' },
359
+ { id: 13, url: 'pics/IMG_3953.JPG', caption: 'Grace wrapped in petals and ribbons — a soft moment from a blessed baptism day.' },
360
+ { id: 14, url: 'pics/IMG_3808.JPG', caption: 'Just me, the silence, and a sky that doesn’t need stars.' },
361
+ { id: 15, url: 'pics/IMG_0477.JPG', caption: 'Soft blooms, cool hues, and quiet corners — where time slows down and colors speak🥀.' },
362
+ { id: 16, url: 'pics/IMG_4699.JPG', caption: 'Raindrops linger, blurring greens and blues into quiet calm.' },
363
+ { id: 17, url: 'pics/IMG_5871.JPG', caption: 'Where colors dance and stories breathe — Kerala’s timeless spirit in a frame.' },
364
+ { id: 18, url: 'pics/IMG_3922.JPG', caption: 'Somewhere between earth and monochrome skies, where time slows down and thoughts get lighter.' },
365
+ { id: 19, url: 'pics/Snapseed (5).jpg', caption: 'Tea gardens kissed by morning mist☀.' },
366
+ { id: 20, url: 'pics/IMG_0496.JPG', caption: 'A slice of happiness layered with red velvet & cheesecake magic🍰 — sweet moments.' },
367
+ { id: 21, url: 'pics/IMG_2700.JPG', caption: 'Chasing the sunrise, one altitude at a time. Golden horizons and quiet skies.' },
368
+ { id: 22, url: 'pics/IMG_3727.JPG', caption: 'Drenched in purple dreams — where every bloom whispers calm and chaos all at once.' },
369
+ { id: 23, url: 'pics/IMG_4622.JPG', caption: 'Golden tuskers🐘, burning flames, and beats of tradition — Thrissur Pooram magic captured.' },
370
+ { id: 24, url: 'pics/Snapseed.jpg', caption: 'Signed by the sea, sealed with a wave. 🌊✍️☀️' },
371
+ { id: 25, url: 'pics/IMG_4605.JPG', caption: 'Spinning stories under a sunset sky—where the sea listens and the lights begin to sing. 🌇🎡💫' },
372
+ { id: 26, url: 'pics/FullSizeRender.jpg', caption: 'Cruising altitude comfort. ✈️😴🎶' },
373
+ { id: 27, url: 'pics/IMG_4573.JPG', caption: 'Rain on the runway, wanderlust in my veins. 🛫🌧️🌍 ' },
374
+ { id: 28, url: 'pics/FullSizeRender (2).jpg', caption: 'Caught him living the sweet life. 🍦🙈🌿' }
375
+ ];
376
+
377
+ let scrollPosition = 0;
378
+ let isSingleView = false;
379
+ let currentIndex = 0;
380
+
381
+ // DOM elements
382
+ const leftColumn = document.getElementById('leftColumn');
383
+ const rightColumn = document.getElementById('rightColumn');
384
+ const singleView = document.getElementById('singleView');
385
+ const fullImage = document.getElementById('fullImage');
386
+ const imageCaption = document.getElementById('imageCaption');
387
+ const backBtn = document.getElementById('backBtn');
388
+ const closeBtn = document.getElementById('closeBtn');
389
+
390
+ // Create image element
391
+ function createImageElement(item, index) {
392
+ const wrapper = document.createElement('div');
393
+ wrapper.className = 'image-wrapper';
394
+
395
+ // Skeleton loader
396
+ const skeleton = document.createElement('div');
397
+ skeleton.style.width = '100%';
398
+ skeleton.style.height = '100%';
399
+ skeleton.style.background = 'linear-gradient(90deg, #222 25%, #333 50%, #222 75%)';
400
+ skeleton.style.backgroundSize = '200% 100%';
401
+ skeleton.style.animation = 'shimmer 1.5s infinite linear';
402
+ skeleton.style.borderRadius = '12px';
403
+ wrapper.appendChild(skeleton);
404
+
405
+ // Image element
406
+ const img = document.createElement('img');
407
+ img.src = item.url;
408
+ img.alt = `Image ${item.id}`;
409
+ img.dataset.index = index;
410
+ img.style.display = 'none';
411
+
412
+ // Handle image load
413
+ img.onload = () => {
414
+ skeleton.remove();
415
+ img.style.display = 'block';
416
+ wrapper.appendChild(img);
417
+ };
418
+
419
+ // Handle image error
420
+ img.onerror = () => {
421
+ console.error('Failed to load image:', item.url);
422
+ skeleton.style.background = '#333';
423
+ skeleton.innerHTML = '<div style="color:white;text-align:center;padding:10px;">Image failed to load</div>';
424
+ };
425
+
426
+ // Ripple effect
427
+ wrapper.addEventListener('click', (e) => {
428
+ const rect = wrapper.getBoundingClientRect();
429
+ const x = e.clientX - rect.left;
430
+ const y = e.clientY - rect.top;
431
+
432
+ const ripple = document.createElement('div');
433
+ ripple.className = 'ripple';
434
+ ripple.style.left = `${x - 10}px`;
435
+ ripple.style.top = `${y - 10}px`;
436
+ wrapper.appendChild(ripple);
437
+
438
+ ripple.addEventListener('animationend', () => {
439
+ ripple.remove();
440
+ });
441
+
442
+ showSingleView(index);
443
+ });
444
+
445
+ return wrapper;
446
+ }
447
+
448
+ // Render gallery with balanced columns
449
+ function renderGallery() {
450
+ leftColumn.innerHTML = '';
451
+ rightColumn.innerHTML = '';
452
+
453
+ // Track cumulative height of columns
454
+ let leftHeight = 0;
455
+ let rightHeight = 0;
456
+
457
+ imageData.forEach((item, index) => {
458
+ const wrapper = createImageElement(item, index);
459
+
460
+ // Create a mock element to estimate height
461
+ const mockElement = document.createElement('div');
462
+ mockElement.style.width = '100%';
463
+ mockElement.style.paddingBottom = '133.33%'; // 3:4 aspect ratio
464
+ document.body.appendChild(mockElement);
465
+ const estimatedHeight = mockElement.offsetHeight;
466
+ document.body.removeChild(mockElement);
467
+
468
+ // Decide which column to add to
469
+ if (index % 2 === 0 || (index === imageData.length - 1 && leftHeight <= rightHeight)) {
470
+ leftColumn.appendChild(wrapper);
471
+ leftHeight += estimatedHeight;
472
+ } else {
473
+ rightColumn.appendChild(wrapper);
474
+ rightHeight += estimatedHeight;
475
+ }
476
+ });
477
+ }
478
+
479
+ // Show single image view
480
+ function showSingleView(index) {
481
+ currentIndex = index;
482
+ scrollPosition = window.scrollY;
483
+ isSingleView = true;
484
+
485
+ // Hide gallery and show full view
486
+ document.body.style.overflow = 'hidden'; // Prevent body scroll
487
+ singleView.style.display = 'block';
488
+ singleView.scrollTop = 0; // Reset scroll position
489
+
490
+ const item = imageData[index];
491
+ fullImage.src = item.url;
492
+ imageCaption.textContent = item.caption;
493
+
494
+ // Animate image in
495
+ fullImage.style.opacity = 0;
496
+ fullImage.style.transform = 'scale(0.9)';
497
+ requestAnimationFrame(() => {
498
+ fullImage.style.opacity = 1;
499
+ fullImage.style.transform = 'scale(1)';
500
+ });
501
+
502
+ history.pushState({ view: 'single', index }, '', `?image=${item.id}`);
503
+ }
504
+
505
+ // Return to gallery
506
+ function returnToGallery() {
507
+ isSingleView = false;
508
+ document.body.style.overflow = ''; // Restore body scroll
509
+ singleView.style.display = 'none';
510
+
511
+ // Restore scroll position
512
+ window.scrollTo(0, scrollPosition);
513
+
514
+ history.pushState({ view: 'gallery' }, '', window.location.pathname);
515
+ }
516
+
517
+ // Navigate to previous/next image
518
+ function navigateImage(direction) {
519
+ let newIndex = currentIndex + direction;
520
+ if (newIndex >= 0 && newIndex < imageData.length) {
521
+ showSingleView(newIndex);
522
+ }
523
+ }
524
+
525
+ // Handle swipe gestures
526
+ let startX = 0;
527
+ let startY = 0;
528
+ let isSwiping = false;
529
+
530
+ function handleTouchStart(e) {
531
+ if (isSingleView) {
532
+ startX = e.touches[0].clientX;
533
+ startY = e.touches[0].clientY;
534
+ isSwiping = true;
535
+ }
536
+ }
537
+
538
+ function handleTouchMove(e) {
539
+ if (!isSwiping) return;
540
+
541
+ const deltaX = e.touches[0].clientX - startX;
542
+ const deltaY = Math.abs(e.touches[0].clientY - startY);
543
+
544
+ if (Math.abs(deltaX) > 30 && deltaY < 30) {
545
+ if (deltaX > 0) {
546
+ navigateImage(-1); // Swipe right to go back
547
+ } else {
548
+ navigateImage(1); // Swipe left to go forward
549
+ }
550
+ isSwiping = false;
551
+ }
552
+ }
553
+
554
+ function handleTouchEnd() {
555
+ isSwiping = false;
556
+ }
557
+
558
+ // Event listeners
559
+ backBtn.addEventListener('click', returnToGallery);
560
+ closeBtn.addEventListener('click', returnToGallery);
561
+
562
+ // Carousel navigation
563
+ document.getElementById('prevBtn').addEventListener('click', () => navigateImage(-1));
564
+ document.getElementById('nextBtn').addEventListener('click', () => navigateImage(1));
565
+
566
+ // Keyboard navigation
567
+ document.addEventListener('keydown', (e) => {
568
+ if (isSingleView) {
569
+ if (e.key === 'ArrowLeft') navigateImage(-1);
570
+ if (e.key === 'ArrowRight') navigateImage(1);
571
+ if (e.key === 'Escape') returnToGallery();
572
+ }
573
+ });
574
+
575
+ // Touch event listeners
576
+
577
+ document.addEventListener('touchstart', handleTouchStart);
578
+ document.addEventListener('touchmove', handleTouchMove);
579
+ document.addEventListener('touchend', handleTouchEnd);
580
+
581
+ // Handle browser back/forward navigation
582
+ window.addEventListener('popstate', (event) => {
583
+ if (event.state?.view === 'gallery') {
584
+ returnToGallery();
585
+ } else if (event.state?.view === 'single') {
586
+ showSingleView(event.state.index);
587
+ }
588
+ });
589
+
590
+ // Initialize on load
591
+ window.addEventListener('load', renderGallery);
592
+ </script>
593
+ </body>
594
+ </html>