Skip to content

Implement theme system#514

Merged
compscidr merged 8 commits intomainfrom
feature/theme-system
Mar 17, 2026
Merged

Implement theme system#514
compscidr merged 8 commits intomainfrom
feature/theme-system

Conversation

@compscidr
Copy link
Collaborator

Summary

Introduces a WordPress-style theme system. Templates and theme-specific CSS now live in themes/{name}/ directories, and the active theme is configurable via the theme admin setting.

Directory structure

themes/
  default/
    templates/        # All HTML templates
      header.html
      footer.html
      admin_nav.html  # NEW: shared admin navigation (was duplicated 9x)
      post.html
      home.html
      ...
    static/           # Theme CSS/assets (served at /theme/)
      css/
        goblog.css

How to create a new theme

  1. Copy themes/default/ to themes/my-theme/
  2. Customize the templates and CSS
  3. Set the theme setting to my-theme in admin settings
  4. Restart the server

Changes

  • Move all templates from templates/themes/default/templates/
  • Move www/css/goblog.cssthemes/default/static/css/goblog.css
  • Load templates from themes/{active_theme}/templates/ based on the theme setting
  • Serve theme static files at /theme/ URL path
  • Extract duplicated admin nav into shared admin_nav.html partial — was copy-pasted across 9 admin templates with hardcoded active states. Now uses JS to highlight the active link based on the current URL.
  • Add theme setting to seed defaults (value: "default")

What stays in www/

General static assets that aren't theme-specific: favicon, images, uploads, admin-script.js, site.webmanifest, etc.

Closes #481

Test plan

  • All existing tests pass
  • Start server — templates load from themes/default/
  • CSS loads from /theme/css/goblog.css
  • Admin nav highlights the correct active page
  • Copy themes/default/ to themes/custom/, change something, set theme=custom — custom theme loads

🤖 Generated with Claude Code

Move templates and theme CSS into themes/default/ directory structure,
making it possible to create alternate themes by adding new theme
folders and switching via the "theme" setting.

