triflix commited on
Commit
cec4e62
·
verified ·
1 Parent(s): f63e55f

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +107 -256
templates/index.html CHANGED
@@ -24,7 +24,7 @@
24
  --text-primary: var(--primary-dark-ref);
25
  --text-secondary: #666666;
26
  --text-placeholder: #999999;
27
- --text-email-on-light: rgba(27, 27, 29, 0.7); /* Lighter for email as per brief */
28
 
29
  /* Typography */
30
  --font-main: 'Noto Sans', 'Poppins', sans-serif;
@@ -33,10 +33,9 @@
33
  /* UI Elements */
34
  --radius-sharp: 4px;
35
  --radius-softer: 6px;
36
- --radius-profile-card: 12px; /* For profile cards */
37
  --shadow-none: none;
38
- --shadow-interactive: 0 1px 3px rgba(0,0,0,0.07);
39
- --shadow-profile-card: 0 4px 10px rgba(0,0,0,0.1); /* Softer, more modern shadow */
40
 
41
  --nav-height: 60px;
42
  }
@@ -71,7 +70,6 @@
71
  }
72
  section.active { display: flex; flex-direction: column; }
73
 
74
- /* Common Button Style (Red Accent) */
75
  button, .button-like {
76
  background: var(--accent-red);
77
  color: var(--text-on-accent);
@@ -105,7 +103,6 @@
105
  cursor: not-allowed;
106
  }
107
 
108
- /* --- Uploader & History Styles (Keep as is from previous version) --- */
109
  .uploader { display: flex; flex-direction: column; gap: 16px; width: 100%; max-width: 480px; margin: auto; }
110
  .file-input-area { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 25px 20px; border: 2px dashed var(--border-medium); border-radius: var(--radius-softer); background-color: var(--surface-primary); cursor: pointer; transition: border-color 0.2s, background-color 0.2s; text-align: center; }
