From bde585eab78582bbd51cd2d321ced15627ae8b11 Mon Sep 17 00:00:00 2001
From: Knutwurst <36196269+knutwurst@users.noreply.github.com>
Date: Fri, 16 Oct 2026 19:04:03 +0200
Subject: [PATCH] Add a Buy me a coffee link with a QR code to the UI
The sidebar footer and the end of Settings open a dialog with a QR code
for PayPal, so it works from the TV, plus a direct link for phones.
---
web/app.js | 39 +++++++++++++++++++++++++++++++++++++++
web/index.html | 6 ++++++
web/styles.css | 17 +++++++++++++++++
3 files changed, 62 insertions(+)
diff --git a/web/app.js b/web/app.js
index 630f853..78ca59d 100644
--- a/web/app.js
+++ b/web/app.js
@@ -122,8 +122,47 @@ document.addEventListener("DOMContentLoaded", () => {
loadInitialData().then(openGuideFromHash);
window.addEventListener("hashchange", openGuideFromHash);
setInterval(watchTitles, 5000);
+ document.querySelectorAll("[data-donate]").forEach((b) => b.addEventListener("click", openDonate));
});
+const DONATE_URL = "https://paypal.me/oliverkoester";
+
+// Donation dialog. On the TV a link is no use, so it shows a QR code for
+// the phone (hidden on phones, where the button opens PayPal directly).
+function openDonate() {
+ const back = document.activeElement;
+ const matrix = qrEncode(DONATE_URL);
+ const wrap = document.createElement("div");
+ wrap.className = "guide-backdrop";
+ wrap.innerHTML = `
+
+
+
+
Support PatchDL
+
Buy me a coffee
+
+
+
+
If you like what I do, you can buy me a coffee.
+ ${matrix ? `
${qrSvg(matrix)}
+ Scan with your phone to open PayPal:
+ ${escapeHtml(DONATE_URL)}
It doesn't have to be a generous donation. A few cents are enough to show me who is interested in further development. So the motivation stays and I just know that I am not programming for the bin ;)
+ `;
+ const close = () => {
+ document.removeEventListener("keydown", onKey);
+ wrap.remove();
+ if (back && document.contains(back)) back.focus();
+ };
+ const onKey = (e) => { if (e.key === "Escape") close(); };
+ wrap.querySelector(".guide-close").addEventListener("click", close);
+ wrap.addEventListener("click", (e) => { if (e.target === wrap) close(); });
+ document.addEventListener("keydown", onKey);
+ document.body.appendChild(wrap);
+ wrap.querySelector(".guide-close").focus();
+}
+
// The server rescans on its own when games are added or removed and bumps
// titles_gen whenever the list or an update check changes; reload quietly then.
let watchBusy = false;
diff --git a/web/index.html b/web/index.html
index 54b9335..456f43f 100644
--- a/web/index.html
+++ b/web/index.html
@@ -58,6 +58,7 @@