MarkTheArtist commited on
Commit
fd901fd
·
verified ·
1 Parent(s): 27131bb

Remove repeat interface element and set default to 1 - Initial Deployment

Browse files
Files changed (3) hide show
  1. README.md +7 -5
  2. index.html +517 -19
  3. prompts.txt +2 -0
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Image Slideshow
3
- emoji: 🦀
4
- colorFrom: purple
5
- colorTo: pink
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: image-slideshow
3
+ emoji: 🐳
4
+ colorFrom: yellow
5
+ colorTo: blue
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,517 @@
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>Advanced Image Slideshow Viewer</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
9
+ <script src="https://unpkg.com/feather-icons"></script>
10
+ <style>
11
+ body {
12
+ background-color: #1a1a2e;
13
+ color: #e6e6e6;
14
+ height: 100vh;
15
+ overflow: hidden;
16
+ }
17
+ .image-container {
18
+ position: relative;
19
+ width: 100%;
20
+ height: 100%;
21
+ display: flex;
22
+ align-items: center;
23
+ justify-content: center;
24
+ }
25
+ .image-display {
26
+ position: absolute;
27
+ top: 0;
28
+ left: 0;
29
+ width: 100%;
30
+ height: 100%;
31
+ object-fit: contain;
32
+ transition: opacity 0.3s ease;
33
+ }
34
+ .image-display.fade-out {
35
+ opacity: 0;
36
+ }
37
+ .banner {
38
+ position: absolute;
39
+ top: 0;
40
+ left: 0;
41
+ width: 100%;
42
+ background: linear-gradient(135deg, #2d1b69 0%, #1a1a2e 50%, #16213e 100%);
43
+ padding: 15px 0;
44
+ z-index: 20;
45
+ box-shadow: 0 4px 20px rgba(0,0,0,0.5);
46
+ border-bottom: 2px solid #6a6aaa;
47
+ transition: transform 0.3s ease;
48
+ text-align: center;
49
+ }
50
+ .banner.hidden {
51
+ transform: translateY(-100%);
52
+ }
53
+ .banner-title {
54
+ font-size: 28px;
55
+ font-weight: bold;
56
+ background: linear-gradient(45deg, #ffffff, #e6e6e6, #ccccff);
57
+ background-clip: text;
58
+ -webkit-background-clip: text;
59
+ -webkit-text-fill-color: transparent;
60
+ text-shadow: 0 2px 10px rgba(255,255,255,0.1);
61
+ letter-spacing: 1px;
62
+ }
63
+ .controls {
64
+ position: absolute;
65
+ bottom: 20px;
66
+ left: 50%;
67
+ transform: translateX(-50%);
68
+ background: rgba(0,0,0,0.9);
69
+ padding: 15px 25px;
70
+ border-radius: 20px;
71
+ display: flex;
72
+ flex-direction: column;
73
+ gap: 10px;
74
+ align-items: center;
75
+ z-index: 10;
76
+ transition: opacity 0.3s ease;
77
+ box-shadow: 0 0 20px rgba(0,0,0,0.5);
78
+ }
79
+ .control-row {
80
+ display: flex;
81
+ gap: 15px;
82
+ align-items: center;
83
+ width: 100%;
84
+ justify-content: center;
85
+ }
86
+ .toggle-container {
87
+ display: flex;
88
+ align-items: center;
89
+ gap: 8px;
90
+ padding: 5px 10px;
91
+ background: rgba(255,255,255,0.1);
92
+ border-radius: 10px;
93
+ }
94
+ .slider-container {
95
+ display: flex;
96
+ align-items: center;
97
+ gap: 8px;
98
+ padding: 5px 10px;
99
+ background: rgba(255,255,255,0.1);
100
+ border-radius: 10px;
101
+ }
102
+ .toggle {
103
+ position: relative;
104
+ display: inline-block;
105
+ width: 50px;
106
+ height: 24px;
107
+ }
108
+ .toggle input {
109
+ opacity: 0;
110
+ width: 0;
111
+ height: 0;
112
+ }
113
+ .slider {
114
+ position: absolute;
115
+ cursor: pointer;
116
+ top: 0;
117
+ left: 0;
118
+ right: 0;
119
+ bottom: 0;
120
+ background-color: #3a3a5a;
121
+ transition: .4s;
122
+ border-radius: 24px;
123
+ }
124
+ .slider:before {
125
+ position: absolute;
126
+ content: "";
127
+ height: 16px;
128
+ width: 16px;
129
+ left: 4px;
130
+ bottom: 4px;
131
+ background-color: white;
132
+ transition: .4s;
133
+ border-radius: 50%;
134
+ }
135
+ input:checked + .slider {
136
+ background-color: #6a6aaa;
137
+ }
138
+ input:not(:checked) + .slider {
139
+ background-color: #3a3a5a;
140
+ opacity: 0.7;
141
+ }
142
+ input:checked + .slider:before {
143
+ transform: translateX(26px);
144
+ }
145
+ .range-slider {
146
+ width: 120px;
147
+ margin: 0 10px;
148
+ }
149
+ .range-value {
150
+ min-width: 30px;
151
+ text-align: center;
152
+ font-weight: bold;
153
+ color: #fff;
154
+ }
155
+ .controls.hidden {
156
+ opacity: 0;
157
+ pointer-events: none;
158
+ }
159
+ .file-input {
160
+ display: none;
161
+ }
162
+ .btn {
163
+ background: #4a4a8a;
164
+ color: white;
165
+ border: none;
166
+ padding: 8px 16px;
167
+ border-radius: 20px;
168
+ cursor: pointer;
169
+ display: flex;
170
+ align-items: center;
171
+ gap: 8px;
172
+ transition: all 0.3s ease;
173
+ box-shadow: 0 2px 5px rgba(0,0,0,0.2);
174
+ }
175
+ .btn:hover {
176
+ background: #6a6aaa;
177
+ }
178
+ .reload-btn {
179
+ position: absolute;
180
+ top: 80px;
181
+ right: 20px;
182
+ z-index: 10;
183
+ display: none;
184
+ }
185
+ .status {
186
+ font-size: 14px;
187
+ color: #fff;
188
+ background: rgba(0,0,0,0.5);
189
+ padding: 5px 10px;
190
+ border-radius: 5px;
191
+ margin-left: 10px;
192
+ max-width: 300px;
193
+ overflow: hidden;
194
+ text-overflow: ellipsis;
195
+ white-space: nowrap;
196
+ }
197
+ .fullscreen {
198
+ position: absolute;
199
+ top: 0;
200
+ left: 0;
201
+ width: 100%;
202
+ height: 100%;
203
+ z-index: 5;
204
+ }
205
+ .loading {
206
+ position: absolute;
207
+ top: 50%;
208
+ left: 50%;
209
+ transform: translate(-50%, -50%);
210
+ color: #6a6aaa;
211
+ font-size: 18px;
212
+ z-index: 8;
213
+ }
214
+ </style>
215
+ </head>
216
+ <body class="font-sans">
217
+ <div class="banner" id="banner">
218
+ <h1 class="banner-title">Advanced Image Slideshow Viewer</h1>
219
+ </div>
220
+
221
+ <div class="image-container">
222
+ <img id="imageDisplay" class="image-display" alt="Slideshow Image" style="display: none;">
223
+ <div class="loading" id="loading" style="display: none;">Loading...</div>
224
+ <div class="fullscreen" id="clickArea"></div>
225
+
226
+ <button id="reloadBtn" class="btn reload-btn">
227
+ <i data-feather="refresh-cw"></i>
228
+ Reload
229
+ </button>
230
+ <div class="controls" id="controls">
231
+ <div class="control-row">
232
+ <button id="selectFilesBtn" class="btn">
233
+ <i data-feather="image"></i>
234
+ Select Images
235
+ </button>
236
+ <button id="startBtn" class="btn" style="display: none;">
237
+ <i data-feather="play"></i>
238
+ Start Slideshow
239
+ </button>
240
+ <span id="status" class="status">No images selected</span>
241
+ <input type="file" id="fileInput" class="file-input" accept="image/*" multiple>
242
+ </div>
243
+ <div class="control-row">
244
+ <div class="toggle-container">
245
+ <label class="toggle">
246
+ <input type="checkbox" id="autoplayToggle" checked>
247
+ <span class="slider"></span>
248
+ </label>
249
+ <span>Autoplay</span>
250
+ </div>
251
+ <div class="slider-container">
252
+ <span>Duration:</span>
253
+ <input type="range" id="durationSlider" class="range-slider" min="1" max="10" value="3" step="1">
254
+ <span id="durationValue" class="range-value">3s</span>
255
+ </div>
256
+ </div>
257
+ </div>
258
+ </div>
259
+
260
+ <script>
261
+ document.addEventListener('DOMContentLoaded', () => {
262
+ feather.replace();
263
+
264
+ const fileInput = document.getElementById('fileInput');
265
+ const selectFilesBtn = document.getElementById('selectFilesBtn');
266
+ const startBtn = document.getElementById('startBtn');
267
+ const imageDisplay = document.getElementById('imageDisplay');
268
+ const status = document.getElementById('status');
269
+ const clickArea = document.getElementById('clickArea');
270
+ const autoplayToggle = document.getElementById('autoplayToggle');
271
+ const durationSlider = document.getElementById('durationSlider');
272
+ const durationValue = document.getElementById('durationValue');
273
+ const controls = document.getElementById('controls');
274
+ const banner = document.getElementById('banner');
275
+ const loading = document.getElementById('loading');
276
+
277
+ let files = [];
278
+ let fileNames = [];
279
+ let currentFileIndex = 0;
280
+ let duration = parseInt(durationSlider.value) * 1000; // Convert to milliseconds
281
+ let isAutoplay = autoplayToggle.checked;
282
+ let slideshowTimer = null;
283
+ let isPlaying = false;
284
+
285
+ // Update duration value display
286
+ durationSlider.addEventListener('input', (e) => {
287
+ duration = parseInt(e.target.value) * 1000;
288
+ durationValue.textContent = parseInt(e.target.value) + 's';
289
+ if (isPlaying && isAutoplay) {
290
+ // Restart timer with new duration
291
+ clearTimeout(slideshowTimer);
292
+ startSlideshowTimer();
293
+ }
294
+ });
295
+
296
+ // Handle autoplay toggle
297
+ autoplayToggle.addEventListener('change', () => {
298
+ isAutoplay = autoplayToggle.checked;
299
+ console.log('Autoplay toggled:', isAutoplay);
300
+ if (isAutoplay && isPlaying) {
301
+ startSlideshowTimer();
302
+ } else {
303
+ clearTimeout(slideshowTimer);
304
+ }
305
+ if (files.length > 0) {
306
+ updateStatus();
307
+ }
308
+ });
309
+
310
+ function updateStatus() {
311
+ if (fileNames.length > 0) {
312
+ const fileName = fileNames[currentFileIndex];
313
+ status.textContent = `Showing ${currentFileIndex + 1}/${fileNames.length}: ${fileName}`;
314
+ }
315
+ }
316
+
317
+ function startSlideshowTimer() {
318
+ if (!isAutoplay) return;
319
+
320
+ clearTimeout(slideshowTimer);
321
+ slideshowTimer = setTimeout(() => {
322
+ handleImageTimeout();
323
+ }, duration);
324
+ }
325
+
326
+ function handleImageTimeout() {
327
+ console.log('Image timeout. Autoplay:', isAutoplay);
328
+
329
+ if (isAutoplay) {
330
+ // Move to next image
331
+ console.log('Moving to next image');
332
+ currentFileIndex = (currentFileIndex + 1) % fileNames.length;
333
+ showImage(currentFileIndex);
334
+ } else {
335
+ // When autoplay is off, just keep showing current image
336
+ updateStatus();
337
+ }
338
+ }
339
+
340
+ selectFilesBtn.addEventListener('click', () => {
341
+ fileInput.click();
342
+ });
343
+
344
+ startBtn.addEventListener('click', () => {
345
+ if (files.length > 0) {
346
+ currentFileIndex = 0;
347
+ showImage(currentFileIndex);
348
+ }
349
+ });
350
+
351
+ fileInput.addEventListener('change', (e) => {
352
+ const selectedFiles = Array.from(e.target.files);
353
+ if (selectedFiles.length > 0) {
354
+ fileNames = selectedFiles.map(file => file.name);
355
+ files = selectedFiles;
356
+ status.textContent = `${selectedFiles.length} images selected - Ready to view`;
357
+ startBtn.style.display = 'flex'; // Show start button
358
+ currentFileIndex = 0;
359
+ isPlaying = false;
360
+ clearTimeout(slideshowTimer);
361
+
362
+ // Don't auto-start, wait for user to click start button
363
+ console.log('Files selected, waiting for start button click');
364
+ }
365
+ });
366
+
367
+ let longPressTimer;
368
+
369
+ clickArea.addEventListener('mousedown', () => {
370
+ longPressTimer = setTimeout(() => {
371
+ controls.classList.toggle('hidden');
372
+ banner.classList.toggle('hidden');
373
+ }, 1000);
374
+ });
375
+
376
+ clickArea.addEventListener('mouseup', () => {
377
+ clearTimeout(longPressTimer);
378
+ });
379
+
380
+ clickArea.addEventListener('mouseleave', () => {
381
+ clearTimeout(longPressTimer);
382
+ });
383
+
384
+ clickArea.addEventListener('click', (e) => {
385
+ if (e.target === clickArea && fileNames.length > 0) {
386
+ currentFileIndex = (currentFileIndex + 1) % fileNames.length;
387
+ showImage(currentFileIndex);
388
+ }
389
+ });
390
+
391
+ function showImage(index) {
392
+ if (index >= 0 && index < files.length) {
393
+ console.log('Showing image:', index, 'of', files.length);
394
+
395
+ clearTimeout(slideshowTimer);
396
+
397
+ // Clean up previous URLs
398
+ if (imageDisplay.src && imageDisplay.src.startsWith('blob:')) {
399
+ URL.revokeObjectURL(imageDisplay.src);
400
+ }
401
+
402
+ isPlaying = true;
403
+
404
+ // Show loading
405
+ loading.style.display = 'block';
406
+ imageDisplay.style.display = 'none';
407
+
408
+ // Load current image
409
+ const currentFile = files[index];
410
+ const currentImageURL = URL.createObjectURL(currentFile);
411
+
412
+ // Create new image to preload
413
+ const tempImage = new Image();
414
+ tempImage.onload = () => {
415
+ imageDisplay.src = currentImageURL;
416
+ imageDisplay.style.display = 'block';
417
+ loading.style.display = 'none';
418
+
419
+ updateStatus();
420
+
421
+ // Only hide controls and banner if slideshow is actually starting
422
+ if (isPlaying) {
423
+ controls.classList.add('hidden');
424
+ banner.classList.add('hidden');
425
+ }
426
+
427
+ // Only request fullscreen if slideshow is running
428
+ if (isPlaying && !document.fullscreenElement && document.body.requestFullscreen) {
429
+ document.body.requestFullscreen().catch(e => {
430
+ console.log('Fullscreen error:', e);
431
+ });
432
+ }
433
+
434
+ // Start timer for autoplay
435
+ if (isAutoplay) {
436
+ startSlideshowTimer();
437
+ }
438
+ };
439
+
440
+ tempImage.onerror = () => {
441
+ loading.style.display = 'none';
442
+ status.textContent = `Error loading image: ${fileNames[index]}`;
443
+ console.error('Error loading image:', fileNames[index]);
444
+ };
445
+
446
+ tempImage.src = currentImageURL;
447
+ }
448
+ }
449
+
450
+ // Handle fullscreen toggle
451
+ clickArea.addEventListener('dblclick', () => {
452
+ if (!document.fullscreenElement) {
453
+ if (document.body.requestFullscreen) {
454
+ document.body.requestFullscreen();
455
+ } else if (document.body.webkitRequestFullscreen) {
456
+ document.body.webkitRequestFullscreen();
457
+ } else if (document.body.msRequestFullscreen) {
458
+ document.body.msRequestFullscreen();
459
+ }
460
+ } else {
461
+ if (document.exitFullscreen) {
462
+ document.exitFullscreen();
463
+ } else if (document.webkitExitFullscreen) {
464
+ document.webkitExitFullscreen();
465
+ } else if (document.msExitFullscreen) {
466
+ document.msExitFullscreen();
467
+ }
468
+ }
469
+ });
470
+
471
+ // Keyboard navigation
472
+ document.addEventListener('keydown', (e) => {
473
+ if (files.length === 0) return;
474
+
475
+ switch(e.key) {
476
+ case 'ArrowRight':
477
+ case ' ':
478
+ e.preventDefault();
479
+ currentFileIndex = (currentFileIndex + 1) % fileNames.length;
480
+ repeatCount = 0;
481
+ showImage(currentFileIndex);
482
+ break;
483
+ case 'ArrowLeft':
484
+ e.preventDefault();
485
+ currentFileIndex = (currentFileIndex - 1 + fileNames.length) % fileNames.length;
486
+ repeatCount = 0;
487
+ showImage(currentFileIndex);
488
+ break;
489
+ case 'Escape':
490
+ controls.classList.remove('hidden');
491
+ banner.classList.remove('hidden');
492
+ break;
493
+ }
494
+ });
495
+
496
+ // Reload button functionality
497
+ const reloadBtn = document.getElementById('reloadBtn');
498
+ reloadBtn.addEventListener('click', () => {
499
+ location.reload();
500
+ });
501
+
502
+ // Show reload button when not in fullscreen
503
+ document.addEventListener('fullscreenchange', () => {
504
+ reloadBtn.style.display = document.fullscreenElement ? 'none' : 'block';
505
+ });
506
+
507
+ // Cleanup on page unload
508
+ window.addEventListener('beforeunload', () => {
509
+ clearTimeout(slideshowTimer);
510
+ if (imageDisplay.src && imageDisplay.src.startsWith('blob:')) {
511
+ URL.revokeObjectURL(imageDisplay.src);
512
+ }
513
+ });
514
+ });
515
+ </script>
516
+ </body>
517
+ </html>
prompts.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ Move the repeat feature,
2
+ Remove repeat interface element and set default to 1