Commit 85aaafbc54

85aaafbc544fb49d8cc195c3ea2edaf1b6d339c2

parent: ccb99e80cf

Verified · cmc ci/build: success ci/lint: success

cmc <hello@cleberg.net> · 2026-10-07 22:54 UTC

update salary, readme, and detour templates

Layout: unified · split

README.md deleted −167
@@ -1,167 +0,0 @@
1# cleberg.net
2
3This repository holds the files for [cleberg.net](https://cleberg.net),
4a static-site with blog posts, personal links, and more.
5
6This site uses [orgo](https://gitbay.org/krz/orgo) to build the
7static site.
8
9## Site Structure
10
11I write content pages (e.g., blog posts) in org-mode and templates in
12HTML. orgo builds these files into a static site, and then I deploy
13them to a web server.
14
15The main site components are:
16
17- Org source files in `content/`, containing blog posts and pages.
18 That directory is the site's URL root: `content/blog/post.org`
19 publishes at `/blog/post.html`.
20- A configuration file (`content/orgo.toml`) that specifies the base
21 URL, navigation, templates, and the generated pages (home, blog and
22 garden indexes, tags, and the RSS feed).
23- HTML templates in `content/templates/`.
24- Assets such as images and style sheets, located in designated
25 subdirectories. `theme/static/` is published at `/`.
26- Utility scripts (e.g., `build.py`) to facilitate building and
27 deployment.
28
29## Dependencies
30
31The publishing system depends on:
32
33- [orgo](https://gitbay.org/krz/orgo), the static site
34 generator, installed with `cargo install --git
35 https://gitbay.org/krz/orgo`.
36- `rsync` for deployment.
37- [uv](https://github.com/astral-sh/uv) to run `build.py`.
38
39## Configuration
40
41You can customize site settings within the `content/orgo.toml` file.
42This file establishes key variables such as:
43
44- The base URL for links.
45- Which pages appear in the navigation, and in what order.
46- Per-directory template rules.
47- The collections that generate the indexes, tag pages, and feed.
48
49Users intending to modify site parameters should review and edit this
50file accordingly. The orgo documentation contains extensive details on
51configuration options and expected formats.
52
53## Setup Instructions
54
55To obtain a working copy of this repository, execute the following
56commands within a shell environment or Emacs shell interface:
57
58``` shell
59git clone https://gitbay.org/cmc/cleberg.net
60cd cleberg.net
61emacs -nw
62```
63
64For users employing Doom Emacs, open any repository Org file using
65`SPC f f` to access the content.
66
67## Building and Publishing the Site
68
69The `build.py` script wraps the build: it runs orgo, rewrites the footer's
70orgo version to match the orgo that ran, and then either deploys the result
71or serves it locally.
72
73Environment variables control what it does, and all default to off:
74
75- `BUILD=true` performs the build.
76- `DEPLOY=true` deploys in production, or starts a development server
77 on port 8000 otherwise.
78- `ENV=prod` selects production: image URLs are rewritten to be
79 root-relative (see Deployment below) and the `ruff` pass is skipped.
80 Anything else builds for development.
81- `DRY_RUN=true` turns a production deploy into a report. Production
82 only; ignored everywhere else.
83
84Exactly one combination writes to the server:
85
86| `ENV` | `BUILD` | `DEPLOY` | `DRY_RUN` | What happens | Output | Server |
87|--------|---------|----------|-----------|---------------------------------------|--------------|-------------------|
88| unset | `true` | — | — | Development build, `ruff` first | `.build-dev/`| Untouched |
89| unset | `true` | `true` | — | Development build, then serve on :8000| `.build-dev/`| Untouched |
90| `prod` | `true` | — | — | Production build and image rewrite | `.build/` | Untouched |
91| `prod` | — | `true` | `true` | Reports what a deploy would change | — | Read only |
92| `prod` | `true` | `true` | — | Production build, then deploy | `.build/` | **Overwritten** |
93
94``` shell
95# Development build:
96BUILD=true uv run build.py
97
98# Development build, then serve it on localhost:8000:
99BUILD=true DEPLOY=true uv run build.py
100
101# Production build, no deploy:
102ENV=prod BUILD=true uv run build.py
103
104# What would a deploy change? Connects, compares, transfers nothing:
105ENV=prod DEPLOY=true DRY_RUN=true uv run build.py
106
107# Production build and deploy. This is the one that writes to the server:
108ENV=prod BUILD=true DEPLOY=true uv run build.py
109```
110
111Generated site files reside in `.build/` for production and
112`.build-dev/` for development.
113
114The deploy is `rsync --delete-before`, so files the build no longer
115produces are removed from the server. That is what makes the dry run
116worth having: a build that silently produced fewer pages would quietly
117delete the rest. Lines beginning `*deleting` in the dry-run output are
118what the real deploy would remove.
119
120Builds are incremental: orgo keeps an `.orgo-cache.json` inside the
121output directory and re-renders only what changed, so the directory is
122left in place between runs. Delete it for a clean build. The two
123environments use separate directories because production rewrites image
124URLs in the output and development does not.
125
126orgo can also build and preview on its own, without `build.py`:
127
128``` shell
129orgo serve content -o /tmp/preview
130```
131
132## Deployment
133
134Production builds rewrite image URLs to root-relative ones
135(`/img/blog/...`) instead of absolute `https://img.cleberg.net/` ones so
136the site renders standalone on the onion service without fetching assets
137off-onion. The stylesheet is already same-origin.
138
139This means the web server must serve the image store at `/img/` on the
140`cleberg.net` vhost. The images live at `/var/www/img/` (their own host,
141`img.cleberg.net`); expose them under `cleberg.net/img/` with a symlink:
142
143``` shell
144ln -s /var/www/img /var/www/cleberg.net/img
145```
146
147Without this, images 404 in production. Development builds keep the
148absolute `img.cleberg.net` URLs, so local previews load images from the
149live host and need no symlink.
150
151Once assets are same-origin, the vhost CSP can tighten `img-src`,
152`style-src`, and `font-src` back to `'self'`, and drop `bubbles.town`
153from `script-src`/`connect-src` (the vote widget was removed; only a
154plain link to Bubbles remains). After deploying, purge the Cloudflare
155cache (responses carry a 31-day `max-age`).
156
157## Creating New Blog Posts
158
159To add new blog content, follow this procedure within Emacs:
160
1611. Open a new Org file (via `C-x C-f` or Doom\'s `SPC f f`).
1622. Insert the contents of the post template with `C-x i`, sourcing from
163 `utils/template.org`.
1643. Modify the new file as needed to add post content and metadata.
165
166This method streamlines content creation by reusing a preformatted
167template.
README.org added +165
@@ -0,0 +1,165 @@
1* cleberg.net
2
3This repository holds the files for [[https://cleberg.net][cleberg.net]],
4a static-site with blog posts, personal links, and more.
5
6This site uses [[https://gitbay.org/krz/orgo][orgo]] to build the
7static site.
8
9** Site Structure
10
11I write content pages (e.g., blog posts) in org-mode and templates in HTML. orgo
12builds these files into a static site, and then I deploy them to a web server.
13
14The main site components are:
15
16- Org source files in =content/=, containing blog posts and pages. That directory
17 is the site's URL root: =content/blog/post.org= publishes at =/blog/post.html=.
18- A configuration file (=content/orgo.toml=) that specifies the base
19 URL, navigation, templates, and the generated pages (home, blog and
20 garden indexes, tags, and the RSS feed).
21- HTML templates in =content/templates/=.
22- Assets such as images and style sheets, located in designated
23 subdirectories. =theme/static/= is published at =/=.
24- Utility scripts (e.g., =build.py=) to facilitate building and
25 deployment.
26
27** Dependencies
28
29The publishing system depends on:
30
31- [[https://gitbay.org/krz/orgo][orgo]], the static site
32 generator, installed with =cargo install --git
33 https://gitbay.org/krz/orgo=.
34- =rsync= for deployment.
35- [[https://github.com/astral-sh/uv][uv]] to run =build.py=.
36
37** Configuration
38
39You can customize site settings within the =content/orgo.toml= file.
40This file establishes key variables such as:
41
42- The base URL for links.
43- Which pages appear in the navigation, and in what order.
44- Per-directory template rules.
45- The collections that generate the indexes, tag pages, and feed.
46
47Users intending to modify site parameters should review and edit this
48file accordingly. The orgo documentation contains extensive details on
49configuration options and expected formats.
50
51** Setup Instructions
52
53To obtain a working copy of this repository, execute the following
54commands within a shell environment or Emacs shell interface:
55
56#+begin_src shell
57git clone https://gitbay.org/cmc/cleberg.net
58cd cleberg.net
59emacs -nw
60#+end_src
61
62For users employing Doom Emacs, open any repository Org file using
63=SPC f f= to access the content.
64
65** Building and Publishing the Site
66
67The =build.py= script wraps the build: it runs orgo, rewrites the footer's
68orgo version to match the orgo that ran, and then either deploys the result
69or serves it locally.
70
71Environment variables control what it does, and all default to off:
72
73- =BUILD=true= performs the build.
74- =DEPLOY=true= deploys in production, or starts a development server
75 on port 8000 otherwise.
76- =ENV=prod= selects production: image URLs are rewritten to be
77 root-relative (see Deployment below) and the =ruff= pass is skipped.
78 Anything else builds for development.
79- =DRY_RUN=true= turns a production deploy into a report. Production
80 only; ignored everywhere else.
81
82Exactly one combination writes to the server:
83
84| =ENV= | =BUILD= | =DEPLOY= | =DRY_RUN= | What happens | Output | Server |
85|--------+---------+----------+-----------+---------------------------------------+--------------+-------------------|
86| unset | =true= | — | — | Development build, =ruff= first | =.build-dev/=| Untouched |
87| unset | =true= | =true= | — | Development build, then serve on :8000| =.build-dev/=| Untouched |
88| =prod= | =true= | — | — | Production build and image rewrite | =.build/= | Untouched |
89| =prod= | — | =true= | =true= | Reports what a deploy would change | — | Read only |
90| =prod= | =true= | =true= | — | Production build, then deploy | =.build/= | *Overwritten* |
91
92#+begin_src shell
93# Development build:
94BUILD=true uv run build.py
95
96# Development build, then serve it on localhost:8000:
97BUILD=true DEPLOY=true uv run build.py
98
99# Production build, no deploy:
100ENV=prod BUILD=true uv run build.py
101
102# What would a deploy change? Connects, compares, transfers nothing:
103ENV=prod DEPLOY=true DRY_RUN=true uv run build.py
104
105# Production build and deploy. This is the one that writes to the server:
106ENV=prod BUILD=true DEPLOY=true uv run build.py
107#+end_src
108
109Generated site files reside in =.build/= for production and
110=.build-dev/= for development.
111
112The deploy is =rsync --delete-before=, so files the build no longer
113produces are removed from the server. That is what makes the dry run
114worth having: a build that silently produced fewer pages would quietly
115delete the rest. Lines beginning =*deleting= in the dry-run output are
116what the real deploy would remove.
117
118Builds are incremental: orgo keeps an =.orgo-cache.json= inside the
119output directory and re-renders only what changed, so the directory is
120left in place between runs. Delete it for a clean build. The two
121environments use separate directories because production rewrites image
122URLs in the output and development does not.
123
124orgo can also build and preview on its own, without =build.py=:
125
126#+begin_src shell
127orgo serve content -o /tmp/preview
128#+end_src
129
130** Deployment
131
132Production builds rewrite image URLs to root-relative ones
133(=/img/blog/...=) instead of absolute =https://img.cleberg.net/= ones so
134the site renders standalone on the onion service without fetching assets
135off-onion. The stylesheet is already same-origin.
136
137This means the web server must serve the image store at =/img/= on the
138=cleberg.net= vhost. The images live at =/var/www/img/= (their own host,
139=img.cleberg.net=); expose them under =cleberg.net/img/= with a symlink:
140
141#+begin_src shell
142ln -s /var/www/img /var/www/cleberg.net/img
143#+end_src
144
145Without this, images 404 in production. Development builds keep the
146absolute =img.cleberg.net= URLs, so local previews load images from the
147live host and need no symlink.
148
149Once assets are same-origin, the vhost CSP can tighten =img-src=,
150=style-src=, and =font-src= back to ='self'=, and drop =bubbles.town=
151from =script-src=/=connect-src= (the vote widget was removed; only a
152plain link to Bubbles remains). After deploying, purge the Cloudflare
153cache (responses carry a 31-day =max-age=).
154
155** Creating New Blog Posts
156
157To add new blog content, follow this procedure within Emacs:
158
1591. Open a new Org file (via =C-x C-f= or Doom\'s =SPC f f=).
1602. Insert the contents of the post template with =C-x i=, sourcing from
161 =utils/template.org=.
1623. Modify the new file as needed to add post content and metadata.
163
164This method streamlines content creation by reusing a preformatted
165template.
content/salary/index.org +14 −20
@@ -1,21 +1,29 @@
1#+title: Salary 1#+title: Salary Transparency
2#+slug: index 2#+slug: index
3#+options: toc:nil 3#+options: toc:nil
4 4
5** Salary Transparency
6
7I've worked in the IT Audit field since 2018, across internal and external 5I've worked in the IT Audit field since 2018, across internal and external
8audit, small companies and Big 4, in person and remote. Across five companies 6audit, small companies and Big 4, in person and remote. Across five companies
9and both sides of the compensation conversation, I've watched good people leave 7and both sides of the compensation conversation, I've watched good people leave
10money on the table because they didn't have the information they needed. That's 8money on the table because they didn't have the information they needed. That's
11what this page is for - the playing field should be level. 9what this page is for: I believe the playing field should be level.
10
11#+begin_export html
12<figure>
13<a href="https://img.cleberg.net/blog/salary/salary.webp">
14<picture>
15<source srcset="https://img.cleberg.net/blog/salary/salary-dark.webp" media="(prefers-color-scheme: dark)">
16<img src="https://img.cleberg.net/blog/salary/salary.webp" alt="Step chart of annualized pay by job from 2017 to 2027. Each job is a horizontal segment colored by company and labeled with its pay and title. Hourly jobs are dotted and show the hourly rate. The area after today is shaded.">
17</picture>
18</a>
19<figcaption>Salary visualization. Click for full size.</figcaption>
20</figure>
21#+end_export
12 22
13The table goes back to 2017 because I'm proud of where I started and what it 23The table goes back to 2017 because I'm proud of where I started and what it
14took to get where I am today. I took what I could get to break into the auditing 24took to get where I am today. I took what I could get to break into the auditing
15field while finishing school, and I've worked hard every day since. 25field while finishing school, and I've worked hard every day since.
16 26
17** Salary Data
18
19This table is a compressed version of the data so that it can fit reliably on 27This table is a compressed version of the data so that it can fit reliably on
20screens. For the full dataset with all fields, you can view the [[https://cleberg.net/salary.csv][source data]]. 28screens. For the full dataset with all fields, you can view the [[https://cleberg.net/salary.csv][source data]].
21 29
@@ -35,20 +43,6 @@ screens. For the full dataset with all fields, you can view the [[https://cleber
35| Teaching Assistant | College of Business | [[https://www.unl.edu/][UNL]] | 2017 | $7/hour | 43| Teaching Assistant | College of Business | [[https://www.unl.edu/][UNL]] | 2017 | $7/hour |
36| Community Management Intern | Store/Retail | [[https://www.walgreensbootsalliance.com/][Walgreens]] | 2017 | $14/hour | 44| Community Management Intern | Store/Retail | [[https://www.walgreensbootsalliance.com/][Walgreens]] | 2017 | $14/hour |
37 45
38** Salary Visualization
39
40#+begin_export html
41<figure>
42<a href="https://img.cleberg.net/blog/salary/salary.webp">
43<picture>
44<source srcset="https://img.cleberg.net/blog/salary/salary-dark.webp" media="(prefers-color-scheme: dark)">
45<img src="https://img.cleberg.net/blog/salary/salary.webp" alt="Step chart of annualized pay by job from 2017 to 2027. Each job is a horizontal segment colored by company and labeled with its pay and title. Hourly jobs are dotted and show the hourly rate. The area after today is shaded.">
46</picture>
47</a>
48<figcaption>Salary visualization. Click for full size.</figcaption>
49</figure>
50#+end_export
51
52[[https://xeiaso.net/salary-transparency/][Xe Iaso]] put it better than I would: 46[[https://xeiaso.net/salary-transparency/][Xe Iaso]] put it better than I would:
53 47
54#+begin_quote 48#+begin_quote
content/templates/detour.org +1 −1
@@ -26,4 +26,4 @@
26 26
27* Overview 27* Overview
28 28
29* Going 29* Going\ No newline at end of file