# Personal Blog A small static personal blog. No build step, no backend — plain HTML, CSS, and vanilla JavaScript. ## Pages - `index.html` — home page - `reading.html` — reading list page (curated links grouped by category, rendered from `data/reading-list.js`) - `contact.html` — contact page (opens the visitor's mail client with the form fields pre-filled via a `mailto:` 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 the `Authorization` header. **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`: ```js { 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.: ```sh python3 -m http.server 8000 ``` Then open . ## Tests Tests use Node's built-in test runner (no dependencies to install): ```sh npm test ``` ## Project layout ```text 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 ```