perf: self-host fonts, eliminate CLS, a11y and contrast fixes

- Self-host Inter and JetBrains Mono (woff2, 69KB total)
- Remove Google Fonts dependency entirely (no external requests)
- Service Worker pre-caches font files
- Eliminate font-swap layout shifts
- WCAG contrast fix: disabled button uses solid color instead of opacity
- Footer link always underlined for distinguishability
- Translated aria-labels via data-i18n-aria
- Dimmed QR with "Bezahlt" stamp on paid invoices
- Hide wallet/address buttons when invoice is paid
This commit is contained in:
Alexander Schmidt
2026-03-25 16:56:10 +01:00
parent 8bcdb33fa3
commit 6a9a5b6a75
5 changed files with 20 additions and 20 deletions

BIN
fonts/inter-400.woff2 Normal file

Binary file not shown.

BIN
fonts/jetbrains-400.woff2 Normal file

Binary file not shown.

View File

@@ -6,10 +6,7 @@
<title>xmrpay.link — Monero Invoice Generator</title> <title>xmrpay.link — Monero Invoice Generator</title>
<meta name="description" content="Create Monero payment requests in seconds. No account, no backend, no KYC."> <meta name="description" content="Create Monero payment requests in seconds. No account, no backend, no KYC.">
<link rel="icon" id="favicon" href="favicon.svg" type="image/svg+xml"> <link rel="icon" id="favicon" href="favicon.svg" type="image/svg+xml">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&family=JetBrains+Mono:wght@400&display=swap" rel="stylesheet" media="print" onload="this.media='all'">
</head> </head>
<body> <body>

View File

@@ -1,19 +1,19 @@
@font-face { @font-face {
font-family: 'Inter fallback'; font-family: 'Inter';
src: local('Arial'); font-style: normal;
size-adjust: 107%; font-weight: 100 900;
ascent-override: 90%; font-display: swap;
descent-override: 25%; src: url('fonts/inter-400.woff2') format('woff2');
line-gap-override: 0%; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
} }
@font-face { @font-face {
font-family: 'JetBrains Mono fallback'; font-family: 'JetBrains Mono';
src: local('Courier New'); font-style: normal;
size-adjust: 112%; font-weight: 400;
ascent-override: 78%; font-display: swap;
descent-override: 22%; src: url('fonts/jetbrains-400.woff2') format('woff2');
line-gap-override: 0%; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
} }
:root { :root {
@@ -28,8 +28,8 @@
--success: #4caf50; --success: #4caf50;
--error: #f44336; --error: #f44336;
--radius: 8px; --radius: 8px;
--font: 'Inter', 'Inter fallback', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; --font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--mono: 'JetBrains Mono', 'JetBrains Mono fallback', 'Fira Code', monospace; --mono: 'JetBrains Mono', 'Fira Code', monospace;
} }
* { * {
@@ -320,7 +320,8 @@ textarea {
} }
.btn-primary:disabled { .btn-primary:disabled {
opacity: 0.5; background: #804020;
color: #ccc;
cursor: not-allowed; cursor: not-allowed;
} }

6
sw.js
View File

@@ -5,8 +5,10 @@ var ASSETS = [
'/app.js', '/app.js',
'/i18n.js', '/i18n.js',
'/style.css', '/style.css',
'/lib/qrcode.min.js' '/lib/qrcode.min.js',
// xmr-crypto.bundle.js is lazy-loaded and runtime-cached '/fonts/inter-400.woff2',
'/fonts/jetbrains-400.woff2'
// xmr-crypto.bundle.js and jspdf.min.js are lazy-loaded and runtime-cached
]; ];
self.addEventListener('install', function (e) { self.addEventListener('install', function (e) {