Repository for a Ghost theme associated to the DSA SF website. It includes a dev setup, python module for interfacing with the Ghost API, and fixtures that set up the basic website. https://ghost.mattyz.one
Find a file
good_matty 9956b927f5
All checks were successful
Deploy Theme / build (push) Successful in 1m7s
Deploy Theme / deploy (push) Successful in 30s
Fix readme link
2026-02-02 00:10:33 -08:00
.devcontainer Add stubs for fix 2026-01-30 12:16:20 -08:00
.github/workflows add linting steps to workflow and fix typescript errors 2026-01-19 23:06:42 -08:00
.vscode Fix lints 2026-01-22 15:43:46 -08:00
assets Make code of conduct do an accordion type deal 2026-01-27 18:53:12 -08:00
dist Add dist/ folder 2025-09-03 11:28:05 -04:00
fixtures Seed Code of Conduct page content 2026-01-27 18:12:36 -08:00
lib/vite Generate partials to avoid race condition 2026-01-25 00:56:49 -08:00
members Iterate theme templates 2025-08-30 09:46:34 -04:00
partials Update card partial to use React 2026-01-19 13:28:00 -08:00
scripts Add stubs for fix 2026-01-30 12:16:20 -08:00
.editorconfig Update templates to use TW. Iterate vite-assets plugin 2025-08-29 10:44:05 -04:00
.env.template Use .env.local for devpod, .env for remote sync 2026-01-20 09:44:01 -08:00
.gitignore Gitignore additions 2026-01-21 19:04:43 -08:00
author.hbs Standardized CSS naming convention and reorganized layout.css structure 2026-01-22 10:27:46 -08:00
biome.json Remove error checking in biome, fix package 2026-01-27 18:52:58 -08:00
components.json Big lint 2026-01-22 10:20:37 -08:00
default.hbs Make a Cool Header 2026-01-19 13:32:37 -08:00
DESIGN.md Minor copy edits to design 2026-01-30 10:37:11 -08:00
error.hbs Add in logo 2026-01-19 12:02:12 -08:00
index.hbs Start migrating to semantic classes 2026-01-20 18:57:43 -08:00
LICENSE Fixed the year, thanks Jenbo 2026-01-25 11:49:00 -08:00
MIGRATION.md Add in initial migration doc 2026-01-29 17:02:20 -08:00
ORIGINAL_README.md Add .env and move README over. 2026-01-18 11:00:42 -08:00
package-lock.json Remove error checking in biome, fix package 2026-01-27 18:52:58 -08:00
package.json Remove error checking in biome, fix package 2026-01-27 18:52:58 -08:00
page-accessibility.hbs Update pages to use heroes, document 2026-01-21 14:56:36 -08:00
page-calendar.hbs Add FilteredEventList islands to calendar page 2026-01-26 18:31:47 -08:00
page-chapter-bodies.hbs Update pages to use heroes, document 2026-01-21 14:56:36 -08:00
page-code-of-conduct.hbs Make code of conduct do an accordion type deal 2026-01-27 18:53:12 -08:00
page-having-trouble.hbs Add having trouble page + fixture 2026-01-21 19:20:18 -08:00
page-join.hbs Add in newsletter signup 2026-01-21 23:22:26 -08:00
page-news.hbs Update pages to use contrast box 2026-01-21 15:44:03 -08:00
page-priorities.hbs Add priorities page 2026-01-21 19:47:55 -08:00
page-who-we-are.hbs Refactor who we are, introduce some semantic classes 2026-01-21 21:15:38 -08:00
page.hbs More migrations 2026-01-20 19:04:46 -08:00
post.hbs Add content sheet class and style post 2026-01-21 15:52:29 -08:00
README.md Fix readme link 2026-02-02 00:10:33 -08:00
renovate.json Big lint 2026-01-22 10:20:37 -08:00
tag.hbs More migrations 2026-01-20 19:04:46 -08:00
tsconfig.json Big lint 2026-01-22 10:20:37 -08:00
vite.config.js Fix lints 2026-01-22 15:43:46 -08:00

DSA SF Ghost Theme

Overview

A Ghost theme for DSA San Francisco built with Vite, React Islands, and Tailwind CSS.

Basic tech stack

  • Ghost CMS: Server-side rendering using Handlebars templates.
  • Vite & React: Fast asset bundling and island architecture for interactive components embedded in static HTML.
  • Tailwind CSS: Utility-first styling configured with a custom Neobrutalism design system (see Design).
  • Python: Automation scripts for seeding content and configuring the instance.
  • DevPod: Containerized development workflow.

Branches

  • main: Current development branch with React Islands integration and full Neobrutalism design system.
  • clean-vapour-dev: Pre-React baseline. This branch contains the original Vapour theme (Handlebars-only) with verified DevPod support and automated testing. Use this as a clean starting point for developers or to test the base theme without React complexity.

Design

This theme uses a Neobrutalist aesthetic with components from neobrutalism.dev. See DESIGN.md for grid layout, color variables, and component guidelines.

Changes

Here's how to make changes to various parts of the content in the theme. In general, this follows the conventions from Ghost, e.g. various pages are templated using Handlebars with the automatic naming conventions outlined in the Ghost documentation.

Styling changes

The styling is handled by Tailwind CSS. The configuration is in vite.config.js. The design system is based on neobrutalism.dev. See DESIGN.md for further details about conventions.

Navigation

The theme supports nested menus in the navigation bar. To create a nested menu item, use the Ghost Admin navigation settings and prefix the label with a dash and a space (- ). The item will be rendered as a child of the preceding top-level item.