111
  .file-input-area:hover, .file-input-area.dragover { border-color: var(--accent-red); background-color: #fff5f5; }
@@ -137,205 +134,46 @@
137
  .history-item-url { font-size: 0.75em; color: var(--text-secondary); word-break: break-all; display: block; text-decoration: none; font-family: var(--font-mono); }
138
  .history-item-url:hover { color: var(--accent-red); text-decoration: underline;}
139
  .history-item button { padding: 7px 10px; font-size: 0.75rem; min-width: 80px; }
140
- /* --- END Uploader & History Styles --- */
141
 
142
-
143
- /* Profile UI - Revamped */
144
  .profile-container {
145
  display: flex;
146
  flex-direction: column;
147
  align-items: center;
148
- gap: 24px; /* Increased spacing between profile sections */
149
- padding: 16px 0; /* Padding for top/bottom within the section */
150
- width: 100%;
151
- max-width: 450px; /* Control max width */
152
- margin: auto; /* Center it */
153
- }
154
-
155
- .profile-header {
156
- text-align: center;
157
- margin-bottom: 16px; /* Space below header */
158
- }
159
- .profile-avatar-wrapper {
160
- position: relative;
161
- width: 120px; /* Avatar size */
162
- height: 120px;
163
- margin: 0 auto 20px auto; /* Centered, space below */
164
- }
165
- .profile-avatar {
166
- width: 100%;
167
- height: 100%;
168
- border-radius: 50%;
169
- object-fit: cover;
170
- border: 3px solid var(--surface-primary); /* Inner border to lift from ring */
171
- box-shadow: 0 2px 4px rgba(0,0,0,0.1); /* Subtle shadow on avatar */
172
- position: relative;
173
- z-index: 2;
174
- }
175
- .profile-avatar-ring {
176
- position: absolute;
177
- top: -5px; left: -5px; right: -5px; bottom: -5px; /* Make it slightly larger than avatar */
178
- border-radius: 50%;
179
- border: 2px dotted var(--accent-red);
180
- animation: rotateRing 20s linear infinite;
181
- z-index: 1;
182
- }
183
- @keyframes rotateRing {
184
- from { transform: rotate(0deg); }
185
- to { transform: rotate(360deg); }
186
- }
187
-
188
- .profile-name {
189
- font-family: var(--font-mono); /* Pixel-style font */
190
- font-size: 1.8rem; /* Prominent name */
191
- color: var(--text-primary);
192
- margin-bottom: 4px;
193
- letter-spacing: 0.5px; /* Adjust for "pixel" feel */
194
- }
195
- .profile-email {
196
- font-family: var(--font-main); /* Clean sans-serif */
197
- font-size: 0.95rem;
198
- color: var(--text-email-on-light); /* Lighter email text */
199
- }
200
-
201
- .profile-action-card {
202
- background-color: var(--surface-primary);
203
- border-radius: var(--radius-profile-card);
204
- padding: 16px;
205
  width: 100%;
206
- box-shadow: var(--shadow-profile-card);
207
- text-align: center;
208
- }
209
- .portfolio-button {
210
- display: inline-flex; /* Changed to inline-flex to behave like a button */
211
- align-items: center;
212
- justify-content: center;
213
- gap: 8px;
214
- background-color: var(--accent-red);
215
- color: var(--text-on-accent);
216
- font-family: var(--font-main);
217
- font-size: 1rem;
218
- font-weight: 500;
219
- padding: 12px 24px;
220
- border-radius: var(--radius-sharp); /* Sharp radius for button itself */
221
- text-decoration: none;
222
- text-transform: uppercase;
223
- letter-spacing: 0.5px;
224
- transition: background-color 0.15s ease;
225
- width: auto; /* Let it size by content or set a min-width */
226
- min-width: 200px;
227
- }
228
- .portfolio-button:hover {
229
- background-color: var(--accent-red-hover);
230
- }
231
- .portfolio-button .material-icons {
232
- font-size: 20px; /* Icon size in button */
233
- }
234
-
235
-
236
- .profile-social-links {
237
- display: grid;
238
- grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); /* Responsive grid */
239
- gap: 16px;
240
- width: 100%;
241
- padding: 0 8px; /* Slight horizontal padding for the grid */
242
- }
243
- .social-link-card {
244
- background-color: var(--surface-primary);
245
- border-radius: var(--radius-profile-card);
246
- padding: 16px;
247
- box-shadow: var(--shadow-profile-card);
248
- display: flex;
249
- flex-direction: column;
250
- align-items: center;
251
- justify-content: center;
252
- text-decoration: none;
253
- color: var(--text-primary);
254
- gap: 8px;
255
- transition: transform 0.2s ease, box-shadow 0.2s ease;
256
- min-height: 100px; /* Ensure cards have some height */
257
- }
258
- .social-link-card:hover {
259
- transform: translateY(-3px) scale(1.03);
260
- box-shadow: 0 6px 12px rgba(0,0,0,0.12);
261
- color: var(--accent-red); /* Change text/icon color on hover */
262
- }
263
  .social-link-card .social-icon {
264
- font-size: 2rem; /* Placeholder for icon size */
265
- width: 32px; /* If using SVGs, control size here */
266
- height: 32px;
267
- display: flex;
268
- align-items: center;
269
- justify-content: center;
270
- /* Basic Text Icon Styling - REPLACE WITH SVGS or ICON FONT */
271
- font-family: var(--font-mono);
272
- font-weight: bold;
273
- border: 1px solid var(--border-light);
274
- border-radius: 50%;
275
- line-height: 30px; /* Center text icon */
276
- transition: color 0.2s ease, border-color 0.2s ease;
277
- }
278
- .social-link-card:hover .social-icon {
279
- color: var(--accent-red);
280
- border-color: var(--accent-red);
281
  }
282
- .social-link-card span { /* Label for social icon */
283
- font-family: var(--font-main);
284
- font-size: 0.8rem;
285
- font-weight: 500;
286
- text-align: center;
287
- }
288
-
289
 
