QR Gen

import React, { useState, useEffect, useRef, useMemo } from ‘react’; // — Icons (Inline SVGs for portability) — const Icons = { QrCode: () => , Palette: () => , Shapes: () => , Image: () => , Settings: () => , Download: () => }; // — Custom Hook to load external script — const useScript = (url) => { const [loaded, setLoaded] = useState(false); useEffect(() => { if (document.querySelector(`script[src=”${url}”]`)) { setLoaded(true); return; } const script = document.createElement(‘script’); script.src = url; script.async = true; script.onload = () => setLoaded(true); document.body.appendChild(script); }, [url]); return loaded; }; // — Reusable UI Components — const Label = ({ children }) => ; const Input = (props) => ; const Select = ({ children, …props }) => ; const ColorPicker = ({ label, value, onChange }) => (
onChange(e.target.value)} className=”absolute -top-2 -left-2 w-16 h-16 cursor-pointer” />
onChange(e.target.value)} className=”uppercase font-mono text-sm” />
); const Range = ({ label, min, max, step, value, onChange, unit = “” }) => (
{value}{unit}
onChange(parseFloat(e.target.value))} className=”w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-indigo-600″ />
); const Toggle = ({ label, checked, onChange }) => ( ); // — Main Application — export default function App() { const isQrLibraryLoaded = useScript(“https://cdn.jsdelivr.net/npm/qr-code-styling@1.6.0-rc.1/lib/qr-code-styling.js”); const [activeTab, setActiveTab] = useState(‘data’); const qrRef = useRef(null); const [qrCodeInstance, setQrCodeInstance] = useState(null); // — Data State — const [dataType, setDataType] = useState(‘url’); const [dataValues, setDataValues] = useState({ url: ‘https://example.com’, text: ‘Hello World’, email: ‘contact@example.com’, subject: ”, body: ”, phone: ‘+1234567890’, sms: ‘+1234567890’, smsMsg: ”, wifiSsid: ‘MyNetwork’, wifiPass: ‘password’, wifiEnc: ‘WPA’, wifiHidden: false, vcFirst: ‘John’, vcLast: ‘Doe’, vcOrg: ‘Company’, vcTitle: ‘Developer’, vcPhone: ‘+1234567890’, vcEmail: ‘john@example.com’ }); // — QR Options State — const [options, setOptions] = useState({ width: 1024, // High resolution internally for sharp downloads height: 1024, type: “svg”, data: “https://example.com”, image: “”, margin: 10, qrOptions: { typeNumber: 0, mode: “Byte”, errorCorrectionLevel: “H” // H is best when using logos }, imageOptions: { hideBackgroundDots: true, imageSize: 0.4, margin: 10, crossOrigin: “anonymous”, }, dotsOptions: { color: “#0f172a”, // Slate 900 type: “rounded” }, backgroundOptions: { color: “#ffffff”, }, cornersSquareOptions: { color: “#4f46e5”, // Indigo 600 type: “extra-rounded” }, cornersDotOptions: { color: “#4f46e5”, type: “dot” } }); // — Extras for UI State — const [useGradient, setUseGradient] = useState(false); const [gradientColor1, setGradientColor1] = useState(“#4f46e5”); const [gradientColor2, setGradientColor2] = useState(“#ec4899”); const [gradientType, setGradientType] = useState(“linear”); const [transparentBg, setTransparentBg] = useState(false); const [bgColor, setBgColor] = useState(“#ffffff”); // Compile specific data types into a single string for the QR code useEffect(() => { let finalData = ”; const v = dataValues; switch (dataType) { case ‘url’: finalData = v.url || ‘ ‘; break; case ‘text’: finalData = v.text || ‘ ‘; break; case ’email’: finalData = `mailto:${v.email}?subject=${encodeURIComponent(v.subject)}&body=${encodeURIComponent(v.body)}`; break; case ‘phone’: finalData = `tel:${v.phone}`; break; case ‘sms’: finalData = `smsto:${v.sms}:${v.smsMsg}`; break; case ‘wifi’: finalData = `WIFI:T:${v.wifiEnc};S:${v.wifiSsid};P:${v.wifiPass};H:${v.wifiHidden};;`; break; case ‘vcard’: finalData = `BEGIN:VCARD\nVERSION:3.0\nN:${v.vcLast};${v.vcFirst}\nFN:${v.vcFirst} ${v.vcLast}\nORG:${v.vcOrg}\nTITLE:${v.vcTitle}\nTEL:${v.vcPhone}\nEMAIL:${v.vcEmail}\nEND:VCARD`; break; default: finalData = v.url; } updateOption(‘data’, finalData); }, [dataType, dataValues]); // Handle Gradients and Backgrounds useEffect(() => { let newDots = { …options.dotsOptions }; if (useGradient) { newDots.gradient = { type: gradientType, rotation: 0.5, colorStops: [{ offset: 0, color: gradientColor1 }, { offset: 1, color: gradientColor2 }] }; delete newDots.color; } else { newDots.color = options.dotsOptions.color || “#0f172a”; delete newDots.gradient; } setOptions(prev => ({ …prev, dotsOptions: newDots, backgroundOptions: { color: transparentBg ? “transparent” : bgColor } })); }, [useGradient, gradientColor1, gradientColor2, gradientType, transparentBg, bgColor]); // Initialize QR Code engine useEffect(() => { if (isQrLibraryLoaded && !qrCodeInstance) { const qr = new window.QRCodeStyling(options); qr.append(qrRef.current); setQrCodeInstance(qr); } }, [isQrLibraryLoaded]); // Update QR Code when options change useEffect(() => { if (qrCodeInstance) { qrCodeInstance.update(options); } }, [options, qrCodeInstance]); // State Updaters const updateOption = (key, value) => setOptions(prev => ({ …prev, [key]: value })); const updateNestedOption = (category, key, value) => { setOptions(prev => ({ …prev, [category]: { …prev[category], [key]: value } })); }; const handleDataChange = (key, val) => setDataValues(prev => ({ …prev, [key]: val })); const handleLogoUpload = (e) => { const file = e.target.files[0]; if (file) { const reader = new FileReader(); reader.onload = (event) => updateOption(‘image’, event.target.result); reader.readAsDataURL(file); } }; const handleDownload = (ext) => { if (qrCodeInstance) { qrCodeInstance.download({ name: “my-custom-qr”, extension: ext }); } }; const tabs = [ { id: ‘data’, label: ‘Data’, icon: }, { id: ‘colors’, label: ‘Colors’, icon: }, { id: ‘shapes’, label: ‘Shapes’, icon: }, { id: ‘logo’, label: ‘Logo’, icon: }, { id: ‘settings’, label: ‘Settings’, icon: }, ]; if (!isQrLibraryLoaded) { return (
); } return (
{/* Header */}

QR Studio Pro

{/* Left Column: Controls (8 cols) */}
{/* Sidebar Tabs */}
{tabs.map(tab => ( ))}
{/* Control Content */}
{/* — DATA TAB — */} {activeTab === ‘data’ && (
{[‘url’, ‘text’, ’email’, ‘phone’, ‘wifi’, ‘vcard’].map(type => ( ))}
{dataType === ‘url’ && (
handleDataChange(‘url’, e.target.value)} />
)} {dataType === ‘text’ && (
)} {dataType === ’email’ && ( <>
handleDataChange(’email’, e.target.value)} />
handleDataChange(‘subject’, e.target.value)} />
)} {dataType === ‘phone’ && (
handleDataChange(‘phone’, e.target.value)} />
)} {dataType === ‘wifi’ && (
handleDataChange(‘wifiSsid’, e.target.value)} />
handleDataChange(‘wifiPass’, e.target.value)} />
handleDataChange(‘wifiHidden’, v)} />
)} {dataType === ‘vcard’ && (
handleDataChange(‘vcFirst’, e.target.value)} />
handleDataChange(‘vcLast’, e.target.value)} />
handleDataChange(‘vcOrg’, e.target.value)} />
handleDataChange(‘vcTitle’, e.target.value)} />
handleDataChange(‘vcPhone’, e.target.value)} />
handleDataChange(‘vcEmail’, e.target.value)} />
)}
)} {/* — COLORS TAB — */} {activeTab === ‘colors’ && (
{/* Background */}

Background

{!transparentBg && }
{/* Foreground (Dots) */}

Pattern Color

{!useGradient ? ( updateNestedOption(‘dotsOptions’, ‘color’, c)} /> ) : (
)}
{/* Eyes Colors */}

Eye Colors

updateNestedOption(‘cornersSquareOptions’, ‘color’, c)} /> updateNestedOption(‘cornersDotOptions’, ‘color’, c)} />
)} {/* — SHAPES TAB — */} {activeTab === ‘shapes’ && (
{[‘square’, ‘dots’, ’rounded’, ‘extra-rounded’, ‘classy’, ‘classy-rounded’].map(type => ( ))}
)} {/* — LOGO TAB — */} {activeTab === ‘logo’ && (

Upload Logo

PNG, JPG, SVG allowed. Square images work best.

{options.image && (
Logo preview Logo Active
updateNestedOption(‘imageOptions’, ‘hideBackgroundDots’, v)} /> updateNestedOption(‘imageOptions’, ‘imageSize’, v)} /> updateNestedOption(‘imageOptions’, ‘margin’, v)} unit=”px” />
)}
)} {/* — SETTINGS TAB — */} {activeTab === ‘settings’ && (

Higher levels allow more damage/logos but make the code denser.

updateOption(‘margin’, v)} unit=”px” />
)}
{/* Right Column: Preview (4 cols) */}

Preview

{/* QR Code Canvas Container */}
{/* We use CSS to scale down the high-res generated SVG/Canvas */}
*’: { width: ‘100%’, height: ‘auto’, display: ‘block’ } }} > {/* The library injects canvas/svg here */}
{/* Download Actions */}
); }