bank landing: Linux/POSIX command-line paths, shared expand panel

Side-by-side tech row under Get the wallet: gold penguin left
(Debian/Ubuntu apt from deb.taler.net), gold terminal right
(Unix/POSIX from source). Both open the same area below; CLI
boxes allow single-line selection/copy. Withdraw stays separate.
This commit is contained in:
Hernâni Marques 2026-07-10 20:29:00 +02:00
parent 5b84adf864
commit 5f3d309cef
No known key found for this signature in database
2 changed files with 357 additions and 6 deletions

View file

@ -17,7 +17,7 @@ point merchants at `taler.hacktivism.ch`.
## Page layout (top → bottom)
1. Hero (badge, short shared-account line)
2. **Get the wallet** — Play / F-Droid / iOS / web hub (Chrome · Firefox · Opera · Ubuntu Touch; solid blue icons, [taler.net wallet](https://www.taler.net/de/wallet.html))
2. **Get the wallet** — Play / F-Droid / iOS / web hub + **Debian/Ubuntu · Command line** (apt) + **Unix / POSIX · from source** (build monorepo or run `.mjs`)
3. **Withdraw GOA** — compact QR_Taler, open CTA, live pool balance note, generate-own-account link
4. **GOA shop · samples** — always visible (2 products + merchant link)
5. **How the shared account works** — collapsed fold (click to expand)

View file

@ -4,13 +4,13 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>GOA Exploration Bank</title>
<meta name="description" content="Withdraw GOA with one QR from the shared pool, try GOA shop samples, pay with GNU Taler — no IBAN." />
<meta name="description" content="Get your GOA in one step from the shared bank account, try GOA shop samples, pay with GNU Taler — no IBAN." />
<link rel="canonical" href="https://bank.hacktivism.ch/intro/" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content="hacktivism.ch · GOA" />
<meta property="og:locale" content="en_US" />
<meta property="og:title" content="GOA Exploration Bank" />
<meta property="og:description" content="Withdraw GOA with one QR, browse GOA shop samples, pay with GNU Taler." />
<meta property="og:description" content="Get your GOA in one step from the shared bank account, browse GOA shop samples, pay with GNU Taler." />
<meta property="og:url" content="https://bank.hacktivism.ch/intro/" />
<meta property="og:image" content="https://bank.hacktivism.ch/intro/og-goa-shop.png" />
<meta property="og:image:secure_url" content="https://bank.hacktivism.ch/intro/og-goa-shop.png" />
@ -20,7 +20,7 @@
<meta property="og:image:alt" content="GOA shop product samples — pay with GNU Taler" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="GOA Exploration Bank" />
<meta name="twitter:description" content="Withdraw GOA with one QR, browse GOA shop samples, pay with GNU Taler." />
<meta name="twitter:description" content="Get your GOA in one step from the shared bank account, browse GOA shop samples, pay with GNU Taler." />
<meta name="twitter:image" content="https://bank.hacktivism.ch/intro/og-goa-shop.png" />
<meta name="twitter:image:alt" content="GOA shop product samples — pay with GNU Taler" />
<style>
@ -422,6 +422,18 @@
stroke-linecap: round;
stroke-linejoin: round;
}
/* git branch: solid nodes, stroked edges */
.app-ico.branch-ico circle {
fill: currentColor;
stroke: none;
}
.app-ico.branch-ico path {
fill: none;
stroke: currentColor;
stroke-width: 1.7;
stroke-linecap: round;
stroke-linejoin: round;
}
.app-ico.gold { color: #f0c86a; }
.app-ico.blue { color: #3ecfbf; }
.app-btn .app-ico.gold { color: #f0c86a; }
@ -435,6 +447,18 @@
}
.hub-icons .app-ico { width: 1.25rem; height: 1.25rem; }
.hub-icons .browser-ico { border-radius: 3px; flex-shrink: 0; }
/* command-line marks: gold penguin (deb) · gold terminal (posix) */
button.app-btn.cli-toggle > .app-ico.penguin-ico,
button.app-btn.cli-toggle > .app-ico.console-ico {
width: 1.2rem;
height: 1.2rem;
flex-shrink: 0;
border-radius: 0;
}
button.app-btn.cli-toggle > .app-ico.console-ico rect,
button.app-btn.cli-toggle > .app-ico.console-ico path {
fill: none;
}
.step-tagline .app-ico {
width: 1rem;
height: 1rem;
@ -445,6 +469,133 @@
.step-tagline .app-ico.ios { color: #f0c86a; }
.step-tagline .app-ico.android { color: #f0c86a; }
/* Two tech options side-by-side; both open the same panel below */
.cli-tech-row {
display: flex;
flex-wrap: wrap;
gap: 0.45rem;
width: 100%;
flex: 1 1 100%;
}
button.app-btn.cli-toggle {
flex: 1 1 calc(50% - 0.25rem);
min-width: 9.5rem;
max-width: 100%;
border-color: rgba(232, 168, 56, 0.4);
color: #f0d090;
font-size: 0.72rem;
cursor: pointer;
font-family: inherit;
font-weight: 650;
width: auto;
justify-content: flex-start;
align-items: center;
gap: 0.4rem;
padding: 0.55rem 0.65rem;
line-height: 1.25;
}
button.app-btn.cli-toggle .cli-label {
flex: 1 1 auto;
text-align: left;
min-width: 0;
}
button.app-btn.cli-toggle .cli-chevron {
margin-left: auto;
flex-shrink: 0;
color: #3ecfbf;
font-size: 1rem;
font-weight: 700;
line-height: 1;
transition: transform 0.15s ease;
}
button.app-btn.cli-toggle[aria-expanded="true"] .cli-chevron {
transform: rotate(90deg);
}
button.app-btn.cli-toggle .app-ico { color: #f0c86a; }
button.app-btn.cli-toggle[aria-expanded="true"] {
border-color: rgba(240, 200, 106, 0.75);
background: rgba(232, 168, 56, 0.12);
}
/* Shared expand area under both tech buttons (does not cover withdraw) */
.cli-panel {
display: none;
width: 100%;
max-width: 100%;
margin: 0.55rem 0 0.25rem;
text-align: left;
border: 1px solid rgba(232, 168, 56, 0.32);
border-radius: 12px;
background: rgba(0, 0, 0, 0.28);
padding: 0.85rem 0.9rem 1rem;
box-sizing: border-box;
position: relative;
z-index: 0;
clear: both;
}
.cli-panel.open { display: block; }
.cli-pane { display: none; }
.cli-pane.active { display: block; }
.step-card[aria-labelledby="step1-title"] .step-body {
align-items: stretch;
}
.step-card[aria-labelledby="step1-title"] .app-links {
width: 100%;
}
#withdraw {
position: relative;
z-index: 1;
}
.cli-panel .cli-lead {
margin: 0 0 0.75rem;
color: var(--muted);
font-size: 0.86rem;
line-height: 1.4;
}
.cli-panel a {
color: #e8c878;
text-decoration: none;
border-bottom: 1px solid rgba(232, 168, 56, 0.35);
}
.cli-panel a:hover {
color: #f0d090;
border-bottom-color: #e8c878;
}
.cli-panel .cli-h {
margin: 0.85rem 0 0.35rem;
font-size: 0.78rem;
font-weight: 750;
letter-spacing: 0.04em;
text-transform: uppercase;
color: #f0c86a;
}
.cli-panel .cli-h:first-of-type { margin-top: 0.15rem; }
.cli-panel .cli-note {
margin: 0 0 0.45rem;
color: var(--muted);
font-size: 0.8rem;
line-height: 1.4;
}
/* Allow selecting/copying individual lines (not whole block at once) */
.cli-block {
margin: 0 0 0.35rem;
padding: 0.65rem 0.7rem;
border-radius: 10px;
background: rgba(0, 0, 0, 0.45);
border: 1px solid rgba(240, 200, 106, 0.22);
color: #e8e0d0;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: 0.7rem;
line-height: 1.45;
overflow-x: auto;
white-space: pre;
-webkit-overflow-scrolling: touch;
-webkit-user-select: text;
user-select: text;
cursor: text;
}
.cli-block .cmt { color: #8a9a90; }
.cli-block .hi { color: #5eead4; }
/* Optional block: collapsed by default, expand like settlement / wallet fold */
.more-section {
margin-top: 1.5rem;
@ -836,7 +987,7 @@
<span class="badge">Intergalactic · GOA · no IBAN</span>
<h1>GOA Exploration Bank</h1>
<p class="sub">
<strong>One QR</strong> withdraws GOA from a
Get your <strong>GOA in one step</strong> from the
<strong>shared bank account</strong> into your wallet — no registration.
</p>
</header>
@ -897,6 +1048,160 @@
</span>
Web browsers (experimental)
</a>
<!-- Linux (left) · POSIX (right) — same expand area below -->
<div class="cli-tech-row" role="group" aria-label="Command-line wallet paths">
<button type="button" class="app-btn hub cli-toggle" id="deb-cli-toggle"
aria-expanded="false" aria-controls="cli-shared-body"
data-cli-pane="cli-pane-deb"
aria-label="Debian/Ubuntu · Command line">
<svg class="app-ico browser-ico penguin-ico" viewBox="0 0 24 24" width="20" height="20" role="img" aria-label="Linux penguin">
<path fill="#f0c86a" d="M12 2.8c-2.2 0-3.8 1.7-3.8 3.6 0 .5.1 1 .3 1.4C6.4 8.8 5 11 5 13.6c0 2.6 1.3 4.5 3.2 5.6-.2.5-.3 1-.3 1.5 0 1.2.9 2.2 2.2 2.2.7 0 1.3-.3 1.7-.8.4.1.8.2 1.2.2s.8-.1 1.2-.2c.4.5 1 .8 1.7.8 1.3 0 2.2-1 2.2-2.2 0-.5-.1-1-.3-1.5 1.9-1.1 3.2-3 3.2-5.6 0-2.6-1.4-4.8-3.5-5.8.2-.4.3-.9.3-1.4C15.8 4.5 14.2 2.8 12 2.8z"/>
<ellipse cx="12" cy="14.5" rx="3.2" ry="4.2" fill="#1a1410" opacity="0.28"/>
<circle cx="10.4" cy="6.6" r="0.75" fill="#1a1410"/>
<circle cx="13.6" cy="6.6" r="0.75" fill="#1a1410"/>
<path fill="#e8a838" d="M11.2 8 12 9.4 12.8 8z"/>
<ellipse cx="9.2" cy="21.2" rx="1.8" ry="0.9" fill="#e8a838"/>
<ellipse cx="14.8" cy="21.2" rx="1.8" ry="0.9" fill="#e8a838"/>
</svg>
<span class="cli-label">Debian/Ubuntu · Command line</span>
<span class="cli-chevron" aria-hidden="true"></span>
</button>
<button type="button" class="app-btn hub cli-toggle" id="unix-cli-toggle"
aria-expanded="false" aria-controls="cli-shared-body"
data-cli-pane="cli-pane-unix"
aria-label="Unix / POSIX · from source">
<svg class="app-ico browser-ico console-ico" viewBox="0 0 24 24" width="20" height="20" aria-hidden="true">
<rect x="2.5" y="4" width="19" height="15" rx="2.2" fill="none" stroke="#f0c86a" stroke-width="1.7"/>
<path d="M6.5 9.2 9.8 12 6.5 14.8" fill="none" stroke="#f0c86a" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M11.5 14.8h5.2" fill="none" stroke="#f0c86a" stroke-width="1.7" stroke-linecap="round"/>
</svg>
<span class="cli-label">Unix / POSIX · from source</span>
<span class="cli-chevron" aria-hidden="true"></span>
</button>
</div>
</div>
<!-- Shared expand area under both tech buttons (sibling of app-links; above withdraw) -->
<div class="cli-panel" id="cli-shared-body" hidden>
<div class="cli-pane" id="cli-pane-deb">
<p class="cli-lead">
<strong>Usual path on Debian &amp; Ubuntu:</strong> install the prebuilt
<a href="https://docs.taler.net/manpages/taler-wallet-cli.1.html" target="_blank" rel="noopener noreferrer"><strong>taler-wallet-cli</strong></a>
package from
<a href="https://deb.taler.net/" target="_blank" rel="noopener noreferrer">deb.taler.net</a>
— no compile. Then withdraw &amp; pay with the shell recipes below.
</p>
<p class="cli-h">1 · Install</p>
<p class="cli-note">
Add the GNU Taler apt source for your release from
<a href="https://deb.taler.net/" target="_blank" rel="noopener noreferrer">deb.taler.net</a>
(key + <code>sources.list</code> line), then:
</p>
<pre class="cli-block"><span class="cmt"># after the Taler apt source is configured</span>
sudo apt-get update
sudo apt-get install -y taler-wallet-cli
taler-wallet-cli --version</pre>
<p class="cli-h">2 · Withdraw &amp; pay (shared pool)</p>
<pre class="cli-block"><span class="cmt"># after package install — taler-wallet-cli is on PATH</span>
export EX=https://exchange.hacktivism.ch/
export WDB="$HOME/.local/share/taler-wallet-goa.sqlite3"
mkdir -p "$(dirname "$WDB")"
alias tw='taler-wallet-cli --wallet-db="$WDB" --no-throttle'
tw exchanges add "$EX" || true
tw exchanges update "$EX" || true
tw exchanges accept-tos "$EX"
WURI=$(curl -fsS https://bank.hacktivism.ch/intro/demo-withdraw.json \
| python3 -c 'import sys,json;print(json.load(sys.stdin)["taler_withdraw_uri"])')
tw withdraw accept-uri --exchange "$EX" "$WURI"
tw run-until-done
tw balance
PAY=taler://pay-template/taler.hacktivism.ch/instances/goa-shop/orbit-sticker
tw handle-uri --yes --non-interactive "$PAY"
tw run-until-done
tw balance</pre>
</div>
<div class="cli-pane" id="cli-pane-unix">
<p class="cli-lead">
<strong>Other Unix / POSIX systems</strong> (and anyone who prefers source):
there is usually <em>no</em> distro package — build
<a href="https://docs.taler.net/manpages/taler-wallet-cli.1.html" target="_blank" rel="noopener noreferrer"><strong>taler-wallet-cli</strong></a>
from the monorepo on
<a href="https://git.taler.net/" target="_blank" rel="noopener noreferrer">git.taler.net</a>
(<code>taler-typescript-core</code><code>packages/taler-wallet-cli</code>),
or run the compiled <code>.mjs</code> with Node without a system install.
</p>
<p class="cli-h">1 · Packages you usually need (build)</p>
<p class="cli-note">
<strong>Typical:</strong> <code>git</code>, <code>curl</code>,
<code>python3</code> (≥&nbsp;3.8), <code>nodejs</code> (≥&nbsp;20),
<code>npm</code>, <code>pnpm</code> (≥&nbsp;11 — often
<code>npm install -g pnpm</code>), <code>jq</code>, <code>zip</code>.
<strong>At runtime</strong> for the GOA recipes: <code>curl</code>,
<code>python3</code>, and either <code>taler-wallet-cli</code> on
<code>PATH</code> or <code>node</code> + the <code>.mjs</code> file.
</p>
<pre class="cli-block"><span class="cmt"># example on a Debian-like host used only as a build box</span>
sudo apt-get update
sudo apt-get install -y git curl python3 nodejs npm jq zip
sudo npm install -g pnpm
<span class="cmt"># Fedora/RHEL-ish: dnf install git curl python3 nodejs npm jq zip (then npm i -g pnpm)</span>
<span class="cmt"># macOS: brew install git python node jq (then npm i -g pnpm)</span></pre>
<p class="cli-h">2 · Clone, compile, install <em>or</em> just run</p>
<pre class="cli-block"><span class="cmt">#!/bin/sh</span>
set -eu
git clone https://git.taler.net/taler-typescript-core.git
<span class="cmt"># or: git clone git://git.taler.net/taler-typescript-core.git</span>
cd taler-typescript-core
./bootstrap
./configure <span class="cmt"># optional: --prefix="$HOME/.local"</span>
make
<span class="cmt"># optional system install: make install</span>
pnpm install
pnpm run compile
<span class="cmt"># just use without install (usual for day-to-day dev):</span>
WCLI="$PWD/packages/taler-wallet-cli/bin/taler-wallet-cli.mjs"
node "$WCLI" --version</pre>
<p class="cli-h">3 · Withdraw &amp; pay (POSIX <code>sh</code>)</p>
<pre class="cli-block"><span class="cmt">#!/bin/sh</span>
set -eu
: "${HOME?HOME is unset}"
EX=https://exchange.hacktivism.ch/
BANK=https://bank.hacktivism.ch
MER=taler.hacktivism.ch
WDB=${WDB:-$HOME/.local/share/taler-wallet-goa.sqlite3}
mkdir -p "$(dirname "$WDB")"
<span class="cmt"># package/install path:</span>
<span class="cmt"># tw() { taler-wallet-cli --wallet-db="$WDB" --no-throttle "$@"; }</span>
<span class="cmt"># monorepo path (no make install):</span>
WCLI=${WCLI:-$HOME/src/taler-typescript-core/packages/taler-wallet-cli/bin/taler-wallet-cli.mjs}
tw() { node "$WCLI" --wallet-db="$WDB" --no-throttle "$@"; }
tw exchanges add "$EX" || true
tw exchanges update "$EX" || true
tw exchanges accept-tos "$EX"
WURI=$(curl -fsS "$BANK/intro/demo-withdraw.json" \
| python3 -c 'import sys,json;print(json.load(sys.stdin)["taler_withdraw_uri"])')
tw withdraw accept-uri --exchange "$EX" "$WURI"
tw run-until-done
tw balance
PAY="taler://pay-template/$MER/instances/goa-shop/orbit-sticker"
tw handle-uri --yes --non-interactive "$PAY"
tw run-until-done
tw balance</pre>
</div>
</div>
</div>
</section>
@ -904,7 +1209,7 @@
<!-- ========== STEP 2: one-click community pool withdraw (compact) ========== -->
<section class="step-card step-money" id="withdraw" aria-labelledby="step2-title">
<h2 id="step2-title"><span class="step-num">2</span> Withdraw GOA</h2>
<p class="step-tagline">One QR · shared pool · no registration</p>
<p class="step-tagline">One step · shared pool · no registration</p>
<div class="step-body">
<div class="qr-taler-wrap">
<div class="goa-pay-taler-qr" id="qr-withdraw-demo-wrap">
@ -1320,6 +1625,52 @@
});
}
wireFold("how-fold", "how-fold-toggle", "how-fold-body");
(function wireCliFolds() {
var panel = document.getElementById("cli-shared-body");
var btns = [
document.getElementById("deb-cli-toggle"),
document.getElementById("unix-cli-toggle")
].filter(Boolean);
if (!panel || !btns.length) return;
var panes = panel.querySelectorAll(".cli-pane");
function showPane(paneId) {
for (var i = 0; i < panes.length; i++) {
panes[i].classList.toggle("active", panes[i].id === paneId);
}
}
function setExpanded(activeBtn) {
for (var i = 0; i < btns.length; i++) {
btns[i].setAttribute(
"aria-expanded",
btns[i] === activeBtn ? "true" : "false"
);
}
}
function closeAll() {
panel.classList.remove("open");
panel.setAttribute("hidden", "");
for (var i = 0; i < panes.length; i++) panes[i].classList.remove("active");
setExpanded(null);
}
btns.forEach(function (btn) {
btn.addEventListener("click", function () {
var paneId = btn.getAttribute("data-cli-pane");
var already =
panel.classList.contains("open") &&
btn.getAttribute("aria-expanded") === "true";
if (already) {
closeAll();
return;
}
showPane(paneId);
panel.classList.add("open");
panel.removeAttribute("hidden");
setExpanded(btn);
});
});
})();
var paintWebuiQrOnce = (function () {
var webuiPainted = false;
return function () {