Example:

  • Resources
    • Technology
    • Wiki

There is a working example of this configuration in the fixtures, which is applied by the setup script (scripts/setup_ghost.py).

Calendar

The calendar page displays a calendar built with FullCalendar. It uses the Google Calendar plugin to fetch events from a Google Calendar. The calendar ID is set in the .env file, along with the Google Calendar API key. These can also be set in the Ghost admin panel under the custom theme settings variables.

Who We Are page

The template for the "Who We Are" page is set in page-who-we-are.hbs. The copy is hard-coded in that template. To edit it, simply look at that file and change the text. You don't need to modify anything else.

News

The template for the news page is set in page-news.hbs. It is filtered to display only posts with the tag news. The most recent post is displayed in on the main page.

Development setup

DevPod creates reproducible development environments with robust setup, automatic file syncing, and health checks. Theme changes auto-sync to Ghost.

Architecture

Two-container setup:

  • Ghost container: Runs Ghost CMS 6.13.2 with theme files auto-synced from workspace
  • App container: Runs Vite dev server for hot-reloading React/CSS assets

1. Install DevPod

First, install DevPod. You'll want to set Docker as the backend.

Install Docker (if needed):

2. Configure Docker backend

devpod provider add docker
devpod provider use docker

3. Start DevPod

devpod up .

What happens:

  • Builds custom Ghost image with rsync and file watcher
  • Starts Ghost with theme directory pre-synced
  • Waits for Ghost health check (Admin API ready)
  • Runs fixture setup automatically (first run only)
  • Starts Vite dev server

Startup time: ~1-2 minutes on first run, ~30 seconds on subsequent starts

4. Access the application

  • Site: http://localhost:2368
  • Vite dev server: http://localhost:5173
  • Admin: http://localhost:2368/ghost
  • Default credentials: admin@example.com / Th1sIsAStr0ng!Pass

5. Development workflow

Editing files:

  • React/CSS: Auto hot-reload via Vite
  • Handlebars templates: File watcher syncs → browser refresh
  • New templates: File watcher syncs → restart Ghost

Available commands (from inside devcontainer):

npm run setup:ghost    # Re-run fixture setup (if needed)
npm run dev            # Start Vite dev server (runs automatically)
npm run build          # Build for production
npm run test           # Validate theme with gscan

Available commands (from host machine):

# Restart Ghost container (after adding new templates)
docker compose -f .devcontainer/docker-compose.yml restart ghost

# View Ghost logs (watch file sync activity)
docker compose -f .devcontainer/docker-compose.yml logs -f ghost

# Access Ghost container shell
docker compose -f .devcontainer/docker-compose.yml exec ghost sh

Resetting the environment:

From host machine:

# Stop workspace
devpod stop <workspace-name>

# Delete everything (including database and volumes)
devpod delete <workspace-name>

# Start fresh
devpod up .

6. Troubleshooting

Ghost won't start:

# Check Ghost logs
docker compose -f .devcontainer/docker-compose.yml logs ghost

Theme not appearing:

# Check theme files synced
docker compose -f .devcontainer/docker-compose.yml exec ghost ls /var/lib/ghost/content/themes/dsasf-ghost-theme/

# Restart Ghost
docker compose -f .devcontainer/docker-compose.yml restart ghost

File watcher not working:

# Check watcher process
docker compose -f .devcontainer/docker-compose.yml exec ghost ps aux | grep inotify

# Check watcher logs
docker compose -f .devcontainer/docker-compose.yml logs ghost | grep "Watching"

Changes not syncing:

# Make a test change and watch logs
docker compose -f .devcontainer/docker-compose.yml logs -f ghost

# Expected: "Detected change: modify file.hbs in /workspace" → "Theme synced"

Clean slate:

devpod delete .
devpod up .

7. (Optional) Configure IDE

You can have DevPod spin up an IDE that's already open inside of the container. See the DevPod IDE documentation for details.

Prerequisites:

  • Node 20+
  • Ghost CLI: npm install -g ghost-cli

Steps:

  1. Install Ghost locally:

    ghost install local
    
  2. Install dependencies and start dev server:

    npm install
    npm run dev  # Vite dev server on :5173
    
  3. Link theme to Ghost:

    ln -s $(pwd) /path/to/ghost/content/themes/dsasf-ghost-theme
    
  4. Restart Ghost and activate the theme in admin.

Fixtures

The scripts/setup_ghost.py script seeds content from fixtures/ directory. It runs automatically on first DevPod startup.

Re-running manually (if needed):

npm run setup:ghost

What it does:

  • Creates posts from fixtures/posts/*.json
  • Creates pages from fixtures/pages/*.json
  • Configures site settings, navigation, and theme options
  • Uploads logo/icon assets
  • Activates the theme

Run for remote instances:

Step 1 - Configure environment:

Copy .env.template to .env and set your Ghost URL and credentials:

GHOST_URL=https://yourdomain.com
GHOST_ADMIN_EMAIL=admin@example.com
GHOST_ADMIN_PASSWORD=yourpassword
GOOGLE_CALENDAR_API_KEY=your_api_key_here
GOOGLE_CALENDAR_ID=your-calendar@group.calendar.google.com

Note: The calendar feature requires valid Google Calendar API credentials. Without them, the calendar page won't load events.

Step 2 - Run the script:

From your local machine:

export $(cat .env | xargs) && python3 scripts/setup_ghost.py

Building

npm run build  # Outputs to assets/built/

Deployment

Push to main triggers automatic deployment via GitHub Actions.