Files
QR-Code-Generator/index.html
2025-06-23 09:42:12 +02:00

669 lines
32 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<!-- saved from url=(0024)https://qr.alster.space/ -->
<html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Just a QR Code</title>
<link rel="icon" href="data:image/svg+xml;utf8,&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; viewBox=&#39;0 0 32 32&#39;&gt;&lt;rect width=&#39;32&#39; height=&#39;32&#39; fill=&#39;%23ffffff&#39; rx=&#39;3&#39; ry=&#39;3&#39;/&gt;&lt;rect x=&#39;8&#39; y=&#39;8&#39; width=&#39;4&#39; height=&#39;4&#39; fill=&#39;%23000000&#39;/&gt;&lt;rect x=&#39;12&#39; y=&#39;8&#39; width=&#39;4&#39; height=&#39;4&#39; fill=&#39;%23000000&#39;/&gt;&lt;rect x=&#39;16&#39; y=&#39;8&#39; width=&#39;4&#39; height=&#39;4&#39; fill=&#39;%23000000&#39;/&gt;&lt;rect x=&#39;8&#39; y=&#39;12&#39; width=&#39;4&#39; height=&#39;4&#39; fill=&#39;%23000000&#39;/&gt;&lt;rect x=&#39;8&#39; y=&#39;16&#39; width=&#39;4&#39; height=&#39;4&#39; fill=&#39;%23000000&#39;/&gt;&lt;rect x=&#39;20&#39; y=&#39;8&#39; width=&#39;4&#39; height=&#39;4&#39; fill=&#39;%23000000&#39;/&gt;&lt;rect x=&#39;16&#39; y=&#39;12&#39; width=&#39;4&#39; height=&#39;4&#39; fill=&#39;%23000000&#39;/&gt;&lt;rect x=&#39;20&#39; y=&#39;16&#39; width=&#39;4&#39; height=&#39;4&#39; fill=&#39;%23000000&#39;/&gt;&lt;rect x=&#39;8&#39; y=&#39;20&#39; width=&#39;4&#39; height=&#39;4&#39; fill=&#39;%23000000&#39;/&gt;&lt;rect x=&#39;12&#39; y=&#39;20&#39; width=&#39;4&#39; height=&#39;4&#39; fill=&#39;%23000000&#39;/&gt;&lt;rect x=&#39;16&#39; y=&#39;20&#39; width=&#39;4&#39; height=&#39;4&#39; fill=&#39;%23000000&#39;/&gt;&lt;rect x=&#39;20&#39; y=&#39;20&#39; width=&#39;4&#39; height=&#39;4&#39; fill=&#39;%23000000&#39;/&gt;&lt;rect x=&#39;20&#39; y=&#39;12&#39; width=&#39;4&#39; height=&#39;4&#39; fill=&#39;%23000000&#39;/&gt;&lt;/svg&gt;">
<script src="./assets/qrious.min.js.Download"></script>
<!--
Licensed under the Creative Commons Attribution-NonCommercial (BY-NC) 4.0 license.
Feel free to use this for anything noncommercial.
Credit appreciated but not required.
If you don't like the news, go out and make some of your own.
-->
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
line-height: 1.6;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background-color: #f5f5f7;
color: #333;
}
h1 {
text-align: center;
margin-bottom: 30px;
color: #1d1d1f;
cursor: default;
user-select: none;
}
.container {
background-color: white;
border-radius: 10px;
padding: 30px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
position: relative;
}
.input-section {
margin-bottom: 40px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: 500;
}
input, select {
width: 100%;
padding: 10px;
margin-bottom: 15px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
font-size: 16px;
}
.text-input-wrapper {
position: relative;
margin-bottom: 15px;
}
.text-input-wrapper input {
padding-right: 40px;
margin-bottom: 0;
}
.clear-button {
position: absolute;
right: 0;
top: 0;
height: 100%;
width: 40px;
background: none;
border: none;
color: #666;
font-size: 18px;
cursor: pointer;
display: none;
padding: 0;
}
.clear-button:hover {
color: #333;
background: none;
}
.options-row {
display: flex;
gap: 15px;
}
.options-col {
flex: 1;
}
.color-input-wrapper {
position: relative;
}
input[type="color"] {
width: 100%;
height: 40px;
padding: 0;
border: 1px solid #ccc;
border-radius: 4px;
background-color: transparent;
cursor: pointer;
}
input[type="color"]::-webkit-color-swatch-wrapper {
padding: 0;
}
input[type="color"]::-webkit-color-swatch {
border: none;
border-radius: 3px;
}
.output-section {
text-align: center;
margin-top: 30px;
}
#qrcode-container {
text-align: center;
}
#qrcode, #qrcode-img {
margin: 0 auto;
padding: 15px;
background-color: white;
border-radius: 4px;
display: block;
}
.download-btn {
background-color: #ff9500;
margin-top: 15px;
display: none;
}
.download-btn:hover {
background-color: #e68600;
}
.error {
color: #e74c3c;
margin-top: 5px;
}
button {
background-color: #0071e3;
color: white;
border: none;
padding: 12px 20px;
border-radius: 6px;
cursor: pointer;
font-size: 16px;
font-weight: 500;
transition: background-color 0.2s;
width: 100%;
}
button:hover {
background-color: #0058b9;
}
.info-button {
position: absolute;
top: 20px;
right: 20px;
width: 30px;
height: 30px;
border-radius: 50%;
background: none;
border: none;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 18px;
color: #999;
transition: color 0.2s ease;
z-index: 10;
}
.info-button:hover {
color: #333;
background: none;
}
.info-panel {
position: fixed;
top: 0;
right: -350px;
width: 330px;
height: 100%;
background-color: white;
box-shadow: -2px 0 10px rgba(0,0,0,0.1);
transition: right 0.3s ease;
z-index: 100;
overflow-y: auto;
padding: 20px;
box-sizing: border-box;
}
.info-panel.open {
right: 0;
}
.info-panel-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
}
.info-panel-header h2 {
margin: 0;
color: #333;
}
.info-close {
background: none;
border: none;
font-size: 22px;
color: #666;
cursor: pointer;
width: auto;
padding: 5px;
}
.info-close:hover {
color: #333;
background: none;
}
.info-content h3 {
font-size: 16px;
margin-top: 20px;
margin-bottom: 10px;
}
.info-content p {
font-size: 14px;
line-height: 1.6;
color: #555;
margin-bottom: 20px;
}
.footer {
margin-top: 30px;
text-align: center;
font-size: 14px;
color: #666;
}
.credit {
margin-top: 5px;
font-size: 12px;
color: #888;
}
.credit a {
text-decoration: none;
}
.credit a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="container">
<h1 id="title">Just a QR Code</h1>
<button id="info-button" class="info-button" aria-label="Information">?</button>
<div class="input-section">
<label for="text">Text oder URL:</label>
<div class="text-input-wrapper">
<input type="text" id="text" placeholder="https://example.com" value="" autofocus="">
<button type="button" id="clear-text" class="clear-button" aria-label="Clear text" style="display: none;"></button>
</div>
<div class="options-row">
<div class="options-col">
<label for="wifi-ssid">WLAN SSID:</label>
<input type="text" id="wifi-ssid" placeholder="">
</div>
<div class="options-col">
<label for="wifi-password">WLAN Passwort:</label>
<input type="password" id="wifi-password" placeholder="">
</div>
</div>
<div class="options-row">
<div class="options-col">
<label for="size">QR Code Gr&ouml;sse:</label>
<select id="size">
<option value="128">Klein (128×128)</option>
<option value="256" selected="">Mittel (256×256)</option>
<option value="512">Groß (512×512)</option>
<option value="1024">XL (1024×1024)</option>
</select>
</div>
<div class="options-col">
<label for="errorCorrection">Fehlerkorrektur:</label>
<select id="errorCorrection">
<option value="L">Klein (7%)</option>
<option value="M" selected="">Mittel (15%)</option>
<option value="Q">Viertel (25%)</option>
<option value="H">Hoch (30%)</option>
</select>
</div>
</div>
<div class="options-row">
<div class="options-col">
<label for="foreground">Vodergrundfarbe:</label>
<div class="color-input-wrapper">
<input type="color" id="foreground" value="#000000">
</div>
</div>
<div class="options-col">
<label for="background">Hintergrundfarbe:</label>
<div class="color-input-wrapper">
<input type="color" id="background" value="#ffffff">
</div>
</div>
</div>
</div>
<div class="output-section">
<div id="qrcode-container">
<canvas id="qrcode" style="display: none;" height="256" width="256"></canvas>
<img id="qrcode-img" style="display: block;" alt="Generated QR Code" src="data:image/png;base64,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">
</div>
<div id="error-message" class="error"></div>
<button id="download" class="download-btn" style="display: inline-block;">Download QR Code</button>
</div>
</div>
<div class="info-panel" id="info-panel">
<div class="info-panel-header">
<h2>About</h2>
<button class="info-close" id="info-close"></button>
</div>
<div class="info-content">
<p>I needed to make a QR code again. It's one of those tasks that's useful enough to pop up regularly, but not frequently enough for you to have a go-to solution. When the need arises, you end up googling "QR code generator" and picking the least sketchy-looking option from the results. A couple ads and some invisible trackers are just the price you pay, right?</p>
<p>Not today.</p>
<p>Rather than bemoan the fact that there's no easy way to get just a QR code without the low-key parasitic monetization, I found a library (qrious) and put together just enough Javascript code to generate QR codes in the browser. No ads, no trackers, no sending your data to someone else's server for who-knows-what-reason.</p>
<p>Go ahead and inspect the page source. Save it to your computer, copy it, remix it, whatever you want.</p>
<p>This is my act of resistance: I'll pay for the domain name and hosting just so you and I don't ever have to give one more click or tracker data-point to some questionable "free" site again. If you find this useful, you can pay it back by making or doing something of your own and giving it away freely.</p>
<p>This is the web we were trying to build.</p>
<p>Be excellent to each other.</p>
</div>
</div>
<div class="footer">
Dieser QR-Code-Generator funktioniert vollständig in deinem Browser. Es werden keine Daten an einen Server gesendet. <i>Quellcode und README bei <a href="https://gitea.elpatron.me/elpatron/QR-Code-Generator" target="_blank">Gitea</a></i>.
<p class="credit">Made with ❤️ and 🍪 by Markus. Self hosted on <a href="https://unraid.net" target="_blank">Unraid</a> for <a href="https://medisoftware.de" target="_blank">medisoftware</a>. Credits: <a href="https://qr.alster.space/" target="_blank">alsternerd</a></p>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const textInput = document.getElementById('text');
const clearTextBtn = document.getElementById('clear-text');
const wifiSsidInput = document.getElementById('wifi-ssid');
const wifiPasswordInput = document.getElementById('wifi-password');
const sizeSelect = document.getElementById('size');
const errorCorrectionSelect = document.getElementById('errorCorrection');
const foregroundColor = document.getElementById('foreground');
const backgroundColor = document.getElementById('background');
const downloadBtn = document.getElementById('download');
const qrcodeCanvas = document.getElementById('qrcode');
const qrcodeImg = document.getElementById('qrcode-img');
const errorMessage = document.getElementById('error-message');
const infoButton = document.getElementById('info-button');
const infoPanel = document.getElementById('info-panel');
const infoClose = document.getElementById('info-close');
const titleElement = document.getElementById('title');
// Title Easter egg
let titleClickCount = 0;
let titleTimeoutId = null;
titleElement.addEventListener('click', function() {
titleClickCount++;
clearTimeout(titleTimeoutId);
if (titleClickCount === 1) {
this.textContent = "Just a [bleep]ing QR Code";
titleTimeoutId = setTimeout(() => {
this.textContent = "Just a QR Code";
titleClickCount = 0;
}, 500);
}
});
// Info panel toggle
infoButton.addEventListener('click', function() {
infoPanel.classList.add('open');
});
infoClose.addEventListener('click', function() {
infoPanel.classList.remove('open');
});
// Close info panel when clicking outside
document.addEventListener('click', function(event) {
if (infoPanel.classList.contains('open') &&
!infoPanel.contains(event.target) &&
event.target !== infoButton) {
infoPanel.classList.remove('open');
}
});
// Close info panel with Escape key
document.addEventListener('keydown', function(event) {
if (event.key === 'Escape' && infoPanel.classList.contains('open')) {
infoPanel.classList.remove('open');
}
});
// Set random compliment as default text and select it
textInput.value = 'https://medisoftware.de';
textInput.select();
// Show/hide clear button based on text input content
function toggleClearButton() {
if (textInput.value.length > 0) {
clearTextBtn.style.display = 'block';
} else {
clearTextBtn.style.display = 'none';
}
}
// Initialize clear button visibility
toggleClearButton();
// Clear text when clear button is clicked
clearTextBtn.addEventListener('click', function() {
textInput.value = '';
wifiSsidInput.value = '';
wifiPasswordInput.value = '';
toggleClearButton();
textInput.focus();
generateQRCode();
});
// Update clear button visibility when text changes
textInput.addEventListener('input', function() {
toggleClearButton();
// Only generate QR code if no wifi data is being entered
const wifiSsid = wifiSsidInput.value.trim();
const wifiPassword = wifiPasswordInput.value.trim();
if (!wifiSsid && !wifiPassword) {
generateQRCode();
}
});
let qr = null;
// Generate QR code when settings change
sizeSelect.addEventListener('change', generateQRCode);
errorCorrectionSelect.addEventListener('change', generateQRCode);
foregroundColor.addEventListener('input', generateQRCode);
backgroundColor.addEventListener('input', generateQRCode);
// Generate QR code when wifi settings change
wifiSsidInput.addEventListener('input', function() {
updateTextDisplay();
generateQRCode();
});
wifiPasswordInput.addEventListener('input', function() {
updateTextDisplay();
generateQRCode();
});
// Download QR code as image
downloadBtn.addEventListener('click', downloadQRCode);
// Or check for URL parameters if present
const urlParams = new URLSearchParams(window.location.search);
if (urlParams.has('text')) {
textInput.value = urlParams.get('text');
}
if (urlParams.has('ssid')) {
wifiSsidInput.value = urlParams.get('ssid');
}
if (urlParams.has('password')) {
wifiPasswordInput.value = urlParams.get('password');
}
if (urlParams.has('size')) {
const sizeValue = urlParams.get('size');
if (['128', '256', '512', '1024'].includes(sizeValue)) {
sizeSelect.value = sizeValue;
}
}
if (urlParams.has('errorCorrection')) {
const ecValue = urlParams.get('errorCorrection').toUpperCase();
if (['L', 'M', 'Q', 'H'].includes(ecValue)) {
errorCorrectionSelect.value = ecValue;
}
}
if (urlParams.has('foreground')) {
const fgValue = urlParams.get('foreground');
if (/^#[0-9A-F]{6}$/i.test(fgValue)) {
foregroundColor.value = fgValue;
}
}
if (urlParams.has('background')) {
const bgValue = urlParams.get('background');
if (/^#[0-9A-F]{6}$/i.test(bgValue)) {
backgroundColor.value = bgValue;
}
}
generateQRCode();
function generateQRCode() {
const text = textInput.value.trim();
const wifiSsid = wifiSsidInput.value.trim();
const wifiPassword = wifiPasswordInput.value.trim();
const size = parseInt(sizeSelect.value);
const errorCorrection = errorCorrectionSelect.value.toLowerCase();
const fgColor = foregroundColor.value;
const bgColor = backgroundColor.value;
// Update the gabe link color to match foreground color
const gabeLink = document.querySelector('.credit a');
if (gabeLink) {
gabeLink.style.color = fgColor;
}
// Clear previous error
errorMessage.textContent = '';
downloadBtn.style.display = 'none';
// Determine what to encode
let qrText = text;
// If wifi credentials are provided, generate wifi QR code
if (wifiSsid && wifiPassword) {
// Wifi QR code format: WIFI:S:<SSID>;T:WPA;P:<password>;;
qrText = `WIFI:S:${escapeSpecialChars(wifiSsid)};T:WPA;P:${escapeSpecialChars(wifiPassword)};;`;
} else if (wifiSsid && !wifiPassword) {
// SSID only (open network)
qrText = `WIFI:S:${escapeSpecialChars(wifiSsid)};T:nopass;;`;
} else if (!wifiSsid && wifiPassword) {
// Password without SSID is invalid
errorMessage.textContent = 'Bitte geben Sie eine SSID ein, wenn Sie ein Passwort angeben';
qrcodeCanvas.style.display = 'none';
qrcodeImg.style.display = 'none';
return;
}
// Validate input
if (qrText === '') {
errorMessage.textContent = 'Bitte geben Sie Text/URL oder Wifi-Daten ein';
// Hide both canvas and image
qrcodeCanvas.style.display = 'none';
qrcodeImg.style.display = 'none';
return;
}
// Create new QR code on canvas
try {
if (!qr) {
qr = new QRious({
element: qrcodeCanvas,
size: size,
value: qrText,
foreground: fgColor,
background: bgColor,
level: errorCorrection
});
} else {
qr.set({
size: size,
value: qrText,
foreground: fgColor,
background: bgColor,
level: errorCorrection
});
}
// Convert canvas to image
const dataURL = qrcodeCanvas.toDataURL('image/png');
qrcodeImg.src = dataURL;
// Show image (hide canvas) and download button
qrcodeCanvas.style.display = 'none';
qrcodeImg.style.display = 'block';
downloadBtn.style.display = 'inline-block';
} catch (err) {
errorMessage.textContent = 'Error generating QR code: ' + err.message;
qrcodeCanvas.style.display = 'none';
qrcodeImg.style.display = 'none';
}
}
// Helper function to escape special characters in wifi strings
function escapeSpecialChars(str) {
return str.replace(/[\\;:,]/g, '\\$&');
}
function downloadQRCode() {
// Use the image source for download
const link = document.createElement('a');
link.download = 'qrcode.png';
link.href = qrcodeImg.src;
// Simulate click to trigger download
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
// Show success feedback
const originalText = downloadBtn.textContent;
downloadBtn.textContent = 'Downloaded!';
// Reset button after a short delay
setTimeout(() => {
downloadBtn.textContent = originalText;
}, 2000);
}
// Function to update the text display with current QR code content
function updateTextDisplay() {
const wifiSsid = wifiSsidInput.value.trim();
const wifiPassword = wifiPasswordInput.value.trim();
if (wifiSsid && wifiPassword) {
// Show wifi QR code format
textInput.value = `WIFI:S:${escapeSpecialChars(wifiSsid)};T:WPA;P:${escapeSpecialChars(wifiPassword)};;`;
} else if (wifiSsid && !wifiPassword) {
// Show open network format
textInput.value = `WIFI:S:${escapeSpecialChars(wifiSsid)};T:nopass;;`;
} else {
// If no wifi data, keep original text input value
// Don't change it here to avoid overwriting user input
}
// Update clear button visibility
toggleClearButton();
}
});
</script>
</body></html>