Elementor #1384

hacker maaz

QR Code Generator
QRFlow Pro SaaS :root{--bg:#f4f7fc;--surface:#fff;--surface-2:#f7faff;--text:#0f172a;--muted:#64748b;--line:#e3e9f3;--primary:#1b63f8;--primary-soft:#eaf1ff;--danger:#e5484d;--ok:#10a36b;--radius-xl:20px;--radius-lg:14px;--radius-md:10px;--shadow-lg:0 18px 40px rgba(15,23,42,.09);--shadow-md:0 8px 24px rgba(15,23,42,.08)} *{box-sizing:border-box;margin:0;padding:0} body{font-family:Inter,"Segoe UI",sans-serif;background:radial-gradient(circle at 0 0,#ecf3ff 0,transparent 30%),radial-gradient(circle at 100% 0,#edfef7 0,transparent 30%),var(--bg);color:var(--text);min-height:100vh;display:flex;flex-direction:column} a{text-decoration:none;color:inherit} button,input,select,textarea{font-family:inherit} .app{flex:1;display:flex;flex-direction:column} .container{width:min(1280px,100% - 30px);margin:0 auto} .header{position:sticky;top:0;z-index:70;background:rgba(255,255,255,.88);backdrop-filter:blur(12px);border-bottom:1px solid var(--line)} .header-inner{height:74px;display:grid;grid-template-columns:220px 1fr auto;align-items:center;gap:14px} .logo{display:flex;align-items:center;gap:10px;border:none;background:none;font-weight:800;font-size:1.05rem;color:var(--text);cursor:pointer} .logo-badge{width:34px;height:34px;border-radius:11px;background:linear-gradient(135deg,var(--primary),#22b0ff);display:grid;place-items:center;color:#fff;box-shadow:var(--shadow-md)} .center-nav{display:flex;justify-content:center;gap:8px;flex-wrap:wrap} .nav-link{padding:9px 12px;border-radius:11px;border:1px solid transparent;color:var(--muted);font-weight:600;cursor:pointer;background:none;transition:.2s} .nav-link:hover{color:var(--text)} .nav-link.active{background:var(--primary-soft);color:var(--primary)} .auth-area{display:flex;align-items:center;gap:8px} .btn{padding:10px 14px;border-radius:11px;border:1px solid transparent;background:none;color:var(--muted);font-weight:600;cursor:pointer;transition:.2s} .btn:hover{transform:translateY(-1px)} .btn.primary{background:linear-gradient(135deg,var(--primary),#1da4ff);color:#fff;box-shadow:var(--shadow-md)} .btn.secondary{background:var(--surface);border-color:var(--line);color:var(--text)} .user-chip{padding:8px 11px;border-radius:999px;border:1px solid var(--line);background:var(--surface);font-size:.86rem;color:var(--muted)} .mobile-top{display:none;justify-content:space-between;align-items:center;gap:10px;margin-top:8px} .hamburger{width:42px;height:42px;border-radius:12px;border:1px solid var(--line);background:var(--surface);display:grid;place-items:center;cursor:pointer;font-size:1.1rem} .main{padding:18px 0 22px} .page{display:none;animation:fade .28s ease} .page.active{display:block} .shell{display:grid;grid-template-columns:280px 1fr;gap:16px} .sidebar{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-xl);padding:14px;box-shadow:var(--shadow-md);position:sticky;top:92px;height:calc(100vh - 110px);overflow:auto} .sidebar h3{font-size:1rem} .sub{color:var(--muted);font-size:.9rem;line-height:1.45;margin-top:6px} .tool-list{display:grid;gap:8px;margin-top:12px} .tool-item{width:100%;text-align:left;padding:10px 11px;border-radius:11px;border:1px solid var(--line);background:var(--surface-2);font-weight:600;color:var(--text);cursor:pointer;transition:.2s} .tool-item.active{background:var(--primary-soft);color:var(--primary);border-color:var(--primary)} .tool-item:hover{border-color:var(--primary)} .workspace{display:grid;grid-template-columns:1.15fr .85fr;gap:14px;align-items:start} .card{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius-xl);padding:16px;box-shadow:var(--shadow-md)} .card h2,.card h3{letter-spacing:-.02em} .forms section{display:none;gap:10px;margin-top:12px} .forms section.active{display:grid} .field{display:grid;gap:6px} .field label{font-size:.85rem;color:var(--muted);font-weight:600} input,select,textarea{border:1px solid var(--line);background:var(--surface-2);color:var(--text);border-radius:10px;padding:10px 11px;outline:none;width:100%} textarea{min-height:95px;resize:vertical} input:focus,select:focus,textarea:focus{border-color:var(--primary);box-shadow:0 0 0 3px rgba(27,99,248,.14)} .inline-2{display:grid;grid-template-columns:1fr 1fr;gap:10px} .preview-wrap{min-height:340px;border:1px dashed var(--line);border-radius:16px;background:linear-gradient(145deg,var(--surface),var(--surface-2));display:grid;place-items:center;position:relative;margin-top:10px} .preview-hint{color:var(--muted);font-size:.9rem} .controls{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:12px} .check{display:flex;align-items:center;gap:8px;color:var(--muted);font-size:.9rem;margin-top:8px} .check input{width:auto} .actions{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px} .actions .btn{width:100%} .history-list{display:grid;gap:10px;max-height:300px;overflow:auto;margin-top:12px} .history-item{border:1px solid var(--line);border-radius:12px;padding:10px;background:var(--surface-2)} .history-top{display:flex;justify-content:space-between;gap:8px;color:var(--muted);font-size:.82rem} .history-item strong{display:block;color:var(--text);margin-bottom:4px} .history-actions{display:flex;gap:8px;margin-top:8px} .stats{display:grid;grid-template-columns:repeat(4,minmax(120px,1fr));gap:10px;margin-top:12px} .stat{border:1px solid var(--line);border-radius:13px;background:var(--surface);padding:14px;box-shadow:var(--shadow-md)} .stat p{color:var(--muted);font-size:.84rem;margin-bottom:7px} .stat h3{font-size:1.35rem} .grid-2{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:12px} .grid-3{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;margin-top:12px} .panel{border:1px solid var(--line);border-radius:16px;background:var(--surface);box-shadow:var(--shadow-md);padding:16px} .panel p{color:var(--muted);margin-top:8px;line-height:1.45} .graph{height:190px;border:1px solid var(--line);border-radius:14px;background:linear-gradient(160deg,var(--surface-2),var(--surface));display:flex;align-items:flex-end;gap:10px;padding:12px} .bar{flex:1;background:linear-gradient(180deg,#8fb3ff,var(--primary));border-radius:10px 10px 4px 4px;animation:grow .5s ease} .price-pop{border-color:var(--primary);outline:3px solid rgba(27,99,248,.13)} .big-price{font-size:2rem;font-weight:800;letter-spacing:-.02em} .contact-grid{display:grid;grid-template-columns:1.1fr .9fr;gap:12px;margin-top:12px} .map-block{height:220px;border:1px dashed var(--line);border-radius:14px;background:linear-gradient(145deg,var(--surface-2),var(--surface));display:grid;place-items:center;color:var(--muted);font-weight:600} footer{margin-top:auto;background:var(--surface);border-top:1px solid var(--line)} .footer-inner{padding:28px 0 24px;display:grid;grid-template-columns:1.1fr .8fr .8fr;gap:16px;align-items:start} .footer-col h4{font-size:1rem;margin-bottom:8px} .footer-col p,.footer-col a{font-size:.9rem;color:var(--muted);line-height:1.5} .quick-links,.socials{display:grid;gap:6px} .social-row{display:flex;gap:8px;margin-top:8px} .social-btn{width:34px;height:34px;border:1px solid var(--line);background:var(--surface-2);border-radius:10px;display:grid;place-items:center;color:var(--muted)} .copy{margin-top:10px;font-size:.84rem;color:var(--muted)} .toast-wrap{position:fixed;right:14px;bottom:14px;display:grid;gap:8px;max-width:320px;z-index:80} .toast{border:1px solid var(--line);border-left:4px solid var(--primary);border-radius:12px;background:var(--surface);padding:10px 12px;box-shadow:var(--shadow-md);font-size:.9rem} .modal{position:fixed;inset:0;background:rgba(15,23,42,.45);display:none;align-items:center;justify-content:center;padding:16px;z-index:90} .modal.open{display:flex} .modal-card{width:min(520px,100%);background:var(--surface);border:1px solid var(--line);border-radius:18px;box-shadow:var(--shadow-lg);padding:16px} .tabs{display:flex;gap:8px;margin-bottom:12px} .tab{flex:1} .form-msg{font-size:.86rem;margin-top:4px;display:none} .form-msg.show{display:block} .form-msg.ok{color:var(--ok)} .form-msg.err{color:var(--danger)} .loader{width:18px;height:18px;border:2.4px solid rgba(255,255,255,.35);border-top-color:#fff;border-radius:50%;display:inline-block;animation:spin .7s linear infinite} .hidden{display:none !important} @keyframes spin{to{transform:rotate(360deg)}} @keyframes fade{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}} @keyframes grow{from{transform:scaleY(.1);transform-origin:bottom}to{transform:scaleY(1);transform-origin:bottom}} @media (max-width:1100px){.workspace,.grid-2,.grid-3,.contact-grid{grid-template-columns:1fr}.stats{grid-template-columns:1fr 1fr}.footer-inner{grid-template-columns:1fr 1fr}} @media (max-width:900px){.header-inner{grid-template-columns:1fr auto}.center-nav{display:none}.mobile-top{display:flex}.shell{grid-template-columns:1fr}.sidebar{display:none;position:fixed;left:10px;top:90px;z-index:75;width:min(320px,calc(100% - 20px));height:calc(100vh - 100px)}.sidebar.open{display:block}.workspace{grid-template-columns:1fr}.actions{grid-template-columns:1fr}} @media (max-width:620px){.stats,.inline-2,.controls,.footer-inner{grid-template-columns:1fr}.header-inner{height:auto;padding:12px 0}.auth-area{width:100%;justify-content:flex-end}.btn{padding:10px 12px}}

Website URL QR

Create QR codes for links, campaigns, and landing pages.

QR Preview & Customization

Live styling controls with download and edit options.

Generate a QR to preview.

SquareDotsRounded
SquareDotRounded
LMQH

Dashboard

Track QR performance and recent activity.

Total QR Generated

0

History Items

0

Most Used Tool

-

Logged User

Guest

Analytics

Visual trend placeholder with card-based UI.

Recent History

Most recent generated records.

Work

Enterprise-ready QR solutions built for modern growth teams.

Custom Branding

Branded QR visuals with logos, style controls, and campaign-level consistency for print and digital channels.

Enterprise Integrations

Connect QR outputs to CRM, ERP, and customer success workflows for measurable operational performance.

API Usage

Automate generation and distribution across onboarding, support, and transactional funnels.

Marketing Campaigns

Drive real-world conversion with packaging, retail, OOH, and event activation use cases.

Product Docs

Deliver guides, manuals, and update logs in a single scan experience for end users.

Event Journeys

Power check-ins, attendee content, and follow-up messaging through smart QR orchestration.

Pricing

Flexible plans designed for solo teams and enterprise scale.

Free

$0

Up to 50 QR / month

Core tools and PNG export

Pro

$19

Unlimited generation

Advanced styling + SVG export

History management tools

Business

$69

Team workflows

API and enterprise support

Priority SLA

About Us

We build premium QR infrastructure for modern SaaS teams.

Our Mission

Enable every business to launch smart, branded QR experiences without engineering overhead.

Why Choose Us

We focus on reliability, clean UX, and production-ready tooling designed for business outcomes.

Startup Speed

From idea to launch in minutes with configurable templates and seamless edit workflows.

Security Mindset

Client-side generation options, safe encoding patterns, and structured validation for confidence.

Professional Design

White-premium design language, polished motion, and consistent typography across modules.

Scalable Platform

Designed to grow from solo creators to enterprise teams with analytics and automation needs.

Contact Us

Reach our team for onboarding, support, and enterprise needs.

Contact Information

Email: support@qrflowpro.com

Phone: +1 (202) 555-0149

Address: 345 Market Street, San Francisco, CA

Map Placeholder
const STORAGE={ auth:"qrflow_auth_user", users:"qrflow_users", history:"qrflow_history", total:"qrflow_total" }; const tools=[ {id:"website",name:"Website URL QR",sub:"Generate QR for websites.",fields:[{id:"url",label:"Website URL",type:"url",req:1,ph:"https://example.com"}],build:v=>v.url.trim()}, {id:"wifi",name:"WiFi QR",sub:"Share WiFi credentials.",fields:[{id:"ssid",label:"SSID",type:"text",req:1,ph:"Office_WiFi"},{id:"pass",label:"Password",type:"text",ph:"Password"},{id:"enc",label:"Encryption",type:"select",opts:["WPA","WEP","nopass"],req:1}],build:v=>`WIFI:T:${v.enc};S:${esc(v.ssid)};P:${esc(v.pass||"")};;`}, {id:"email",name:"Email QR",sub:"Prefill email details.",fields:[{id:"email",label:"Email",type:"email",req:1,ph:"hello@example.com"},{id:"subject",label:"Subject",type:"text",ph:"Subject"},{id:"body",label:"Body",type:"textarea",ph:"Message"}],build:v=>`mailto:${v.email}?subject=${encodeURIComponent(v.subject||"")}&body=${encodeURIComponent(v.body||"")}`}, {id:"phone",name:"Phone QR",sub:"Tap to call.",fields:[{id:"phone",label:"Phone",type:"tel",req:1,ph:"+12025550123"}],build:v=>`tel:${v.phone}`}, {id:"text",name:"Text QR",sub:"Encode plain text.",fields:[{id:"text",label:"Text",type:"textarea",req:1,ph:"Your text"}],build:v=>v.text}, {id:"vcard",name:"vCard QR",sub:"Share contact card.",fields:[{id:"first",label:"First Name",type:"text",req:1,ph:"John"},{id:"last",label:"Last Name",type:"text",req:1,ph:"Doe"},{id:"org",label:"Organization",type:"text",ph:"Company"},{id:"email",label:"Email",type:"email",req:1,ph:"john@company.com"},{id:"phone",label:"Phone",type:"tel",req:1,ph:"+12025550123"}],build:v=>`BEGIN:VCARD\nVERSION:3.0\nN:${v.last};${v.first};;;\nFN:${v.first} ${v.last}\nORG:${v.org||""}\nEMAIL:${v.email}\nTEL:${v.phone}\nEND:VCARD`}, {id:"location",name:"Location QR",sub:"Share map location.",fields:[{id:"lat",label:"Latitude",type:"text",req:1,ph:"37.7749"},{id:"lng",label:"Longitude",type:"text",req:1,ph:"-122.4194"}],build:v=>`https://maps.google.com/?q=${encodeURIComponent(v.lat+","+v.lng)}`}, {id:"pdf",name:"PDF QR",sub:"Share PDF links.",fields:[{id:"pdf",label:"PDF URL",type:"url",req:1,ph:"https://example.com/doc.pdf"}],build:v=>v.pdf} ]; const state={page:"generator",tool:"website",qrData:"",logo:"",history:[],total:0,qr:null,currentFields:{}}; const pages=["generator","dashboard","work","pricing","about","contact"]; const $=id=>document.getElementById(id); function init(){ loadStorage(); renderNav(); renderAuthArea(); renderToolList(); renderForms(); bindCommon(); initQrEngine(); setTool("website"); setPage("generator"); renderHistory(); refreshDashboard(); } function renderNav(){ const m=$("mobileNav"); m.innerHTML=pages.filter(p=>p!=="generator").map(p=>``).join(""); } function bindCommon(){ document.querySelectorAll("[data-nav]").forEach(el=>el.addEventListener("click",e=>{e.preventDefault();const p=el.dataset.nav||"generator";setPage(p);if(window.innerWidth$("sidebar").classList.toggle("open")); ["fg","bg","grad","dotType","eyeType","ecLevel","qrSize","qrMargin","useGradient"].forEach(id=>{const el=$(id);el.addEventListener("input",updateQR);el.addEventListener("change",updateQR);}); $("logoInput").addEventListener("change",async e=>{const f=e.target.files[0];if(!f)return;state.logo=await fileToDataURL(f);updateQR();toast("Logo uploaded")}); $("downloadPNG").addEventListener("click",()=>downloadQR("png")); $("downloadSVG").addEventListener("click",()=>downloadQR("svg")); $("copyQR").addEventListener("click",copyQRImage); $("editCurrent").addEventListener("click",()=>toast("Update form fields and generate again.")); $("exportHistory").addEventListener("click",exportHistory); $("clearHistory").addEventListener("click",clearHistory); $("historyList").addEventListener("click",onHistoryAction); $("dashHistory").addEventListener("click",onHistoryAction); $("contactSubmit").addEventListener("click",submitContact); // Auth modal interactions $("tabLogin").addEventListener("click",()=>toggleAuthPane("login")); $("tabSignup").addEventListener("click",()=>toggleAuthPane("signup")); $("loginBtn").addEventListener("click",doLogin); $("signupBtn").addEventListener("click",doSignup); $("forgotBtn").addEventListener("click",()=>showMsg("loginMsg","Reset link UI simulated. Please use your registered email.",0)); $("authModal").addEventListener("click",e=>{if(e.target.id==="authModal")closeAuthModal();}); } function setPage(page){ state.page=page; document.querySelectorAll(".page").forEach(p=>p.classList.remove("active")); const target=$("page-"+page)||$("page-generator"); target.classList.add("active"); document.querySelectorAll(".nav-link").forEach(n=>n.classList.toggle("active",n.dataset.nav===page)); const showSidebar=page==="generator"; $("sidebar").style.display=showSidebar?"block":"none"; refreshDashboard(); } function renderToolList(){ $("toolList").innerHTML=tools.map(t=>``).join(""); $("toolList").addEventListener("click",e=>{const b=e.target.closest(".tool-item");if(!b)return;setTool(b.dataset.tool);}); } function renderForms(){ $("forms").innerHTML=tools.map(t=>`
${t.fields.map(fieldTemplate).join("")}
`).join(""); $("forms").addEventListener("click",e=>{const b=e.target.closest("[data-generate]");if(b)generateForTool(b.dataset.generate,b)}); $("forms").addEventListener("input",()=>{if(state.qrData)updateQR();}); } function fieldTemplate(f){ if(f.type==="textarea")return `
`; if(f.type==="select")return `
${f.opts.map(o=>`${o}`).join("")}
`; return `
`; } function setTool(id){ state.tool=id; const tool=getTool(id); $("toolTitle").textContent=tool.name; $("toolSub").textContent=tool.sub; document.querySelectorAll(".tool-item").forEach(btn=>btn.classList.toggle("active",btn.dataset.tool===id)); document.querySelectorAll(".forms section").forEach(sec=>sec.classList.toggle("active",sec.dataset.form===id)); setPage("generator"); } function initQrEngine(){ state.qr=new QRCodeStyling({ width:300,height:300,type:"svg",margin:8,data:"https://example.com", qrOptions:{errorCorrectionLevel:"M"},dotsOptions:{color:"#111827",type:"square"},backgroundOptions:{color:"#fff"},cornersSquareOptions:{type:"square"}, imageOptions:{crossOrigin:"anonymous",margin:4,imageSize:.25,hideBackgroundDots:true} }); state.qr.append($("qrMount")); } async function generateForTool(toolId,btn){ const t=getTool(toolId); const form=document.querySelector(`section[data-form="${toolId}"]`); const values={}; form.querySelectorAll("[data-field]").forEach(i=>values[i.dataset.field]=i.value.trim()); const check=validateToolValues(t,values); if(!check.ok){toast(check.msg,1);return;} const prev=btn.innerHTML; btn.innerHTML=''; btn.disabled=true; await wait(520); const payload=t.build(values); state.qrData=payload; state.currentFields=values; $("previewHint").style.display="none"; updateQR(); saveHistory(toolId,payload,values); renderHistory(); refreshDashboard(); btn.innerHTML=prev; btn.disabled=false; toast(`${t.name} generated successfully`); } function validateToolValues(tool,v){ for(const f of tool.fields){ if(f.req && !v[f.id])return {ok:0,msg:`${f.label} is required.`}; if(v[f.id] && f.type==="url"){try{new URL(v[f.id]);}catch{return{ok:0,msg:`Invalid URL in ${f.label}.`};}} if(v[f.id] && f.type==="email" && !/^\S+@\S+\.\S+$/.test(v[f.id]))return {ok:0,msg:`Invalid email in ${f.label}.`}; } if(tool.id==="location" && (Number.isNaN(Number(v.lat)) || Number.isNaN(Number(v.lng))))return {ok:0,msg:"Latitude and Longitude must be numeric."}; return {ok:1}; } function qrOptions(){ const fg=$("fg").value,bg=$("bg").value,grad=$("grad").value,useGrad=$("useGradient").checked,dotType=$("dotType").value,eyeType=$("eyeType").value,ec=$("ecLevel").value,size=+$("qrSize").value,margin=+$("qrMargin").value; const dots=useGrad?{type:dotType,gradient:{type:"linear",rotation:0,colorStops:[{offset:0,color:fg},{offset:1,color:grad}]}}:{color:fg,type:dotType}; return {width:size,height:size,data:state.qrData||"https://example.com",margin,qrOptions:{errorCorrectionLevel:ec},dotsOptions:dots,backgroundOptions:{color:bg},cornersSquareOptions:{type:eyeType},image:state.logo||undefined,imageOptions:{crossOrigin:"anonymous",margin:4,imageSize:.25,hideBackgroundDots:true}}; } function updateQR(){if(!state.qr)return;state.qr.update(qrOptions());} async function downloadQR(type){ if(!state.qrData){toast("Generate a QR first.",1);return;} const blob=await state.qr.getRawData(type); const ext=type==="svg"?"svg":"png"; triggerDownload(blob,`qrflow-${Date.now()}.${ext}`); toast(`Downloaded ${ext.toUpperCase()} file`); } async function copyQRImage(){ if(!state.qrData){toast("Generate a QR first.",1);return;} try{ const blob=await state.qr.getRawData("png"); await navigator.clipboard.write([new ClipboardItem({"image/png":blob})]); toast("QR copied to clipboard"); }catch{toast("Clipboard copy is not supported in this browser.",1);} } function saveHistory(tool,payload,fields){ const item={id:`${Date.now()}_${Math.random().toString(36).slice(2,7)}`,tool,payload,fields,style:{fg:$("fg").value,bg:$("bg").value,grad:$("grad").value,useGradient:$("useGradient").checked,dotType:$("dotType").value,eyeType:$("eyeType").value,ec:$("ecLevel").value,size:$("qrSize").value,margin:$("qrMargin").value},at:new Date().toISOString()}; state.history.unshift(item); state.history=state.history.slice(0,60); state.total+=1; persistStorage(); } function renderHistory(){ const html=state.history.length?state.history.slice(0,12).map(h=>{const t=getTool(h.tool),d=new Date(h.at).toLocaleString(),sn=h.payload.length>70?escapeHtml(h.payload.slice(0,70)+"..."):escapeHtml(h.payload);return `
${t.name}${d}

${sn}

`;}).join(""):'

No history yet.

'; $("historyList").innerHTML=html; $("dashHistory").innerHTML=html; } function onHistoryAction(e){ const b=e.target.closest("[data-action]"); if(!b)return; const id=b.dataset.id; if(b.dataset.action==="delete"){ state.history=state.history.filter(x=>x.id!==id); persistStorage(); renderHistory(); refreshDashboard(); toast("History item deleted"); return; } const item=state.history.find(x=>x.id===id); if(!item)return; setTool(item.tool); const form=document.querySelector(`section[data-form="${item.tool}"]`); Object.entries(item.fields).forEach(([k,v])=>{const i=form.querySelector(`[data-field="${k}"]`);if(i)i.value=v;}); if(item.style){ $("fg").value=item.style.fg||$("fg").value; $("bg").value=item.style.bg||$("bg").value; $("grad").value=item.style.grad||$("grad").value; $("useGradient").checked=!!item.style.useGradient; $("dotType").value=item.style.dotType||$("dotType").value; $("eyeType").value=item.style.eyeType||$("eyeType").value; $("ecLevel").value=item.style.ec||$("ecLevel").value; $("qrSize").value=item.style.size||$("qrSize").value; $("qrMargin").value=item.style.margin||$("qrMargin").value; } state.qrData=item.payload; $("previewHint").style.display="none"; updateQR(); toast("Loaded history item for editing"); } function refreshDashboard(){ $("statTotal").textContent=String(state.total); $("statCount").textContent=String(state.history.length); $("statTop").textContent=getMostUsedTool(); const auth=getAuthUser(); $("statUser").textContent=auth?auth.name:"Guest"; renderGraph(); } function renderGraph(){ const g=$("graph"); const list=state.history.slice(0,8); if(!list.length){g.innerHTML='

Generate QR codes to populate analytics.

';return;} g.innerHTML=list.map((_,i)=>`
`).join(""); } function getMostUsedTool(){ if(!state.history.length)return"-"; const count={}; state.history.forEach(h=>count[h.tool]=(count[h.tool]||0)+1); const top=Object.entries(count).sort((a,b)=>b[1]-a[1])[0][0]; return getTool(top).name; } function submitContact(){ const name=$("contactName").value.trim(),email=$("contactEmail").value.trim(),msg=$("contactMessage").value.trim(); const target=$("contactMsg"); if(!name||!email||!msg)return showMsg("contactMsg","All fields are required.",1); if(!/^\S+@\S+\.\S+$/.test(email))return showMsg("contactMsg","Please enter a valid email address.",1); showMsg("contactMsg","Message submitted successfully. We will contact you soon.",0); $("contactName").value="";$("contactEmail").value="";$("contactMessage").value=""; toast("Contact form submitted"); } // Auth system (frontend simulation with localStorage) function openAuthModal(){ $("authModal").classList.add("open"); toggleAuthPane("login"); } function closeAuthModal(){$("authModal").classList.remove("open");} function toggleAuthPane(pane){ const login=pane==="login"; $("loginPane").classList.toggle("hidden",!login); $("signupPane").classList.toggle("hidden",login); $("tabLogin").classList.toggle("primary",login); $("tabSignup").classList.toggle("primary",!login); } function doSignup(){ const name=$("signupName").value.trim(),email=$("signupEmail").value.trim(),pass=$("signupPassword").value.trim(); if(!name||!email||!pass)return showMsg("signupMsg","All signup fields are required.",1); if(!/^\S+@\S+\.\S+$/.test(email))return showMsg("signupMsg","Invalid email format.",1); if(pass.lengthu.email.toLowerCase()===email.toLowerCase()))return showMsg("signupMsg","Account already exists for this email.",1); users.push({name,email,password:pass}); localStorage.setItem(STORAGE.users,JSON.stringify(users)); showMsg("signupMsg","Account created. You can now login.",0); $("loginEmail").value=email; toggleAuthPane("login"); } function doLogin(){ const email=$("loginEmail").value.trim(),pass=$("loginPassword").value.trim(); if(!email||!pass)return showMsg("loginMsg","Email and password are required.",1); if(!/^\S+@\S+\.\S+$/.test(email))return showMsg("loginMsg","Invalid email format.",1); const users=getUsers(); const user=users.find(u=>u.email.toLowerCase()===email.toLowerCase()&&u.password===pass); if(!user)return showMsg("loginMsg","Invalid credentials.",1); localStorage.setItem(STORAGE.auth,JSON.stringify({name:user.name,email:user.email})); showMsg("loginMsg","Login successful.",0); renderAuthArea(); refreshDashboard(); closeAuthModal(); toast(`Welcome, ${user.name}`); } function logout(){ localStorage.removeItem(STORAGE.auth); renderAuthArea(); refreshDashboard(); toast("Logged out successfully"); } function renderAuthArea(){ const auth=getAuthUser(); const area=$("authArea"); if(!auth){ area.innerHTML=''; $("authCTA").addEventListener("click",openAuthModal); return; } area.innerHTML=`${escapeHtml(auth.name)}`; $("logoutBtn").addEventListener("click",logout); } function getUsers(){try{return JSON.parse(localStorage.getItem(STORAGE.users)||"[]");}catch{return [];}} function getAuthUser(){try{return JSON.parse(localStorage.getItem(STORAGE.auth)||"null");}catch{return null;}} function exportHistory(){ const blob=new Blob([JSON.stringify(state.history,null,2)],{type:"application/json"}); triggerDownload(blob,`qrflow-history-${Date.now()}.json`); toast("History exported as JSON"); } function clearHistory(){ state.history=[]; persistStorage(); renderHistory(); refreshDashboard(); toast("History cleared"); } function loadStorage(){ try{state.history=JSON.parse(localStorage.getItem(STORAGE.history)||"[]");state.total=Number(localStorage.getItem(STORAGE.total)||"0");} catch{state.history=[];state.total=0;} } function persistStorage(){ localStorage.setItem(STORAGE.history,JSON.stringify(state.history)); localStorage.setItem(STORAGE.total,String(state.total)); } function getTool(id){return tools.find(t=>t.id===id)||tools[0];} function triggerDownload(blob,name){const u=URL.createObjectURL(blob),a=document.createElement("a");a.href=u;a.download=name;document.body.appendChild(a);a.click();a.remove();URL.revokeObjectURL(u);} function esc(v){return (v||"").replace(/([\\;,:\"])/g,"\\$1");} function label(p){return p==="about"?"About":p==="contact"?"Contact":p.charAt(0).toUpperCase()+p.slice(1);} function wait(ms){return new Promise(r=>setTimeout(r,ms));} function fileToDataURL(file){return new Promise((resolve,reject)=>{const r=new FileReader();r.onload=()=>resolve(r.result);r.onerror=reject;r.readAsDataURL(file);});} function showMsg(id,text,isErr){const el=$(id);el.textContent=text;el.className=`form-msg show ${isErr?"err":"ok"}`;} function escapeHtml(str){return (str||"").replace(/&/g,"&").replace(//g,">").replace(/\"/g,""").replace(/'/g,"'");} function toast(msg,err){const t=document.createElement("div");t.className="toast";if(err)t.style.borderLeftColor="var(--danger)";t.textContent=msg;$("toastWrap").appendChild(t);setTimeout(()=>t.remove(),2800);} window.addEventListener("DOMContentLoaded",init);
Scroll to Top