(function() { let allRecords = []; let isGenerating = false; // Create styles function createStyles() { const style = document.createElement('style'); style.textContent = ` .id-generator-app { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%); min-height: 600px; padding: 40px 20px; border-radius: 20px; margin: 20px 0; position: relative; box-sizing: border-box; } .id-gen-container { max-width: 800px; margin: 0 auto; } .id-gen-header { text-align: center; margin-bottom: 40px; } .id-gen-title { font-size: 3rem; font-weight: bold; color: white; margin-bottom: 16px; margin-top: 0; } .id-gen-subtitle { font-size: 1.25rem; color: rgba(255, 255, 255, 0.9); margin: 0; } .id-gen-card { background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(10px); border-radius: 24px; padding: 32px; margin-bottom: 32px; border: 1px solid rgba(255, 255, 255, 0.2); box-shadow: 0 25px 50px rgba(0, 0, 0, 0.15); } .id-gen-label { display: block; color: white; font-size: 1.125rem; font-weight: 600; margin-bottom: 12px; } .id-gen-input { width: 100%; padding: 16px 24px; border-radius: 12px; border: 2px solid transparent; background: white; font-size: 1.125rem; margin-bottom: 24px; box-sizing: border-box; transition: all 0.3s ease; } .id-gen-input:focus { outline: none; border-color: #667eea; box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); } .id-gen-btn { width: 100%; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; font-weight: bold; padding: 16px 32px; border-radius: 12px; border: none; font-size: 1.125rem; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 10px 25px rgba(102, 126, 234, 0.3); } .id-gen-btn:hover { background: linear-gradient(135deg, #5568d3 0%, #63408a 100%); transform: translateY(-2px); box-shadow: 0 15px 35px rgba(102, 126, 234, 0.4); } .id-gen-btn:disabled { opacity: 0.6; cursor: not-allowed; transform: none; } .id-gen-result { margin-top: 32px; background: white; border-radius: 16px; padding: 24px; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1); display: none; } .id-gen-result.show { display: block; } .id-gen-result-label { color: #666; font-size: 0.875rem; margin-bottom: 8px; margin-top: 0; } .id-gen-result-id { background: linear-gradient(90deg, #667eea 0%, #764ba2 50%, #f093fb 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; font-size: 2rem; font-weight: bold; margin-bottom: 16px; margin-top: 0; word-break: break-all; } .id-gen-copy-btn { width: 100%; background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); color: white; font-weight: bold; padding: 12px 24px; border-radius: 12px; border: none; cursor: pointer; transition: all 0.3s ease; } .id-gen-copy-btn:hover { background: linear-gradient(135deg, #e082ea 0%, #e4465b 100%); transform: translateY(-2px); } .id-gen-table { width: 100%; background: white; border-radius: 16px; overflow: hidden; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1); border-collapse: collapse; } .id-gen-table-header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; } .id-gen-table th, .id-gen-table td { padding: 16px; text-align: left; border-bottom: 1px solid #f0f0f0; } .id-gen-table tr:hover { background: rgba(102, 126, 234, 0.05); } .id-gen-empty { text-align: center; padding: 48px; color: #999; font-size: 1.125rem; background: white; border-radius: 0 0 16px 16px; } .id-gen-notification { position: fixed; top: 20px; right: 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 16px 24px; border-radius: 12px; box-shadow: 0 10px 25px rgba(102, 126, 234, 0.3); opacity: 0; transform: translateY(-20px); transition: all 0.3s ease; z-index: 10000; } .id-gen-notification.show { opacity: 1; transform: translateY(0); } .id-gen-history-title { color: white; font-size: 1.5rem; font-weight: bold; margin-bottom: 24px; margin-top: 0; } .id-gen-table-container { overflow-x: auto; } .id-gen-status { background: rgba(34, 197, 94, 0.2); color: white; padding: 12px 16px; border-radius: 8px; margin-bottom: 20px; font-size: 0.875rem; text-align: center; } .id-gen-delete-btn { color: #ef4444; background: none; border: none; cursor: pointer; font-size: 0.875rem; font-weight: 600; margin-left: 8px; } .id-gen-delete-btn:hover { color: #dc2626; } @media (max-width: 768px) { .id-gen-title { font-size: 2rem; } .id-gen-card { padding: 24px; } .id-gen-table { font-size: 0.875rem; } .id-gen-table th, .id-gen-table td { padding: 12px 8px; } } `; document.head.appendChild(style); } // Data SDK functions (keeping the Canva Sheet functionality) const dataHandler = { onDataChanged(data) { allRecords = data || []; renderHistory(); } }; // Create the main app structure function createApp() { const app = document.createElement('div'); app.className = 'id-generator-app'; // Create notification const notification = document.createElement('div'); notification.className = 'id-gen-notification'; notification.id = 'idGenNotification'; notification.textContent = 'ID copied to clipboard!'; document.body.appendChild(notification); const container = document.createElement('div'); container.className = 'id-gen-container'; // Create status indicator const status = document.createElement('div'); status.id = 'idGenStatus'; status.className = 'id-gen-status'; status.textContent = '✅ Ready to generate IDs - Data saves automatically to your sheet'; // Create header const header = document.createElement('div'); header.className = 'id-gen-header'; const title = document.createElement('h1'); title.className = 'id-gen-title'; title.textContent = 'ID Generator'; const subtitle = document.createElement('p'); subtitle.className = 'id-gen-subtitle'; subtitle.textContent = 'Generate unique IDs instantly'; header.appendChild(title); header.appendChild(subtitle); // Create generator card const generatorCard = document.createElement('div'); generatorCard.className = 'id-gen-card'; const label = document.createElement('label'); label.className = 'id-gen-label'; label.textContent = 'Enter Your Name'; label.setAttribute('for', 'idGenNameInput'); const input = document.createElement('input'); input.type = 'text'; input.id = 'idGenNameInput'; input.className = 'id-gen-input'; input.placeholder = 'John Doe'; const generateBtn = document.createElement('button'); generateBtn.id = 'idGenGenerateBtn'; generateBtn.className = 'id-gen-btn'; generateBtn.textContent = 'Generate ID'; // Create result section const resultDiv = document.createElement('div'); resultDiv.id = 'idGenResult'; resultDiv.className = 'id-gen-result'; const resultLabel = document.createElement('p'); resultLabel.className = 'id-gen-result-label'; resultLabel.textContent = 'Your Generated ID:'; const resultId = document.createElement('p'); resultId.id = 'idGenResultId'; resultId.className = 'id-gen-result-id'; const copyBtn = document.createElement('button'); copyBtn.id = 'idGenCopyBtn'; copyBtn.className = 'id-gen-copy-btn'; copyBtn.textContent = 'Copy ID'; resultDiv.appendChild(resultLabel); resultDiv.appendChild(resultId); resultDiv.appendChild(copyBtn); generatorCard.appendChild(label); generatorCard.appendChild(input); generatorCard.appendChild(generateBtn); generatorCard.appendChild(resultDiv); // Create history card const historyCard = document.createElement('div'); historyCard.className = 'id-gen-card'; const historyTitle = document.createElement('h2'); historyTitle.className = 'id-gen-history-title'; historyTitle.textContent = 'Generated IDs History'; const tableContainer = document.createElement('div'); tableContainer.className = 'id-gen-table-container'; const table = document.createElement('table'); table.className = 'id-gen-table'; const thead = document.createElement('thead'); thead.className = 'id-gen-table-header'; const headerRow = document.createElement('tr'); const headers = ['Name', 'Generated ID', 'Date', 'Actions']; headers.forEach(headerText => { const th = document.createElement('th'); th.textContent = headerText; headerRow.appendChild(th); }); thead.appendChild(headerRow); const tbody = document.createElement('tbody'); tbody.id = 'idGenHistoryTable'; table.appendChild(thead); table.appendChild(tbody); const emptyState = document.createElement('div'); emptyState.id = 'idGenEmptyState'; emptyState.className = 'id-gen-empty'; emptyState.textContent = 'No IDs generated yet. Create your first one above!'; tableContainer.appendChild(table); tableContainer.appendChild(emptyState); historyCard.appendChild(historyTitle); historyCard.appendChild(tableContainer); // Assemble everything container.appendChild(status); container.appendChild(header); container.appendChild(generatorCard); container.appendChild(historyCard); app.appendChild(container); return app; } // Generate unique ID function generateUniqueId() { const timestamp = Date.now().toString(36); const randomStr = Math.random().toString(36).substring(2, 9); return `ID-${timestamp}-${randomStr}`.toUpperCase(); } // Show notification function showNotification(message) { const notification = document.getElementById('idGenNotification'); if (notification) { notification.textContent = message; notification.classList.add('show'); setTimeout(() => { notification.classList.remove('show'); }, 3000); } } // Copy to clipboard async function copyToClipboard(text) { try { await navigator.clipboard.writeText(text); showNotification('📋 ID copied to clipboard!'); } catch (err) { showNotification('❌ Failed to copy ID'); } } // Delete record async function deleteRecord(record) { if (!window.dataSdk) { showNotification('❌ Sheet connection not available'); return; } const result = await window.dataSdk.delete(record); if (result.isOk) { showNotification('🗑️ ID deleted from sheet'); } else { showNotification('❌ Failed to delete ID'); } } // Render history table function renderHistory() { const tbody = document.getElementById('idGenHistoryTable'); const emptyState = document.getElementById('idGenEmptyState'); if (!tbody || !emptyState) return; if (allRecords.length === 0) { tbody.innerHTML = ''; emptyState.style.display = 'block'; return; } emptyState.style.display = 'none'; const sortedRecords = [...allRecords].sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt) ); tbody.innerHTML = ''; sortedRecords.forEach(record => { const row = document.createElement('tr'); const nameCell = document.createElement('td'); nameCell.style.fontWeight = '500'; nameCell.textContent = record.name; const idCell = document.createElement('td'); idCell.style.fontFamily = 'monospace'; idCell.style.fontSize = '0.875rem'; idCell.style.color = '#666'; idCell.textContent = record.generatedId; const dateCell = document.createElement('td'); dateCell.style.fontSize = '0.875rem'; dateCell.style.color = '#666'; const date = new Date(record.createdAt); dateCell.textContent = date.toLocaleDateString() + ' ' + date.toLocaleTimeString(); const actionCell = document.createElement('td'); const copyButton = document.createElement('button'); copyButton.style.color = '#8b5cf6'; copyButton.style.fontWeight = '600'; copyButton.style.fontSize = '0.875rem'; copyButton.style.background = 'none'; copyButton.style.border = 'none'; copyButton.style.cursor = 'pointer'; copyButton.textContent = 'Copy'; copyButton.onclick = () => copyToClipboard(record.generatedId); const deleteButton = document.createElement('button'); deleteButton.className = 'id-gen-delete-btn'; deleteButton.textContent = 'Delete'; deleteButton.onclick = () => deleteRecord(record); actionCell.appendChild(copyButton); actionCell.appendChild(deleteButton); row.appendChild(nameCell); row.appendChild(idCell); row.appendChild(dateCell); row.appendChild(actionCell); tbody.appendChild(row); }); } // Generate ID handler async function handleGenerate() { if (isGenerating) return; const nameInput = document.getElementById('idGenNameInput'); if (!nameInput) return; const name = nameInput.value.trim(); if (!name) { showNotification('⚠️ Please enter a name'); return; } if (!window.dataSdk) { showNotification('❌ Sheet connection not available'); return; } if (allRecords.length >= 999) { showNotification('⚠️ Maximum limit of 999 IDs reached'); return; } isGenerating = true; const generateBtn = document.getElementById('idGenGenerateBtn'); if (generateBtn) { generateBtn.disabled = true; generateBtn.textContent = 'Generating...'; } const generatedId = generateUniqueId(); const newRecord = { name: name, generatedId: generatedId, createdAt: new Date().toISOString() }; const result = await window.dataSdk.create(newRecord); if (result.isOk) { // Show result const resultId = document.getElementById('idGenResultId'); const resultDiv = document.getElementById('idGenResult'); if (resultId && resultDiv) { resultId.textContent = generatedId; resultDiv.classList.add('show'); } nameInput.value = ''; showNotification('✅ ID saved to sheet!'); } else { showNotification('❌ Failed to save ID to sheet'); } isGenerating = false; if (generateBtn) { generateBtn.disabled = false; generateBtn.textContent = 'Generate ID'; } } // Initialize the app async function initApp() { // Create styles createStyles(); // Create and append the app const app = createApp(); // Find a container or append to body const container = document.getElementById('id-generator-container') || document.body; container.appendChild(app); // Initialize Data SDK if available if (window.dataSdk) { const initResult = await window.dataSdk.init(dataHandler); if (!initResult.isOk) { showNotification('❌ Failed to connect to sheet'); } } // Event listeners const generateBtn = document.getElementById('idGenGenerateBtn'); const nameInput = document.getElementById('idGenNameInput'); const copyBtn = document.getElementById('idGenCopyBtn'); if (generateBtn) { generateBtn.addEventListener('click', handleGenerate); } if (nameInput) { nameInput.addEventListener('keypress', function(e) { if (e.key === 'Enter') { handleGenerate(); } }); } if (copyBtn) { copyBtn.addEventListener('click', function() { const idText = document.getElementById('idGenResultId'); if (idText) { copyToClipboard(idText.textContent); } }); } } // Initialize when DOM is ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initApp); } else { initApp(); } })();