alexandremoraisdarosa's picture
Em português, nas cores branca, preta e cinza, criado, implementado com as dependências e rodando local, um aplicativo para gerar QRCODE a partir do código: <!DOCTYPE html> <html lang="pt-BR"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Gerador de QRCode</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/qrious/4.0.2/qrious.min.js"></script> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; background: linear-gradient(135deg, #f5f5f5 0%, #e8e8e8 100%); min-height: 100vh; padding: 20px; line-height: 1.6; } .container { max-width: 1200px; margin: 0 auto; } .header { text-align: center; margin-bottom: 40px; } .logo { width: 64px; height: 64px; background: linear-gradient(135deg, #333 0%, #666 100%); margin: 0 auto 20px; border-radius: 16px; display: flex; align-items: center; justify-content: center; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); } .logo svg { width: 32px; height: 32px; fill: white; } h1 { font-size: 3rem; font-weight: 800; background: linear-gradient(135deg, #333 0%, #666 100%); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; margin-bottom: 10px; } .subtitle { color: #666; font-size: 1.2rem; } .main-card { background: white; border-radius: 24px; box-shadow: 0 20px 60px rgba(0, 0, 0, 0.1); overflow: hidden; } .tab-nav { display: flex; border-bottom: 1px solid #e0e0e0; } .tab-btn { flex: 1; padding: 20px; background: none; border: none; cursor: pointer; font-size: 1rem; font-weight: 600; color: #666; transition: all 0.3s ease; display: flex; align-items: center; justify-content: center; gap: 8px; } .tab-btn.active { color: #333; background: #f8f8f8; border-bottom: 2px solid #333; } .tab-btn:hover { background: #f5f5f5; color: #333; } .tab-btn svg { width: 20px; height: 20px; fill: currentColor; } .content { padding: 40px; } .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; } @media (max-width: 768px) { .grid { grid-template-columns: 1fr; gap: 30px; } } .section-title { font-size: 1.5rem; font-weight: 700; color: #333; margin-bottom: 30px; } .form-group { margin-bottom: 20px; } .form-label { display: block; font-weight: 600; color: #333; margin-bottom: 8px; } .form-input, .form-textarea { width: 100%; padding: 16px; border: 2px solid #e0e0e0; border-radius: 12px; font-size: 1rem; transition: all 0.3s ease; background: white; } .form-input:focus, .form-textarea:focus { outline: none; border-color: #333; box-shadow: 0 0 0 3px rgba(51, 51, 51, 0.1); } .form-textarea { resize: vertical; min-height: 120px; } .form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; } .help-text { font-size: 0.875rem; color: #666; margin-top: 4px; } .btn { padding: 16px 24px; border: none; border-radius: 12px; font-weight: 600; cursor: pointer; transition: all 0.3s ease; display: inline-flex; align-items: center; justify-content: center; gap: 8px; text-decoration: none; font-size: 1rem; } .btn-primary { background: linear-gradient(135deg, #333 0%, #666 100%); color: white; box-shadow: 0 8px 24px rgba(51, 51, 51, 0.2); } .btn-primary:hover { transform: translateY(-2px); box-shadow: 0 12px 32px rgba(51, 51, 51, 0.3); } .btn-secondary { background: #f5f5f5; color: #333; } .btn-secondary:hover { background: #e8e8e8; } .btn-clear { width: 100%; background: #f0f0f0; color: #666; margin-top: 20px; } .btn-clear:hover { background: #e0e0e0; } .qr-section { text-align: center; } .qr-container { background: #f8f8f8; border-radius: 16px; padding: 40px; margin-bottom: 30px; } .qr-placeholder { padding: 80px 20px; color: #999; } .qr-placeholder svg { width: 64px; height: 64px; fill: #ccc; margin-bottom: 16px; } .qr-canvas { max-width: 300px; height: auto; border-radius: 12px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1); background: white; padding: 16px; } .qr-info { color: #666; margin-top: 16px; } .action-buttons { display: flex; gap: 16px; margin-bottom: 30px; } .action-buttons .btn { flex: 1; } .data-preview { text-align: left; } .data-preview h3 { font-size: 1rem; font-weight: 600; color: #333; margin-bottom: 8px; } .data-content { background: #f5f5f5; border-radius: 8px; padding: 16px; font-family: 'Courier New', monospace; font-size: 0.875rem; color: #666; max-height: 150px; overflow-y: auto; white-space: pre-wrap; word-break: break-all; } .footer { text-align: center; margin-top: 40px; color: #666; font-size: 0.875rem; } .tab-content { display: none; } .tab-content.active { display: block; } .success-message { color: #4CAF50; font-weight: 600; } @keyframes fadeIn { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } .qr-canvas { animation: fadeIn 0.5s ease; } </style> </head> <body> <div class="container"> <div class="header"> <div class="logo"> <svg viewBox="0 0 24 24"> <path d="M3,11H5V13H3V11M11,5H13V9H11V5M9,11H13V15H9V11M15,11H17V13H15V11M19,11H21V13H19V11M5,5H9V9H5V5M3,19H5V21H3V19M5,19H9V21H5V19M11,19H13V21H11V19M15,19H17V21H15V19M19,19H21V21H19V19M15,5H21V11H15V5M17,7H19V9H17V7M21,15H19V17H21V15M21,19H19V21H21V19M3,5H5V9H3V5M7,5H9V7H7V5M3,15H9V21H3V15M5,17H7V19H5V17Z"/> </svg> </div> <h1>Gerador de QRCode</h1> <p class="subtitle">Gere códigos QR para URLs, texto e informações de contato</p> </div> <div class="main-card"> <div class="tab-nav"> <button class="tab-btn active" data-tab="url"> <svg viewBox="0 0 24 24"> <path d="M10.59,13.41C11,13.8 11,14.4 10.59,14.81C10.2,15.2 9.6,15.2 9.19,14.81L7.77,13.39L9.19,12C9.6,11.6 10.2,11.6 10.59,12C11,12.4 11,13 10.59,13.41M13.41,9.19C13.8,8.8 14.4,8.8 14.81,9.19C15.2,9.6 15.2,10.2 14.81,10.59L13.39,12L14.81,13.41C15.2,13.8 15.2,14.4 14.81,14.81C14.4,15.2 13.8,15.2 13.41,14.81L12,13.39L10.59,14.81C10.2,15.2 9.6,15.2 9.19,14.81C8.8,14.4 8.8,13.8 9.19,13.41L10.59,12L9.19,10.59C8.8,10.2 8.8,9.6 9.19,9.19C9.6,8.8 10.2,8.8 10.59,9.19L12,10.59L13.41,9.19M15.5,4L14.5,0L7.5,0L6.5,4H2V6H4.12L5.5,19L18.5,19L19.88,6H22V4H15.5Z"/> </svg> URL </button> <button class="tab-btn" data-tab="text"> <svg viewBox="0 0 24 24"> <path d="M12,3C13.73,3 16.39,3.71 18.5,5.3C19.29,5.9 20,6.5 20,7.5C20,8.5 19.29,9.1 18.5,9.7C16.39,11.29 13.73,12 12,12C10.27,12 7.61,11.29 5.5,9.7C4.71,9.1 4,8.5 4,7.5C4,6.5 4.71,5.9 5.5,5.3C7.61,3.71 10.27,3 12,3M18.5,12.3C19.29,12.9 20,13.5 20,14.5C20,15.5 19.29,16.1 18.5,16.7C16.39,18.29 13.73,19 12,19C10.27,19 7.61,18.29 5.5,16.7C4.71,16.1 4,15.5 4,14.5C4,13.5 4.71,12.9 5.5,12.3L5.5,12.3M18.5,17.3C19.29,17.9 20,18.5 20,19.5C20,20.5 19.29,21.1 18.5,21.7C16.39,23.29 13.73,24 12,24C10.27,24 7.61,23.29 5.5,21.7C4.71,21.1 4,20.5 4,19.5C4,18.5 4.71,17.9 5.5,17.3V17.3Z"/> </svg> Texto </button> <button class="tab-btn" data-tab="contact"> <svg viewBox="0 0 24 24"> <path d="M12,4A4,4 0 0,1 16,8A4,4 0 0,1 12,12A4,4 0 0,1 8,8A4,4 0 0,1 12,4M12,14C16.42,14 20,15.79 20,18V20H4V18C4,15.79 7.58,14 12,14Z"/> </svg> Contato </button> </div> <div class="content"> <div class="grid"> <div class="input-section"> <!-- Tab URL --> <div class="tab-content active" id="url-tab"> <h2 class="section-title">Inserir URL</h2> <div class="form-group"> <label class="form-label">URL do Site</label> <input type="url" id="url-input" class="form-input" placeholder="exemplo.com ou https://exemplo.com"> <p class="help-text">Insira uma URL de site. Se não incluir http://, adicionaremos https:// automaticamente.</p> </div> </div> <!-- Tab Texto --> <div class="tab-content" id="text-tab"> <h2 class="section-title">Inserir Texto</h2> <div class="form-group"> <label class="form-label">Conteúdo de Texto</label> <textarea id="text-input" class="form-textarea" placeholder="Digite qualquer texto para gerar código QR..."></textarea> </div> </div> <!-- Tab Contato --> <div class="tab-content" id="contact-tab"> <h2 class="section-title">Informações de Contato</h2> <div class="form-grid"> <div class="form-group"> <label class="form-label">Nome</label> <input type="text" id="contact-first-name" class="form-input" placeholder="João"> </div> <div class="form-group"> <label class="form-label">Sobrenome</label> <input type="text" id="contact-last-name" class="form-input" placeholder="Silva"> </div> </div> <div class="form-group"> <label class="form-label">Telefone</label> <input type="tel" id="contact-phone" class="form-input" placeholder="+55 (11) 99999-9999"> </div> <div class="form-group"> <label class="form-label">E-mail</label> <input type="email" id="contact-email" class="form-input" placeholder="[email protected]"> </div> <div class="form-group"> <label class="form-label">Organização</label> <input type="text" id="contact-organization" class="form-input" placeholder="Nome da Empresa"> </div> <div class="form-group"> <label class="form-label">Site</label> <input type="url" id="contact-url" class="form-input" placeholder="https://exemplo.com"> </div> </div> <button class="btn btn-clear" onclick="clearAllFields()">Limpar Todos os Campos</button> </div> <div class="qr-section"> <h2 class="section-title">Código QR Gerado</h2> <div class="qr-container"> <div id="qr-placeholder" class="qr-placeholder"> <svg viewBox="0 0 24 24"> <path d="M3,11H5V13H3V11M11,5H13V9H11V5M9,11H13V15H9V11M15,11H17V13H15V11M19,11H21V13H19V11M5,5H9V9H5V5M3,19H5V21H3V19M5,19H9V21H5V19M11,19H13V21H11V19M15,19H17V21H15V19M19,19H21V21H19V19M15,5H21V11H15V5M17,7H19V9H17V7M21,15H19V17H21V15M21,19H19V21H21V19M3,5H5V9H3V5M7,5H9V7H7V5M3,15H9V21H3V15M5,17H7V19H5V17Z"/> </svg> <p>Preencha o formulário para gerar seu código QR</p> </div> <div id="qr-result" style="display: none;"> <canvas id="qr-canvas" class="qr-canvas"></canvas> <p class="qr-info">Escaneie este código QR com seu dispositivo</p> </div> </div> <div id="action-buttons" class="action-buttons" style="display: none;"> <button class="btn btn-primary" onclick="downloadQR()"> <svg viewBox="0 0 24 24" style="width: 16px; height: 16px; fill: currentColor;"> <path d="M5,20H19V18H5M19,9H15V3H9V9H5L12,16L19,9Z"/> </svg> Download </button> <button class="btn btn-secondary" onclick="copyData()"> <svg viewBox="0 0 24 24" style="width: 16px; height: 16px; fill: currentColor;"> <path d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"/> </svg> <span id="copy-text">Copiar Dados</span> </button> </div> <div id="data-preview" class="data-preview" style="display: none;"> <h3>Dados do Código QR:</h3> <div id="data-content" class="data-content"></div> </div> </div> </div> </div> </div> <div class="footer"> <p>Gere códigos QR instantaneamente • Nenhum dado armazenado • Gratuito</p> </div> </div> <script> let currentTab = 'url'; let currentQRData = ''; // Inicialização document.addEventListener('DOMContentLoaded', function() { setupTabs(); setupEventListeners(); }); function setupTabs() { const tabBtns = document.querySelectorAll('.tab-btn'); const tabContents = document.querySelectorAll('.tab-content'); tabBtns.forEach(btn => { btn.addEventListener('click', () => { const tabId = btn.getAttribute('data-tab'); // Remove active class from all buttons and contents tabBtns.forEach(b => b.classList.remove('active')); tabContents.forEach(c => c.classList.remove('active')); // Add active class to clicked button and corresponding content btn.classList.add('active'); document.getElementById(tabId + '-tab').classList.add('active'); currentTab = tabId; generateQR(); }); }); } function setupEventListeners() { // URL input document.getElementById('url-input').addEventListener('input', generateQR); // Text input document.getElementById('text-input').addEventListener('input', generateQR); // Contact inputs const contactInputs = ['contact-first-name', 'contact-last-name', 'contact-phone', 'contact-email', 'contact-organization', 'contact-url']; contactInputs.forEach(id => { document.getElementById(id).addEventListener('input', generateQR); }); } function formatUrl(url) { if (!url.trim()) return ''; if (!url.startsWith('http://') && !url.startsWith('https://')) { return 'https://' + url; } return url; } function generateVCard() { const firstName = document.getElementById('contact-first-name').value; const lastName = document.getElementById('contact-last-name').value; const phone = document.getElementById('contact-phone').value; const email = document.getElementById('contact-email').value; const organization = document.getElementById('contact-organization').value; const url = document.getElementById('contact-url').value; if (!firstName && !lastName && !phone && !email) { return ''; } const vcard = `BEGIN:VCARD VERSION:3.0 FN:${firstName} ${lastName} N:${lastName};${firstName};;; ORG:${organization} TEL:${phone} EMAIL:${email} URL:${url} END:VCARD`; return vcard; } function generateQR() { let data = ''; switch (currentTab) { case 'url': data = formatUrl(document.getElementById('url-input').value); break; case 'text': data = document.getElementById('text-input').value; break; case 'contact': data = generateVCard(); break; } currentQRData = data; if (!data.trim()) { showPlaceholder(); return; } try { const canvas = document.getElementById('qr-canvas'); const qr = new QRious({ element: canvas, value: data, size: 300, background: 'white', foreground: 'black', level: 'M' }); showQRResult(); updateDataPreview(data); } catch (error) { console.error('Erro ao gerar código QR:', error); showPlaceholder(); } } function showPlaceholder() { document.getElementById('qr-placeholder').style.display = 'block'; document.getElementById('qr-result').style.display = 'none'; document.getElementById('action-buttons').style.display = 'none'; document.getElementById('data-preview').style.display = 'none'; } function showQRResult() { document.getElementById('qr-placeholder').style.display = 'none'; document.getElementById('qr-result').style.display = 'block'; document.getElementById('action-buttons').style.display = 'flex'; document.getElementById('data-preview').style.display = 'block'; } function updateDataPreview(data) { document.getElementById('data-content').textContent = data; } function downloadQR() { if (!currentQRData) return; const canvas = document.getElementById('qr-canvas'); const link = document.createElement('a'); link.download = `qr-code-${currentTab}.png`; link.href = canvas.toDataURL(); link.click(); } async function copyData() { if (!currentQRData) return; try { await navigator.clipboard.writeText(currentQRData); const copyText = document.getElementById('copy-text'); const originalText = copyText.textContent; copyText.textContent = 'Copiado!'; copyText.classList.add('success-message'); setTimeout(() => { copyText.textContent = originalText; copyText.classList.remove('success-message'); }, 2000); } catch (err) { console.error('Erro ao copiar texto:', err); alert('Erro ao copiar texto para a área de transferência'); } } function clearAllFields() { // Clear URL document.getElementById('url-input').value = ''; // Clear text document.getElementById('text-input').value = ''; // Clear contact fields document.getElementById('contact-first-name').value = ''; document.getElementById('contact-last-name').value = ''; document.getElementById('contact-phone').value = ''; document.getElementById('contact-email').value = ''; document.getElementById('contact-organization').value = ''; document.getElementById('contact-url').value = ''; currentQRData = ''; showPlaceholder(); } </script> </body> </html> - Initial Deployment
1b3ff7b verified