refactor: reuse shared style.css and language switcher on privacy page

This commit is contained in:
Alexander Schmidt
2026-03-26 08:01:59 +01:00
parent 2263fbf659
commit dc330d2367

View File

@@ -3,114 +3,68 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>xmrpay.link - Privacy and Terms</title> <title>xmrpay.link Privacy & Terms</title>
<meta name="description" content="Privacy policy and terms of use for xmrpay.link."> <meta name="description" content="Privacy policy and terms of use for xmrpay.link.">
<link rel="icon" href="favicon.svg" type="image/svg+xml">
<link rel="stylesheet" href="style.css">
<style> <style>
:root { main.legal-main {
--bg: #0d0d0d; max-width: 920px;
--card: #1a1a1a;
--border: #333;
--text: #e0e0e0;
--muted: #a0a0a0;
--accent: #e87830;
--font: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
} }
* { box-sizing: border-box; } .legal-card {
body {
margin: 0;
background: var(--bg);
color: var(--text);
font-family: var(--font);
line-height: 1.55; line-height: 1.55;
} }
main { .legal-card h2 {
max-width: 920px; margin-bottom: 0.4rem;
margin: 0 auto; color: var(--accent-text);
padding: 24px 16px 64px; font-size: 1.2rem;
} }
.top { .legal-card h3 {
display: flex; margin: 1rem 0 0.4rem;
flex-wrap: wrap; font-size: 1rem;
gap: 10px;
align-items: center;
justify-content: space-between;
margin-bottom: 14px;
}
.back {
color: var(--accent);
text-decoration: none;
font-weight: 600;
}
h1 {
margin: 0 0 6px;
font-size: 1.8rem;
}
.intro {
color: var(--muted);
margin: 0 0 16px;
font-size: 0.95rem;
}
.tabs {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 14px;
}
.tab {
border: 1px solid var(--border);
background: var(--card);
color: var(--text); color: var(--text);
border-radius: 8px;
padding: 6px 10px;
cursor: pointer;
font-size: 0.85rem;
} }
.tab.active { .legal-card p,
border-color: var(--accent); .legal-card li {
color: var(--accent); color: var(--text-muted);
font-size: 0.92rem;
} }
.lang { .legal-card ul {
margin: 0 0 0 1.2rem;
padding: 0;
}
.legal-card li {
margin-bottom: 0.35rem;
}
.legal-lang {
display: none; display: none;
background: var(--card);
border: 1px solid var(--border);
border-radius: 12px;
padding: 16px;
margin-bottom: 16px;
} }
.lang.active { display: block; } .legal-lang.active {
h2 { margin: 0 0 10px; font-size: 1.2rem; } display: block;
h3 { margin: 16px 0 8px; font-size: 1rem; } }
ul { margin: 0 0 0 20px; padding: 0; } .legal-top-link {
li { margin-bottom: 6px; } display: inline-block;
p { margin: 0 0 10px; } margin-bottom: 0.75rem;
.note { color: var(--muted); font-size: 0.9rem; margin-top: 10px; } color: var(--accent-text);
}
</style> </style>
</head> </head>
<body> <body>
<main> <header>
<div class="top"> <h1><a href="/" id="homeLink">xmr<span>pay</span>.link</a></h1>
<a class="back" href="/">&larr; xmrpay.link</a> <p>Privacy &amp; Terms</p>
</div> </header>
<h1>Privacy &amp; Terms</h1> <main class="legal-main">
<p class="intro">Select your language. This page explains data handling and terms of use for xmrpay.link.</p> <div class="card legal-card">
<a class="legal-top-link" href="/">&larr; Back to invoice generator</a>
<div class="tabs" id="tabs"> <section class="legal-lang" data-lang="en">
<button class="tab" data-lang="en">English</button>
<button class="tab" data-lang="de">Deutsch</button>
<button class="tab" data-lang="fr">Français</button>
<button class="tab" data-lang="it">Italiano</button>
<button class="tab" data-lang="es">Español</button>
<button class="tab" data-lang="pt">Português</button>
<button class="tab" data-lang="ru">Русский</button>
</div>
<section class="lang" data-lang="en">
<h2>English</h2> <h2>English</h2>
<h3>Privacy Policy</h3> <h3>Privacy Policy</h3>
<p>xmrpay.link is designed to minimize data collection. No account is required.</p> <p>xmrpay.link is designed to minimize data collection. No account is required.</p>
<ul> <ul>
<li><strong>Rate limiting:</strong> temporary IP-based records are stored in server files to protect the API from abuse.</li> <li><strong>Rate limiting:</strong> temporary IP-based records are stored to protect the API from abuse.</li>
<li><strong>Short links:</strong> invoice hash data is stored for generated short URLs.</li> <li><strong>Short links:</strong> invoice hash data is stored for generated short URLs.</li>
<li><strong>Payment proof:</strong> if used, tx hash, amount, confirmations and timestamp are stored. No Monero address is stored in the proof database.</li> <li><strong>Payment proof:</strong> if used, tx hash, amount, confirmations and timestamp are stored. No Monero address is stored in the proof database.</li>
<li><strong>No tracking:</strong> no analytics, no ads, no profiling.</li> <li><strong>No tracking:</strong> no analytics, no ads, no profiling.</li>
@@ -124,45 +78,45 @@
</ul> </ul>
</section> </section>
<section class="lang" data-lang="de"> <section class="legal-lang" data-lang="de">
<h2>Deutsch</h2> <h2>Deutsch</h2>
<h3>Datenschutzerklärung</h3> <h3>Datenschutzerklaerung</h3>
<p>xmrpay.link ist auf minimale Datenerhebung ausgelegt. Es ist kein Konto erforderlich.</p> <p>xmrpay.link ist auf minimale Datenerhebung ausgelegt. Es ist kein Konto erforderlich.</p>
<ul> <ul>
<li><strong>Rate-Limiting:</strong> temporäre IP-basierte Einträge werden zum Schutz der API gespeichert.</li> <li><strong>Rate-Limiting:</strong> temporaere IP-basierte Eintraege werden zum Schutz der API gespeichert.</li>
<li><strong>Kurzlinks:</strong> Rechnungs-Hash-Daten werden für erzeugte Kurzlinks gespeichert.</li> <li><strong>Kurzlinks:</strong> Rechnungs-Hash-Daten werden fuer erzeugte Kurzlinks gespeichert.</li>
<li><strong>Zahlungsnachweis:</strong> falls genutzt, werden TX-Hash, Betrag, Bestätigungen und Zeitstempel gespeichert. Keine Monero-Adresse wird in der Proof-Datenbank gespeichert.</li> <li><strong>Zahlungsnachweis:</strong> falls genutzt, werden TX-Hash, Betrag, Bestaetigungen und Zeitstempel gespeichert. Keine Monero-Adresse wird in der Proof-Datenbank gespeichert.</li>
<li><strong>Kein Tracking:</strong> keine Analytics, keine Werbung, kein Profiling.</li> <li><strong>Kein Tracking:</strong> keine Analytics, keine Werbung, kein Profiling.</li>
</ul> </ul>
<h3>Nutzungsbedingungen</h3> <h3>Nutzungsbedingungen</h3>
<ul> <ul>
<li>Der Dienst wird ohne Gewähr bereitgestellt.</li> <li>Der Dienst wird ohne Gewaehr bereitgestellt.</li>
<li>Du bist für die Einhaltung der Gesetze in deiner Jurisdiktion verantwortlich.</li> <li>Du bist fuer die Einhaltung der Gesetze in deiner Jurisdiktion verantwortlich.</li>
<li>Missbrauch, rechtswidrige Nutzung oder Angriffe auf den Dienst sind verboten.</li> <li>Missbrauch, rechtswidrige Nutzung oder Angriffe auf den Dienst sind verboten.</li>
<li>Die Verfügbarkeit ist nicht garantiert; Funktionen können jederzeit geändert werden.</li> <li>Die Verfuegbarkeit ist nicht garantiert; Funktionen koennen jederzeit geaendert werden.</li>
</ul> </ul>
</section> </section>
<section class="lang" data-lang="fr"> <section class="legal-lang" data-lang="fr">
<h2>Français</h2> <h2>Francais</h2>
<h3>Politique de confidentialité</h3> <h3>Politique de confidentialite</h3>
<p>xmrpay.link est conçu pour minimiser la collecte de données. Aucun compte n'est requis.</p> <p>xmrpay.link est concu pour minimiser la collecte de donnees. Aucun compte n'est requis.</p>
<ul> <ul>
<li><strong>Limitation de débit:</strong> des enregistrements temporaires basés sur l'IP sont stockés pour protéger l'API.</li> <li><strong>Limitation de debit:</strong> des enregistrements temporaires bases sur l'IP sont stockes pour proteger l'API.</li>
<li><strong>Liens courts:</strong> les données de hachage de facture sont stockées pour les liens courts générés.</li> <li><strong>Liens courts:</strong> les donnees de hachage de facture sont stockees pour les liens courts generes.</li>
<li><strong>Preuve de paiement:</strong> si utilisée, le hash tx, le montant, les confirmations et l'horodatage sont stockés. Aucune adresse Monero n'est stockée dans la base de preuves.</li> <li><strong>Preuve de paiement:</strong> si utilisee, le hash tx, le montant, les confirmations et l'horodatage sont stockes. Aucune adresse Monero n'est stockee dans la base de preuves.</li>
<li><strong>Pas de suivi:</strong> pas d'analytics, pas de publicité, pas de profilage.</li> <li><strong>Pas de suivi:</strong> pas d'analytics, pas de publicite, pas de profilage.</li>
</ul> </ul>
<h3>Conditions d'utilisation</h3> <h3>Conditions d'utilisation</h3>
<ul> <ul>
<li>Le service est fourni "tel quel" sans garantie.</li> <li>Le service est fourni "tel quel" sans garantie.</li>
<li>Vous êtes responsable du respect des lois de votre juridiction.</li> <li>Vous etes responsable du respect des lois de votre juridiction.</li>
<li>Les abus, l'utilisation illégale ou les attaques contre le service sont interdits.</li> <li>Les abus, l'utilisation illegale ou les attaques contre le service sont interdits.</li>
<li>La disponibilité n'est pas garantie; les fonctionnalités peuvent changer à tout moment.</li> <li>La disponibilite n'est pas garantie; les fonctionnalites peuvent changer a tout moment.</li>
</ul> </ul>
</section> </section>
<section class="lang" data-lang="it"> <section class="legal-lang" data-lang="it">
<h2>Italiano</h2> <h2>Italiano</h2>
<h3>Informativa sulla privacy</h3> <h3>Informativa sulla privacy</h3>
<p>xmrpay.link e progettato per ridurre al minimo la raccolta dati. Non e richiesto alcun account.</p> <p>xmrpay.link e progettato per ridurre al minimo la raccolta dati. Non e richiesto alcun account.</p>
@@ -181,10 +135,10 @@
</ul> </ul>
</section> </section>
<section class="lang" data-lang="es"> <section class="legal-lang" data-lang="es">
<h2>Español</h2> <h2>Espanol</h2>
<h3>Politica de privacidad</h3> <h3>Politica de privacidad</h3>
<p>xmrpay.link esta diseñado para minimizar la recopilacion de datos. No se requiere cuenta.</p> <p>xmrpay.link esta disenado para minimizar la recopilacion de datos. No se requiere cuenta.</p>
<ul> <ul>
<li><strong>Limitacion de tasa:</strong> se almacenan registros temporales basados en IP para proteger la API del abuso.</li> <li><strong>Limitacion de tasa:</strong> se almacenan registros temporales basados en IP para proteger la API del abuso.</li>
<li><strong>Enlaces cortos:</strong> se almacenan datos hash de factura para enlaces cortos generados.</li> <li><strong>Enlaces cortos:</strong> se almacenan datos hash de factura para enlaces cortos generados.</li>
@@ -200,8 +154,8 @@
</ul> </ul>
</section> </section>
<section class="lang" data-lang="pt"> <section class="legal-lang" data-lang="pt">
<h2>Português</h2> <h2>Portugues</h2>
<h3>Politica de privacidade</h3> <h3>Politica de privacidade</h3>
<p>xmrpay.link foi projetado para minimizar a coleta de dados. Nao e necessaria conta.</p> <p>xmrpay.link foi projetado para minimizar a coleta de dados. Nao e necessaria conta.</p>
<ul> <ul>
@@ -219,62 +173,62 @@
</ul> </ul>
</section> </section>
<section class="lang" data-lang="ru"> <section class="legal-lang" data-lang="ru">
<h2>Русский</h2> <h2>Russkiy</h2>
<h3>Политика конфиденциальности</h3> <h3>Politika konfidentsialnosti</h3>
<p>xmrpay.link создан с минимальным сбором данных. Аккаунт не требуется.</p> <p>xmrpay.link sozdan s minimalnym sborom dannykh. Akkount ne trebuetsya.</p>
<ul> <ul>
<li><strong>Ограничение запросов:</strong> временные IP-записи сохраняются для защиты API от злоупотреблений.</li> <li><strong>Ogranichenie zaprosov:</strong> vremennye IP-zapisi sokhranyayutsya dlya zashchity API ot zloupotrebleniy.</li>
<li><strong>Короткие ссылки:</strong> хеш-данные счета сохраняются для созданных коротких ссылок.</li> <li><strong>Korotkie ssylki:</strong> khesh-dannye scheta sokhranyayutsya dlya sozdannykh korotkikh ssylok.</li>
<li><strong>Подтверждение платежа:</strong> при использовании сохраняются tx hash, сумма, подтверждения и метка времени. Адрес Monero в базе подтверждений не хранится.</li> <li><strong>Podtverzhdenie platezha:</strong> pri ispolzovanii sokhranyayutsya tx hash, summa, podtverzhdeniya i metka vremeni. Adres Monero v baze podtverzhdeniy ne khranitsya.</li>
<li><strong>Без трекинга:</strong> без аналитики, без рекламы, без профилирования.</li> <li><strong>Bez trekinga:</strong> bez analitiki, bez reklamy, bez profilirovaniya.</li>
</ul> </ul>
<h3>Условия использования</h3> <h3>Usloviya ispolzovaniya</h3>
<ul> <ul>
<li>Сервис предоставляется "как есть" без гарантий.</li> <li>Servis predostavlyaetsya "kak est" bez garantiy.</li>
<li>Вы несете ответственность за соблюдение законов вашей юрисдикции.</li> <li>Vy nesete otvetstvennost za soblyudenie zakonov vashey yurisdiktsii.</li>
<li>Злоупотребления, незаконное использование и атаки на сервис запрещены.</li> <li>Zloupotrebleniya, nezakonnoe ispolzovanie i ataki na servis zapreshcheny.</li>
<li>Доступность не гарантируется; функции могут изменяться в любое время.</li> <li>Dostupnost ne garantiruetsya; funktsii mogut izmenyatsya v lyuboe vremya.</li>
</ul> </ul>
</section> </section>
<p class="note">Last updated: 2026-03-26</p> <p style="margin-top:1rem;color:var(--text-muted);font-size:0.82rem;">Last updated: 2026-03-26</p>
</div>
</main> </main>
<script> <footer>
(function () { <p data-i18n-html="footer">Open Source &middot; No Tracking &middot; No KYC &middot; <a href="https://gitea.schmidt.eco/schmidt1024/xmrpay.link" target="_blank" rel="noopener noreferrer">Source</a> &middot; <a href="http://mc6wfeaqc7oijgdcudrr5zsotmwok3jzk3tu2uezzyjisn7nzzjjizyd.onion" title="Tor Hidden Service">Onion</a> &middot; <a href="/privacy.html">Privacy &amp; Terms</a></p>
var sections = Array.prototype.slice.call(document.querySelectorAll('.lang')); </footer>
var tabs = Array.prototype.slice.call(document.querySelectorAll('.tab'));
var supported = ['en', 'de', 'fr', 'it', 'es', 'pt', 'ru'];
function setLang(lang) { <div class="lang-picker" id="langPicker">
if (supported.indexOf(lang) === -1) lang = 'en'; <button class="lang-toggle" id="langToggle" aria-label="Language">
sections.forEach(function (s) { <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
s.classList.toggle('active', s.getAttribute('data-lang') === lang); <circle cx="12" cy="12" r="10"/>
<path d="M2 12h20"/>
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10A15.3 15.3 0 0 1 12 2z"/>
</svg>
</button>
<div class="lang-dropdown" id="langDropdown"></div>
</div>
<script src="i18n.min.js" defer></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
var supported = ['en', 'de', 'fr', 'it', 'es', 'pt', 'ru'];
var sections = document.querySelectorAll('.legal-lang');
function applyLang(lang) {
var activeLang = supported.indexOf(lang) !== -1 ? lang : 'en';
sections.forEach(function (el) {
el.classList.toggle('active', el.getAttribute('data-lang') === activeLang);
}); });
tabs.forEach(function (t) {
t.classList.toggle('active', t.getAttribute('data-lang') === lang);
});
try {
localStorage.setItem('xmrpay_lang', lang);
} catch (e) {}
} }
tabs.forEach(function (tab) { applyLang(I18n.getLang());
tab.addEventListener('click', function () { I18n.onChange(function (lang) {
setLang(tab.getAttribute('data-lang')); applyLang(lang);
}); });
}); });
var initial = 'en';
try {
var saved = localStorage.getItem('xmrpay_lang');
if (saved && supported.indexOf(saved) !== -1) initial = saved;
} catch (e) {}
var nav = (navigator.language || 'en').slice(0, 2).toLowerCase();
if (supported.indexOf(nav) !== -1) initial = nav;
setLang(initial);
})();
</script> </script>
</body> </body>
</html> </html>