149 lines
4.6 KiB
Org Mode
149 lines
4.6 KiB
Org Mode
#+TITLE: Personal Site
|
|
#+DESCRIPTION: Source for my personal website
|
|
|
|
* Overview
|
|
|
|
Static personal website built with [[https://nixos.org/][Nix]] and [[https://orgmode.org/manual/Publishing.html][org-publish]].
|
|
Deployed to Cloudflare Pages via CI/CD on a Gitea runner (Raspberry Pi).
|
|
|
|
* Quick Start
|
|
|
|
#+begin_src sh
|
|
nix run # build site and serve at http://localhost:8080
|
|
nix run .#tunnel # serve + Cloudflare HTTPS tunnel + QR code
|
|
nix build # build only → result/ symlink
|
|
#+end_src
|
|
|
|
* Project Structure
|
|
|
|
#+begin_example
|
|
personal-site/
|
|
├── flake.nix Nix flake — inputs, build derivation, run apps
|
|
├── build.el Emacs Lisp org-publish configuration
|
|
├── content/ Source pages as org files
|
|
│ ├── index.org Homepage → /index.html
|
|
│ └── about.org About page → /about.html
|
|
├── static/ Static assets, copied verbatim
|
|
│ └── style.css Site stylesheet
|
|
├── README.org This file
|
|
└── CLAUDE.md Instructions for the Claude AI assistant
|
|
#+end_example
|
|
|
|
The build produces a =public/= directory (gitignored) which becomes the =nix build= output.
|
|
Sub-projects are embedded as subdirectories (e.g. =/project-a/=).
|
|
|
|
* Maintenance
|
|
|
|
** Adding a page
|
|
|
|
1. Create =content/<name>.org= with at minimum:
|
|
#+begin_src org
|
|
#+TITLE: Page Title
|
|
|
|
Content here.
|
|
#+end_src
|
|
|
|
2. Add a link to the nav in =build.el= (the =site-nav= variable at the top).
|
|
|
|
** Adding a sub-project
|
|
|
|
Sub-projects are separate Nix flakes that produce a static site as their default package.
|
|
|
|
1. Add the flake input in =flake.nix=:
|
|
#+begin_src nix
|
|
project-a = {
|
|
url = "path:/path/to/project-a"; # or git URL
|
|
inputs.nixpkgs.follows = "nixpkgs";
|
|
};
|
|
#+end_src
|
|
|
|
2. Expose the package in the =let= block:
|
|
#+begin_src nix
|
|
subProjectA = inputs.project-a.packages.${system}.default;
|
|
#+end_src
|
|
|
|
3. Copy it into the site output in =installPhase=:
|
|
#+begin_src nix
|
|
mkdir -p $out/project-a
|
|
cp -r ${subProjectA}/. $out/project-a/
|
|
#+end_src
|
|
|
|
4. Optionally add a nav link in =build.el=.
|
|
|
|
** Styling
|
|
|
|
=static/style.css= uses CSS custom properties defined in =:root=.
|
|
Dark mode is applied automatically via =@media (prefers-color-scheme: dark)=.
|
|
|
|
Key variables:
|
|
| Variable | Purpose |
|
|
|----------------+--------------------------|
|
|
| =--bg= | Page background |
|
|
| =--fg= | Body text |
|
|
| =--accent= | Links and highlights |
|
|
| =--muted= | Secondary text |
|
|
| =--border= | Dividers and box borders |
|
|
| =--code-bg= | Code block background |
|
|
| =--max-width= | Content column width |
|
|
|
|
** Updating dependencies
|
|
|
|
#+begin_src sh
|
|
nix flake update
|
|
#+end_src
|
|
|
|
* Deployment
|
|
|
|
The site is deployed to Cloudflare Pages automatically on push via a Gitea Actions
|
|
workflow (=.gitea/workflows/deploy.yml=) running on a Raspberry Pi runner (=aarch64-linux=).
|
|
The =nix build= output is uploaded directly as the Pages deployment artifact.
|
|
|
|
** First-time setup
|
|
|
|
*** 1. Create a Cloudflare Pages project
|
|
|
|
In the Cloudflare dashboard → Pages → Create a project → *Direct Upload*.
|
|
Name it =personal-site= (must match the =--project-name= flag in the workflow).
|
|
Skip the initial upload — CI will handle it.
|
|
|
|
Alternatively, create it with Wrangler locally:
|
|
|
|
#+begin_src sh
|
|
npx wrangler pages project create personal-site
|
|
#+end_src
|
|
|
|
*** 2. Get your Cloudflare credentials
|
|
|
|
- *Account ID*: Cloudflare dashboard → right sidebar, or any zone overview page.
|
|
- *API Token*: My Profile → API Tokens → Create Token.
|
|
Use the *Edit Cloudflare Pages* template, or create a custom token with:
|
|
- Permission: =Cloudflare Pages= → =Edit=
|
|
- Account resource: your account
|
|
|
|
*** 3. Add secrets to Gitea
|
|
|
|
In the Gitea repo → Settings → Secrets → Actions, add:
|
|
|
|
| Secret name | Value |
|
|
|--------------------------+------------------------------|
|
|
| =CLOUDFLARE_API_TOKEN= | the API token from step 2 |
|
|
| =CLOUDFLARE_ACCOUNT_ID= | your numeric account ID |
|
|
|
|
*** 4. Verify the runner label
|
|
|
|
The workflow uses =runs-on: ubuntu-latest=.
|
|
Check your Gitea runner's label in *Site Administration → Runners* and update the
|
|
workflow if your runner uses a different label (e.g. =nix=, =self-hosted=, etc.).
|
|
|
|
The runner needs *Nix* (with flakes enabled) and *Node.js* on =PATH=.
|
|
If Node.js is not available system-wide you can prepend the build step with:
|
|
|
|
#+begin_src sh
|
|
nix-shell -p nodejs --run "npx --yes wrangler@3 pages deploy ..."
|
|
#+end_src
|
|
|
|
*** 5. Push to master
|
|
|
|
The workflow triggers on every push to =master=.
|
|
Check the Actions tab in Gitea to monitor runs.
|