Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>QR Code Generator Pro</title> | |
| <script src="https://cdn.jsdelivr.net/npm/qrcode@1.5.1/build/qrcode.min.js"></script> | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| min-height: 100vh; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| padding: 10px; | |
| } | |
| .container { | |
| background: rgba(255, 255, 255, 0.95); | |
| backdrop-filter: blur(10px); | |
| border-radius: 20px; | |
| box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1); | |
| padding: 30px; | |
| max-width: 500px; | |
| width: 100%; | |
| animation: slideUp 0.8s ease-out; | |
| } | |
| @keyframes slideUp { | |
| from { | |
| opacity: 0; | |
| transform: translateY(30px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| .header { | |
| text-align: center; | |
| margin-bottom: 25px; | |
| } | |
| .title { | |
| font-size: 28px; | |
| font-weight: 700; | |
| background: linear-gradient(135deg, #667eea, #764ba2); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| margin-bottom: 8px; | |
| } | |
| .subtitle { | |
| color: #666; | |
| font-size: 14px; | |
| } | |
| .category-selector { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(80px, 1fr)); | |
| gap: 8px; | |
| margin-bottom: 20px; | |
| } | |
| .category-btn { | |
| padding: 10px 8px; | |
| border: none; | |
| border-radius: 12px; | |
| background: #f8f9ff; | |
| color: #666; | |
| font-size: 12px; | |
| font-weight: 500; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| text-align: center; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| gap: 4px; | |
| } | |
| .category-btn:hover { | |
| background: #e8f0ff; | |
| transform: translateY(-2px); | |
| } | |
| .category-btn.active { | |
| background: linear-gradient(135deg, #667eea, #764ba2); | |
| color: white; | |
| box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4); | |
| } | |
| .category-icon { | |
| font-size: 16px; | |
| } | |
| .input-group { | |
| margin-bottom: 15px; | |
| } | |
| .input-label { | |
| display: block; | |
| margin-bottom: 6px; | |
| font-weight: 600; | |
| color: #333; | |
| font-size: 13px; | |
| } | |
| .input-field { | |
| width: 100%; | |
| padding: 12px 16px; | |
| border: 2px solid #e9ecef; | |
| border-radius: 12px; | |
| font-size: 14px; | |
| transition: all 0.3s ease; | |
| background: #fafbff; | |
| } | |
| .input-field:focus { | |
| outline: none; | |
| border-color: #667eea; | |
| box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); | |
| background: white; | |
| } | |
| .input-row { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 12px; | |
| } | |
| .customization { | |
| background: #f8f9ff; | |
| border-radius: 12px; | |
| padding: 20px; | |
| margin-bottom: 20px; | |
| } | |
| .custom-title { | |
| font-weight: 600; | |
| color: #333; | |
| margin-bottom: 15px; | |
| font-size: 14px; | |
| } | |
| .color-controls { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); | |
| gap: 15px; | |
| margin-bottom: 15px; | |
| } | |
| .color-group { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .color-input { | |
| width: 40px; | |
| height: 40px; | |
| border: none; | |
| border-radius: 8px; | |
| cursor: pointer; | |
| box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); | |
| } | |
| .size-control { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| margin-bottom: 10px; | |
| } | |
| .size-slider { | |
| flex: 1; | |
| height: 6px; | |
| background: #e9ecef; | |
| border-radius: 3px; | |
| outline: none; | |
| cursor: pointer; | |
| } | |
| .generate-btn { | |
| width: 100%; | |
| padding: 15px; | |
| background: linear-gradient(135deg, #667eea, #764ba2); | |
| color: white; | |
| border: none; | |
| border-radius: 12px; | |
| font-size: 16px; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| margin-bottom: 20px; | |
| } | |
| .generate-btn:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 10px 25px rgba(102, 126, 234, 0.3); | |
| } | |
| .generate-btn:active { | |
| transform: translateY(0); | |
| } | |
| .qr-output { | |
| text-align: center; | |
| padding: 20px; | |
| background: white; | |
| border-radius: 12px; | |
| box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08); | |
| } | |
| .qr-canvas { | |
| max-width: 100%; | |
| border-radius: 8px; | |
| margin-bottom: 15px; | |
| } | |
| .download-controls { | |
| display: flex; | |
| gap: 10px; | |
| justify-content: center; | |
| flex-wrap: wrap; | |
| } | |
| .download-btn { | |
| padding: 10px 20px; | |
| border: 2px solid #667eea; | |
| background: white; | |
| color: #667eea; | |
| border-radius: 8px; | |
| font-size: 13px; | |
| font-weight: 500; | |
| cursor: pointer; | |
| transition: all 0.3s ease; | |
| } | |
| .download-btn:hover { | |
| background: #667eea; | |
| color: white; | |
| } | |
| .hidden { | |
| display: none; | |
| } | |
| .error { | |
| color: #e74c3c; | |
| font-size: 12px; | |
| margin-top: 5px; | |
| } | |
| @media (max-width: 480px) { | |
| .container { | |
| padding: 20px; | |
| margin: 10px; | |
| } | |
| .category-selector { | |
| grid-template-columns: repeat(3, 1fr); | |
| } | |
| .input-row { | |
| grid-template-columns: 1fr; | |
| } | |
| .color-controls { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <div class="header"> | |
| <h1 class="title">QR Generator Pro</h1> | |
| <p class="subtitle">Create professional QR codes with advanced customization</p> | |
| </div> | |
| <div class="category-selector"> | |
| <button class="category-btn active" data-type="text"> | |
| <span class="category-icon">📝</span> | |
| <span>Text</span> | |
| </button> | |
| <button class="category-btn" data-type="url"> | |
| <span class="category-icon">🔗</span> | |
| <span>URL</span> | |
| </button> | |
| <button class="category-btn" data-type="email"> | |
| <span class="category-icon">✉️</span> | |
| <span>Email</span> | |
| </button> | |
| <button class="category-btn" data-type="phone"> | |
| <span class="category-icon">📞</span> | |
| <span>Phone</span> | |
| </button> | |
| <button class="category-btn" data-type="sms"> | |
| <span class="category-icon">💬</span> | |
| <span>SMS</span> | |
| </button> | |
| <button class="category-btn" data-type="wifi"> | |
| <span class="category-icon">📶</span> | |
| <span>WiFi</span> | |
| </button> | |
| <button class="category-btn" data-type="vcard"> | |
| <span class="category-icon">👤</span> | |
| <span>vCard</span> | |
| </button> | |
| <button class="category-btn" data-type="location"> | |
| <span class="category-icon">📍</span> | |
| <span>Location</span> | |
| </button> | |
| <button class="category-btn" data-type="event"> | |
| <span class="category-icon">📅</span> | |
| <span>Event</span> | |
| </button> | |
| </div> | |
| <div id="input-forms"> | |
| <!-- Text Form --> | |
| <div id="text-form" class="form-section"> | |
| <div class="input-group"> | |
| <label class="input-label">Enter your text</label> | |
| <textarea class="input-field" id="text-input" rows="3" placeholder="Type your message here..."></textarea> | |
| </div> | |
| </div> | |
| <!-- URL Form --> | |
| <div id="url-form" class="form-section hidden"> | |
| <div class="input-group"> | |
| <label class="input-label">Website URL</label> | |
| <input type="url" class="input-field" id="url-input" placeholder="https://example.com"> | |
| </div> | |
| </div> | |
| <!-- Email Form --> | |
| <div id="email-form" class="form-section hidden"> | |
| <div class="input-group"> | |
| <label class="input-label">Email Address</label> | |
| <input type="email" class="input-field" id="email-input" placeholder="user@example.com"> | |
| </div> | |
| <div class="input-group"> | |
| <label class="input-label">Subject (Optional)</label> | |
| <input type="text" class="input-field" id="email-subject" placeholder="Email subject"> | |
| </div> | |
| <div class="input-group"> | |
| <label class="input-label">Message (Optional)</label> | |
| <textarea class="input-field" id="email-body" rows="2" placeholder="Email message"></textarea> | |
| </div> | |
| </div> | |
| <!-- Phone Form --> | |
| <div id="phone-form" class="form-section hidden"> | |
| <div class="input-group"> | |
| <label class="input-label">Phone Number</label> | |
| <input type="tel" class="input-field" id="phone-input" placeholder="+1234567890"> | |
| </div> | |
| </div> | |
| <!-- SMS Form --> | |
| <div id="sms-form" class="form-section hidden"> | |
| <div class="input-group"> | |
| <label class="input-label">Phone Number</label> | |
| <input type="tel" class="input-field" id="sms-phone" placeholder="+1234567890"> | |
| </div> | |
| <div class="input-group"> | |
| <label class="input-label">Message</label> | |
| <textarea class="input-field" id="sms-message" rows="2" placeholder="SMS message"></textarea> | |
| </div> | |
| </div> | |
| <!-- WiFi Form --> | |
| <div id="wifi-form" class="form-section hidden"> | |
| <div class="input-group"> | |
| <label class="input-label">Network Name (SSID)</label> | |
| <input type="text" class="input-field" id="wifi-ssid" placeholder="My WiFi Network"> | |
| </div> | |
| <div class="input-row"> | |
| <div class="input-group"> | |
| <label class="input-label">Password</label> | |
| <input type="text" class="input-field" id="wifi-password" placeholder="password123"> | |
| </div> | |
| <div class="input-group"> | |
| <label class="input-label">Security</label> | |
| <select class="input-field" id="wifi-security"> | |
| <option value="WPA">WPA/WPA2</option> | |
| <option value="WEP">WEP</option> | |
| <option value="nopass">None</option> | |
| </select> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- vCard Form --> | |
| <div id="vcard-form" class="form-section hidden"> | |
| <div class="input-row"> | |
| <div class="input-group"> | |
| <label class="input-label">First Name</label> | |
| <input type="text" class="input-field" id="vcard-firstname" placeholder="John"> | |
| </div> | |
| <div class="input-group"> | |
| <label class="input-label">Last Name</label> | |
| <input type="text" class="input-field" id="vcard-lastname" placeholder="Doe"> | |
| </div> | |
| </div> | |
| <div class="input-group"> | |
| <label class="input-label">Organization</label> | |
| <input type="text" class="input-field" id="vcard-org" placeholder="Company Name"> | |
| </div> | |
| <div class="input-row"> | |
| <div class="input-group"> | |
| <label class="input-label">Phone</label> | |
| <input type="tel" class="input-field" id="vcard-phone" placeholder="+1234567890"> | |
| </div> | |
| <div class="input-group"> | |
| <label class="input-label">Email</label> | |
| <input type="email" class="input-field" id="vcard-email" placeholder="john@example.com"> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Location Form --> | |
| <div id="location-form" class="form-section hidden"> | |
| <div class="input-row"> | |
| <div class="input-group"> | |
| <label class="input-label">Latitude</label> | |
| <input type="number" class="input-field" id="location-lat" placeholder="40.7128" step="any"> | |
| </div> | |
| <div class="input-group"> | |
| <label class="input-label">Longitude</label> | |
| <input type="number" class="input-field" id="location-lng" placeholder="-74.0060" step="any"> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Event Form --> | |
| <div id="event-form" class="form-section hidden"> | |
| <div class="input-group"> | |
| <label class="input-label">Event Title</label> | |
| <input type="text" class="input-field" id="event-title" placeholder="Meeting with Team"> | |
| </div> | |
| <div class="input-row"> | |
| <div class="input-group"> | |
| <label class="input-label">Start Date</label> | |
| <input type="datetime-local" class="input-field" id="event-start"> | |
| </div> | |
| <div class="input-group"> | |
| <label class="input-label">End Date</label> | |
| <input type="datetime-local" class="input-field" id="event-end"> | |
| </div> | |
| </div> | |
| <div class="input-group"> | |
| <label class="input-label">Location (Optional)</label> | |
| <input type="text" class="input-field" id="event-location" placeholder="Conference Room A"> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="customization"> | |
| <div class="custom-title">🎨 Customization</div> | |
| <div class="color-controls"> | |
| <div class="color-group"> | |
| <input type="color" class="color-input" id="fg-color" value="#000000"> | |
| <span>Foreground</span> | |
| </div> | |
| <div class="color-group"> | |
| <input type="color" class="color-input" id="bg-color" value="#ffffff"> | |
| <span>Background</span> | |
| </div> | |
| </div> | |
| <div class="size-control"> | |
| <span>Size:</span> | |
| <input type="range" class="size-slider" id="size-slider" min="128" max="400" value="256"> | |
| <span id="size-display">256px</span> | |
| </div> | |
| </div> | |
| <button class="generate-btn" onclick="generateQR()"> | |
| Generate QR Code | |
| </button> | |
| <div id="qr-output" class="qr-output hidden"> | |
| <canvas id="qr-canvas" class="qr-canvas"></canvas> | |
| <div class="download-controls"> | |
| <button class="download-btn" onclick="downloadQR('png')">PNG</button> | |
| <button class="download-btn" onclick="downloadQR('jpg')">JPG</button> | |
| <button class="download-btn" onclick="downloadQR('svg')">SVG</button> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| let currentType = 'text'; | |
| let currentQRData = ''; | |
| // Category switching | |
| document.querySelectorAll('.category-btn').forEach(btn => { | |
| btn.addEventListener('click', () => { | |
| document.querySelectorAll('.category-btn').forEach(b => b.classList.remove('active')); | |
| btn.classList.add('active'); | |
| const type = btn.dataset.type; | |
| currentType = type; | |
| document.querySelectorAll('.form-section').forEach(form => form.classList.add('hidden')); | |
| document.getElementById(`${type}-form`).classList.remove('hidden'); | |
| }); | |
| }); | |
| // Size slider | |
| document.getElementById('size-slider').addEventListener('input', (e) => { | |
| document.getElementById('size-display').textContent = e.target.value + 'px'; | |
| }); | |
| function generateQRData() { | |
| switch (currentType) { | |
| case 'text': | |
| return document.getElementById('text-input').value; | |
| case 'url': | |
| const url = document.getElementById('url-input').value; | |
| return url.startsWith('http') ? url : `https://${url}`; | |
| case 'email': | |
| const email = document.getElementById('email-input').value; | |
| const subject = document.getElementById('email-subject').value; | |
| const body = document.getElementById('email-body').value; | |
| let mailto = `mailto:${email}`; | |
| const params = []; | |
| if (subject) params.push(`subject=${encodeURIComponent(subject)}`); | |
| if (body) params.push(`body=${encodeURIComponent(body)}`); | |
| if (params.length) mailto += '?' + params.join('&'); | |
| return mailto; | |
| case 'phone': | |
| return `tel:${document.getElementById('phone-input').value}`; | |
| case 'sms': | |
| const smsPhone = document.getElementById('sms-phone').value; | |
| const smsMessage = document.getElementById('sms-message').value; | |
| return `sms:${smsPhone}${smsMessage ? `?body=${encodeURIComponent(smsMessage)}` : ''}`; | |
| case 'wifi': | |
| const ssid = document.getElementById('wifi-ssid').value; | |
| const password = document.getElementById('wifi-password').value; | |
| const security = document.getElementById('wifi-security').value; | |
| return `WIFI:T:${security};S:${ssid};P:${password};;`; | |
| case 'vcard': | |
| const firstName = document.getElementById('vcard-firstname').value; | |
| const lastName = document.getElementById('vcard-lastname').value; | |
| const org = document.getElementById('vcard-org').value; | |
| const phone = document.getElementById('vcard-phone').value; | |
| const vcardEmail = document.getElementById('vcard-email').value; | |
| return `BEGIN:VCARD | |
| VERSION:3.0 | |
| FN:${firstName} ${lastName} | |
| N:${lastName};${firstName};;; | |
| ORG:${org} | |
| TEL:${phone} | |
| EMAIL:${vcardEmail} | |
| END:VCARD`; | |
| case 'location': | |
| const lat = document.getElementById('location-lat').value; | |
| const lng = document.getElementById('location-lng').value; | |
| return `geo:${lat},${lng}`; | |
| case 'event': | |
| const title = document.getElementById('event-title').value; | |
| const start = document.getElementById('event-start').value; | |
| const end = document.getElementById('event-end').value; | |
| const location = document.getElementById('event-location').value; | |
| const formatDate = (dateStr) => { | |
| return new Date(dateStr).toISOString().replace(/[-:]/g, '').split('.')[0] + 'Z'; | |
| }; | |
| return `BEGIN:VEVENT | |
| SUMMARY:${title} | |
| DTSTART:${formatDate(start)} | |
| DTEND:${formatDate(end)} | |
| LOCATION:${location} | |
| END:VEVENT`; | |
| default: | |
| return ''; | |
| } | |
| } | |
| function generateQR() { | |
| const data = generateQRData(); | |
| if (!data.trim()) { | |
| alert('Please enter some data to generate QR code'); | |
| return; | |
| } | |
| currentQRData = data; | |
| const canvas = document.getElementById('qr-canvas'); | |
| const fgColor = document.getElementById('fg-color').value; | |
| const bgColor = document.getElementById('bg-color').value; | |
| const size = parseInt(document.getElementById('size-slider').value); | |
| QRCode.toCanvas(canvas, data, { | |
| width: size, | |
| height: size, | |
| color: { | |
| dark: fgColor, | |
| light: bgColor | |
| }, | |
| errorCorrectionLevel: 'M', | |
| margin: 2 | |
| }, (error) => { | |
| if (error) { | |
| console.error(error); | |
| alert('Error generating QR code'); | |
| } else { | |
| document.getElementById('qr-output').classList.remove('hidden'); | |
| canvas.scrollIntoView({ behavior: 'smooth', block: 'center' }); | |
| } | |
| }); | |
| } | |
| function downloadQR(format) { | |
| const canvas = document.getElementById('qr-canvas'); | |
| if (format === 'svg') { | |
| // Generate SVG version | |
| QRCode.toString(currentQRData, { | |
| type: 'svg', | |
| width: parseInt(document.getElementById('size-slider').value), | |
| color: { | |
| dark: document.getElementById('fg-color').value, | |
| light: document.getElementById('bg-color').value | |
| } | |
| }, (err, string) => { | |
| if (!err) { | |
| const blob = new Blob([string], { type: 'image/svg+xml' }); | |
| const url = URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = `qrcode.svg`; | |
| a.click(); | |
| URL.revokeObjectURL(url); | |
| } | |
| }); | |
| } else { | |
| // PNG or JPG | |
| const mimeType = format === 'png' ? 'image/png' : 'image/jpeg'; | |
| const url = canvas.toDataURL(mimeType, 0.9); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = `qrcode.${format}`; | |
| a.click(); | |
| } | |
| } | |
| // Auto-generate on input for better UX | |
| document.addEventListener('input', (e) => { | |
| if (e.target.classList.contains('input-field') || e.target.id === 'size-slider') { | |
| // Debounce auto-generation | |
| clearTimeout(window.autoGenTimeout); | |
| window.autoGenTimeout = setTimeout(() => { | |
| const data = generateQRData(); | |
| if (data.trim()) { | |
| generateQR(); | |
| } | |
| }, 500); | |
| } | |
| }); | |
| // Initialize with sample data | |
| document.getElementById('text-input').value = 'Hello, World! 👋'; | |
| generateQR(); | |
| </script> | |
| </body> | |
| </html> |