Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

349 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

johnmclevey.com

Personal website served via GitHub Pages from the docs/ directory.

Architecture

I'm using a custom template-based build system. It's weird and you should probably just use Quarto instead. But anyway...

  • Content lives in content/ (markdown with YAML frontmatter)
  • Templates live in templates/ (Jinja2 HTML templates)
  • Output goes to docs/ (static HTML served by GitHub Pages)
.
├── content/                 # CONTENT: All source content
│   ├── index.md             # Home page
│   ├── research.md          # Research page
│   ├── teaching.md          # Teaching overview
│   ├── software-data.md     # Code & Data page
│   ├── books/               # Book pages
│   │   ├── dcss.md
│   │   ├── face-to-face.md
│   │   ├── industrial-development.md
│   │   └── sage-handbook.md
│   ├── teaching/            # Course pages
│   │   └── 3040.md
│   └── posts/               # Blog posts (.qmd notebooks)
│       ├── _quarto.yml      # Quarto project config
│       ├── .gitignore       # Ignores intermediate files
│       └── *.qmd            # Blog post sources
├── templates/               # PRESENTATION: Jinja2 templates
│   ├── base.html            # Common structure (nav, footer)
│   ├── research.html        # Research page (books + articles)
│   ├── teaching.html        # Teaching page (course groups)
│   ├── page.html            # Generic content page
│   ├── index.html           # Home page with profile
│   ├── blog_post.html       # Blog post with syntax highlighting
│   ├── blog_index.html      # Blog listing
│   ├── book.html            # Book page layout
│   ├── course.html          # Course page layout
│   └── cv.html              # CV with TOC sidebar
├── records/                 # DATA: Structured data sources
│   ├── cv.md                # CV data in YAML frontmatter
│   └── github_cache.json    # Cached GitHub API responses
├── docs/                    # OUTPUT: Built static site
│   ├── styles.css           # Site-wide styles (edit this)
│   ├── images/              # Static images (edit this)
│   └── pdfs/                # PDF files (edit this)
└── scripts/                 # Build scripts
    ├── build_site.py        # Unified site builder
    └── build_cv.py          # CV-specific builder

Prerequisites

  • Pixi for environment management
  • Quarto for rendering .qmd notebooks
  • Run pixi install to set up Python dependencies

Build Commands

Command Description
pixi run build Build entire site (pages + blog + CV)
pixi run build-pages Build static pages only
pixi run build-blog Build blog posts only
pixi run build-cv Build CV only
pixi run preview Start local server at http://localhost:8080

Legacy aliases update-blog and update-cv also work.

Content Workflow

Static Pages

Content files use YAML frontmatter to specify the template and metadata:

---
template: page
title: Research
active: research
---

Page content in markdown (can include raw HTML)...

Available templates:

  • page - Generic content page
  • index - Home page with profile, books, articles, teaching, and blog sections
  • research - Research page with featured books and selected articles
  • teaching - Teaching page with course groups and supervision section
  • book - Book page with cover image and metadata
  • course - Course page with schedule info

The index, research, and teaching templates read structured lists (books, articles, course groups) from their content file's YAML frontmatter.

Common frontmatter fields:

  • template - Which template to use (defaults to page)
  • active - Which nav item to highlight (cv, research, teaching, software, blog)
  • title - Page title (appears in browser tab)

Book Pages

---
template: book
title: Doing Computational Social Science
authors: John McLevey
publisher: Sage, London
year: 2022
image: DCSS.png
---

Book description and content...

Course Pages

---
template: course
title: Quantitative Research Methods
code: SOCI/CRIM 3040-001
schedule: Tuesday and Thursday, 1:30-2:50 pm in C2003
term: Winter 2026
active: teaching
---

Course content...

Blog Posts

Blog posts are Quarto notebooks (.qmd) with executable Python code.

  1. Create: Add content/posts/YYYY-MM-DD-slug.qmd
  2. Add minimal frontmatter (execution/format settings inherited from _quarto.yml):
    ---
    title: Your Post Title
    date: 2026-02-03
    excerpt: Brief description for blog index.
    ---
  3. Write content with executable Python code blocks:
    ```{python}
    import pandas as pd
    print("Hello from Python!")
    ```
  4. Build: Run pixi run build-blog

