Commit 85aaafbc54
Verified · cmc ci/build: success ci/lint: success
Layout: unified · split
README.md deleted −167
| @@ -1,167 +0,0 @@ | ||
| 1 | # cleberg.net | |
| 2 | ||
| 3 | This repository holds the files for [cleberg.net](https://cleberg.net), | |
| 4 | a static-site with blog posts, personal links, and more. | |
| 5 | ||
| 6 | This site uses [orgo](https://gitbay.org/krz/orgo) to build the | |
| 7 | static site. | |
| 8 | ||
| 9 | ## Site Structure | |
| 10 | ||
| 11 | I write content pages (e.g., blog posts) in org-mode and templates in | |
| 12 | HTML. orgo builds these files into a static site, and then I deploy | |
| 13 | them to a web server. | |
| 14 | ||
| 15 | The 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 | ||
| 31 | The 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 | ||
| 41 | You can customize site settings within the `content/orgo.toml` file. | |
| 42 | This 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 | ||
| 49 | Users intending to modify site parameters should review and edit this | |
| 50 | file accordingly. The orgo documentation contains extensive details on | |
| 51 | configuration options and expected formats. | |
| 52 | ||
| 53 | ## Setup Instructions | |
| 54 | ||
| 55 | To obtain a working copy of this repository, execute the following | |
| 56 | commands within a shell environment or Emacs shell interface: | |
| 57 | ||
| 58 | ``` shell | |
| 59 | git clone https://gitbay.org/cmc/cleberg.net | |
| 60 | cd cleberg.net | |
| 61 | emacs -nw | |
| 62 | ``` | |
| 63 | ||
| 64 | For 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 | ||
| 69 | The `build.py` script wraps the build: it runs orgo, rewrites the footer's | |
| 70 | orgo version to match the orgo that ran, and then either deploys the result | |
| 71 | or serves it locally. | |
| 72 | ||
| 73 | Environment 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 | ||
| 84 | Exactly 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: | |
| 96 | BUILD=true uv run build.py | |
| 97 | ||
| 98 | # Development build, then serve it on localhost:8000: | |
| 99 | BUILD=true DEPLOY=true uv run build.py | |
| 100 | ||
| 101 | # Production build, no deploy: | |
| 102 | ENV=prod BUILD=true uv run build.py | |
| 103 | ||
| 104 | # What would a deploy change? Connects, compares, transfers nothing: | |
| 105 | ENV=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: | |
| 108 | ENV=prod BUILD=true DEPLOY=true uv run build.py | |
| 109 | ``` | |
| 110 | ||
| 111 | Generated site files reside in `.build/` for production and | |
| 112 | `.build-dev/` for development. | |
| 113 | ||
| 114 | The deploy is `rsync --delete-before`, so files the build no longer | |
| 115 | produces are removed from the server. That is what makes the dry run | |
| 116 | worth having: a build that silently produced fewer pages would quietly | |
| 117 | delete the rest. Lines beginning `*deleting` in the dry-run output are | |
| 118 | what the real deploy would remove. | |
| 119 | ||
| 120 | Builds are incremental: orgo keeps an `.orgo-cache.json` inside the | |
| 121 | output directory and re-renders only what changed, so the directory is | |
| 122 | left in place between runs. Delete it for a clean build. The two | |
| 123 | environments use separate directories because production rewrites image | |
| 124 | URLs in the output and development does not. | |
| 125 | ||
| 126 | orgo can also build and preview on its own, without `build.py`: | |
| 127 | ||
| 128 | ``` shell | |
| 129 | orgo serve content -o /tmp/preview | |
| 130 | ``` | |
| 131 | ||
| 132 | ## Deployment | |
| 133 | ||
| 134 | Production builds rewrite image URLs to root-relative ones | |
| 135 | (`/img/blog/...`) instead of absolute `https://img.cleberg.net/` ones so | |
| 136 | the site renders standalone on the onion service without fetching assets | |
| 137 | off-onion. The stylesheet is already same-origin. | |
| 138 | ||
| 139 | This 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 | |
| 144 | ln -s /var/www/img /var/www/cleberg.net/img | |
| 145 | ``` | |
| 146 | ||
| 147 | Without this, images 404 in production. Development builds keep the | |
| 148 | absolute `img.cleberg.net` URLs, so local previews load images from the | |
| 149 | live host and need no symlink. | |
| 150 | ||
| 151 | Once assets are same-origin, the vhost CSP can tighten `img-src`, | |
| 152 | `style-src`, and `font-src` back to `'self'`, and drop `bubbles.town` | |
| 153 | from `script-src`/`connect-src` (the vote widget was removed; only a | |
| 154 | plain link to Bubbles remains). After deploying, purge the Cloudflare | |
| 155 | cache (responses carry a 31-day `max-age`). | |
| 156 | ||
| 157 | ## Creating New Blog Posts | |
| 158 | ||
| 159 | To add new blog content, follow this procedure within Emacs: | |
| 160 | ||
| 161 | 1. Open a new Org file (via `C-x C-f` or Doom\'s `SPC f f`). | |
| 162 | 2. Insert the contents of the post template with `C-x i`, sourcing from | |
| 163 | `utils/template.org`. | |
| 164 | 3. Modify the new file as needed to add post content and metadata. | |
| 165 | ||
| 166 | This method streamlines content creation by reusing a preformatted | |
| 167 | template. | |
README.org added +165
| @@ -0,0 +1,165 @@ | ||
| 1 | * cleberg.net | |
| 2 | ||
| 3 | This repository holds the files for [[https://cleberg.net][cleberg.net]], | |
| 4 | a static-site with blog posts, personal links, and more. | |
| 5 | ||
| 6 | This site uses [[https://gitbay.org/krz/orgo][orgo]] to build the | |
| 7 | static site. | |
| 8 | ||
| 9 | ** Site Structure | |
| 10 | ||
| 11 | I write content pages (e.g., blog posts) in org-mode and templates in HTML. orgo | |
| 12 | builds these files into a static site, and then I deploy them to a web server. | |
| 13 | ||
| 14 | The 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 | ||
| 29 | The 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 | ||
| 39 | You can customize site settings within the =content/orgo.toml= file. | |
| 40 | This 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 | ||
| 47 | Users intending to modify site parameters should review and edit this | |
| 48 | file accordingly. The orgo documentation contains extensive details on | |
| 49 | configuration options and expected formats. | |
| 50 | ||
| 51 | ** Setup Instructions | |
| 52 | ||
| 53 | To obtain a working copy of this repository, execute the following | |
| 54 | commands within a shell environment or Emacs shell interface: | |
| 55 | ||
| 56 | #+begin_src shell | |
| 57 | git clone https://gitbay.org/cmc/cleberg.net | |
| 58 | cd cleberg.net | |
| 59 | emacs -nw | |
| 60 | #+end_src | |
| 61 | ||
| 62 | For 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 | ||
| 67 | The =build.py= script wraps the build: it runs orgo, rewrites the footer's | |
| 68 | orgo version to match the orgo that ran, and then either deploys the result | |
| 69 | or serves it locally. | |
| 70 | ||
| 71 | Environment 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 | ||
| 82 | Exactly 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: | |
| 94 | BUILD=true uv run build.py | |
| 95 | ||
| 96 | # Development build, then serve it on localhost:8000: | |
| 97 | BUILD=true DEPLOY=true uv run build.py | |
| 98 | ||
| 99 | # Production build, no deploy: | |
| 100 | ENV=prod BUILD=true uv run build.py | |
| 101 | ||
| 102 | # What would a deploy change? Connects, compares, transfers nothing: | |
| 103 | ENV=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: | |
| 106 | ENV=prod BUILD=true DEPLOY=true uv run build.py | |
| 107 | #+end_src | |
| 108 | ||
| 109 | Generated site files reside in =.build/= for production and | |
| 110 | =.build-dev/= for development. | |
| 111 | ||
| 112 | The deploy is =rsync --delete-before=, so files the build no longer | |
| 113 | produces are removed from the server. That is what makes the dry run | |
| 114 | worth having: a build that silently produced fewer pages would quietly | |
| 115 | delete the rest. Lines beginning =*deleting= in the dry-run output are | |
| 116 | what the real deploy would remove. | |
| 117 | ||
| 118 | Builds are incremental: orgo keeps an =.orgo-cache.json= inside the | |
| 119 | output directory and re-renders only what changed, so the directory is | |
| 120 | left in place between runs. Delete it for a clean build. The two | |
| 121 | environments use separate directories because production rewrites image | |
| 122 | URLs in the output and development does not. | |
| 123 | ||
| 124 | orgo can also build and preview on its own, without =build.py=: | |
| 125 | ||
| 126 | #+begin_src shell | |
| 127 | orgo serve content -o /tmp/preview | |
| 128 | #+end_src | |
| 129 | ||
| 130 | ** Deployment | |
| 131 | ||
| 132 | Production builds rewrite image URLs to root-relative ones | |
| 133 | (=/img/blog/...=) instead of absolute =https://img.cleberg.net/= ones so | |
| 134 | the site renders standalone on the onion service without fetching assets | |
| 135 | off-onion. The stylesheet is already same-origin. | |
| 136 | ||
| 137 | This 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 | |
| 142 | ln -s /var/www/img /var/www/cleberg.net/img | |
| 143 | #+end_src | |
| 144 | ||
| 145 | Without this, images 404 in production. Development builds keep the | |
| 146 | absolute =img.cleberg.net= URLs, so local previews load images from the | |
| 147 | live host and need no symlink. | |
| 148 | ||
| 149 | Once assets are same-origin, the vhost CSP can tighten =img-src=, | |
| 150 | =style-src=, and =font-src= back to ='self'=, and drop =bubbles.town= | |
| 151 | from =script-src=/=connect-src= (the vote widget was removed; only a | |
| 152 | plain link to Bubbles remains). After deploying, purge the Cloudflare | |
| 153 | cache (responses carry a 31-day =max-age=). | |
| 154 | ||
| 155 | ** Creating New Blog Posts | |
| 156 | ||
| 157 | To add new blog content, follow this procedure within Emacs: | |
| 158 | ||
| 159 | 1. Open a new Org file (via =C-x C-f= or Doom\'s =SPC f f=). | |
| 160 | 2. Insert the contents of the post template with =C-x i=, sourcing from | |
| 161 | =utils/template.org=. | |
| 162 | 3. Modify the new file as needed to add post content and metadata. | |
| 163 | ||
| 164 | This method streamlines content creation by reusing a preformatted | |
| 165 | template. | |
content/salary/index.org +14 −20
| @@ -1,21 +1,29 @@ | ||
| 1 | #+title: Salary | |
| 1 | #+title: Salary Transparency | |
| 2 | 2 | #+slug: index |
| 3 | 3 | #+options: toc:nil |
| 4 | 4 | |
| 5 | ** Salary Transparency | |
| 6 | ||
| 7 | 5 | I've worked in the IT Audit field since 2018, across internal and external |
| 8 | 6 | audit, small companies and Big 4, in person and remote. Across five companies |
| 9 | 7 | and both sides of the compensation conversation, I've watched good people leave |
| 10 | 8 | money on the table because they didn't have the information they needed. That's |
| 11 | what this page is for - the playing field should be level. | |
| 9 | what 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 | |
| 13 | 23 | The table goes back to 2017 because I'm proud of where I started and what it |
| 14 | 24 | took to get where I am today. I took what I could get to break into the auditing |
| 15 | 25 | field while finishing school, and I've worked hard every day since. |
| 16 | 26 | |
| 17 | ** Salary Data | |
| 18 | ||
| 19 | 27 | This table is a compressed version of the data so that it can fit reliably on |
| 20 | 28 | screens. 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 | 43 | | Teaching Assistant | College of Business | [[https://www.unl.edu/][UNL]] | 2017 | $7/hour | |
| 36 | 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 | 46 | [[https://xeiaso.net/salary-transparency/][Xe Iaso]] put it better than I would: |
| 53 | 47 | |
| 54 | 48 | #+begin_quote |
content/templates/detour.org +1 −1
| @@ -26,4 +26,4 @@ | ||
| 26 | 26 | |
| 27 | 27 | * Overview |
| 28 | 28 | |
| 29 | * Going | |
| 29 | * Going | |
| \ No newline at end of file | ||