From d016a5f3a5da023f6e65f451810a837c44db9291 Mon Sep 17 00:00:00 2001 From: mtblck <105079242+mtblck@users.noreply.github.com> Date: Sat, 7 Nov 2026 05:03:29 +0000 Subject: [PATCH] Add a floating tipjar support button to the landing page The tipjar package (npm) is self-hosted into dist/site/tipjar/ and mounted from site/tip.js, so the CSP stays script-src 'self'. It goes to the same Ko-fi page as the footer line and tucks away while the footer is on screen. Themed with the page's cobalt via --tipjar-* custom properties. ADR 0001 records the choice. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_018HstUkyeaG3BbXgCsZ7eTq --- docs/adr/0001-tipjar-support-button.md | 30 ++++++++++++++++++++++++++ package-lock.json | 16 +++++++++++++- package.json | 3 ++- site/index.html | 2 ++ site/site.css | 9 ++++++++ site/tip.js | 12 +++++++++++ test/site.test.mjs | 2 +- tools/site.mjs | 8 ++++++- 8 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 docs/adr/0001-tipjar-support-button.md create mode 100644 site/tip.js diff --git a/docs/adr/0001-tipjar-support-button.md b/docs/adr/0001-tipjar-support-button.md new file mode 100644 index 0000000..828909a --- /dev/null +++ b/docs/adr/0001-tipjar-support-button.md @@ -0,0 +1,30 @@ +--- +public: false +--- + +# 0001: A floating tipjar button complements the footer's Ko-fi link + +- **Status:** Accepted +- **Date:** 2026-11-07 +- **PR:** (this PR) + +## Context + +The landing page's only support link was the footer's "☕ Support future projects" (Ko-fi), which most +visitors never scroll to. Matt's own `tipjar` package (npm, MIT, zero dependencies) draws a floating support +button. Options: replace the footer line with the button, add the button and keep the line, or leave it. +The site's CSP is `script-src 'self'` and the site self-hosts everything it loads. + +## Decision + +We add the tipjar button to the landing page and keep the footer line. Both go to https://ko-fi.com/mtblck, +and the button tucks itself away (`hideWhenVisible: 'footer'`) while the footer is on screen, so only one +shows at a time. `tools/site.mjs` copies `tipjar/dist/*.js` and `style.css` from node_modules into +`dist/site/tipjar/`, and `site/tip.js` (a module file) mounts it, so no CDN and no CSP change. It takes the +page's cobalt via `--tipjar-*` in `site.css`, so it follows `data-theme`. The docs pages don't get it: they +are for reading, and their footer has no support link to hand over to. + +## Consequences + +Upgrading the button is a `tipjar` version bump in package.json. Clicks are not counted: a new event name +would need adding to Boards' events list first. Revisit if the button crowds the playground on phones. diff --git a/package-lock.json b/package-lock.json index ce5ebd0..40ca8ab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,8 @@ "@fontsource-variable/bricolage-grotesque": "^5.3.0", "@fontsource-variable/jetbrains-mono": "^5.3.0", "marked": "^16.4.2", - "playwright": "1.64.1" + "playwright": "1.64.1", + "tipjar": "^1.2.0" }, "engines": { "node": ">=22" @@ -77,6 +78,19 @@ "engines": { "node": ">=20" } + }, + "node_modules/tipjar": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tipjar/-/tipjar-1.2.0.tgz", + "integrity": "sha512-5M/yHG9WEUcxahX9uNiKh84AoyaMzdjLMaSDOTorLBdnR8rr400W66m7oT5OlXwqM4Y9CLq7GiG9IE2jYbhQEA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://ko-fi.com/mtblck" + } } } } diff --git a/package.json b/package.json index b3e23fe..3c3f376 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@fontsource-variable/bricolage-grotesque": "^5.3.0", "@fontsource-variable/jetbrains-mono": "^5.3.0", "marked": "^16.4.2", - "playwright": "1.64.1" + "playwright": "1.64.1", + "tipjar": "^1.2.0" } } diff --git a/site/index.html b/site/index.html index bb533a4..73396bb 100644 --- a/site/index.html +++ b/site/index.html @@ -15,6 +15,7 @@ + @@ -258,5 +259,6 @@

Install

+ diff --git a/site/site.css b/site/site.css index 3c35012..f5abd8d 100644 --- a/site/site.css +++ b/site/site.css @@ -212,3 +212,12 @@ footer p { margin: 0 0 8px; max-width: 60em; } @media (prefers-reduced-motion: reduce) { * { scroll-behavior: auto !important; } } .prose :not(pre) > code { overflow-wrap: anywhere; } + +/* the floating support button (tipjar): the page's cobalt, ringed in paper; it tucks away at the footer */ +:root { + --tipjar-bg: var(--accent); + --tipjar-label: var(--accent-ink); + --tipjar-ring: var(--paper); + --tipjar-font: var(--sans); + --tipjar-icon-size: 24px; /* pixel icons sit on a 12px grid */ +} diff --git a/site/tip.js b/site/tip.js new file mode 100644 index 0000000..07f573d --- /dev/null +++ b/site/tip.js @@ -0,0 +1,12 @@ +// getisogram.com: the floating "Support" button (the tipjar package, copied in by tools/site.mjs). +// It goes to the same Ko-fi page as the footer's support line and tucks itself away while the +// footer is on screen, so the two never show at once. A module from a file: the CSP is script-src 'self'. +import { mount } from '/tipjar/index.js' + +mount({ + href: 'https://ko-fi.com/mtblck', + description: 'future projects on Ko-fi', + icon: 'coffee', + iconStyle: 'pixel', + hideWhenVisible: 'footer', +}) diff --git a/test/site.test.mjs b/test/site.test.mjs index ce6cd2f..ec4d37e 100644 --- a/test/site.test.mjs +++ b/test/site.test.mjs @@ -10,7 +10,7 @@ const out = path.join(ROOT, 'dist', 'site') test('the site builds', () => { const r = spawnSync(process.execPath, [path.join(ROOT, 'tools/site.mjs')], { encoding: 'utf8' }) assert.equal(r.status, 0, r.stderr) - for (const f of ['index.html', 'docs/index.html', 'docs/skill/index.html', 'docs/api/index.html', 'docs/craft/index.html', 'isogram.js', 'examples.js', 'isogram.skill', 'fonts/bricolage.woff2', 'og.png']) + for (const f of ['index.html', 'docs/index.html', 'docs/skill/index.html', 'docs/api/index.html', 'docs/craft/index.html', 'isogram.js', 'examples.js', 'isogram.skill', 'fonts/bricolage.woff2', 'og.png', 'tip.js', 'tipjar/index.js', 'tipjar/style.css']) assert.ok(fs.existsSync(path.join(out, f)), `${f} missing`) }) diff --git a/tools/site.mjs b/tools/site.mjs index eb9e60a..7f080b3 100644 --- a/tools/site.mjs +++ b/tools/site.mjs @@ -19,7 +19,7 @@ const LOGO = '