290
- /* Bottom Nav */
291
- .bottom-nav {
292
- position: fixed;
293
- bottom: 0;
294
- left: 0;
295
- right: 0;
296
- width: 100%;
297
- background: var(--surface-primary);
298
- display: flex;
299
- justify-content: space-around;
300
- align-items: stretch;
301
- border-top: 1px solid var(--border-light);
302
- padding-bottom: env(safe-area-inset-bottom);
303
- height: calc(var(--nav-height) + env(safe-area-inset-bottom));
304
- box-shadow: var(--shadow-none);
305
- }
306
- .nav-item {
307
- flex: 1;
308
- display: flex;
309
- flex-direction: column;
310
- justify-content: center;
311
- align-items: center;
312
- font-size: 0.7rem;
313
- color: var(--text-secondary);
314
- cursor: pointer;
315
- transition: color 0.15s ease;
316
- padding-top: 5px;
317
- padding-bottom: 3px;
318
- position: relative;
319
- }
320
  .nav-item:hover { color: var(--text-primary); }
321
  .nav-item.active { color: var(--accent-red); font-weight: 700; }
322
- .nav-item.active::after {
323
- content: '';
324
- position: absolute;
325
- bottom: 5px;
326
- left: 50%;
327
- transform: translateX(-50%);
328
- width: 5px;
329
- height: 5px;
330
- background-color: var(--accent-red);
331
- border-radius: 50%;
332
- }
333
- .nav-item .material-icons {
334
- font-size: 24px;
335
- margin-bottom: 2px;
336
- }
337
 
338
- /* Animations */
339
  @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
340
  @keyframes fadeIn { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: translateY(0); } }
341
  </style>
@@ -343,7 +181,6 @@
343
  <body>
344
  <main>
345
  <section id="uploadSection" class="active">
346
- <!-- Uploader HTML (from previous version, unchanged) -->
347
  <div class="uploader">
348
  <label for="fileInput" class="file-input-area">
349
  <i class="material-icons">upload_file</i>
@@ -363,7 +200,6 @@
363
  </section>
364
 
365
  <section id="historySection">
366
- <!-- History HTML (from previous version, unchanged) -->
367
  <div class="history-list" id="historyList"></div>
368
  </section>
369
 
@@ -380,32 +216,30 @@
380
 
381
  <div class="profile-action-card portfolio-cta-card">
382
  <a href="https://www.adityadevarshi.online/" target="_blank" rel="noopener noreferrer" class="portfolio-button">
383
- <i class="material-icons">visibility</i> <!-- Or 'work', 'language', 'auto_stories' -->
384
  <span>View My Work</span>
385
  </a>
386
  </div>
387
 
388
  <div class="profile-social-links">
389
  <a href="https://github.com/devarshiadi/" target="_blank" rel="noopener noreferrer" class="social-link-card" aria-label="GitHub Profile">
390
- <i class="social-icon github-icon">G</i> <!-- Replace with actual SVG/Icon -->
391
  <span>GitHub</span>
392
  </a>
393
  <a href="https://www.linkedin.com/in/aditya-devarshi/" target="_blank" rel="noopener noreferrer" class="social-link-card" aria-label="LinkedIn Profile">
394
- <i class="social-icon linkedin-icon">L</i> <!-- Replace with actual SVG/Icon -->
395
  <span>LinkedIn</span>
396
  </a>
397
  <a href="https://www.instagram.com/curseofwitcher/" target="_blank" rel="noopener noreferrer" class="social-link-card" aria-label="Instagram Profile">
398
- <i class="social-icon instagram-icon">I</i> <!-- Replace with actual SVG/Icon -->
399
  <span>Instagram</span>
400
  </a>
401
- <!-- You can add a 4th item here for a 2x2 grid if desired -->
402
  </div>
403
  </div>
404
  </section>
405
  </main>
406
 
407
  <nav class="bottom-nav">
408
- <!-- Nav HTML (from previous version, unchanged) -->
409
  <div class="nav-item active" data-target="uploadSection">
410
  <i class="material-icons">home</i> Home
411
  </div>
@@ -418,7 +252,8 @@
418
  </nav>
419
 
420
  <script>
421
- // JavaScript (from previous version, largely unchanged for core functionality)
 
422
  const navItems = document.querySelectorAll('.nav-item');
423
  const sections = document.querySelectorAll('section');
424
  const uploadBtn = document.getElementById('uploadBtn');
@@ -435,55 +270,62 @@
435
  let infoTimeout = null;
436
 
