Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
use flake
29 changes: 20 additions & 9 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
name: Deploy to GitHub Pages
name: Build and Deploy

on:
push:
branches: [main]
pull_request:
branches: [main]

permissions:
contents: read
pages: write
id-token: write

# Scope concurrency per ref so PR builds cancel their own stale runs
# without ever cancelling (or being cancelled by) the main deploy.
concurrency:
group: pages
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
Expand All @@ -19,26 +23,33 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: Install Zola
uses: taiki-e/install-action@v2
with:
tool: zola@0.22.1
- name: Install Nix
uses: DeterminateSystems/determinate-nix-action@v3

- name: Build
run: zola build
run: nix build --print-build-logs

# `nix build` writes ./result as a symlink into the read-only store;
# dereference it into a plain directory the Pages artifact step can tar.
# Only needed on main — PRs stop after the build above to verify it.
- name: Stage artifact
if: github.event_name == 'push'
run: cp -rL result public

- name: Upload artifact
uses: actions/upload-pages-artifact@v3
if: github.event_name == 'push'
uses: actions/upload-pages-artifact@v5
with:
path: public

deploy:
needs: build
if: github.event_name == 'push'
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
uses: actions/deploy-pages@v5
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
public/
.idea/
.claude

# Nix build output
result
result-*
.direnv/
25 changes: 25 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# CLAUDE.md

Project-level guidance for Claude Code working in this repo.

## Stack

Zola static site generator. Content lives in `content/`, templates in `templates/`, styles in `sass/main.scss`, structured data in `data/`. No npm. Build with `zola build`; serve locally via the launch config in `.claude/launch.json`.

## Design rules

### Data-derived UI, single source of truth

Any aggregate, summary, count, or breakdown shown in the UI must be **computed by the template** from the underlying records — never stored as a pre-computed sibling field that has to be kept in sync manually.

Hand-tallied summary fields drift the moment the data changes. If a stats panel, totals row, or category breakdown needs to appear, derive it in Tera by iterating the source data (e.g., `data.days[].exercises[]`) and aggregating in-template. External benchmarks (target ranges, thresholds) can still be stored — but the *current state* of the data should always be computed.

If the in-template aggregation gets too gnarly, the next step is a Zola `load_data` shortcode or a build-time preprocessor — not pre-computed fields in the source data.

Reference implementation: `templates/workout-program.html` weekly volume block — each exercise carries `sets_n` and `volume = ["slug", ...]`, and the template sums per muscle group at render time.

### Architectural decisions are recorded as ADRs

Load-bearing design choices are committed as Architecture Decision Records under `docs/adr/`. Don't make a decision that would be confusing or annoying to reverse without writing an ADR for it. See `docs/adr/README.md` for the format and `docs/roadmap.md` for the in-flight roadmap.

When a decision changes, write a new ADR that supersedes the old one — never edit an Accepted ADR in place. The git log of `docs/adr/` is the architectural changelog.
8 changes: 8 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
What's especially interesting about your phrasing is "instantiated with my longing." That's a programmer's word for
what's happening, and it's actually more accurate than the usual humanities vocabulary for this. The lyric is like a
class definition — it specifies the shape of an emotional object, the relationships between its parts, the methods it
supports — but it's not the object itself. You instantiate it by passing in your own arguments: the specific person
you're longing for, the specific arrival you're waiting on, the specific relief you're hoping will be kinder than
expected. The resulting object has the structure the artist designed and the contents only you could provide. That's why
the song can feel like it was written specifically for you despite being written years before you heard it — it was
written for you, in the sense that you're the one who completed it.
178 changes: 0 additions & 178 deletions data/workout_program.json

This file was deleted.

Loading
Loading