Skip to content
This repository was archived by the owner on Jun 19, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions config/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,22 @@ window.APP_CONFIG = {
address: 't1em7Vhge9HKi9BYoBi1tADg2eMe5zj3Fvf',
label: 'zcash',
},
usdt: {
address: '0xe54E5a3ACaa91a2EbFa26cD21372BF9f7E1F1c22',
label: 'usdt',
},
usdc: {
address: '0xe54E5a3ACaa91a2EbFa26cD21372BF9f7E1F1c22',
label: 'usdc',
},
dai: {
address: '0xe54E5a3ACaa91a2EbFa26cD21372BF9f7E1F1c22',
label: 'dai',
},
usd1: {
address: '0xe54E5a3ACaa91a2EbFa26cD21372BF9f7E1F1c22',
label: 'usd1',
},
},
},
};
10 changes: 10 additions & 0 deletions config/text.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ window.APP_TEXT = {
tagline: "your donation helps me keep building open, free, and subversive code && art",
},

preferred: {
title: 'preferred methods',
cash: 'cash',
bitcoin: 'bitcoin',
},

other: {
title: 'donate with crypto',
},

fiat: {
title: 'donate with fiat',
description: '',
Expand Down
17 changes: 10 additions & 7 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self' https://fonts.googleapis.com; font-src https://fonts.gstatic.com; img-src 'self' data:; connect-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; upgrade-insecure-requests">
<meta name="referrer" content="strict-origin-when-cross-origin">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
<link rel="icon" type="image/svg+xml" href="assets/favicon.svg">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="icon" type="image/svg+xml" href="assets/favicon.svg">
<link rel="stylesheet" href="styles/main.css">
</head>
<body>
Expand All @@ -19,8 +17,13 @@ <h1 data-text="header.title"></h1>
<p class="tagline" data-text="header.tagline"></p>
</header>

<main class="options" id="pay-methods" aria-label="Payment options">
<!-- Pay method sections (fiat, crypto, etc.) are injected by scripts -->
<main class="main">
<section class="card-section" aria-label="Preferred methods">
<div class="preferred-methods" id="preferred-methods"></div>
</section>
<section class="card-section" aria-label="Donate with crypto">
<div class="other-options" id="other-options"></div>
</section>
</main>

<footer class="footnote">
Expand All @@ -31,7 +34,7 @@ <h1 data-text="header.title"></h1>
<script src="config/config.js"></script>
<script src="config/text.js"></script>
<script src="scripts/donation-api.js"></script>
<script src="scripts/pay-methods/fiat.js"></script>
<script src="scripts/pay-methods/preferred.js"></script>
<script src="scripts/pay-methods/crypto.js"></script>
<script src="scripts/main.js"></script>
</body>
Expand Down
11 changes: 9 additions & 2 deletions scripts/donation-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
'use strict';

window.DONATION_PAY_METHODS = window.DONATION_PAY_METHODS || [];
window.DONATION_PAY_METHODS_PREFERRED = window.DONATION_PAY_METHODS_PREFERRED || [];
window.DONATION_PAY_METHODS_OTHER = window.DONATION_PAY_METHODS_OTHER || [];

function get(obj, path) {
var keys = path.split('.');
Expand All @@ -38,8 +40,13 @@
* when rendering the page.
*/
function registerMethod(spec) {
if (spec && typeof spec.render === 'function') {
window.DONATION_PAY_METHODS.push({ render: spec.render });
if (!spec || typeof spec.render !== 'function') return;
var entry = { render: spec.render };
window.DONATION_PAY_METHODS.push(entry);
if (spec.preferred) {
window.DONATION_PAY_METHODS_PREFERRED.push(entry);
} else if (spec.other !== false) {
window.DONATION_PAY_METHODS_OTHER.push(entry);
}
}

Expand Down
23 changes: 16 additions & 7 deletions scripts/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

var text = typeof window.APP_TEXT !== 'undefined' ? window.APP_TEXT : {};
var config = typeof window.APP_CONFIG !== 'undefined' ? window.APP_CONFIG : {};
var payMethods = window.DONATION_PAY_METHODS || [];
var get = window.Donation && window.Donation.get;

function applyTextConfig() {
Expand All @@ -15,12 +14,22 @@
});
}

var container = document.getElementById('pay-methods');
if (container) {
for (var i = 0; i < payMethods.length; i++) {
var method = payMethods[i];
if (method && typeof method.render === 'function') {
method.render(container, config, text);
var preferredContainer = document.getElementById('preferred-methods');
var otherContainer = document.getElementById('other-options');
var preferredMethods = window.DONATION_PAY_METHODS_PREFERRED || [];
var otherMethods = window.DONATION_PAY_METHODS_OTHER || [];

if (preferredContainer) {
for (var p = 0; p < preferredMethods.length; p++) {
if (preferredMethods[p] && typeof preferredMethods[p].render === 'function') {
preferredMethods[p].render(preferredContainer, config, text);
}
}
}
if (otherContainer) {
for (var o = 0; o < otherMethods.length; o++) {
if (otherMethods[o] && typeof otherMethods[o].render === 'function') {
otherMethods[o].render(otherContainer, config, text);
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion scripts/pay-methods/crypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@

for (var key in addresses) {
if (!addresses[key] || !addresses[key].address) continue;
if (key.toLowerCase() === 'bitcoin') continue; /* bitcoin is in preferred */
var item = addresses[key];
var label = item.label || key;
var id = 'address-' + key;
Expand All @@ -54,5 +55,5 @@
container.appendChild(section);
}

Donation.registerMethod({ render: render });
Donation.registerMethod({ render: render, other: true });
})();
82 changes: 82 additions & 0 deletions scripts/pay-methods/preferred.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* Preferred methods: Cash (Stripe) and Bitcoin.
* Renders into the top "Preferred methods" block.
*/
(function () {
'use strict';

var Donation = window.Donation;
if (!Donation) return;

function render(container, config, text) {
var get = Donation.get;
var escapeHtml = Donation.escapeHtml;

var section = document.createElement('section');
section.className = 'card card-preferred';
section.setAttribute('aria-labelledby', 'preferred-title');

var preferredTitle = get(text, 'preferred.title');
if (preferredTitle === undefined) preferredTitle = 'preferred methods';
var preferredDescription = get(text, 'preferred.description');
if (preferredDescription === undefined) preferredDescription = '';

var cashLabel = get(text, 'preferred.cash');
if (cashLabel === undefined) cashLabel = 'cash';
var bitcoinLabel = get(text, 'preferred.bitcoin');
if (bitcoinLabel === undefined) bitcoinLabel = 'bitcoin';

var stripeLink = (config && config.fiat && config.fiat.stripe && config.fiat.stripe.link) ? config.fiat.stripe.link : '';
var stripeBtnLabel = get(text, 'fiat.stripe.button') || 'donate with stripe';

var bitcoinAddr = (config && config.crypto && config.crypto.addresses && config.crypto.addresses.bitcoin)
? config.crypto.addresses.bitcoin
: null;
var copyLabel = get(text, 'crypto.copy') || 'copy';
var copyAria = get(text, 'crypto.copyAria') || 'Copy address';

var iconSvg = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>';

var html =
'<div class="card-header">' +
'<div class="card-icon" aria-hidden="true">' + iconSvg + '</div>' +
'<h2 id="preferred-title" data-text="preferred.title">' + escapeHtml(preferredTitle) + '</h2>' +
'</div>';
if (preferredDescription) {
html += '<p data-text="preferred.description">' + escapeHtml(preferredDescription) + '</p>';
}
html += '<div class="preferred-grid">';

// Cash (Stripe)
html += '<div class="preferred-item preferred-cash">';
html += '<span class="preferred-item-label">' + escapeHtml(cashLabel) + '</span>';
html += '<div class="preferred-item-actions">';
if (stripeLink) {
html += '<a href="' + escapeHtml(stripeLink) + '" target="_blank" rel="noopener noreferrer" class="btn" data-text="fiat.stripe.button">' + escapeHtml(stripeBtnLabel) + '</a>';
} else {
html += '<span class="fiat-option-placeholder">Set config.fiat.stripe.link to enable.</span>';
}
html += '</div></div>';

// Bitcoin
html += '<div class="preferred-item preferred-bitcoin">';
html += '<span class="preferred-item-label">' + escapeHtml(bitcoinLabel) + '</span>';
html += '<div class="preferred-item-actions">';
if (bitcoinAddr && bitcoinAddr.address) {
var id = 'address-bitcoin';
html += '<div class="crypto-address-wrap">';
html += '<code class="crypto-address" id="' + id + '">' + escapeHtml(bitcoinAddr.address) + '</code>';
html += '<button type="button" class="copy-btn" data-copy="' + id + '" aria-label="' + escapeHtml(copyAria + ' ' + (bitcoinAddr.label || 'bitcoin')) + '">' + escapeHtml(copyLabel) + '</button>';
html += '</div>';
} else {
html += '<span class="fiat-option-placeholder">No Bitcoin address in config.</span>';
}
html += '</div></div>';

html += '</div>';
section.innerHTML = html;
container.appendChild(section);
}

Donation.registerMethod({ render: render, preferred: true });
})();
69 changes: 66 additions & 3 deletions styles/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,68 @@ body::before {
margin-top: 0.25rem;
}

/* Payment options — two boxes side by side: fiat | crypto */
/* Main: preferred block on top, other options below */
.main {
width: 100%;
max-width: 900px;
display: flex;
flex-direction: column;
gap: clamp(1.25rem, 3vw, 2rem);
margin-top: clamp(0.5rem, 2vw, 1rem);
}

/* Preferred methods — single card with cash + bitcoin side by side */
.card-section {
width: 100%;
}

.preferred-methods {
width: 100%;
}

.preferred-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: clamp(1rem, 3vw, 1.5rem);
}

@media (max-width: 600px) {
.preferred-grid {
grid-template-columns: 1fr;
}
}

.preferred-item {
display: flex;
flex-direction: column;
gap: 0.5rem;
}

.preferred-item-label {
font-size: 0.85rem;
font-weight: 600;
color: var(--neon-bright);
letter-spacing: 0.03em;
}

.preferred-item-actions {
margin-top: 0.25rem;
}

/* Other options — crypto list card(s) below */
.other-section {
width: 100%;
}

.other-options {
width: 100%;
}

.other-options .card {
max-width: 100%;
}

/* Legacy: payment options grid (kept for any non-refactored use) */
.options {
display: grid;
grid-template-columns: 1fr 1fr;
Expand Down Expand Up @@ -193,7 +254,8 @@ body::before {

/* Space between card title and payment content */
.card .fiat-options,
.card .crypto-list {
.card .crypto-list,
.card .preferred-grid {
margin-top: 1.5rem;
}

Expand All @@ -215,7 +277,8 @@ body::before {
}

.card-fiat .card-icon,
.card-crypto .card-icon {
.card-crypto .card-icon,
.card-preferred .card-icon {
color: var(--neon);
border-color: rgba(192, 132, 255, 0.5);
box-shadow: 0 0 15px var(--neon-glow);
Expand Down