437
  function displayInfoMessage(message, type = 'info', persistent = false) {
438
- if (infoTimeout && !persistent) clearTimeout(infoTimeout);
439
- uploadInfo.textContent = message;
440
- uploadInfo.className = 'info';
441
- if (type === 'error') {
442
- uploadInfo.classList.add('error-message');
443
- } else if (type === 'success') {
444
- uploadInfo.classList.add('success-message');
445
- }
 
446
 
447
- if (message && !persistent && (type === 'error' || message === "Please select a file first.")) {
448
- infoTimeout = setTimeout(() => {
449
- if (uploadInfo.textContent === message) {
450
- uploadInfo.textContent = "";
451
- uploadInfo.className = 'info';
452
- }
453
- }, 3000);
 
454
  }
455
  }
456
 
457
  function resetUploadUI(clearMessage = true) {
458
- fileInput.value = '';
459
- fileNameDisplay.textContent = 'No file selected';
460
- uploadBtn.disabled = true;
461
- progressContainer.style.display = 'none';
462
- progressBar.style.width = '0%';
463
  if (clearMessage) {
464
  displayInfoMessage("");
465
  }
466
- loader.style.display = 'none';
467
- shareLinkContainer.style.display = 'none';
468
- shareLinkContainer.innerHTML = '';
469
- progressBar.style.background = 'var(--accent-red)';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
470
  }
471
 
472
- navItems.forEach(item => {
473
- item.addEventListener('click', () => {
474
- navItems.forEach(i => i.classList.remove('active'));
475
- item.classList.add('active');
476
- const targetId = item.dataset.target;
477
- sections.forEach(sec => {
478
- sec.classList.toggle('active', sec.id === targetId);
479
- });
480
- if (targetId === 'historySection') {
481
- loadHistory();
482
- }
483
- });
484
- });
485
 
