From fb93aff837faf266cc6c3903ac9666331b1f5e71 Mon Sep 17 00:00:00 2001 From: florian Date: Thu, 27 Aug 2026 15:35:27 +0200 Subject: [PATCH] =?UTF-8?q?Ajout=20de=20la=20g=C3=A9n=C3=A9ration=20de=20Q?= =?UTF-8?q?R=20codes=20de=20contact=20(vCard)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + app/app.js | 77 ++++++++++++++++++++++++++++++++++++++++++++------ app/index.html | 41 ++++++++++++++++++++++++++- 3 files changed, 110 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 9a3b88b..14213e7 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ L'encodage et le rendu du QR code se font **intégralement dans le navigateur** - Encodage de texte libre ou d'URL en QR code, côté client, via [qrcode-generator](https://github.com/kazuhikoarase/qrcode-generator) - Génération de QR codes de connexion Wi-Fi (SSID, mot de passe, sécurité WPA/WPA2/WPA3/WEP/ouvert, réseau masqué) — scannables directement par l'appareil photo du téléphone +- Génération de QR codes de contact (vCard) : nom, téléphone, email, organisation, fonction, site web — importables directement dans le répertoire - Niveaux de correction d'erreur configurables (L / M / Q / H) - Couleurs de modules et de fond personnalisables - Superposition d'un logo au centre du QR code (force automatiquement la correction d'erreur au niveau H pour rester scannable) diff --git a/app/app.js b/app/app.js index f5c78bd..c675759 100644 --- a/app/app.js +++ b/app/app.js @@ -4,12 +4,20 @@ const modeEl = document.getElementById("qr-mode"); const modeTextWrap = document.getElementById("mode-text"); const modeWifiWrap = document.getElementById("mode-wifi"); + const modeVcardWrap = document.getElementById("mode-vcard"); const textEl = document.getElementById("qr-text"); const wifiSsidEl = document.getElementById("wifi-ssid"); const wifiEncryptionEl = document.getElementById("wifi-encryption"); const wifiPasswordEl = document.getElementById("wifi-password"); const wifiPasswordField = document.getElementById("wifi-password-field"); const wifiHiddenEl = document.getElementById("wifi-hidden"); + const vcardFirstnameEl = document.getElementById("vcard-firstname"); + const vcardLastnameEl = document.getElementById("vcard-lastname"); + const vcardPhoneEl = document.getElementById("vcard-phone"); + const vcardEmailEl = document.getElementById("vcard-email"); + const vcardOrgEl = document.getElementById("vcard-org"); + const vcardTitleEl = document.getElementById("vcard-title"); + const vcardWebsiteEl = document.getElementById("vcard-website"); const cellSizeEl = document.getElementById("qr-cell-size"); const correctionEl = document.getElementById("qr-correction"); const fgColorEl = document.getElementById("qr-fg-color"); @@ -68,10 +76,40 @@ return payload; } + function escapeVcardField(value) { + return String(value).replace(/([\\;,])/g, "\\$1").replace(/\n/g, "\\n"); + } + + function buildVcardPayload() { + const firstName = vcardFirstnameEl.value.trim(); + const lastName = vcardLastnameEl.value.trim(); + const phone = vcardPhoneEl.value.trim(); + const email = vcardEmailEl.value.trim(); + const org = vcardOrgEl.value.trim(); + const title = vcardTitleEl.value.trim(); + const website = vcardWebsiteEl.value.trim(); + + if (!firstName && !lastName) return ""; + + const fullName = [firstName, lastName].filter(Boolean).join(" "); + + let payload = "BEGIN:VCARD\nVERSION:3.0\n"; + payload += `N:${escapeVcardField(lastName)};${escapeVcardField(firstName)};;;\n`; + payload += `FN:${escapeVcardField(fullName)}\n`; + if (org) payload += `ORG:${escapeVcardField(org)}\n`; + if (title) payload += `TITLE:${escapeVcardField(title)}\n`; + if (phone) payload += `TEL;TYPE=CELL:${escapeVcardField(phone)}\n`; + if (email) payload += `EMAIL:${escapeVcardField(email)}\n`; + if (website) payload += `URL:${escapeVcardField(website)}\n`; + payload += "END:VCARD"; + return payload; + } + function updateModeVisibility() { - const isWifi = modeEl.value === "wifi"; - modeTextWrap.style.display = isWifi ? "none" : "block"; - modeWifiWrap.style.display = isWifi ? "block" : "none"; + const mode = modeEl.value; + modeTextWrap.style.display = mode === "text" ? "block" : "none"; + modeWifiWrap.style.display = mode === "wifi" ? "block" : "none"; + modeVcardWrap.style.display = mode === "vcard" ? "block" : "none"; wifiPasswordField.style.display = wifiEncryptionEl.value === "nopass" ? "none" : "block"; } @@ -87,18 +125,41 @@ el.addEventListener("change", render); }); + [ + vcardFirstnameEl, + vcardLastnameEl, + vcardPhoneEl, + vcardEmailEl, + vcardOrgEl, + vcardTitleEl, + vcardWebsiteEl, + ].forEach((el) => { + el.addEventListener("input", render); + }); + function render() { - const isWifi = modeEl.value === "wifi"; - const text = isWifi ? buildWifiPayload() : textEl.value; + const mode = modeEl.value; + let text; + if (mode === "wifi") { + text = buildWifiPayload(); + } else if (mode === "vcard") { + text = buildVcardPayload(); + } else { + text = textEl.value; + } statusEl.classList.remove("error"); if (!text) { ctx.clearRect(0, 0, canvas.width, canvas.height); canvas.width = 280; canvas.height = 280; - statusEl.textContent = isWifi - ? "Renseignez au moins le nom du réseau (SSID) pour générer le QR code." - : "Saisissez un texte ou une URL pour générer le QR code."; + if (mode === "wifi") { + statusEl.textContent = "Renseignez au moins le nom du réseau (SSID) pour générer le QR code."; + } else if (mode === "vcard") { + statusEl.textContent = "Renseignez au moins un prénom ou un nom pour générer le QR code."; + } else { + statusEl.textContent = "Saisissez un texte ou une URL pour générer le QR code."; + } return; } diff --git a/app/index.html b/app/index.html index 0e123d8..8d81456 100644 --- a/app/index.html +++ b/app/index.html @@ -9,7 +9,7 @@

QR Code Generator

-

Générez des QR codes pour du texte, des liens ou une connexion Wi-Fi, avec logo optionnel.

+

Générez des QR codes pour du texte, des liens, une connexion Wi-Fi ou une carte de contact, avec logo optionnel.

🔒 100% local — rien n'est envoyé à un serveur
@@ -22,6 +22,7 @@ @@ -56,6 +57,44 @@

Scanné avec l'appareil photo du téléphone, ce QR code connecte directement l'appareil au réseau Wi-Fi, sans saisir le mot de passe.

+ +