(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();
}
})();