uploads

Log | Files | Refs

commit 750156eb45ddf34224b5c745c7823836599ddd1c
parent 76206b5299ca7f6449d56fcae9a1d27f40dd0777
Author: Amit Dutta <mail@amit.is-a.dev>
Date:   Mon, 20 Jul 2026 20:29:28 +0530

Update index.html
Diffstat:
Mindex.html | 389++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
1 file changed, 236 insertions(+), 153 deletions(-)

diff --git a/index.html b/index.html @@ -10,153 +10,151 @@ const urlParams = new URLSearchParams(window.location.search); const item = urlParams.get('item'); if (item) { - // Instantly redirect to the raw Hugging Face Dataset URL window.location.replace(`https://huggingface.co/datasets/notamitgamer/uploads/resolve/main/${item}`); } </script> - <style> - :root { - --bg: #f4f4f5; - --text: #18181b; - --primary: #000000; - --border: #e4e4e7; - --card-bg: #ffffff; - --radius: 12px; + <!-- Fonts: Lexend --> + <link rel="preconnect" href="https://fonts.googleapis.com"> + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> + <link href="https://fonts.googleapis.com/css2?family=Lexend:wght@300;400;500;600;700&display=swap" rel="stylesheet"> + + <!-- Material Symbols (Icons) --> + <link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0" rel="stylesheet" /> + + <!-- Tailwind CSS --> + <script src="https://cdn.tailwindcss.com"></script> + <script> + tailwind.config = { + theme: { + extend: { + fontFamily: { + sans: ['Lexend', 'sans-serif'], + }, + colors: { + // Material 3 Color Palette (Light/Dark adaptive approximations) + m3: { + surface: '#FEF7FF', + surfaceDark: '#141218', + surfaceContainer: '#F3EDF7', + surfaceContainerDark: '#211F26', + primary: '#6750A4', + primaryDark: '#D0BCFF', + onPrimary: '#FFFFFF', + onPrimaryDark: '#381E72', + secondaryContainer: '#E8DEF8', + onSecondaryContainer: '#1D192B', + error: '#B3261E', + errorDark: '#F2B8B5' + } + } + } + } } + </script> + + <style> body { - font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Segoe UI", Roboto, sans-serif; - background-color: var(--bg); - color: var(--text); - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - min-height: 100vh; - margin: 0; - padding: 20px; - box-sizing: border-box; - -webkit-font-smoothing: antialiased; + /* Fallback background if Tailwind fails to load instantly */ + background-color: #FEF7FF; } - .container { - background: var(--card-bg); - padding: 2.5rem; - border-radius: var(--radius); - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05), 0 1px 3px rgba(0,0,0,0.02); - width: 100%; - max-width: 440px; - text-align: center; + @media (prefers-color-scheme: dark) { + body { background-color: #141218; } } - h1 { - margin-top: 0; - margin-bottom: 1.5rem; - font-size: 1.4rem; - font-weight: 600; - letter-spacing: -0.5px; - } - input[type="text"] { - width: 100%; - padding: 0.85rem 1rem; - margin-bottom: 1.2rem; - border: 1px solid var(--border); - border-radius: 8px; - font-size: 0.95rem; - box-sizing: border-box; - outline: none; - transition: all 0.2s ease; - background-color: #fafafa; - } - input[type="text"]:focus { - border-color: #a1a1aa; - background-color: #ffffff; - box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.05); + + .progress-bar-fill { + transition: width 0.3s cubic-bezier(0.4, 0, 0.2, 1); } - #dropzone { - border: 2px dashed #d4d4d8; - border-radius: 10px; - padding: 3rem 1.5rem; - cursor: pointer; + + .m3-input { transition: all 0.2s ease; - background-color: #fafafa; - position: relative; - } - #dropzone.hover { - border-color: var(--primary); - background-color: #f4f4f5; - } - #dropzone p { - margin: 0; - color: #71717a; - font-size: 0.95rem; - line-height: 1.5; - pointer-events: none; - } - #dropzone svg { - width: 32px; - height: 32px; - color: #a1a1aa; - margin-bottom: 12px; - transition: color 0.2s ease; + box-shadow: 0 1px 0 0 #49454F; /* Bottom border effect */ } - #dropzone.hover svg { - color: var(--primary); - } - #result { - margin-top: 1.5rem; - font-size: 0.9rem; - word-break: break-all; - min-height: 24px; - color: #52525b; - } - a { - color: var(--text); - text-decoration: none; - font-weight: 500; - background: #f4f4f5; - padding: 0.5rem 0.85rem; - border-radius: 6px; - display: inline-block; - margin-top: 0.75rem; - border: 1px solid var(--border); - transition: all 0.2s ease; + .m3-input:focus { + box-shadow: 0 2px 0 0 #6750A4; /* Active bottom border */ + outline: none; } - a:hover { - background: #e4e4e7; + @media (prefers-color-scheme: dark) { + .m3-input { box-shadow: 0 1px 0 0 #CAC4D0; } + .m3-input:focus { box-shadow: 0 2px 0 0 #D0BCFF; } } - .loader { - display: inline-block; - width: 16px; - height: 16px; - border: 2px solid rgba(0,0,0,0.1); - border-radius: 50%; - border-top-color: var(--primary); - animation: spin 0.8s ease-in-out infinite; - vertical-align: middle; - margin-right: 8px; + + /* Smooth fade ins */ + .fade-in { + animation: fadeIn 0.3s ease-in forwards; } - @keyframes spin { - to { transform: rotate(360deg); } + @keyframes fadeIn { + from { opacity: 0; transform: translateY(10px); } + to { opacity: 1; transform: translateY(0); } } - .error { color: #dc2626; } - .success { color: #16a34a; font-weight: 500; } </style> </head> -<body> +<body class="bg-m3-surface dark:bg-m3-surfaceDark text-gray-900 dark:text-gray-100 flex flex-col items-center justify-center min-h-screen p-4 m-0 antialiased font-sans transition-colors duration-300"> - <div class="container" id="ui-container" style="display: none;"> - <h1>Upload File</h1> - - <input type="text" id="custom-id" placeholder="Custom link name (optional)"> + <!-- Main Card Container (Hidden initially to prevent flash before redirect check) --> + <div id="ui-container" class="bg-m3-surfaceContainer dark:bg-m3-surfaceContainerDark w-full max-w-[480px] rounded-[28px] p-8 shadow-sm transition-colors duration-300" style="display: none;"> - <div id="dropzone"> - <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"> - <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" /> - </svg> - <p><strong>Click to upload</strong> or drag and drop<br>Max size: 4.5MB (Vercel Limit)</p> - <input type="file" id="file-input" style="display: none;"> + <!-- Header --> + <div class="flex items-center gap-3 mb-6"> + <div class="bg-m3-secondaryContainer text-m3-onSecondaryContainer p-3 rounded-xl flex items-center justify-center"> + <span class="material-symbols-outlined">cloud_upload</span> + </div> + <div> + <h1 class="text-xl font-semibold leading-tight">Upload File</h1> + <p class="text-sm text-gray-600 dark:text-gray-400">Drag & drop or browse</p> + </div> + </div> + + <!-- Input Field --> + <div class="mb-6 relative"> + <input type="text" id="custom-id" placeholder=" " class="m3-input block w-full px-4 pt-5 pb-2 text-base bg-m3-surface dark:bg-[#2B2930] rounded-t-lg peer placeholder-transparent"> + <label for="custom-id" class="absolute text-sm text-gray-500 dark:text-gray-400 duration-300 transform -translate-y-3 scale-75 top-4 z-10 origin-[0] left-4 peer-placeholder-shown:scale-100 peer-placeholder-shown:translate-y-0 peer-focus:scale-75 peer-focus:-translate-y-3 peer-focus:text-m3-primary dark:peer-focus:text-m3-primaryDark">Custom link ID (Optional)</label> + </div> + + <!-- Dropzone --> + <div id="dropzone" class="border-2 border-dashed border-gray-400 dark:border-gray-600 rounded-[20px] p-8 text-center cursor-pointer hover:bg-m3-surface dark:hover:bg-[#2B2930] hover:border-m3-primary dark:hover:border-m3-primaryDark transition-all duration-200 group relative"> + <span class="material-symbols-outlined text-4xl text-gray-400 group-hover:text-m3-primary dark:group-hover:text-m3-primaryDark mb-3 block transition-colors">upload_file</span> + <p class="text-sm font-medium mb-1">Click or drag a file here</p> + <p class="text-xs text-gray-500 dark:text-gray-400">Max limit: 4.5MB (Vercel limits)</p> + <input type="file" id="file-input" class="hidden"> </div> - <div id="result"></div> + <!-- Status Area (Progress / Result / Error) --> + <div id="status-area" class="mt-6 hidden"> + + <!-- Progress View --> + <div id="progress-container" class="hidden fade-in"> + <div class="flex justify-between items-center mb-2"> + <span class="text-sm font-medium">Uploading...</span> + <span id="progress-text" class="text-sm font-semibold text-m3-primary dark:text-m3-primaryDark">0%</span> + </div> + <div class="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2 overflow-hidden"> + <div id="progress-bar" class="progress-bar-fill bg-m3-primary dark:bg-m3-primaryDark h-2 rounded-full w-0"></div> + </div> + </div> + + <!-- Result View --> + <div id="result-container" class="hidden fade-in bg-m3-surface dark:bg-[#2B2930] rounded-2xl p-4 border border-gray-200 dark:border-gray-700"> + <div class="flex items-center gap-2 mb-3 text-green-600 dark:text-green-400"> + <span class="material-symbols-outlined">check_circle</span> + <span class="font-semibold text-sm">Upload complete!</span> + </div> + + <div class="bg-m3-surfaceContainer dark:bg-m3-surfaceContainerDark p-3 rounded-xl flex items-center justify-between gap-3 overflow-hidden"> + <a id="final-link" href="#" target="_blank" class="text-sm text-m3-primary dark:text-m3-primaryDark truncate hover:underline font-medium"></a> + <button id="copy-btn" class="flex-shrink-0 bg-m3-primary dark:bg-m3-primaryDark text-white dark:text-gray-900 rounded-full w-10 h-10 flex items-center justify-center hover:opacity-90 transition-opacity focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-m3-primary" title="Copy to clipboard"> + <span class="material-symbols-outlined text-[20px]" id="copy-icon">content_copy</span> + </button> + </div> + </div> + + <!-- Error View --> + <div id="error-container" class="hidden fade-in text-m3-error dark:text-m3-errorDark bg-[#F9DEDC] dark:bg-[#8C1D18] bg-opacity-20 dark:bg-opacity-20 p-4 rounded-2xl flex items-start gap-3"> + <span class="material-symbols-outlined">error</span> + <span id="error-text" class="text-sm font-medium mt-0.5"></span> + </div> + + </div> </div> <script> @@ -168,20 +166,36 @@ const dropzone = document.getElementById('dropzone'); const fileInput = document.getElementById('file-input'); const customIdInput = document.getElementById('custom-id'); - const resultDiv = document.getElementById('result'); + + // UI Elements + const statusArea = document.getElementById('status-area'); + const progressContainer = document.getElementById('progress-container'); + const progressBar = document.getElementById('progress-bar'); + const progressText = document.getElementById('progress-text'); + + const resultContainer = document.getElementById('result-container'); + const finalLink = document.getElementById('final-link'); + const copyBtn = document.getElementById('copy-btn'); + const copyIcon = document.getElementById('copy-icon'); + + const errorContainer = document.getElementById('error-container'); + const errorText = document.getElementById('error-text'); + // Drag and drop event bindings dropzone.addEventListener('click', () => fileInput.click()); dropzone.addEventListener('dragover', (e) => { e.preventDefault(); - dropzone.classList.add('hover'); + dropzone.classList.add('border-m3-primary', 'dark:border-m3-primaryDark', 'bg-m3-surface', 'dark:bg-[#2B2930]'); }); - dropzone.addEventListener('dragleave', () => dropzone.classList.remove('hover')); + dropzone.addEventListener('dragleave', () => { + dropzone.classList.remove('border-m3-primary', 'dark:border-m3-primaryDark', 'bg-m3-surface', 'dark:bg-[#2B2930]'); + }); dropzone.addEventListener('drop', (e) => { e.preventDefault(); - dropzone.classList.remove('hover'); + dropzone.classList.remove('border-m3-primary', 'dark:border-m3-primaryDark', 'bg-m3-surface', 'dark:bg-[#2B2930]'); if (e.dataTransfer.files.length) { uploadFile(e.dataTransfer.files[0]); } @@ -193,13 +207,56 @@ } }); - async function uploadFile(file) { + // Copy button logic + copyBtn.addEventListener('click', () => { + const linkToCopy = finalLink.href; + + // Modern clipboard API + navigator.clipboard.writeText(linkToCopy).then(() => { + // Success visual feedback + copyIcon.textContent = 'check'; + copyBtn.classList.add('bg-green-500', 'dark:bg-green-400'); + + setTimeout(() => { + copyIcon.textContent = 'content_copy'; + copyBtn.classList.remove('bg-green-500', 'dark:bg-green-400'); + }, 2000); + }).catch(err => { + console.error('Failed to copy: ', err); + // Fallback for older browsers / strict environments + const tempInput = document.createElement("input"); + tempInput.value = linkToCopy; + document.body.appendChild(tempInput); + tempInput.select(); + document.execCommand("copy"); + document.body.removeChild(tempInput); + + copyIcon.textContent = 'check'; + setTimeout(() => { copyIcon.textContent = 'content_copy'; }, 2000); + }); + }); + + function resetUI() { + statusArea.classList.remove('hidden'); + progressContainer.classList.add('hidden'); + resultContainer.classList.add('hidden'); + errorContainer.classList.add('hidden'); + progressBar.style.width = '0%'; + progressText.innerText = '0%'; + } + + function uploadFile(file) { + resetUI(); + if (file.size > 4.5 * 1024 * 1024) { - resultDiv.innerHTML = `<span class="error">Error: File exceeds 4.5MB Vercel limit.</span>`; + errorText.innerText = "Error: File exceeds 4.5MB Vercel limit."; + errorContainer.classList.remove('hidden'); return; } - resultDiv.innerHTML = '<span class="loader"></span> Uploading...'; + // Show progress state + progressContainer.classList.remove('hidden'); + const formData = new FormData(); formData.append('file', file); @@ -208,29 +265,55 @@ formData.append('custom_id', customId); } - try { - // Send to the Vercel serverless function - const response = await fetch('/api/upload', { - method: 'POST', - body: formData - }); - - const data = await response.json(); + // Use XMLHttpRequest to track progress natively + const xhr = new XMLHttpRequest(); + xhr.open('POST', '/api/upload', true); + + xhr.upload.onprogress = function(e) { + if (e.lengthComputable) { + const percentComplete = Math.round((e.loaded / e.total) * 100); + progressBar.style.width = percentComplete + '%'; + progressText.innerText = percentComplete + '%'; + } + }; + + xhr.onload = function() { + progressContainer.classList.add('hidden'); // Hide progress bar - if (response.ok) { - const finalUrl = `https://upload.amit.is-a.dev/?item=${data.item_id}`; - resultDiv.innerHTML = ` - <span class="success">Upload Complete!</span><br> - <a href="${finalUrl}" target="_blank">${finalUrl}</a> - `; - fileInput.value = ''; - customIdInput.value = ''; + if (xhr.status >= 200 && xhr.status < 300) { + try { + const data = JSON.parse(xhr.responseText); + const finalUrl = `https://upload.amit.is-a.dev/?item=${data.item_id}`; + + finalLink.href = finalUrl; + finalLink.innerText = finalUrl; + resultContainer.classList.remove('hidden'); + + // Reset inputs + fileInput.value = ''; + customIdInput.value = ''; + } catch(err) { + errorText.innerText = "Error: Invalid response from server."; + errorContainer.classList.remove('hidden'); + } } else { - resultDiv.innerHTML = `<span class="error">Error: ${data.detail || 'Upload failed'}</span>`; + try { + const errData = JSON.parse(xhr.responseText); + errorText.innerText = `Error: ${errData.detail || 'Upload failed'}`; + } catch(err) { + errorText.innerText = "Error: Upload failed."; + } + errorContainer.classList.remove('hidden'); } - } catch (error) { - resultDiv.innerHTML = `<span class="error">System Error: Could not connect to server.</span>`; - } + }; + + xhr.onerror = function() { + progressContainer.classList.add('hidden'); + errorText.innerText = "System Error: Could not connect to server."; + errorContainer.classList.remove('hidden'); + }; + + xhr.send(formData); } </script> </body>
© notamitgamer • Site Built: 2026-07-21 13:58:23 UTC • git-mirror commit: 1037f62 [view raw info]
Originally created with stagit • modified by notamitgamer
Forked from github.com/notamitgamer/git-mirror