| | <!DOCTYPE html> |
| | <html lang="en"> |
| | <head> |
| | <meta charset="UTF-8"> |
| | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| | <title>Hugging Face Dataset Creator</title> |
| | <script src="https://cdn.tailwindcss.com"></script> |
| | <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| | <style> |
| | .gradient-bg { |
| | background: linear-gradient(135deg, #6b73ff 0%, #000dff 100%); |
| | } |
| | .dataset-card:hover { |
| | transform: translateY(-5px); |
| | box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); |
| | } |
| | .slide-in { |
| | animation: slideIn 0.3s ease-out forwards; |
| | } |
| | @keyframes slideIn { |
| | from { |
| | opacity: 0; |
| | transform: translateY(20px); |
| | } |
| | to { |
| | opacity: 1; |
| | transform: translateY(0); |
| | } |
| | } |
| | .field-pill { |
| | transition: all 0.2s ease; |
| | } |
| | .field-pill:hover { |
| | background-color: #e0e7ff; |
| | } |
| | </style> |
| | </head> |
| | <body class="bg-gray-50 min-h-screen"> |
| | <div class="gradient-bg text-white py-6 shadow-lg"> |
| | <div class="container mx-auto px-4"> |
| | <div class="flex justify-between items-center"> |
| | <div class="flex items-center space-x-2"> |
| | <i class="fas fa-robot text-3xl"></i> |
| | <h1 class="text-2xl font-bold">Hugging Face Dataset Creator</h1> |
| | </div> |
| | <div class="flex items-center space-x-4"> |
| | <button id="authBtn" class="bg-white text-blue-600 px-4 py-2 rounded-lg font-medium hover:bg-gray-100 transition"> |
| | <i class="fas fa-key mr-2"></i>Authenticate |
| | </button> |
| | </div> |
| | </div> |
| | </div> |
| | </div> |
| |
|
| | |
| | <div id="authModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50"> |
| | <div class="bg-white rounded-lg p-6 w-full max-w-md slide-in"> |
| | <div class="flex justify-between items-center mb-4"> |
| | <h2 class="text-xl font-bold text-gray-800">Hugging Face Authentication</h2> |
| | <button id="closeAuthModal" class="text-gray-500 hover:text-gray-700"> |
| | <i class="fas fa-times"></i> |
| | </button> |
| | </div> |
| | <div class="mb-4"> |
| | <label class="block text-gray-700 text-sm font-medium mb-2" for="hfToken"> |
| | Hugging Face Token |
| | </label> |
| | <input type="password" id="hfToken" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="hf_xxxxxxxxxxxxxxxx"> |
| | <p class="text-xs text-gray-500 mt-1">Get your token from <a href="https://huggingface.co/settings/tokens" target="_blank" class="text-blue-500 hover:underline">Hugging Face settings</a></p> |
| | </div> |
| | <div class="flex justify-end space-x-3"> |
| | <button id="cancelAuth" class="px-4 py-2 border border-gray-300 rounded-md text-gray-700 hover:bg-gray-50"> |
| | Cancel |
| | </button> |
| | <button id="saveToken" class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700"> |
| | Save Token |
| | </button> |
| | </div> |
| | </div> |
| | </div> |
| |
|
| | <div class="container mx-auto px-4 py-8"> |
| | <div class="grid grid-cols-1 lg:grid-cols-3 gap-8"> |
| | |
| | <div class="lg:col-span-1 bg-white rounded-lg shadow-md p-6 h-fit"> |
| | <h2 class="text-xl font-bold text-gray-800 mb-6 flex items-center"> |
| | <i class="fas fa-cog mr-2 text-blue-600"></i> Dataset Configuration |
| | </h2> |
| | |
| | <div class="mb-6"> |
| | <label class="block text-gray-700 text-sm font-medium mb-2" for="datasetName"> |
| | Dataset Name |
| | </label> |
| | <input type="text" id="datasetName" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="my-custom-dataset"> |
| | </div> |
| | |
| | <div class="mb-6"> |
| | <label class="block text-gray-700 text-sm font-medium mb-2" for="datasetDesc"> |
| | Description |
| | </label> |
| | <textarea id="datasetDesc" rows="3" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Describe your dataset..."></textarea> |
| | </div> |
| | |
| | <div class="mb-6"> |
| | <div class="flex justify-between items-center mb-2"> |
| | <label class="block text-gray-700 text-sm font-medium">Fields</label> |
| | <button id="addFieldBtn" class="text-blue-600 text-sm font-medium hover:text-blue-800 flex items-center"> |
| | <i class="fas fa-plus mr-1"></i> Add Field |
| | </button> |
| | </div> |
| | <div id="fieldsContainer" class="space-y-2"> |
| | |
| | </div> |
| | </div> |
| | |
| | <div class="flex space-x-3"> |
| | <button id="createDatasetBtn" class="flex-1 bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 flex items-center justify-center"> |
| | <i class="fas fa-database mr-2"></i> Create Dataset |
| | </button> |
| | </div> |
| | </div> |
| |
|
| |
|
| | |
| | |
| | <div class="lg:col-span-2"> |
| | <div class="bg-white rounded-lg shadow-md p-6 mb-6"> |
| | <div class="flex justify-between items-center mb-6"> |
| | <h2 class="text-xl font-bold text-gray-800 flex items-center"> |
| | <i class="fas fa-edit mr-2 text-blue-600"></i> Data Entry |
| | </h2> |
| | <div class="flex space-x-2"> |
| | <button id="addRowBtn" class="bg-green-600 text-white px-3 py-1 rounded-md text-sm hover:bg-green-700 flex items-center"> |
| | <i class="fas fa-plus mr-1"></i> Add Row |
| | </button> |
| | <button id="clearDataBtn" class="bg-gray-200 text-gray-700 px-3 py-1 rounded-md text-sm hover:bg-gray-300 flex items-center"> |
| | <i class="fas fa-trash-alt mr-1"></i> Clear |
| | </button> |
| | </div> |
| | </div> |
| | |
| | <div id="dataTableContainer" class="overflow-x-auto"> |
| | <table class="min-w-full divide-y divide-gray-200"> |
| | <thead class="bg-gray-50"> |
| | <tr id="tableHeaders"> |
| | |
| | <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"> |
| | Actions |
| | </th> |
| | </tr> |
| | </thead> |
| | <tbody id="tableBody" class="bg-white divide-y divide-gray-200"> |
| | |
| | <tr id="noDataRow"> |
| | <td colspan="100" class="px-6 py-4 text-center text-gray-500"> |
| | No data yet. Add fields and start entering data! |
| | </td> |
| | </tr> |
| | </tbody> |
| | </table> |
| | </div> |
| | </div> |
| | |
| | |
| | <div class="bg-white rounded-lg shadow-md p-6"> |
| | <h2 class="text-xl font-bold text-gray-800 mb-6 flex items-center"> |
| | <i class="fas fa-save mr-2 text-blue-600"></i> Save & Export |
| | </h2> |
| | |
| | <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6"> |
| | <div class="bg-gray-50 p-4 rounded-lg border border-gray-200"> |
| | <h3 class="font-medium text-gray-800 mb-2 flex items-center"> |
| | <i class="fas fa-download mr-2 text-blue-600"></i> Save Locally |
| | </h3> |
| | <p class="text-sm text-gray-600 mb-3">Download your dataset as a JSON file to your computer.</p> |
| | <button id="saveLocalBtn" class="w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 flex items-center justify-center"> |
| | <i class="fas fa-file-export mr-2"></i> Export to JSON |
| | </button> |
| | </div> |
| | |
| | <div class="bg-gray-50 p-4 rounded-lg border border-gray-200"> |
| | <h3 class="font-medium text-gray-800 mb-2 flex items-center"> |
| | <i class="fas fa-cloud-upload-alt mr-2 text-blue-600"></i> Upload to Hugging Face |
| | </h3> |
| | <p class="text-sm text-gray-600 mb-3">Push your dataset directly to your Hugging Face repository.</p> |
| | <button id="uploadHuggingFaceBtn" class="w-full bg-purple-600 text-white py-2 px-4 rounded-md hover:bg-purple-700 flex items-center justify-center"> |
| | <i class="fas fa-robot mr-2"></i> Upload to HF Hub |
| | </button> |
| | </div> |
| | </div> |
| | |
| | <div id="uploadStatus" class="hidden"> |
| | |
| | </div> |
| | </div> |
| | </div> |
| | </div> |
| | </div> |
| |
|
| | <script> |
| | |
| | let state = { |
| | hfToken: localStorage.getItem('hfToken') || null, |
| | fields: [], |
| | data: [], |
| | datasetName: '', |
| | datasetDesc: '' |
| | }; |
| | |
| | |
| | const authBtn = document.getElementById('authBtn'); |
| | const authModal = document.getElementById('authModal'); |
| | const closeAuthModal = document.getElementById('closeAuthModal'); |
| | const cancelAuth = document.getElementById('cancelAuth'); |
| | const saveToken = document.getElementById('saveToken'); |
| | const hfTokenInput = document.getElementById('hfToken'); |
| | const datasetNameInput = document.getElementById('datasetName'); |
| | const datasetDescInput = document.getElementById('datasetDesc'); |
| | const fieldsContainer = document.getElementById('fieldsContainer'); |
| | const addFieldBtn = document.getElementById('addFieldBtn'); |
| | const createDatasetBtn = document.getElementById('createDatasetBtn'); |
| | const addRowBtn = document.getElementById('addRowBtn'); |
| | const clearDataBtn = document.getElementById('clearDataBtn'); |
| | const tableHeaders = document.getElementById('tableHeaders'); |
| | const tableBody = document.getElementById('tableBody'); |
| | const noDataRow = document.getElementById('noDataRow'); |
| | const saveLocalBtn = document.getElementById('saveLocalBtn'); |
| | const uploadHuggingFaceBtn = document.getElementById('uploadHuggingFaceBtn'); |
| | const uploadStatus = document.getElementById('uploadStatus'); |
| | |
| | |
| | document.addEventListener('DOMContentLoaded', () => { |
| | updateAuthUI(); |
| | loadFromLocalStorage(); |
| | renderFields(); |
| | renderTable(); |
| | |
| | |
| | if (!state.datasetName) { |
| | state.datasetName = `my-dataset-${new Date().toISOString().slice(0, 10).replace(/-/g, '')}`; |
| | datasetNameInput.value = state.datasetName; |
| | } |
| | }); |
| | |
| | |
| | authBtn.addEventListener('click', () => { |
| | if (state.hfToken) { |
| | |
| | state.hfToken = null; |
| | localStorage.removeItem('hfToken'); |
| | updateAuthUI(); |
| | } else { |
| | |
| | authModal.classList.remove('hidden'); |
| | hfTokenInput.value = state.hfToken || ''; |
| | } |
| | }); |
| | |
| | closeAuthModal.addEventListener('click', () => authModal.classList.add('hidden')); |
| | cancelAuth.addEventListener('click', () => authModal.classList.add('hidden')); |
| | |
| | saveToken.addEventListener('click', () => { |
| | const token = hfTokenInput.value.trim(); |
| | if (token) { |
| | state.hfToken = token; |
| | localStorage.setItem('hfToken', token); |
| | authModal.classList.add('hidden'); |
| | updateAuthUI(); |
| | showToast('Token saved successfully!', 'success'); |
| | } else { |
| | showToast('Please enter a valid token', 'error'); |
| | } |
| | }); |
| | |
| | addFieldBtn.addEventListener('click', () => { |
| | const fieldName = prompt('Enter field name:'); |
| | if (fieldName && fieldName.trim()) { |
| | const fieldType = prompt('Enter field type (text, number, boolean):', 'text'); |
| | const validTypes = ['text', 'number', 'boolean']; |
| | |
| | if (validTypes.includes(fieldType.toLowerCase())) { |
| | state.fields.push({ |
| | name: fieldName.trim(), |
| | type: fieldType.toLowerCase() |
| | }); |
| | saveToLocalStorage(); |
| | renderFields(); |
| | renderTable(); |
| | } else { |
| | showToast('Invalid field type. Must be text, number, or boolean.', 'error'); |
| | } |
| | } |
| | }); |
| | |
| | createDatasetBtn.addEventListener('click', () => { |
| | state.datasetName = datasetNameInput.value.trim(); |
| | state.datasetDesc = datasetDescInput.value.trim(); |
| | |
| | if (!state.datasetName) { |
| | showToast('Please enter a dataset name', 'error'); |
| | return; |
| | } |
| | |
| | if (state.fields.length === 0) { |
| | showToast('Please add at least one field', 'error'); |
| | return; |
| | } |
| | |
| | saveToLocalStorage(); |
| | showToast('Dataset configuration saved!', 'success'); |
| | }); |
| | |
| | addRowBtn.addEventListener('click', () => { |
| | if (state.fields.length === 0) { |
| | showToast('Please add fields first', 'error'); |
| | return; |
| | } |
| | |
| | state.data.push(createEmptyRow()); |
| | saveToLocalStorage(); |
| | renderTable(); |
| | }); |
| | |
| | clearDataBtn.addEventListener('click', () => { |
| | if (confirm('Are you sure you want to clear all data?')) { |
| | state.data = []; |
| | saveToLocalStorage(); |
| | renderTable(); |
| | showToast('Data cleared', 'info'); |
| | } |
| | }); |
| | |
| | saveLocalBtn.addEventListener('click', () => { |
| | if (state.data.length === 0) { |
| | showToast('No data to export', 'error'); |
| | return; |
| | } |
| | |
| | const dataset = { |
| | name: state.datasetName, |
| | description: state.datasetDesc, |
| | fields: state.fields, |
| | data: state.data |
| | }; |
| | |
| | const blob = new Blob([JSON.stringify(dataset, null, 2)], { type: 'application/json' }); |
| | const url = URL.createObjectURL(blob); |
| | const a = document.createElement('a'); |
| | a.href = url; |
| | a.download = `${state.datasetName}.json`; |
| | document.body.appendChild(a); |
| | a.click(); |
| | document.body.removeChild(a); |
| | URL.revokeObjectURL(url); |
| | |
| | showToast('Dataset exported successfully!', 'success'); |
| | }); |
| | |
| | uploadHuggingFaceBtn.addEventListener('click', async () => { |
| | if (!state.hfToken) { |
| | showToast('Please authenticate with Hugging Face first', 'error'); |
| | authModal.classList.remove('hidden'); |
| | return; |
| | } |
| | |
| | if (state.data.length === 0) { |
| | showToast('No data to upload', 'error'); |
| | return; |
| | } |
| | |
| | try { |
| | uploadStatus.innerHTML = ` |
| | <div class="bg-blue-50 border-l-4 border-blue-500 p-4"> |
| | <div class="flex items-center"> |
| | <div class="flex-shrink-0"> |
| | <i class="fas fa-circle-notch fa-spin text-blue-500"></i> |
| | </div> |
| | <div class="ml-3"> |
| | <p class="text-sm text-blue-700"> |
| | Uploading dataset to Hugging Face... |
| | </p> |
| | </div> |
| | </div> |
| | </div> |
| | `; |
| | uploadStatus.classList.remove('hidden'); |
| | |
| | |
| | |
| | await new Promise(resolve => setTimeout(resolve, 2000)); |
| | |
| | uploadStatus.innerHTML = ` |
| | <div class="bg-green-50 border-l-4 border-green-500 p-4"> |
| | <div class="flex items-center"> |
| | <div class="flex-shrink-0"> |
| | <i class="fas fa-check-circle text-green-500"></i> |
| | </div> |
| | <div class="ml-3"> |
| | <p class="text-sm text-green-700"> |
| | Dataset uploaded successfully to <span class="font-medium">${state.datasetName}</span>! |
| | </p> |
| | </div> |
| | </div> |
| | </div> |
| | `; |
| | |
| | showToast('Dataset uploaded successfully!', 'success'); |
| | } catch (error) { |
| | uploadStatus.innerHTML = ` |
| | <div class="bg-red-50 border-l-4 border-red-500 p-4"> |
| | <div class="flex items-center"> |
| | <div class="flex-shrink-0"> |
| | <i class="fas fa-exclamation-circle text-red-500"></i> |
| | </div> |
| | <div class="ml-3"> |
| | <p class="text-sm text-red-700"> |
| | Error uploading dataset: ${error.message} |
| | </p> |
| | </div> |
| | </div> |
| | </div> |
| | `; |
| | showToast('Error uploading dataset', 'error'); |
| | } |
| | }); |
| | |
| | |
| | function updateAuthUI() { |
| | if (state.hfToken) { |
| | authBtn.innerHTML = '<i class="fas fa-check-circle mr-2"></i> Authenticated'; |
| | authBtn.classList.remove('bg-white', 'text-blue-600'); |
| | authBtn.classList.add('bg-green-100', 'text-green-800'); |
| | } else { |
| | authBtn.innerHTML = '<i class="fas fa-key mr-2"></i> Authenticate'; |
| | authBtn.classList.remove('bg-green-100', 'text-green-800'); |
| | authBtn.classList.add('bg-white', 'text-blue-600'); |
| | } |
| | } |
| | |
| | function createEmptyRow() { |
| | const row = {}; |
| | state.fields.forEach(field => { |
| | row[field.name] = field.type === 'number' ? 0 : field.type === 'boolean' ? false : ''; |
| | }); |
| | return row; |
| | } |
| | |
| | function renderFields() { |
| | fieldsContainer.innerHTML = ''; |
| | |
| | if (state.fields.length === 0) { |
| | fieldsContainer.innerHTML = ` |
| | <div class="text-gray-500 text-sm italic"> |
| | No fields added yet. Click "Add Field" to get started. |
| | </div> |
| | `; |
| | return; |
| | } |
| | |
| | state.fields.forEach((field, index) => { |
| | const fieldElement = document.createElement('div'); |
| | fieldElement.className = 'flex items-center justify-between p-2 border border-gray-200 rounded-md field-pill'; |
| | |
| | fieldElement.innerHTML = ` |
| | <div> |
| | <span class="font-medium text-gray-700">${field.name}</span> |
| | <span class="text-xs text-gray-500 ml-2">(${field.type})</span> |
| | </div> |
| | <button class="text-red-500 hover:text-red-700 delete-field" data-index="${index}"> |
| | <i class="fas fa-trash-alt"></i> |
| | </button> |
| | `; |
| | |
| | fieldsContainer.appendChild(fieldElement); |
| | }); |
| | |
| | |
| | document.querySelectorAll('.delete-field').forEach(btn => { |
| | btn.addEventListenerik('click', (e) => { |
| | const index = parseInt(e.target.closest('.delete-field').getAttribute('data-index')); |
| | state.fields.splice(index, 1); |
| | saveToLocalStorage(); |
| | renderFields(); |
| | renderTable(); |
| | }); |
| | }); |
| | } |
| | |
| | function renderTable() { |
| | |
| | tableHeaders.innerHTML = ''; |
| | tableBody.innerHTML = ''; |
| | |
| | if (state.fields.length === 0) { |
| | tableBody.appendChild(noDataRow); |
| | return; |
| | } |
| | |
| | |
| | state.fields.forEach(field => { |
| | const th = document.createElement('th'); |
| | th.className = 'px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider'; |
| | th.textContent = field.name; |
| | tableHeaders.appendChild(th); |
| | }); |
| | |
| | |
| | const actionsTh = document.createElement('th'); |
| | actionsTh.className = 'px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider'; |
| | actionsTh.textContent = 'Actions'; |
| | tableHeaders.appendChild(actionsTh); |
| | |
| | |
| | if (state.data.length === 0) { |
| | tableBody.appendChild(noDataRow); |
| | } else { |
| | state.data.forEach((row, rowIndex) => { |
| | const tr = document.createElement('tr'); |
| | tr.className = 'hover:bg-gray-50'; |
| | |
| | state.fields.forEach(field => { |
| | const td = document.createElement('td'); |
| | td.className = 'px-6 py-4 whitespace-nowrap text-sm text-gray-500'; |
| | |
| | if (field.type === 'boolean') { |
| | td.innerHTML = ` |
| | <div class="flex items-center"> |
| | <input type="checkbox" ${row[field.name] ? 'checked' : ''} |
| | class="row-checkbox h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded" |
| | data-row="${rowIndex}" data-field="${field.name}"> |
| | </div> |
| | `; |
| | } else { |
| | const input = document.createElement('input'); |
| | input.type = field.type === 'number' ? 'number' : 'text'; |
| | input.value = row[field.name]; |
| | input.className = 'w-full px-2 py-1 border border-gray-300 rounded focus:outline-none focus:ring-1 focus:ring-blue-500'; |
| | input.setAttribute('data-row', rowIndex); |
| | input.setAttribute('data-field', field.name); |
| | |
| | input.addEventListener('change', (e) => { |
| | const value = field.type === 'number' ? parseFloat(e.target.value) : e.target.value; |
| | state.data[e.target.getAttribute('data-row')][e.target.getAttribute('data-field')] = value; |
| | saveToLocalStorage(); |
| | }); |
| | |
| | td.appendChild(input); |
| | } |
| | |
| | tr.appendChild(td); |
| | }); |
| | |
| | |
| | const actionsTd = document.createElement('td'); |
| | actionsTd.className = 'px-6 py-4 whitespace-nowrap text-sm font-medium'; |
| | actionsTd.innerHTML = ` |
| | <button class="text-red-600 hover:text-red-900 delete-row" data-row="${rowIndex}"> |
| | <i class="fas fa-trash-alt"></i> |
| | </button> |
| | `; |
| | tr.appendChild(actionsTd); |
| | |
| | tableBody.appendChild(tr); |
| | }); |
| | |
| | |
| | document.querySelectorAll('.delete-row').forEach(btn => { |
| | btn.addEventListener('click', (e) => { |
| | const rowIndex = parseInt(e.target.closest('.delete-row').getAttribute('data-row')); |
| | state.data.splice(rowIndex, 1); |
| | saveToLocalStorage(); |
| | renderTable(); |
| | }); |
| | }); |
| | |
| | |
| | document.querySelectorAll('.row-checkbox').forEach(checkbox => { |
| | checkbox.addEventListener('change', (e) => { |
| | const rowIndex = parseInt(e.target.getAttribute('data-row')); |
| | const fieldName = e.target.getAttribute('data-field'); |
| | state.data[rowIndex][fieldName] = e.target.checked; |
| | saveToLocalStorage(); |
| | }); |
| | }); |
| | } |
| | } |
| | |
| | function saveToLocalStorage() { |
| | localStorage.setItem('datasetCreatorState', JSON.stringify(state)); |
| | } |
| | |
| | function loadFromLocalStorage() { |
| | const savedState = localStorage.getItem('datasetCreatorState'); |
| | if (savedState) { |
| | const parsedState = JSON.parse(savedState); |
| | state.fields = parsedState.fields || []; |
| | state.data = parsedState.data || []; |
| | state.datasetName = parsedState.datasetName || ''; |
| | state.datasetDesc = parsedState.datasetDesc || ''; |
| | |
| | datasetNameInput.value = state.datasetName; |
| | datasetDescInput.value = state.datasetDesc; |
| | } |
| | } |
| | |
| | function showToast(message, type = 'info') { |
| | const toast = document.createElement('div'); |
| | const colors = { |
| | success: 'bg-green-100 border-green-500 text-green-700', |
| | error: 'bg-red-100 border-red-500 text-red-700', |
| | info: 'bg-blue-100 border-blue-500 text-blue-700' |
| | }; |
| | |
| | toast.className = `fixed bottom-4 right-4 border-l-4 p-4 max-w-xs ${colors[type]} shadow-lg rounded`; |
| | toast.innerHTML = ` |
| | <div class="flex items-center"> |
| | <div class="flex-shrink-0"> |
| | ${type === 'success' ? '<i class="fas fa-check-circle"></i>' : ''} |
| | ${type === 'error' ? '<i class="fas fa-exclamation-circle"></i>' : ''} |
| | ${type === 'info' ? '<i class="fas fa-info-circle"></i>' : ''} |
| | </div> |
| | <div class="ml-3"> |
| | <p class="text-sm">${message}</p> |
| | </div> |
| | </div> |
| | `; |
| | |
| | document.body.appendChild(toast); |
| | |
| | setTimeout(() => { |
| | toast.classList.add('opacity-0', 'transition-opacity', 'duration-300'); |
| | setTimeout(() => toast.remove(), 300); |
| | }, 3000); |
| | } |
| | </script> |
| | <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Egrigor/huggingface-dataset-creator" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| | </html> |