486
- if (fileInput) { // Ensure elements exist before adding listeners
487
  fileInput.addEventListener('change', () => {
488
  if (fileInput.files.length > 0) {
489
  fileNameDisplay.textContent = fileInput.files[0].name;
@@ -542,6 +384,7 @@
542
  }
543
 
544
  function loadHistory() {
 
545
  const data = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
546
  historyList.innerHTML = '';
547
  if (data.length === 0) {
@@ -552,13 +395,16 @@
552
  const el = document.createElement('div');
553
  el.className = 'history-item';
554
  const dateStr = entry.timestamp ? new Date(entry.timestamp).toLocaleDateString() : '';
 
 
 
555
  el.innerHTML = `
556
  <div class="history-item-info">
557
  <div class="history-item-name">${entry.name}</div>
558
- <a href="${entry.url}" target="_blank" rel="noopener noreferrer" class="history-item-url">${entry.url.length > 50 ? entry.url.substring(0,50)+'...' : entry.url}</a>
559
  ${dateStr ? `<span style="font-size:0.7em; color:var(--text-placeholder); display:block; margin-top:2px;">${dateStr}</span>` : ''}
560
  </div>
561
- <button data-url="${entry.url}">Copy</button>
562
  `;
563
  historyList.appendChild(el);
564
  el.querySelector('button').addEventListener('click', function() {
@@ -567,7 +413,7 @@
567
  });
568
  }
569
 
570
- if (uploadBtn) { // Ensure elements exist
571
  uploadBtn.addEventListener('click', () => {
572
  const file = fileInput.files[0];
573
  if (!file) {
@@ -601,29 +447,34 @@
601
  if (xhr.status === 200) {
602
  try {
603
  const response = JSON.parse(xhr.responseText);
 
 
 
604
  progressBar.style.width = '100%';
605
  displayInfoMessage('Upload Complete!', 'success', true);
606
 
607
  shareLinkContainer.innerHTML = `
608
  <p>Share Link:</p>
609
  <div class="share-link-display">
610
- <input type="text" value="${response.download_url}" id="shareableLinkInput-${Date.now()}" readonly>
611
- <button data-url="${response.download_url}">Copy</button>
612
  </div>
613
  `;
614
  shareLinkContainer.style.display = 'block';
615
  shareLinkContainer.querySelector('button').addEventListener('click', function() {
616
  const inputId = this.previousElementSibling.id;
617
  const linkInput = document.getElementById(inputId);
618
- linkInput.select();
619
- linkInput.setSelectionRange(0, 99999);
620
- copyToClipboard(this.dataset.url, this);
 
 
621
  });
622
 
623
  const historyData = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
624
  historyData.unshift({
625
  name: response.filename || file.name,
626
- url: response.download_url,
627
  timestamp: Date.now()
628
  });
629
  localStorage.setItem(STORAGE_KEY, JSON.stringify(historyData.slice(0, 20)));
@@ -635,28 +486,28 @@
635
  } catch (e) {
636
  console.error("Error parsing server response:", e);
637
  displayInfoMessage('Error processing response.', 'error', true);
638
- progressBar.style.width = '0%';
639
  }
640
  } else {
641
  displayInfoMessage(`Upload failed. Status: ${xhr.status}`, 'error', true);
642
- progressBar.style.background = '#dc3545';
643
  }
644
  };
645
 
646
  xhr.onerror = () => {
647
- loader.style.display = 'none';
648
  displayInfoMessage('Upload error. Check connection.', 'error', true);
649
- progressBar.style.background = '#dc3545';
650
  };
651
 
652
- xhr.open('POST', '/upload/', true);
653
  xhr.send(formData);
654
  });
655
  }
656
 
657
  // Initial load
658
- if (typeof resetUploadUI === 'function') resetUploadUI(); // Check if function exists
659
- document.querySelector('.nav-item[data-target="uploadSection"]')?.click(); // Check if element exists
660
 
661
  </script>
662
  </body>
 
24
  --text-primary: var(--primary-dark-ref);
25
  --text-secondary: #666666;
26
  --text-placeholder: #999999;
27
+ --text-email-on-light: rgba(27, 27, 29, 0.7);
28
 
29
  /* Typography */
30
  --font-main: 'Noto Sans', 'Poppins', sans-serif;
 
33
  /* UI Elements */
34
  --radius-sharp: 4px;
35
  --radius-softer: 6px;
36
+ --radius-profile-card: 12px;
37
  --shadow-none: none;
38
+ --shadow-profile-card: 0 4px 10px rgba(0,0,0,0.1);
 
39
 
40
  --nav-height: 60px;
41
  }
 
70
  }
71
  section.active { display: flex; flex-direction: column; }
72
 
 
73
  button, .button-like {
74
  background: var(--accent-red);
75
  color: var(--text-on-accent);
 
103
  cursor: not-allowed;
104
  }
105
 
 
106
  .uploader { display: flex; flex-direction: column; gap: 16px; width: 100%; max-width: 480px; margin: auto; }
107
  .file-input-area { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 25px 20px; border: 2px dashed var(--border-medium); border-radius: var(--radius-softer); background-color: var(--surface-primary); cursor: pointer; transition: border-color 0.2s, background-color 0.2s; text-align: center; }
108
  .file-input-area:hover, .file-input-area.dragover { border-color: var(--accent-red); background-color: #fff5f5; }
 
134
  .history-item-url { font-size: 0.75em; color: var(--text-secondary); word-break: break-all; display: block; text-decoration: none; font-family: var(--font-mono); }
135
  .history-item-url:hover { color: var(--accent-red); text-decoration: underline;}
136
  .history-item button { padding: 7px 10px; font-size: 0.75rem; min-width: 80px; }
 
137
 
 
 
138
  .profile-container {
139
  display: flex;
140
  flex-direction: column;
141
  align-items: center;
142
+ gap: 24px;
143
+ padding: 16px 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  width: 100%;
145
+ max-width: 450px;
146
+ margin: auto;
147
+ }
148
+ .profile-header { text-align: center; margin-bottom: 16px; }
149
+ .profile-avatar-wrapper { position: relative; width: 120px; height: 120px; margin: 0 auto 20px auto; }
150
+ .profile-avatar { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; border: 3px solid var(--surface-primary); box-shadow: 0 2px 4px rgba(0,0,0,0.1); position: relative; z-index: 2; }
151
+ .profile-avatar-ring { position: absolute; top: -5px; left: -5px; right: -5px; bottom: -5px; border-radius: 50%; border: 2px dotted var(--accent-red); animation: rotateRing 20s linear infinite; z-index: 1; }
152
+ @keyframes rotateRing { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
153
+ .profile-name { font-family: var(--font-mono); font-size: 1.8rem; color: var(--text-primary); margin-bottom: 4px; letter-spacing: 0.5px; }
154
+ .profile-email { font-family: var(--font-main); font-size: 0.95rem; color: var(--text-email-on-light); }
155
+ .profile-action-card { background-color: var(--surface-primary); border-radius: var(--radius-profile-card); padding: 16px; width: 100%; box-shadow: var(--shadow-profile-card); text-align: center; }
156
+ .portfolio-button { display: inline-flex; align-items: center; justify-content: center; gap: 8px; background-color: var(--accent-red); color: var(--text-on-accent); font-family: var(--font-main); font-size: 1rem; font-weight: 500; padding: 12px 24px; border-radius: var(--radius-sharp); text-decoration: none; text-transform: uppercase; letter-spacing: 0.5px; transition: background-color 0.15s ease; width: auto; min-width: 200px; }
157
+ .portfolio-button:hover { background-color: var(--accent-red-hover); }
158
+ .portfolio-button .material-icons { font-size: 20px; }
159
+ .profile-social-links { display: grid; grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); gap: 16px; width: 100%; padding: 0 8px; }
160
+ .social-link-card { background-color: var(--surface-primary); border-radius: var(--radius-profile-card); padding: 16px; box-shadow: var(--shadow-profile-card); display: flex; flex-direction: column; align-items: center; justify-content: center; text-decoration: none; color: var(--text-primary); gap: 8px; transition: transform 0.2s ease, box-shadow 0.2s ease, color 0.2s ease; min-height: 100px; }
161
+ .social-link-card:hover { transform: translateY(-3px) scale(1.03); box-shadow: 0 6px 12px rgba(0,0,0,0.12); color: var(--accent-red); }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  .social-link-card .social-icon {
163
+ width: 28px; /* SVG size */
164
+ height: 28px;
165
+ fill: currentColor; /* Inherits color from .social-link-card for hover effect */
166
+ transition: fill 0.2s ease;
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  }
168
+ .social-link-card span { font-family: var(--font-main); font-size: 0.8rem; font-weight: 500; text-align: center; }
 
 
 
 
 
 
169
 
170
+ .bottom-nav { position: fixed; bottom: 0; left: 0; right: 0; width: 100%; background: var(--surface-primary); display: flex; justify-content: space-around; align-items: stretch; border-top: 1px solid var(--border-light); padding-bottom: env(safe-area-inset-bottom); height: calc(var(--nav-height) + env(safe-area-inset-bottom)); box-shadow: var(--shadow-none); }
171
+ .nav-item { flex: 1; display: flex; flex-direction: column; justify-content: center; align-items: center; font-size: 0.7rem; color: var(--text-secondary); cursor: pointer; transition: color 0.15s ease; padding-top: 5px; padding-bottom: 3px; position: relative; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  .nav-item:hover { color: var(--text-primary); }
173
  .nav-item.active { color: var(--accent-red); font-weight: 700; }
174
+ .nav-item.active::after { content: ''; position: absolute; bottom: 5px; left: 50%; transform: translateX(-50%); width: 5px; height: 5px; background-color: var(--accent-red); border-radius: 50%; }
175
+ .nav-item .material-icons { font-size: 24px; margin-bottom: 2px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
176
 
 
177
  @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
178
  @keyframes fadeIn { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: translateY(0); } }
179
  </style>
 
181
  <body>
182
  <main>
183
  <section id="uploadSection" class="active">
 
184
  <div class="uploader">
185
  <label for="fileInput" class="file-input-area">
186
  <i class="material-icons">upload_file</i>
 
200
  </section>
201
 
202
  <section id="historySection">
 
203
  <div class="history-list" id="historyList"></div>
204
  </section>
205
 
 
216
 
217
  <div class="profile-action-card portfolio-cta-card">
218
  <a href="https://www.adityadevarshi.online/" target="_blank" rel="noopener noreferrer" class="portfolio-button">
219
+ <i class="material-icons">visibility</i>
220
  <span>View My Work</span>
221
  </a>
222
  </div>
223
 
224
  <div class="profile-social-links">
225
  <a href="https://github.com/devarshiadi/" target="_blank" rel="noopener noreferrer" class="social-link-card" aria-label="GitHub Profile">
226
+ <svg class="social-icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>
227
  <span>GitHub</span>
228
  </a>
229
  <a href="https://www.linkedin.com/in/aditya-devarshi/" target="_blank" rel="noopener noreferrer" class="social-link-card" aria-label="LinkedIn Profile">
230
+ <svg class="social-icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z"/></svg>
231
  <span>LinkedIn</span>
232
  </a>
233
  <a href="https://www.instagram.com/curseofwitcher/" target="_blank" rel="noopener noreferrer" class="social-link-card" aria-label="Instagram Profile">
234
+ <svg class="social-icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c.001-3.403-2.758-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z"/></svg>
235
  <span>Instagram</span>
236
  </a>
 
237
  </div>
238
  </div>
239
  </section>
240
  </main>
241
 
242
  <nav class="bottom-nav">
 
243
  <div class="nav-item active" data-target="uploadSection">
244
  <i class="material-icons">home</i> Home
245
  </div>
 
252
  </nav>
253
 
254
  <script>
255
+ const BASE_URL = 'https://triflix-uploadkro2.hf.space'; // Define Base URL
256
+
257
  const navItems = document.querySelectorAll('.nav-item');
258
  const sections = document.querySelectorAll('section');
259
  const uploadBtn = document.getElementById('uploadBtn');
 
270
  let infoTimeout = null;
271
 
272
  function displayInfoMessage(message, type = 'info', persistent = false) {
273
+ if (uploadInfo) {
274
+ if (infoTimeout && !persistent) clearTimeout(infoTimeout);
275
+ uploadInfo.textContent = message;
276
+ uploadInfo.className = 'info';
277
+ if (type === 'error') {
278
+ uploadInfo.classList.add('error-message');
279
+ } else if (type === 'success') {
280
+ uploadInfo.classList.add('success-message');
281
+ }
282
 
283
+ if (message && !persistent && (type === 'error' || message === "Please select a file first.")) {
284
+ infoTimeout = setTimeout(() => {
285
+ if (uploadInfo.textContent === message) {
286
+ uploadInfo.textContent = "";
287
+ uploadInfo.className = 'info';
288
+ }
289
+ }, 3000);
290
+ }
291
  }
292
  }
293
 
294
  function resetUploadUI(clearMessage = true) {
295
+ if (fileInput) fileInput.value = '';
296
+ if (fileNameDisplay) fileNameDisplay.textContent = 'No file selected';
297
+ if (uploadBtn) uploadBtn.disabled = true;
298
+ if (progressContainer) progressContainer.style.display = 'none';
299
+ if (progressBar) progressBar.style.width = '0%';
300
  if (clearMessage) {
301
  displayInfoMessage("");
302
  }
303
+ if (loader) loader.style.display = 'none';
304
+ if (shareLinkContainer) {
305
+ shareLinkContainer.style.display = 'none';
306
+ shareLinkContainer.innerHTML = '';
307
+ }
308
+ if (progressBar) progressBar.style.background = 'var(--accent-red)';
309
+ }
310
+
311
+ if (navItems.length) {
312
+ navItems.forEach(item => {
313
+ item.addEventListener('click', () => {
314
+ navItems.forEach(i => i.classList.remove('active'));
315
+ item.classList.add('active');
316
+ const targetId = item.dataset.target;
317
+ sections.forEach(sec => {
318
+ sec.classList.toggle('active', sec.id === targetId);
319
+ });
320
+ if (targetId === 'historySection') {
321
+ loadHistory();
322
+ }
323
+ });
324
+ });
325
  }
326
 
 
 
 
 
 
 
 
 
 
 
 
 
 
327
 
328
+ if (fileInput && fileInputArea && fileNameDisplay && uploadBtn && progressContainer && progressBar && uploadInfo && shareLinkContainer && loader) {
329
  fileInput.addEventListener('change', () => {
330
  if (fileInput.files.length > 0) {
331
  fileNameDisplay.textContent = fileInput.files[0].name;
 
384
  }
385
 
386
  function loadHistory() {
387
+ if (!historyList) return;
388
  const data = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
389
  historyList.innerHTML = '';
390
  if (data.length === 0) {
 
395
  const el = document.createElement('div');
396
  el.className = 'history-item';
397
  const dateStr = entry.timestamp ? new Date(entry.timestamp).toLocaleDateString() : '';
398
+ // Ensure entry.url is a full URL (new entries will be, old ones might not if not migrated)
399
+ const fullUrl = entry.url.startsWith('http') ? entry.url : `${BASE_URL}${entry.url}`;
400
+
401
  el.innerHTML = `
402
  <div class="history-item-info">
403
  <div class="history-item-name">${entry.name}</div>
404
+ <a href="${fullUrl}" target="_blank" rel="noopener noreferrer" class="history-item-url">${fullUrl.length > 50 ? fullUrl.substring(0,50)+'...' : fullUrl}</a>
405
  ${dateStr ? `<span style="font-size:0.7em; color:var(--text-placeholder); display:block; margin-top:2px;">${dateStr}</span>` : ''}
406
  </div>
407
+ <button data-url="${fullUrl}">Copy</button>
408
  `;
409
  historyList.appendChild(el);
410
  el.querySelector('button').addEventListener('click', function() {
 
413
  });
414
  }
415
 
416
+ if (uploadBtn && fileInput && loader && progressContainer && progressBar && uploadInfo && shareLinkContainer) {
417
  uploadBtn.addEventListener('click', () => {
418
  const file = fileInput.files[0];
419
  if (!file) {
 
447
  if (xhr.status === 200) {
448
  try {
449
  const response = JSON.parse(xhr.responseText);
450
+ // Prepend BASE_URL if download_url is relative
451
+ const fullDownloadUrl = response.download_url.startsWith('http') ? response.download_url : `${BASE_URL}${response.download_url}`;
452
+
453
  progressBar.style.width = '100%';
454
  displayInfoMessage('Upload Complete!', 'success', true);
455
 
456
  shareLinkContainer.innerHTML = `
457
  <p>Share Link:</p>
458
  <div class="share-link-display">
459
+ <input type="text" value="${fullDownloadUrl}" id="shareableLinkInput-${Date.now()}" readonly>
460
+ <button data-url="${fullDownloadUrl}">Copy</button>
461
  </div>
462
  `;
463
  shareLinkContainer.style.display = 'block';
464
  shareLinkContainer.querySelector('button').addEventListener('click', function() {
465
  const inputId = this.previousElementSibling.id;
466
  const linkInput = document.getElementById(inputId);
467
+ if (linkInput) {
468
+ linkInput.select();
469
+ linkInput.setSelectionRange(0, 99999);
470
+ copyToClipboard(this.dataset.url, this);
471
+ }
472
  });
473
 
474
  const historyData = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
475
  historyData.unshift({
476
  name: response.filename || file.name,
477
+ url: fullDownloadUrl, // Store the full URL
478
  timestamp: Date.now()
479
  });
480
  localStorage.setItem(STORAGE_KEY, JSON.stringify(historyData.slice(0, 20)));
 
486
  } catch (e) {
487
  console.error("Error parsing server response:", e);
488
  displayInfoMessage('Error processing response.', 'error', true);
489
+ if(progressBar) progressBar.style.width = '0%';
490
  }
491
  } else {
492
  displayInfoMessage(`Upload failed. Status: ${xhr.status}`, 'error', true);
493
+ if(progressBar) progressBar.style.background = '#dc3545';
494
  }
495
  };
496
 
497
  xhr.onerror = () => {
498
+ if(loader) loader.style.display = 'none';
499
  displayInfoMessage('Upload error. Check connection.', 'error', true);
500
+ if(progressBar) progressBar.style.background = '#dc3545';
501
  };
502
 
503
+ xhr.open('POST', '/upload/', true); // DO NOT CHANGE BACKEND
504
  xhr.send(formData);
505
  });
506
  }
507
 
508
  // Initial load
509
+ if (typeof resetUploadUI === 'function') resetUploadUI();
510
+ document.querySelector('.nav-item[data-target="uploadSection"]')?.click();
511
 
512
  </script>
513
  </body>