README.md (5808B)
1 # [davideisinger.com][1] 2 3 [1]: https://davideisinger.com 4 5 ## Local tools 6 7 Run `bundle install` at the repository root to install the Ruby dependencies for 8 `bin/archive`, `bin/elsewhere`, and `bin/newsletter`. Run these commands from the 9 repository root. `bin/elsewhere URL ...` imports third-party articles; 10 `bin/newsletter` creates a newsletter campaign from the latest published post. 11 The image service in `bin/dither` retains its own Gemfile and bundle. 12 13 Run `bin/test` for the local test suite (requires Python 3, Ruby, Git, and Hugo). 14 Individual tests live in `test/`; Git hook helpers live in `.githooks/lib/`. 15 `bin/refresh-dither-alt` remains available for image maintenance. 16 17 SourceHut runs `bin/check-rss-template` during deployment. To run it locally, set 18 `HUGO_VERSION` to the version in `.build.yml`: 19 20 ```sh 21 HUGO_VERSION=0.167.0 bin/check-rss-template 22 ``` 23 24 ## Navigation and audio 25 26 The shared header and its player stay in place during internal page navigation. 27 A small, dependency-free script fetches the next HTML page and replaces the main 28 content and footer, updating the URL, title, canonical link, focus, and scroll 29 position. External links, downloads, modified clicks, and links with 30 `data-no-navigation` use normal browser navigation. Failed requests and changed 31 JavaScript or CSS assets fall back to a full page load. Without JavaScript, every 32 page and link still works normally; audio then stops when leaving the page. 33 34 The header switches to “Now playing” when playback starts. With JavaScript, 35 the music page's players become play/pause buttons for that persistent player; 36 selecting a track updates its title, source link, and audio in the header. The 37 buttons reflect playback and elapsed time, even after leaving and returning to 38 the music page. Without JavaScript, the native players remain available. 39 Starting other embedded audio pauses the current player. Reloading the browser 40 or leaving the site ends playback. 41 42 The script is bundled by Hugo; Node.js is not required to build or deploy it. 43 For browser regression tests, run `npm ci`, then `npm run test:navigation`. 44 These tests use Hugo, a disposable local server, and Playwright (development only). 45 On macOS they use installed Google Chrome; elsewhere run 46 `npx playwright install chromium` first. Set `CHROME_BIN` to use another Chromium 47 executable. The tests cover continuous playback, history, scroll restoration, 48 focus, fragments, metadata, fallback navigation, and browsing without JavaScript. 49 50 ## Image alt text 51 52 `bin/encrypt IMAGE` encrypts an image and uses Codex to write plain, descriptive 53 accessibility alt text for the copied `dither` shortcode. 54 55 Regenerate existing, nonempty `dither` alt text with: 56 57 ```sh 58 bin/refresh-dither-alt --dry-run 59 bin/refresh-dither-alt content/journal/dispatch-44-october-2026/index.md 60 bin/refresh-dither-alt 61 ``` 62 63 With no paths, the script scans all Markdown and HTML files under `content`. 64 `--dry-run` checks image paths and lists matches without calling Codex or changing 65 anything. A real run requires `openssl`, an authenticated `codex` CLI, and the 66 repository's `secret.key`. Each image is decrypted into a temporary directory 67 that is removed after generation, including on failure or interruption. Original 68 images and encrypted files are left alone. Each post is saved only after all its 69 alt text has been generated successfully; failures are reported and other posts 70 continue. Completed posts remain updated if the run is interrupted. Review the 71 resulting Git diff before publishing. Rerunning regenerates all selected alt text. 72 73 ## Publishing Dispatches 74 75 Enable the repository's Git hooks once per clone: 76 77 ```sh 78 git config core.hooksPath .githooks 79 ``` 80 81 Before each commit, `.githooks/lib/check-staged-spelling` runs `npx cspell` on the staged 82 contents of added, changed, or renamed `.md` and `.markdown` files throughout the 83 repository. Unstaged edits and deleted files are skipped. This requires Python 3, 84 Node.js, and npm (`npx`). 85 86 Unknown words are added to `.dictionary`, which is sorted and deduplicated. If it 87 changes, the commit is blocked so you can review `git diff -- .dictionary`. 88 Remove actual typos from the dictionary and fix them in the Markdown; keep valid 89 exceptions. Stage the corrected files and `.dictionary`, then retry the commit. 90 The hook also blocks while `.dictionary` differs from its staged version, so 91 retrying without reviewing and staging it does not silently accept new words. 92 No files are automatically staged. Commits without staged Markdown skip spellcheck. 93 94 Pushing to `origin`'s `main` checks newly added, non-draft Dispatches and existing 95 Dispatches changing from draft to published. Their `date` must be no more than 96 24 hours old. Edits or renames of already-published posts, draft posts, other 97 branches, and other remotes are unaffected. The check reads the committed content 98 being pushed and compares it with the remote's current commit. 99 100 Before publishing, update the date and commit it: 101 102 ```sh 103 bin/timestamp content/journal/dispatch-44-october-2026/index.md 104 git add content/journal/dispatch-44-october-2026/index.md 105 git commit -m "Set publication date" 106 git push origin main 107 ``` 108 109 Without a filename, `bin/timestamp` still prints the timestamp and copies it to 110 the clipboard. For intentional backdating, `git push --no-verify origin main` 111 bypasses local push hooks for that push. The hook must be installed in each clone; 112 it does not enforce dates on server-side merges or pushes from other clones. 113 114 Run `test/dispatch-hook` to exercise the workflow with temporary local Git 115 repositories, without contacting the publishing remote. 116 Run `test/spelling-hook` to test the commit hook offline in a disposable 117 repository with a simulated spellchecker. 118 119 --- 120 121 © [CC BY 4.0 License][2] 122 123 [2]: https://creativecommons.org/licenses/by/4.0/deed.en