Files
QR-Code-Generator/index.html
T
elpatron 30872ad780 update: vCard placeholders updated for organization and position fields
Changed the placeholder text in the vCard input fields to reflect new example values, enhancing user experience and clarity in the form.
2026-04-25 14:12:32 +02:00

588 lines
29 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>
<html lang="de"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' https://plausible.elpatron.me; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self' https://plausible.elpatron.me; object-src 'none';">
<title>QR ohne Schnickschnack</title>
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><rect width='32' height='32' fill='white' rx='6' ry='6'/><rect x='4' y='4' width='8' height='8' fill='black'/><rect x='20' y='4' width='8' height='8' fill='black'/><rect x='4' y='20' width='8' height='8' fill='black'/><rect x='14' y='14' width='4' height='4' fill='black'/></svg>">
<script defer data-domain="qr.elpatron.me" src="https://plausible.elpatron.me/js/script.js"></script>
<script src="./assets/qrious.min.js"></script>
<script src="./main.js"></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: #f8f9fa;
color: #333;
}
h1 {
text-align: center;
margin-bottom: 30px;
color: #1e3a8a;
cursor: default;
user-select: none;
}
.container {
background-color: white;
border-radius: 10px;
padding: 30px;
box-shadow: 0 4px 20px rgba(30, 58, 138, 0.1);
position: relative;
border: 1px solid #e5e7eb;
}
.input-section {
margin-bottom: 40px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: 500;
color: #374151;
}
input, select, textarea {
width: 100%;
padding: 10px;
margin-bottom: 15px;
border: 1px solid #d1d5db;
border-radius: 6px;
box-sizing: border-box;
font-size: 16px;
transition: border-color 0.2s ease;
}
textarea {
min-height: 80px;
resize: vertical;
}
input:focus, select:focus, textarea:focus {
outline: none;
border-color: #1e3a8a;
box-shadow: 0 0 0 3px rgba(30, 58, 138, 0.1);
}
.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: #6b7280;
font-size: 18px;
cursor: pointer;
display: none;
padding: 0;
transition: color 0.2s ease;
}
.clear-button:hover {
color: #1e3a8a;
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 #d1d5db;
border-radius: 6px;
background-color: transparent;
cursor: pointer;
}
input[type="color"]::-webkit-color-swatch-wrapper {
padding: 0;
}
input[type="color"]::-webkit-color-swatch {
border: none;
border-radius: 5px;
}
.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: 8px;
display: block;
border: 1px solid #e5e7eb;
}
.download-btn {
background-color: #1e3a8a;
margin-top: 15px;
display: none;
transition: background-color 0.2s ease;
}
.download-btn:hover {
background-color: #1e40af;
}
.error {
color: #dc2626;
margin-top: 5px;
}
button {
background-color: #1e3a8a;
color: white;
border: none;
padding: 12px 20px;
border-radius: 6px;
cursor: pointer;
font-size: 16px;
font-weight: 500;
transition: background-color 0.2s ease;
width: 100%;
}
button:hover {
background-color: #1e40af;
}
.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: #6b7280;
transition: color 0.2s ease;
z-index: 10;
}
.info-button:hover {
color: #1e3a8a;
background: none;
}
.info-panel {
position: fixed;
top: 0;
right: -350px;
width: 330px;
height: 100%;
background-color: white;
box-shadow: -2px 0 10px rgba(30, 58, 138, 0.1);
transition: right 0.3s ease;
z-index: 100;
overflow-y: auto;
padding: 20px;
box-sizing: border-box;
border-left: 1px solid #e5e7eb;
}
.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 #e5e7eb;
}
.info-panel-header h2 {
margin: 0;
color: #1e3a8a;
}
.info-close {
background: none;
border: none;
font-size: 22px;
color: #6b7280;
cursor: pointer;
width: auto;
padding: 5px;
transition: color 0.2s ease;
}
.info-close:hover {
color: #1e3a8a;
background: none;
}
.info-content h3 {
font-size: 16px;
margin-top: 20px;
margin-bottom: 10px;
color: #1e3a8a;
}
.info-content p {
font-size: 14px;
line-height: 1.6;
color: #374151;
margin-bottom: 20px;
}
.footer {
margin-top: 30px;
text-align: center;
font-size: 14px;
color: #6b7280;
}
.credit {
margin-top: 5px;
font-size: 12px;
color: #9ca3af;
}
.credit a {
text-decoration: none;
color: #1e3a8a;
transition: color 0.2s ease;
}
.credit a:hover {
text-decoration: underline;
color: #1e40af;
}
.event-berlin-preview {
font-size: 14px;
color: #4b5563;
margin: -8px 0 16px 0;
line-height: 1.5;
}
.event-berlin-preview:empty {
display: none;
}
.event-datetime-hint {
font-size: 13px;
color: #6b7280;
margin: -4px 0 12px 0;
line-height: 1.4;
}
.time-24h-block {
margin-bottom: 15px;
}
.time-24h-block .time-24h-row {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.time-24h-block input[type="number"] {
width: 4.25rem;
margin-bottom: 0;
text-align: center;
}
.time-24h-sep {
font-weight: 600;
color: #374151;
user-select: none;
}
.time-24h-hint {
font-size: 12px;
color: #6b7280;
margin-top: 4px;
}
.vcard-preview-label {
margin: 4px 0 6px 0;
color: #374151;
font-weight: 500;
}
.vcard-preview {
margin: 0 0 15px 0;
padding: 10px;
border: 1px solid #e5e7eb;
border-radius: 6px;
background: #f9fafb;
color: #374151;
font-size: 12px;
line-height: 1.45;
white-space: pre-wrap;
word-break: break-word;
min-height: 80px;
}
</style>
</head>
<body>
<div class="container">
<h1 id="title">QR ohne Schnickschnack</h1>
<button id="info-button" class="info-button" aria-label="Information">?</button>
<div class="input-section">
<label for="content-mode">QR-Inhalt:</label>
<select id="content-mode">
<option value="text">Text oder URL</option>
<option value="wifi">WLAN</option>
<option value="event">Termin (Kalender)</option>
<option value="vcard">vCard (Kontakt)</option>
</select>
<div id="section-text" class="content-section">
<label for="text">Text oder URL:</label>
<div class="text-input-wrapper">
<input type="text" id="text" placeholder="https://qr.medisoftware.org" value="" autofocus="">
<button type="button" id="clear-text" class="clear-button" aria-label="Clear text" style="display: none;"></button>
</div>
</div>
<div id="section-wifi" class="content-section" style="display: none;">
<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>
<div id="section-event" class="content-section" style="display: none;" lang="de-DE">
<label for="event-title">Titel:</label>
<input type="text" id="event-title" placeholder="" autocomplete="off">
<p class="event-datetime-hint">Datum über das Kalenderfeld; Uhrzeit als <strong>Stunden 023</strong> und <strong>Minuten 059</strong> (reines 24h-Format, kein AM/PM). Ortszeit <strong>Europe/Berlin</strong>.</p>
<div class="options-row">
<div class="options-col">
<label for="event-start-date">Beginn Datum:</label>
<input type="date" id="event-start-date" autocomplete="off">
</div>
<div class="options-col">
<div class="time-24h-block">
<span class="label" style="display:block; margin-bottom:5px; font-weight:500; color:#374151;">Beginn Uhrzeit (24h):</span>
<div class="time-24h-row" role="group" aria-label="Beginn Uhrzeit 24 Stunden">
<input type="number" id="event-start-hour" min="0" max="23" step="1" placeholder="HH" inputmode="numeric" autocomplete="off" aria-label="Stunde Beginn, 0 bis 23">
<span class="time-24h-sep">:</span>
<input type="number" id="event-start-minute" min="0" max="59" step="1" placeholder="MM" inputmode="numeric" autocomplete="off" aria-label="Minute Beginn, 0 bis 59">
</div>
<p class="time-24h-hint">Stunde 023, Minute 059</p>
</div>
</div>
</div>
<div class="options-row">
<div class="options-col">
<label for="event-end-date">Ende (optional) Datum:</label>
<input type="date" id="event-end-date" autocomplete="off">
</div>
<div class="options-col">
<div class="time-24h-block">
<span class="label" style="display:block; margin-bottom:5px; font-weight:500; color:#374151;">Ende (optional) Uhrzeit (24h):</span>
<div class="time-24h-row" role="group" aria-label="Ende Uhrzeit 24 Stunden">
<input type="number" id="event-end-hour" min="0" max="23" step="1" placeholder="HH" inputmode="numeric" autocomplete="off" aria-label="Stunde Ende, 0 bis 23">
<span class="time-24h-sep">:</span>
<input type="number" id="event-end-minute" min="0" max="59" step="1" placeholder="MM" inputmode="numeric" autocomplete="off" aria-label="Minute Ende, 0 bis 59">
</div>
<p class="time-24h-hint">Stunde 023, Minute 059</p>
</div>
</div>
</div>
<p class="event-berlin-preview" id="event-berlin-preview" aria-live="polite"></p>
<label for="event-location">Ort (optional):</label>
<input type="text" id="event-location" placeholder="" autocomplete="off">
<label for="event-description">Beschreibung (optional):</label>
<textarea id="event-description" placeholder="" rows="3"></textarea>
</div>
<div id="section-vcard" class="content-section" style="display: none;">
<div class="options-row">
<div class="options-col">
<label for="vcard-first-name">Vorname:</label>
<input type="text" id="vcard-first-name" placeholder="Max" autocomplete="off">
</div>
<div class="options-col">
<label for="vcard-last-name">Nachname:</label>
<input type="text" id="vcard-last-name" placeholder="Mustermann" autocomplete="off">
</div>
</div>
<div class="options-row">
<div class="options-col">
<label for="vcard-org">Organisation:</label>
<input type="text" id="vcard-org" placeholder="Knorrlabs Inc." autocomplete="off">
</div>
<div class="options-col">
<label for="vcard-title">Position (optional):</label>
<input type="text" id="vcard-title" placeholder="Master Of Desaster" autocomplete="off">
</div>
</div>
<div class="options-row">
<div class="options-col">
<label for="vcard-phone">Telefon (optional):</label>
<input type="tel" id="vcard-phone" placeholder="+49 30 1234567" autocomplete="off">
</div>
<div class="options-col">
<label for="vcard-email">E-Mail (optional):</label>
<input type="email" id="vcard-email" placeholder="max@beispiel.de" autocomplete="off">
</div>
</div>
<label for="vcard-website">Webseite (optional):</label>
<input type="url" id="vcard-website" placeholder="https://beispiel.de" autocomplete="off">
<label for="vcard-address">Adresse (optional):</label>
<textarea id="vcard-address" placeholder="Musterstraße 1, 10115 Berlin" rows="2"></textarea>
<label for="vcard-note">Notiz (optional):</label>
<textarea id="vcard-note" placeholder="Erreichbar Mo-Fr 9-17 Uhr" rows="2"></textarea>
<p class="vcard-preview-label">vCard-Vorschau:</p>
<pre id="vcard-preview" class="vcard-preview" aria-live="polite">Bitte mindestens Vorname, Nachname oder Organisation eingeben.</pre>
</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>
<div class="button-row" style="display: flex; justify-content: center; gap: 10px; align-items: center;">
<button id="download" class="download-btn" style="display: inline-block;">Download QR Code</button>
<button id="share" class="download-btn" style="display: inline-block;">Teilen</button>
</div>
<div id="share-hint" style="margin-top:8px; color:#dc2626; font-size:13px; display:none;">Achtung: Das WLAN-Passwort wird im Link im Klartext übertragen!</div>
</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 QR ohne Schnickschnak 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; page views are counted with self-hosted Plausible (privacy-friendly, no cookies). Your QR content is not sent anywhere.</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>
<h3>Modi</h3>
<p>Unter <strong>QR-Inhalt</strong> wählst du, was kodiert wird: freier Text oder URL, WLAN-Zugangsdaten (WIFI-QR), ein <strong>Kalendertermin</strong> oder eine <strong>vCard</strong>. Im Modus „Termin“ erzeugt der QR-Code einen Standard-iCalendar-Eintrag (VEVENT), den viele Smartphones beim Scannen in die Kalender-App übernehmen. Datumseingabe als <strong>TT/MM/JJJJ</strong>, Uhrzeit im <strong>24-Stunden-Format</strong>; die Zeitzone ist <strong>Europe/Berlin</strong>. Im Modus „vCard“ wird ein Kontakt im vCard-Format (3.0) erzeugt, den viele Geräte direkt als Kontakt speichern. Deine Eingaben für den QR-Code werden nicht an einen Server gesendet.</p>
</div>
</div>
<div class="footer">
Dieser QR-Code-Generator funktioniert vollständig in deinem Browser; QR-Inhalte werden nicht hochgeladen. Seitenaufrufe werden mit selbst gehostetem Plausible aggregiert (ohne Cookies). <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>
</body></html>