Structure:
  themes/{name}/templates/*.html  - Template files
  themes/{name}/static/           - Theme CSS/assets served at /theme/

Changes:
- Move all templates from templates/ to themes/default/templates/
- Move goblog.css from www/css/ to themes/default/static/css/
- Load templates from themes/{active_theme}/templates/ based on
  the "theme" setting (defaults to "default")
- Serve theme static files at /theme/ path
- Extract duplicated admin nav into shared admin_nav.html partial
  (was copy-pasted across 9 admin templates with different active
  states). Active link now highlighted via JS based on current URL.
- Add "theme" setting to seed defaults

Closes #481

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 16, 2026 23:09
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a theme-based template/static loading mechanism (with a new default theme) and adds a set of new HTML templates for the blog, admin UI, and install wizard flows.

Changes:

  • Add a theme setting and load templates/static assets from themes/<theme>/... (defaulting to default).
  • Introduce the themes/default theme (templates + CSS) including install wizard pages and multiple blog/admin pages.
  • Refactor admin navigation into a shared admin_nav.html include.

Reviewed changes

Copilot reviewed 15 out of 41 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tools/migrate.go Seeds a new default theme setting (default).
goblog.go Loads templates from the active theme directory and serves theme static assets under /theme/.
blog/blog_test.go Updates test template glob path to the new default theme templates.
admin/admin_test.go Updates test template glob path to the new default theme templates.
themes/default/static/css/goblog.css Adds theme-specific CSS (now served via /theme/css/goblog.css).
themes/default/templates/header.html Updates stylesheet path to /theme/css/goblog.css.
themes/default/templates/footer.html Adds new footer layout and “Most Recent Post” section.
themes/default/templates/admin_nav.html New shared admin navigation partial + active link script.
themes/default/templates/admin.html Switches to using admin_nav.html.
themes/default/templates/admin_all_posts.html Switches to using admin_nav.html.
themes/default/templates/admin_dashboard.html Switches to using admin_nav.html.
themes/default/templates/admin_new_post.html Switches to using admin_nav.html.
themes/default/templates/admin_pages.html Switches to using admin_nav.html.
themes/default/templates/admin_edit_page.html Switches to using admin_nav.html.
themes/default/templates/admin_post_types.html Switches to using admin_nav.html.
themes/default/templates/admin_edit_post_type.html Switches to using admin_nav.html.
themes/default/templates/admin_settings.html Switches to using admin_nav.html.
themes/default/templates/wizard_db.html New DB setup wizard page with AJAX “test DB”.
themes/default/templates/wizard_settings.html New settings wizard page that posts settings via JS.
themes/default/templates/wizard_auth.html New GitHub OAuth wizard page for client id/secret.
themes/default/templates/wizard_success.html New wizard completion page with timed redirect.
themes/default/templates/home.html New home/landing page template.
themes/default/templates/login.html New login page template with GitHub OAuth flow script.
themes/default/templates/post.html New post view template with markdown rendering + comments UI.
themes/default/templates/post-admin.html New post admin editor template with preview + revisions.
themes/default/templates/posts.html New posts listing template.
themes/default/templates/search.html New search page template and results listing.
themes/default/templates/tags.html New tags index template.
themes/default/templates/tag.html New single-tag listing template.
themes/default/templates/archives.html New archives index template.
themes/default/templates/page_archives.html New archives page template variant using year/month groupings.
themes/default/templates/page_content.html New generic “page markdown content” renderer template.
themes/default/templates/page_research.html New research page template variant.
themes/default/templates/page_tags.html New tags page template variant.
themes/default/templates/page_writing.html New writing page template listing posts.
themes/default/templates/post_type_listing.html New post-type listing template.
themes/default/templates/research.html New research/publications template.
themes/default/templates/projects.html New projects page template (video hero + placeholder text).
themes/default/templates/presentations.html New presentations/speaking template (placeholder text).
themes/default/templates/about.html New about page template content.
themes/default/templates/error.html New error page template.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

compscidr and others added 7 commits March 16, 2026 16:19
A clean, modern theme with visual differences from the default:
- Inter sans-serif font instead of Source Code Pro monospace
- Blue accent color (#2563eb) instead of gray
- Rounded corners on inputs and buttons
- Simplified home page layout
- Streamlined footer with narrower content width
- Slate-colored footer bar instead of dark gray

To test: set the "theme" setting to "minimal" and restart.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Scan themes/ directory for available themes and display as a
  dropdown in admin settings instead of a text input
- Hot-reload templates when theme setting changes via OnThemeChange
  callback — no server restart required
- Serve theme static files dynamically based on active theme so
  CSS switches immediately too
- Handle <select> elements in settings JS to preserve "text" type

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Header: horizontal nav bar with site name as text (not logo box),
  blue accent border, flexbox layout instead of centered float
- Posts listing: narrower content column (720px), article cards with
  bottom borders, long-form date format, no video hero
- Single post: narrower column, larger h1 title, horizontal rule
  separator, increased line-height for readability
- Footer: subtle top border, narrower "Latest" section, short date

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Landing page:
- Squared profile image (not circle) with side-by-side name layout
- Two-column layout: recent posts list + tag cloud
- No socials on landing page (moved to footer only)

Header:
- Light gray background bar with 1px border (no logo box)
- Site initials as text link, nav links inline, search on the right

Pages:
- No hero images/videos — clean text-only layouts
- Narrower 720px content column throughout

Footer:
- Light gray background with socials + powered-by in a row
- No "Most Recent Post" section (landing page handles this)

Also fix hardcoded "Software Engineer" title in Home handler — now
uses site_subtitle setting. Pass recent_posts and tags to home
template so themes can use them.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add getTopTags(n) that sorts tags by number of associated posts
(most popular first) and limits to n. The home page now shows
the 20 most-used tags instead of all tags.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ath traversal

Minimal theme login:
- Clean centered card with "Sign In" heading and "Continue with GitHub"
  button instead of circle photo + social button
- Uses site_title setting in the description text

Default theme login:
- Replace hardcoded img/jason.jpg with landing_page_image setting
- Replace hardcoded "Jason Ernst" alt text with site_title setting

Security:
- Sanitize theme static file path with filepath.Clean and filepath.Join
  to prevent path traversal via ../

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…atching

- Guard GetSettings() call with IsDbNil() check so the server can
  start before DB is configured (install wizard flow)
- Validate theme names: only allow alphanumeric/hyphens/underscores,
  verify the theme directory exists on disk before loading
- Fall back to default theme with a warning if the configured theme
  is invalid or fails to parse
- Admin nav now highlights parent sections for nested pages
  (e.g. /admin/pages/123 highlights the Pages tab) using prefix
  matching, with dashboard excluded to avoid false matches

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@compscidr compscidr merged commit 00e77db into main Mar 17, 2026
1 check passed
@compscidr compscidr deleted the feature/theme-system branch March 17, 2026 00:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

implement a templating system

2 participants