Shared settings in _quarto.yml (don't repeat in posts):

  • author: John McLevey
  • execute: echo, warning, message, cache, freeze
  • format: gfm with all rendering options

Optional per-post overrides:

  • author - If different from default
  • execute.echo: false - To hide code for a specific post
  • categories - For tagging

The build process:

  • Executes all Python code blocks via Quarto
  • Embeds outputs (text, tables, figures) in the HTML
  • Copies generated figures to docs/blog/figures/
  • Cleans up intermediate files
  • Updates the blog index and home page "Latest Posts"

CV

The CV is built from YAML data in records/cv.md:

  1. Edit the YAML frontmatter in records/cv.md
  2. Build: Run pixi run build-cv

For software entries with GitHub URLs, the build fetches metadata (version, stars, last commit) from the GitHub API. Responses are cached in records/github_cache.json with a 15-minute TTL. Set the GITHUB_TOKEN environment variable for higher API rate limits.

Build Pipeline

                           ┌─────────────────────┐
                           │  templates/*.html   │
                           │  (Jinja2 templates) │
                           └──────────┬──────────┘
                                      │
┌──────────────────┐                  │                  ┌───────────────────┐
│ content/*.md     │──────┐           │           ┌──────│ docs/*.html       │
│ content/books/   │      │           │           │      │ docs/books/       │
│ content/teaching/│      │           │           │      │ docs/teaching/    │
└──────────────────┘      │           │           │      └───────────────────┘
                          │           │           │
┌──────────────────┐      │     ┌─────┴─────┐     │      ┌───────────────────┐
│ content/posts/   │──────┼────▸│build_site │─────┼─────▸│ docs/blog/*.html  │
│ (*.qmd files)    │      │     │   .py     │     │      │ docs/blog.html    │
└──────────────────┘      │     └─────┬─────┘     │      └───────────────────┘
                          │           │           │
┌──────────────────┐      │           │           │      ┌───────────────────┐
│ records/cv.md    │──────┘           │           └──────│ docs/cv.html      │
│ (YAML data)      │                  │                  └───────────────────┘
└──────────────────┘                  │
                           ┌──────────┴──────────┐
                           │    GitHub API       │
                           │ (software metadata) │
                           └─────────────────────┘

File Reference

Source Files (Edit These)

Location Purpose
content/*.md Top-level pages
content/books/*.md Book pages
content/teaching/*.md Course pages
content/posts/*.qmd Blog posts
content/posts/_quarto.yml Quarto config for blog
records/cv.md CV data (YAML frontmatter)
templates/*.html Page templates
docs/styles.css Site-wide CSS styles
docs/images/* Static images (profile, book covers)
docs/pdfs/* PDF files

Generated Files (Don't Edit Directly)

File Source
docs/index.html content/index.md
docs/research.html content/research.md
docs/teaching.html content/teaching.md
docs/software-data.html content/software-data.md
docs/books/*.html content/books/*.md
docs/teaching/*.html content/teaching/*.md
docs/blog/*.html content/posts/*.qmd
docs/blog.html Generated blog index
docs/blog/figures/* Generated from code in posts
docs/cv.html records/cv.md

Deployment

The site deploys automatically when you push to master. GitHub Pages serves the docs/ directory.

pixi run build
git add .
git commit -m "Update site"
git push

The custom domain is configured via docs/CNAME.

Technical Notes

Why This Architecture?

  1. All content in one place - Everything you edit is in content/
  2. Consistent workflow - All pages work the same way
  3. Single build script - One command builds everything
  4. Easy to maintain - Change a template, rebuild, done

Intermediate Files

These are generated during builds and ignored by git (via content/posts/.gitignore):

  • content/posts/*.md - Intermediate markdown from Quarto
  • content/posts/*_files/ - Quarto figure directories
  • content/posts/.quarto/ - Quarto cache
  • content/posts/_freeze/ - Quarto freeze directory
  • content/posts/.jupyter_cache/ - Jupyter execution cache

Template Inheritance

All templates extend base.html, which provides:

  • Compact navigation header with a responsive mobile menu
  • Shared footer rendered inline (no JavaScript fetch)
  • Skip link, focus styles, and Instrument Sans webfont loading

Templates can override these blocks:

  • {% block head_extra %} - Additional <head> content
  • {% block before_main %} - Content before <main> (e.g., sidebars)
  • {% block content %} - Main page content
  • {% block scripts %} - Additional scripts at end of body

Used by

Contributors

Languages