diff --git a/index.html b/index.html index 3a270b6..35382a0 100644 --- a/index.html +++ b/index.html @@ -27,9 +27,30 @@ a { color: rgb(34, 125, 230); } + a:hover { color: rgb(0, 105, 224); } + + .loader-svg { + width: 28px; + height: 28px; + } + + .loader-spin { + animation: spinner 0.9s linear infinite; + transform-origin: center; + } + + @keyframes spinner { + from { + transform: rotate(0deg); + } + + to { + transform: rotate(360deg); + } + } @@ -37,48 +58,30 @@
- -
- - - - - -
- -
- - - - + +
+ + + +
-
+ + +
PNG - - + SVG
@@ -95,6 +98,182 @@ const size = document.getElementById('imgSize') + const qrTypes = { + url: { + name: 'URL / Text', + fields: [ + { + id: 'urlBox', + placeholder: 'URL', + type: 'text' + } + ], + format: (vals) => vals[0], + inline: true, + helpLink: "https://github.com/zxing/zxing/wiki/Barcode-Contents" + }, + wifi: { + name: 'WIFI', + fields: [ + { + id: 'ssidBox', + placeholder: 'SSID', + type: 'text' + }, + { + id: 'pwdBox', + placeholder: 'Password', + type: 'password' + } + ], + format: (vals) => `WIFI:S:${vals[0]};H:true;T:WPA2;P:${vals[1]};;`, + inline: true, + helpLink: "https://github.com/zxing/zxing/wiki/Barcode-Contents" + } + } + + function genDropdown() { + const qrType = document.getElementById('qrType') + for (const key in qrTypes) { + const option = document.createElement('option') + option.value = key + option.textContent = qrTypes[key].name + + qrType.appendChild(option) + } + } + + function genInputsForSelectedOption() { + const qrType = document.getElementById('qrType').value + const inputs = document.getElementById('inputs') + inputs.innerHTML = '' + + const config = qrTypes[qrType] + const fields = config.fields + const isInline = config.inline ?? config.inlineFields ?? false + const helpLink = (config.helpLink ?? '').trim() + + const container = document.createElement('div') + container.classList.add('flex', 'rounded', 'border-gray-900', 'bg-gray-800', 'border-1', 'text-white', 'mb-2', 'w-full', 'max-w-full') + + if (isInline) { + container.classList.add('flex-row', 'items-center', 'h-14') + } else { + container.classList.add('flex-row', 'items-stretch') + } + + if (helpLink !== '') { + const help = document.createElement('a') + help.href = helpLink + help.target = '_blank' + help.rel = 'noopener noreferrer' + help.classList.add('p-2', 'block', 'flex', 'flex-row', 'items-center', 'justify-center', 'hover:bg-gray-700', 'shrink-0') + + if (isInline) { + help.classList.add('h-full') + } else { + help.classList.add('self-stretch') + } + + help.innerHTML = ` + + ` + container.appendChild(help) + } + + const fieldsContainer = document.createElement('div') + fieldsContainer.classList.add('flex', 'flex-1') + + if (isInline) { + fieldsContainer.classList.add('flex-row', 'items-center', 'h-full') + } else { + fieldsContainer.classList.add('flex-col') + } + + const generateBtn = document.createElement('button') + generateBtn.type = 'button' + generateBtn.textContent = 'Generate' + generateBtn.classList.add('pl-3', 'pr-3', 'border-l-gray-900', 'border-l-1', 'hover:bg-gray-700', 'shrink-0') + + if (isInline) { + generateBtn.classList.add('h-full') + } else { + generateBtn.classList.add('self-stretch') + } + + generateBtn.onclick = generateFromSelectedOption + + fields.forEach((field, index) => { + const input = document.createElement('input') + + input.type = field.type + input.placeholder = field.placeholder + input.id = field.id + + if (isInline) { + input.classList.add('h-full', 'pl-3', 'text-current', 'bg-transparent', 'focus:outline-none', 'w-full') + } else { + input.classList.add('py-3', 'px-2', 'text-current', 'bg-transparent', 'focus:outline-none', 'w-full') + if (index > 0) { + input.classList.add('border-t-1', 'border-t-gray-700') + } + } + + input.addEventListener('keydown', (e) => { + if (e.key === 'Enter') { + e.preventDefault() + generateBtn.click() + } + }) + + fieldsContainer.appendChild(input) + }) + + container.appendChild(fieldsContainer) + container.appendChild(generateBtn) + inputs.appendChild(container) + } + + function generateFromSelectedOption() { + const qrType = document.getElementById('qrType').value + const config = qrTypes[qrType] + + const values = config.fields.map((field) => { + const el = document.getElementById(field.id) + return el ? el.value : '' + }) + + const val = config.format(values) + const qr = document.getElementById("qrcode") + + qr.innerHTML = genSvg(val) + lastQuery = val + } + + function setInitialLoading(isLoading) { + const loader = document.getElementById('initLoader') + const inputs = document.getElementById('inputs') + const qr = document.getElementById('qrcode') + + if (!loader || !inputs || !qr) { + return + } + + if (isLoading) { + loader.classList.remove('hidden') + inputs.classList.add('hidden') + qr.classList.add('hidden') + } else { + loader.classList.add('hidden') + inputs.classList.remove('hidden') + qr.classList.remove('hidden') + } + } + function genSvg(val) { return new QRCode({ content: val, @@ -119,49 +298,34 @@ return canvas.toDataURL('img/png') } - // Wifi QR Code - // Format: WIFI:S:SSID_NAME;H:true;T:WPA2;P:PASSWORD;; - window.onload = () => { // Check query params const params = new Proxy(new URLSearchParams(window.location.search), { get: (searchParams, prop) => searchParams.get(prop), }); - - let btn = document.getElementById("genBtn") - let link = document.getElementById("linkBox") - let qr = document.getElementById("qrcode"); - - let genWifiBtn = document.getElementById("genWifiBtn") - let ssidBox = document.getElementById("ssidBox") - let pwdBox = document.getElementById("pwdBox") - // Standard QR - btn.onclick = () => { - qr.innerHTML = genSvg(link.value) - lastQuery = link.value - } + let qr = document.getElementById("qrcode"); + setInitialLoading(true) - // Wifi QR - genWifiBtn.onclick = () => { - const ssid = ssidBox.value - const pwd = pwdBox.value - - const wifi = `WIFI:S:${ssid};H:true;T:WPA2;P:${pwd};;` - qr.innerHTML = genSvg(wifi) - lastQuery = wifi - } + genDropdown(); + document.getElementById('qrType').addEventListener('change', genInputsForSelectedOption) + genInputsForSelectedOption(); const qlink = params.link - if(qlink && qlink.trim() !== '') { - link.value = qlink - - qr.innerHTML = genSvg(qlink) - lastQuery = qlink - } - else + if (qlink && qlink.trim() !== '') { + const urlField = document.getElementById('urlBox') + if (urlField) { + urlField.value = qlink + generateFromSelectedOption() + } else { + qr.innerHTML = genSvg(qlink) + lastQuery = qlink + } + } else { qr.innerHTML = genSvg('https://google.com') - + } + setInitialLoading(false) + // Download var dlPng = document.getElementById('dlpng') var dlSvg = document.getElementById('dlsvg') @@ -170,27 +334,34 @@ const dataUrl = genPng(lastQuery) const blob = await (await fetch(dataUrl)).blob() const blobUrl = URL.createObjectURL(blob) + var link = document.createElement('a') link.download = `${encodeURI(lastQuery)}.png` link.href = blobUrl + document.body.appendChild(link) link.click() + document.body.removeChild(link) URL.revokeObjectURL(blobUrl) } dlSvg.onclick = async (e) => { e.preventDefault() - const svgBlob = new Blob([genSvg(lastQuery)], {type:"image/svg+xml"}) + const svgBlob = new Blob([genSvg(lastQuery)], { type: "image/svg+xml" }) const svgUrl = URL.createObjectURL(svgBlob) + let link = document.createElement('a') link.download = `${encodeURI(lastQuery)}.svg` link.href = svgUrl + document.body.appendChild(link) link.click() + document.body.removeChild(link) URL.revokeObjectURL(svgUrl) } + }