Personal website for Shawn Mix — blog, digital garden (Obsidian notes), resume, and links hub. Built on a customized Jekyll Garden theme.
# Install dependencies
bundle install
# Run local dev server
export PATH="/opt/homebrew/opt/[email protected]/bin:$PATH"
bundle exec jekyll serve
# Build static site
bundle exec jekyll build
macOS ships with Ruby 2.6. Always use Homebrew Ruby 3.2 at
/opt/homebrew/opt/[email protected]/bin/for Jekyll 4.
All pages share one layout: _layouts/Post.html. It branches using Liquid conditionals on page.permalink and page.content-type:
| Condition | Page type |
|---|---|
permalink: / |
Homepage — renders pages/index.md via Content.html |
permalink: /notes |
Notes index — search + feed |
permalink: /blog |
Blog index — post listing |
content-type: notes |
Individual note — back button + backlinks |
content-type: post |
Blog post — back button + date + read time |
content-type: static |
Static page (about, resume, etc.) |
| File | Purpose |
|---|---|
_config.yml |
Site config, feature toggles; menu is empty (nav is via landing page cards) |
_layouts/Post.html |
Universal layout; theme attribute set here |
_includes/Nav.html |
Top nav — square logo left, theme toggle right; all theme JS lives here |
_includes/Footer.html |
Empty spacer — no copyright, no credits |
_includes/Feed.html |
Notes feed list (feed-container wrapper) |
_includes/Backlinks.html |
Backlinks grid on note/post pages |
assets/css/style.css |
All styles — plain CSS, no Sass |
pages/index.md |
Landing page — name, bio, 2×2 card grid |
pages/about.md |
About page |
pages/resume.md |
Resume (placeholder, specialized layout planned) |
pages/notes.md |
Notes index |
pages/blog.md |
Blog index |
_notes/ |
Digital garden notes (Obsidian-compatible, [[wiki links]] supported) |
_posts/ |
Blog posts — filename must be YYYY-MM-DD-title.md |
_notes/ — published at /notes/:name_posts/ — published at /blog/:title/All values live in :root (light) and [data-theme="dark"] (dark) in style.css. Never use hardcoded values — always reference or add a variable.
| Variable | Value |
|---|---|
--space-xs |
0.4rem |
--space-sm |
0.8rem |
--space-md |
1.2rem |
--space-lg |
2rem |
--space-xl |
3rem |
--back-button-offset |
8rem |
| Variable | Value | Usage |
|---|---|---|
--scale-xs |
0.8rem |
Small labels |
--scale-sm |
0.933rem |
Back button, captions |
--scale-meta |
0.875rem |
Post metadata (date, read time) |
--scale-base |
1rem |
Body text |
--scale-lg |
1.2rem |
Subheadings |
| Variable | Value |
|---|---|
--weight-light |
300 |
--weight-medium |
400 |
--weight-bold |
600 |
Font: Inter (Google Fonts), loaded at weights 300/400/600. Loaded via @import in style.css only — no separate <link> tag in the layout.
| Variable | Value | Usage |
|---|---|---|
--line-height |
1.5 |
Default — headings, code, search results |
--line-height-relaxed |
1.6 |
Blockquotes, list items |
--line-height-loose |
1.7 |
Body paragraphs |
| Variable | Dark (Mocha) | Light (Latte) |
|---|---|---|
--bg |
#181825 Mantle |
#eff1f5 Base |
--bg2 |
#1e1e2e Base |
#e6e9ef Mantle |
--text |
#cdd6f4 Text |
#4c4f69 Text |
--title |
#ffffff White |
#1e1e2e Dark |
--brand |
#45475a Surface 1 |
#9ca0b0 Surface 1 |
--border |
#313244 Surface 0 |
#ccd0da Surface 0 |
Accent hover color (not a variable — used inline): rgba(137, 180, 250, 0.22) — Catppuccin Blue at low opacity.
<script> in <head> before first paint (prevents flash). JS reads localStorage and falls back to 'dark'.Nav.html.color: var(--text), text-decoration: underline (1px), no color change on hover.48rem, centered.| Element | Hover effect |
|---|---|
| Landing page cards | rgba(137, 180, 250, 0.22) blue tint + border stays visible |
| Backlinks grid items | Same blue tint |
| Notes/blog feed list items | None — no highlight |
| Back button | Opacity 0.7 → 1 |
CSS ::after on a[href^="http"] — theme-aware SVG stroke (#4c4f69 light / #cdd6f4 dark). Suppressed on: nav, footer, search, feed wrappers. On card grid: suppressed on <a> wrapper, applied to h4::after so the arrow appears beside the title, not after the description.
← Back to Notes / ← Back to Blogposition: fixed; left: var(--back-button-offset); top: var(--back-button-offset)Rendered beneath <h1> on post pages:
· min read
page.content | number_of_words | divided_by: site.reading_speed, floored at 1. Speed configured in _config.yml (reading_speed: 200 wpm)--scale-meta, --weight-light, opacity: 0.5, class .post-metaFile: _posts/YYYY-MM-DD-title.md
---
title: "Post Title"
date: YYYY-MM-DD
feed: show
---
File: _notes/Public/Note Title.md
---
title: "Note Title"
feed: show
date: YYYY-MM-DD
---
File: pages/slug.md
---
title: "Page Title"
layout: Post
content-type: "static"
permalink: /slug
---
Notes in _notes/Public/ are not edited directly. They are synced automatically from the lifeOS Obsidian vault (iCloud) via a Python script. The Obsidian vault is the single source of truth.
To publish a note from Obsidian: Add publish: true to the note’s frontmatter. The sync runs every 20 minutes automatically, or can be triggered on-demand via QuickAdd inside Obsidian.
To un-publish a note: Set publish: false. The next sync will delete the file from this repo.
Full pipeline documentation: SOP - Notes Publishing Pipeline in the Obsidian vault at 3 Resources/SOPs/.
Sync script (source of truth): lifeOS/3 Resources/scripts/sync_to_jekyll.py
Do not manually edit files in _notes/Public/ — changes will be overwritten on the next sync.
If the launchd wrapper at ~/scripts/run-jekyll-sync.sh is lost, recreate it with:
#!/usr/bin/env bash
export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:$PATH"
SYNC_SCRIPT="/Users/shawnmix/Library/Mobile Documents/iCloud~md~obsidian/Documents/lifeOS/3 Resources/scripts/sync_to_jekyll.py"
if [[ ! -f "$SYNC_SCRIPT" ]]; then
brctl download "$SYNC_SCRIPT" 2>/dev/null || true
sleep 3
if [[ ! -f "$SYNC_SCRIPT" ]]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: sync_to_jekyll.py not found" >&2
exit 1
fi
fi
exec python3 "$SYNC_SCRIPT" --scheduled "$@"
Then: chmod +x ~/scripts/run-jekyll-sync.sh && launchctl load ~/Library/LaunchAgents/com.shawnmix.jekyll-sync.plist