Personal Blog
A small static personal blog. No build step, no backend — plain HTML, CSS, and vanilla JavaScript.
Pages
index.html— home pagereading.html— reading list page (curated links grouped by category, rendered fromdata/reading-list.js)contact.html— contact page (opens the visitor's mail client with the form fields pre-filled via amailto:link)newsletter.html— newsletter signup page (posts the visitor's email to a configured serverless endpoint; no self-hosted backend or subscriber list management)
Newsletter signup
The signup form on newsletter.html POSTs the visitor's email to a serverless
endpoint. Everything is configured in one file — js/newsletter-config.js:
NEWSLETTER_ENDPOINT— the serverless endpoint the form POSTs to.NEWSLETTER_API_TOKEN— the API token sent in theAuthorizationheader.
Security: a real API token must never be committed to the repository. The
committed default is an empty placeholder; the deployer sets the real token in
js/newsletter-config.js at deploy time, and only then. The page logic reads
the token from this config module and never hardcodes one.
When the token is missing or the endpoint rejects it, the visitor sees a fixed, user-safe error message — the token or endpoint internals are never surfaced. After a successful signup a confirmation message is shown.
Reading list
The reading list is a single data file: data/reading-list.js. The page code
renders whatever is in it, so it can grow to hundreds of entries without code
changes.
To add a link, edit data/reading-list.js only — add an entry with a title,
a url, a category, and an optional one-line note:
{
category: "Engineering",
title: "A new article",
url: "https://example.com/article",
note: "Optional one-liner shown under the title.",
},
Categories appear on the page in the order they are first used; entries keep the order they are listed in.
Development
Serve the directory with any static file server, e.g.:
python3 -m http.server 8000
Then open http://localhost:8000.
Tests
Tests use Node's built-in test runner (no dependencies to install):
npm test
Project layout
index.html Home page
reading.html Reading list page
contact.html Contact page
newsletter.html Newsletter signup page
css/style.css Global + responsive styles
data/reading-list.js Curated reading list data (edit to add links)
js/newsletter-config.js Newsletter endpoint + API token (edit at deploy time)
js/newsletter.js Newsletter signup wiring: POST + user-safe errors (tested)
js/mailto.js Pure mailto: URL builder (unit tested)
js/contact.js Contact form wiring (browser + tests)
js/reading-list.js Reading list renderer: data file -> grouped HTML (tested)
tests/ Node built-in test suite
.gitea/workflows/ ci.yml runs `npm test` on PRs and pushes to main