Theme Documentation

A comprehensive guide to understanding and customizing the mrogers.london Jekyll theme.

Overview

This is a custom Jekyll theme built specifically for GitHub Pages deployment. The theme features a modular SCSS architecture designed for maintainability and easy customization.

Design Philosophy:

  • Warm, reading-focused aesthetic with a carefully chosen color palette
  • Modular SCSS structure for clean separation of concerns
  • Responsive design that prioritizes content readability

Visual Design:

  • Primary color: Terracotta (#C45533)
  • Secondary color: Sage (#7A9E7E)
  • Accent color: Warm gold (#D4A853)
  • Background: Warm cream (#FAF8F5)
  • Typography: Newsreader (serif) for body text, Rethink Sans for UI elements

Architecture

Directory Structure

mrogers-london/
├── _sass/              # Modular SCSS partials
│   ├── _variables.scss # Design tokens (colors, fonts, spacing)
│   ├── _base.scss      # HTML element resets and defaults
│   ├── _typography.scss # Font styles and headings
│   ├── _layout.scss    # Page structure, header, footer
│   └── _components.scss # Reusable UI components
├── assets/css/
│   └── main.scss       # Main entry point (imports partials)
├── _layouts/           # Page templates
│   ├── default.html    # Base template
│   ├── page.html       # Static pages
│   ├── post.html       # Blog posts
│   └── home.html       # Homepage
├── _includes/          # Reusable components
│   ├── head.html       # HTML head section
│   ├── header.html     # Site header
│   ├── footer.html     # Site footer
│   └── post-meta.html  # Post metadata
└── assets/images/      # Image assets

SCSS Structure

Modular System

Each SCSS file has a single responsibility, making the codebase easier to maintain and customize. The files are imported in a specific order in assets/css/main.scss.

File Breakdown

_variables.scss - Design Tokens

  • Color palette: $color-primary, $color-secondary, $color-tertiary, $color-background, $color-text, $color-border, $color-muted
  • Typography: $font-serif (Newsreader), $font-sans (Rethink Sans), $font-mono
  • Spacing scale: $spacing-xs, $spacing-sm, $spacing-md, $spacing-lg, $spacing-xl, $spacing-2xl
  • Font sizes and weights
  • Breakpoints for responsive design
  • Content width constraints

_base.scss - Reset and Base Styles

  • Box-sizing reset
  • Margin resets for consistency
  • HTML and body base styles
  • Image defaults
  • Link styles
  • List styling
  • Horizontal rules
  • Text selection color

_typography.scss - Text Styles

  • Heading styles (h1-h6)
  • Font sizes and weights
  • Line heights
  • Text utilities

_layout.scss - Page Structure

  • Page content wrapper
  • Site header and navigation
  • Site footer and social links
  • Homepage-specific styles
  • Post page layout
  • Static page layout
  • Responsive container widths

_components.scss - Reusable Components

  • Avatar styles
  • Type badges (category pills)
  • Post list items
  • Post metadata
  • Newsletter signup
  • Other UI components

Import Chain

The assets/css/main.scss file imports all partials in the correct order:

  1. Google Fonts (external)
  2. Variables (must be first for use in other files)
  3. Base styles
  4. Typography
  5. Layout
  6. Components
  7. Additional custom styles

Customization Guide

Changing Colors

Edit the color variables in _sass/_variables.scss:

// Example: Change primary color from terracotta to blue
$color-primary: #3B82F6;  // Change from #C45533

All links, highlights, and accent colors will update automatically throughout the site.

Color Variables:

  • $color-background - Page background color
  • $color-text - Main text color
  • $color-primary - Links and highlights
  • $color-secondary - Secondary accent (currently sage)
  • $color-tertiary - Tertiary accent (currently warm gold)
  • $color-border - Borders and dividers
  • $color-muted - Muted/secondary text

Modifying Fonts

Step 1: Update the Google Fonts import in assets/css/main.scss:

@import url('https://fonts.googleapis.com/css2?family=Your-Font:wght@400;600&display=swap');

Step 2: Update font variables in _sass/_variables.scss:

$font-serif: 'Your-Serif-Font', Georgia, serif;
$font-sans: 'Your-Sans-Font', -apple-system, sans-serif;
$font-mono: 'Your-Mono-Font', Monaco, monospace;

Current Fonts:

  • Serif (body text): Newsreader
  • Sans-serif (UI): Rethink Sans
  • Monospace (code): SF Mono fallback chain

Adjusting Spacing

Edit the spacing scale in _sass/_variables.scss:

$spacing-xs: 0.5rem;   // 8px
$spacing-sm: 0.75rem;  // 12px
$spacing-md: 1rem;     // 16px
$spacing-lg: 1.5rem;   // 24px
$spacing-xl: 2rem;     // 32px
$spacing-2xl: 3rem;    // 48px

Spacing variables are used throughout the theme for consistent vertical rhythm and component spacing.

Changing Layout Width

Adjust content width constraints in _sass/_variables.scss:

$content-max-width: 680px;  // Main content column width
$page-max-width: 1200px;    // Full page width

Adding New Components

Add new components to _sass/_components.scss following the existing patterns:

.my-component {
  padding: $spacing-md;
  background-color: $color-background;
  border: 1px solid $color-border;
  border-radius: 4px;

  &:hover {
    background-color: rgba($color-primary, 0.05);
  }
}

Best Practices:

  • Use variables for colors and spacing (never hardcode values)
  • Follow the existing naming conventions
  • Keep selectors flat and simple
  • Use BEM-style naming for clarity
  • Add comments for complex styles

Responsive Design

The theme uses responsive breakpoints defined in _variables.scss:

$breakpoint-sm: 576px;
$breakpoint-md: 768px;
$breakpoint-lg: 1024px;

Use media queries with these breakpoints:

.my-element {
  font-size: 1rem;

  @media (min-width: $breakpoint-md) {
    font-size: 1.125rem;
  }
}

Layout System

Layout Hierarchy

The theme uses a hierarchical layout system:

default.html (base)
  ├── page.html (static pages)
  ├── post.html (blog posts)
  └── home.html (homepage)

When to Use Each Layout

default.html - Base Template

  • Contains the HTML skeleton
  • Includes header, footer, and content wrapper
  • Used as the foundation for all other layouts
  • Not typically assigned directly to pages

page.html - Static Pages

  • Extends default.html
  • Used for: About page, Archives, etc.
  • Simple content container without post metadata

post.html - Blog Posts

  • Extends default.html
  • Includes post metadata (date, category, reading time)
  • Adds post-specific styling and structure
  • Automatically assigned to files in _posts/

home.html - Homepage

  • Custom layout with hero section
  • Displays avatar, title, tagline
  • Lists recent blog posts
  • Only used for index.md

Customizing Layouts

Layouts are found in _layouts/ and can be edited directly. They use Jekyll’s Liquid templating language.

Common Liquid Variables:

  • `<article class="page">

    Beehiiv Integration Setup Guide

This document outlines all the work required to complete the Beehiiv cross-posting integration.

Current Status

COMPLETED:

  • Beehiiv subscribe form integrated on GitHub Pages site
  • RSS feed removed from site
  • Sync script created (scripts/sync_to_beehiiv.py)
  • GitHub Actions workflow created (.github/workflows/beehiiv-sync.yml)
  • Dependencies file created (scripts/requirements.txt)
  • Documentation created (scripts/README.md)

PENDING: API access and configuration (see below)


Required Work

1. Request Beehiiv Enterprise API Access

Status: ⏳ NOT STARTED

Action Required:

  1. Log into your Beehiiv dashboard
  2. Navigate to Help page or click the Chatbot Assistant
  3. Send message requesting Enterprise API access:
    Hi, I'd like to request access to the Beehiiv Send API / Create Post endpoint.
    I want to programmatically cross-post content from my Jekyll blog to Beehiiv.
    
  4. Wait for response from Beehiiv support
  5. Once approved, obtain:
    • API key
    • Publication ID

Resources:

Expected Timeline: Days to weeks (depends on Beehiiv support response time)

Blockers: Cannot proceed with remaining steps until API access is granted


2. Verify API Endpoint and Payload Structure

Status: ⏳ BLOCKED (waiting for API access)

Action Required:

Once you have API access, verify these details in the sync script:

File: scripts/sync_to_beehiiv.py

Search for # TODO: comments and verify:

a) API Base URL (Line ~36)

# TODO: Verify API endpoint URL with Beehiiv documentation once you have API access
API_BASE_URL = 'https://api.beehiiv.com/v2'
  • Check: Is https://api.beehiiv.com/v2 the correct base URL?
  • Reference: Beehiiv API documentation

b) Request Payload Field Names (Lines ~212-237)

# TODO: Verify these field names match actual Beehiiv API specification
payload = {
    "title": post_data['title'],
    "status": "confirmed",
    "platform": "both",
    "content": {
        "html": html_content
    }
}

Verify these field names are correct:

  • title - Post title
  • status - Publication status (“confirmed” for immediate publish)
  • platform - Where to publish (“both” for email + web)
  • content.html - HTML content structure
  • subtitle - Excerpt/subtitle field name
  • content_tags - Tags field name
  • web_url_override - Canonical URL field name
  • send_at - Publish date field name and format

c) Response Structure (Line ~250)

# TODO: Verify response structure with actual API - adjust path to post ID if needed
post_id = result.get('id') or result.get('data', {}).get('id')
  • Check: Where is the post ID in the API response?
  • Adjust code if the post ID is at a different path

d) Date Format (Line ~236)

# TODO: Verify date format expected by Beehiiv (ISO 8601 assumed)
payload["send_at"] = post_data['date']
  • Check: Does Beehiiv expect ISO 8601 format? (e.g., “2025-04-13T10:00:00Z”)
  • Adjust if different format needed

Testing Method:

  1. Make a test API call with curl or Postman
  2. Verify request/response structure
  3. Update script if needed
  4. Run local test (see Testing section below)

3. Configure GitHub Secrets

Status: ⏳ BLOCKED (waiting for API access)

Action Required:

  1. Go to your GitHub repository: https://github.com/m-01101101/mrogers-london
  2. Navigate to: SettingsSecrets and variablesActions
  3. Click New repository secret
  4. Add two secrets:

Secret 1: BEEHIIV_API_KEY

  • Name: BEEHIIV_API_KEY
  • Value: Your API key from Beehiiv (obtained in step 1)

Secret 2: BEEHIIV_PUBLICATION_ID

  • Name: BEEHIIV_PUBLICATION_ID
  • Value: Your publication ID from Beehiiv

How to find Publication ID:

  • Check Beehiiv dashboard URL (may be in the URL)
  • Check API documentation
  • Contact Beehiiv support if unclear

Documentation:


4. Local Testing (Before Deployment)

Status: ⏳ BLOCKED (waiting for API access and secrets)

Action Required:

Test the sync script locally before deploying to GitHub Actions:

# Navigate to repo directory
cd /Users/michael/m-01101101/mrogers-london

# Set environment variables
export BEEHIIV_API_KEY="your_actual_api_key_here"
export BEEHIIV_PUBLICATION_ID="your_actual_publication_id_here"

# Install dependencies
pip install -r scripts/requirements.txt

# Run sync script
python scripts/sync_to_beehiiv.py

Expected Outcome:

  • Script finds 5 posts in _posts/
  • Each post is converted to HTML
  • Posts are created on Beehiiv via API
  • State file .beehiiv_sync_state.json is created
  • No errors in output

If errors occur:

  1. Check API endpoint URL
  2. Verify payload field names
  3. Check response parsing logic
  4. Review error messages for hints
  5. Update script as needed

Validation:

  • Script runs without errors
  • 5 posts created on Beehiiv
  • Posts have correct titles, dates, content
  • Images load correctly (absolute URLs to mrogers.london)
  • State file created with all posts tracked

5. Initial Backfill via GitHub Actions

Status: ⏳ BLOCKED (waiting for local testing to pass)

Action Required:

Once local testing succeeds, trigger the GitHub Actions workflow:

Method 1: Manual Trigger

  1. Go to GitHub repo → Actions tab
  2. Select “Sync to Beehiiv” workflow
  3. Click “Run workflow”
  4. Select branch: main
  5. Click “Run workflow” button

Method 2: Automatic Trigger

  1. Make any commit to _posts/ directory
  2. Push to main branch
  3. Workflow triggers automatically

Validation:

  • Workflow runs successfully (green checkmark)
  • No errors in workflow logs
  • All 5 posts appear on Beehiiv
  • State file (.beehiiv_sync_state.json) committed to repo
  • State file contains all 5 posts

If workflow fails:

  1. Check workflow logs in GitHub Actions
  2. Verify GitHub Secrets are set correctly
  3. Check for API errors in logs
  4. Debug and re-run

6. Enable “Remove Indexing” on Beehiiv

Status: ⏳ BLOCKED (waiting for successful backfill)

Action Required:

After posts are successfully syncing to Beehiiv:

  1. Log into Beehiiv dashboard
  2. Navigate to: SettingsPublication Settings
  3. Find setting: “Remove Indexing” or “Disable Indexing”
  4. Toggle it ON

Why: This prevents Google from indexing your Beehiiv site, avoiding duplicate content SEO issues. Your primary site (mrogers.london) remains the SEO-indexed version.

Important: Only do this AFTER you verify posts are syncing correctly. If you enable this too early, you won’t be able to check if posts appear on Beehiiv web.

Validation:

  • Setting enabled in Beehiiv
  • Beehiiv posts still accessible to subscribers (not publicly indexed)
  • mrogers.london remains Google-indexed

Reference:


7. Test End-to-End Workflow

Status: ⏳ BLOCKED (waiting for all above steps)

Action Required:

Create a test post to verify the full workflow:

# Create a test post
cat > _posts/2025-12-28-test-post.md <<'EOF'
---
title: "Test Post - Delete Me"
date: 2025-12-28
type: essay
excerpt: "This is a test post to verify Beehiiv integration."
tags: [test]
---

This is a test post to verify that:
- Markdown converts to HTML
- Images work correctly: ![Test](/assets/images/avatar.jpg)
- Cross-posting works automatically

You can delete this post after verification.
EOF

# Commit and push
git add _posts/2025-12-28-test-post.md
git commit -m "Test: Beehiiv integration"
git push origin main

Expected Behavior:

  1. GitHub Actions workflow triggers automatically
  2. Script detects new post
  3. Post created on Beehiiv (web + email)
  4. State file updated and committed
  5. Post appears on both mrogers.london and Beehiiv

Validation Checklist:

  • Post appears on mrogers.london
  • Post appears on Beehiiv web
  • Email sent to subscribers (check your inbox)
  • Images load correctly in Beehiiv
  • Canonical URL links back to mrogers.london
  • State file updated in repo
  • Workflow completed successfully (green checkmark)

Clean Up: After successful test, delete the test post:

git rm _posts/2025-12-28-test-post.md
git commit -m "Remove test post"
git push origin main

Quick Reference: All TODO Items in Code

Search for # TODO: in these files:

scripts/sync_to_beehiiv.py

  1. Line ~27: Set BEEHIIV_API_KEY and BEEHIIV_PUBLICATION_ID in GitHub Secrets
  2. Line ~35: Verify API base URL
  3. Line ~212: Verify request payload field names
  4. Line ~224: Verify optional field names (subtitle, tags, canonical URL)
  5. Line ~236: Verify date format
  6. Line ~250: Verify response structure (post ID location)

Troubleshooting

API Access Issues

Problem: Beehiiv hasn’t responded to API access request

Solution:

  • Follow up with support after 3-5 business days
  • Check spam folder for email response
  • Try reaching out via different channel (email vs. chat)

Authentication Errors

Problem: Authentication failed. Check BEEHIIV_API_KEY

Solutions:

  • Verify API key is correctly copied (no extra spaces)
  • Check GitHub Secret name matches exactly: BEEHIIV_API_KEY
  • Confirm you have Enterprise API access (not just regular account)

Field Name Errors

Problem: Validation error or Unknown field from API

Solutions:

  • Review Beehiiv API documentation for correct field names
  • Update payload structure in sync_to_beehiiv.py
  • Test with minimal payload first, then add optional fields

Posts Not Appearing

Problem: Script runs without errors but posts don’t appear on Beehiiv

Possible Causes:

  • Posts created as drafts instead of published (check status field)
  • Posts scheduled for future date (check send_at field)
  • Posts on Beehiiv but not visible due to permissions

Solutions:

  • Check Beehiiv dashboard for draft posts
  • Verify status: "confirmed" in payload
  • Check send_at is not in the future

Timeline Estimate

Task Time Required Depends On
1. Request API access 1 hour work, days/weeks wait -
2. Verify API details 1-2 hours Task 1
3. Configure GitHub Secrets 10 minutes Task 1
4. Local testing 30-60 minutes Tasks 2, 3
5. Initial backfill 15 minutes Task 4
6. Enable “Remove Indexing” 5 minutes Task 5
7. End-to-end testing 30 minutes Tasks 1-6

Total Active Work: 3-5 hours Total Calendar Time: Days to weeks (waiting for API access)


Support Resources

Beehiiv Documentation:

  • API Getting Started: https://developers.beehiiv.com/welcome/getting-started
  • Create Post: https://developers.beehiiv.com/api-reference/posts/create
  • Send API Guide: https://beehiivhelp.zendesk.com/hc/en-us/articles/36759164012439

GitHub Documentation:

  • Actions: https://docs.github.com/en/actions
  • Secrets: https://docs.github.com/en/actions/security-guides/encrypted-secrets

Project Documentation:

  • Script README: scripts/README.md
  • Plan Document: .claude/plans/nested-greeting-wirth.md

Getting Help:

  • Beehiiv API issues → Contact Beehiiv support
  • Script errors → Check script logs, review TODOs
  • GitHub Actions issues → Check workflow logs

Success Criteria

You’ll know the integration is complete when:

✅ All 5 existing posts cross-posted to Beehiiv ✅ New posts automatically sync within 5 minutes of push ✅ Images display correctly in Beehiiv ✅ No duplicate content SEO issues (“Remove Indexing” enabled) ✅ State file tracks all synced posts ✅ Zero manual work required for publishing


Next Steps

Start here:

  1. Request Beehiiv Enterprise API access (Task #1 above)
  2. Wait for approval
  3. Return to this document and continue with Task #2

Track your progress: Check off items as you complete them.

</div> </article> ` - Page/post content

  • Theme Documentation - Page/post title
  • `` - Post date
  • `` - Post category
  • Michael Rogers - Site title from _config.yml

Using Includes

Reusable components are in _includes/ and can be included in layouts:

<header class="site-header">
  <div class="wrapper">
    <a class="site-title" href="/">Michael Rogers</a>

    <nav class="site-nav">
      
        
        
          <a href="/about/">About</a>
        
      
    </nav>
  </div>
</header>

<div class="post-meta">
  <time datetime="">
    
  </time>
</div>

<footer class="site-footer">
  <div class="wrapper">
    <p class="tagline">Individuals surprise. Populations rhyme.</p>

    <div class="social-links">
      <!-- X/Twitter -->
      <a href="https://x.com/_mrogers" aria-label="X (Twitter)" target="_blank" rel="noopener noreferrer">
        <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
          <path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/>
        </svg>
      </a>

      <!-- LinkedIn -->
      <a href="https://linkedin.com/in/mrogerslondon" aria-label="LinkedIn" target="_blank" rel="noopener noreferrer">
        <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
          <path d="M19 3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h14m-.5 15.5v-5.3a3.26 3.26 0 0 0-3.26-3.26c-.85 0-1.84.52-2.32 1.3v-1.11h-2.79v8.37h2.79v-4.93c0-.77.62-1.4 1.39-1.4a1.4 1.4 0 0 1 1.4 1.4v4.93h2.79M6.88 8.56a1.68 1.68 0 0 0 1.68-1.68c0-.93-.75-1.69-1.68-1.69a1.69 1.69 0 0 0-1.69 1.69c0 .93.76 1.68 1.69 1.68m1.39 9.94v-8.37H5.5v8.37h2.77z"/>
        </svg>
      </a>
    </div>
  </div>
</footer>

Development Workflow

Local Development

1. Install dependencies:

bundle install

2. Start the Jekyll server:

bundle exec jekyll serve

3. Visit the site:

Open http://localhost:4000 in your browser

Making Style Changes

  1. Edit SCSS files in the _sass/ directory
  2. Jekyll watches for changes and rebuilds automatically (usually takes 1-2 seconds)
  3. Refresh your browser to see the updates
  4. No need to restart the server for style changes

Hot Reload:

  • SCSS changes: Automatic rebuild
  • Layout/include changes: Automatic rebuild
  • Config changes: Requires server restart

Testing Changes

Before committing style changes:

  1. Test responsive breakpoints - Resize browser to test mobile, tablet, desktop views
  2. Test all page types - Check homepage, blog posts, static pages
  3. Verify typography - Ensure headings, paragraphs, lists render correctly
  4. Check components - Test avatars, badges, navigation, footer
  5. Test color contrast - Ensure text is readable on all backgrounds

Deployment

The site deploys automatically via GitHub Pages:

  1. Commit your changes:
    git add .
    git commit -m "Update theme styles"
    
  2. Push to the main branch:
    git push origin main
    
  3. GitHub Pages builds and deploys automatically (usually takes 1-2 minutes)

  4. Visit https://mrogers.london to see your changes live

Note: The site uses the github-pages gem to ensure local development matches GitHub’s build environment exactly.

Asset Organization

Images

Storage Location: assets/images/

Organization:

  • Post-specific images: assets/images/[post-slug]/image.jpg
  • Site-wide images: assets/images/ (avatar, logo, etc.)

Naming Conventions:

  • Use lowercase filenames
  • Use hyphens for spaces (e.g., my-post-hero.jpg)
  • Be descriptive: financial-markets-chart.jpg not image1.jpg

Optimization:

  • Compress images before committing
  • Recommended max width: 1200px for blog post images
  • Use appropriate formats: JPG for photos, PNG for graphics with transparency
  • Consider WebP with JPG/PNG fallbacks for better performance

Referencing in Posts:

![Alt text](/assets/images/post-slug/image.jpg)

CSS Assets

Location: assets/css/main.scss

This is the only CSS file that should exist in assets/css/. All other styles should be added to the modular partials in _sass/.

Never:

  • Add inline styles in HTML
  • Create additional CSS files in assets/css/
  • Use <style> tags in layouts

Always:

  • Edit SCSS partials in _sass/
  • Use variables for colors and spacing
  • Follow the modular structure

Troubleshooting

Common Issues

Issue: Styles not updating

  • Solution: Hard refresh your browser (Cmd+Shift+R on Mac, Ctrl+Shift+R on Windows)
  • Check that Jekyll rebuild completed without errors
  • Verify you edited the correct SCSS file

Issue: Broken layout after changes

  • Solution: Check the terminal for Jekyll build errors
  • Validate your SCSS syntax
  • Ensure you didn’t accidentally delete required CSS classes

Issue: Fonts not loading

  • Solution: Check the Google Fonts import URL in assets/css/main.scss
  • Verify font names match exactly in the import and variables
  • Check browser console for font loading errors

Issue: Local site doesn’t match production

  • Solution: Ensure you’re using bundle exec jekyll serve (not just jekyll serve)
  • Update gems: bundle update
  • Check that _config.yml settings match

Getting Help

If you encounter issues:

  1. Check Jekyll build output for specific error messages
  2. Validate your SCSS syntax
  3. Review recent changes in git: git diff
  4. Check browser console for JavaScript/CSS errors

Additional Resources