HarborFM

Page Themes

Public shows use the default React SPA feed unless you pick a page theme under Page Customizations. Packaged themes are Liquid templates with CSS, optional images/fonts, and HarborFM mount points for interactive blocks (episodes, player, cast, reviews, and so on).

For show-level toggles (accent, which blocks appear), see Podcasts: Page Customizations. For listener-facing feed behavior, see Public feeds and embed.

Choosing a Theme

  1. Open the show and click Page Customizations.
  2. Pick a Page Theme:
    • Default HarborFM - built-in React feed layout.
    • Server-wide themes - Fluid, Folio, and any theme an admin has promoted.
    • Imported themes - packages you imported under Themes (on podcasts you own).
  3. Optionally set Primary Color and visibility toggles (author, descriptions, funding, podroll, cast, reviews, and related blocks).

The picker shows package preview images when the theme provides one. When a theme sets homepage in theme.json, Preview opens that live URL.

Visibility toggles and accent color apply to both Default and packaged themes. Packaged themes can read accent colors and show.* flags in template context.

Themes Studio

Users with Can Import Theme can open Themes to:

  • Browse Server Themes (preview thumbnails, description, live Preview when homepage is set)
  • Download a server theme as a zip
  • Import a theme zip (max 10 MB; rate limited to 2 per minute per user)
  • Edit an imported copy in the near-fullscreen theme editor (name, version, home template, page routes, Liquid/CSS/images/fonts)

Re-importing the same theme.json id updates that theme in place (including personal copies of server-wide themes). Theme files count toward the account storage limit.

Assigning a server-wide theme id uses the data-backed server package. To use your fork, pick your imported copy’s row in Page Customizations.

Admins

Admins can promote a personal theme to a server-wide theme (available to every show), demote it back, delete server themes, and edit server theme files. Admin edits and promote set allowOverride: false so customized server themes are not overwritten on upgrade.

Built-Ins and Storage

Fluid and Folio ship with HarborFM and are seeded into {DATA_DIR}/themes/server on first boot. Folio is multi-page (home plus about, crew, support, connect, episodes). Both include preview images, homepage demo links, and optional not_found templates for unknown theme .html routes.

On upgrade, HarborFM replaces a data copy only when its theme.json still allows override (default) and the shipped version differs. Packages under {DATA_DIR}/themes/server persist across Docker image updates.

Gallery and Authoring Docs

Community/gallery themes (with previews) are published from harborfm-themes and listed on the docs Themes page.

Authoring guides:

Local developers can clone harborfm-themes/ next to the HarborFM tree and run pnpm themes:sync to copy gallery packages into {DATA_DIR}/themes/server. See the main README.

Package Layout

theme.json                 required (id, name, version; optional fields below)
templates/podcast.liquid   required
templates/episode.liquid   required
templates/*.liquid         optional extra pages and _partials
css/                       optional (*.css; all auto-linked)
images/                    optional (png, jpg, jpeg, gif, webp)
fonts/                     optional (.woff2, .ttf)

Optional theme.json fields:

Field Purpose
description Short blurb for Themes cards and the gallery
preview Path under images/ for picker / gallery cards
homepage https URL for live Preview
index Home template basename (default podcast)
pages Map template basename → public .html filename
not_found Template for unknown theme pages (HTTP 404; not a public page)
allowOverride When false, shipped upgrades do not overwrite this server theme

Extra templates become /feed/{slug}/{page}.html (or /{page}.html on a custom domain). Theme pages are included in the podcast sitemap.

Mounts and Actions

Interactive HarborFM blocks use Liquid mounts:

{% render 'harborfm/episodes' %}
{% render 'harborfm/player' %}
{% render 'harborfm/search' %}
{% render 'harborfm/reviews' %}
{% render 'harborfm/cast' %}
{% render 'harborfm/funding' %}
{% render 'harborfm/links' %}
{% render 'harborfm/podroll' %}
{% render 'harborfm/site_header' %}
{% render 'harborfm/show_header' %}
{% render 'harborfm/breadcrumbs' %}

Put harborfm/episodes on exactly one page. Themes can also wire native controls:

<button type="button" data-harborfm-action="subscribe">Subscribe</button>
<button type="button" data-harborfm-action="share">Share</button>
<a href="{{ podcast.rss_url }}" data-harborfm-action="feed">RSS</a>
<button type="button" data-harborfm-action="message">Message</button>
<button type="button" data-harborfm-action="alerts">Alerts</button>
<button type="button" data-harborfm-action="write-review">Write a review</button>

Unavailable actions are hidden automatically.

Script tags, event handlers, javascript: URLs, and the Liquid | raw filter are rejected on import.

Liquid Context and Styling

Useful context includes podcast, episode / episodes, cast, funding_links, links, podroll, reviews, theme (id/name/version/homepage), accent (including accent.fg for text on accent), show (visibility booleans), urls (home, pages, theme_asset_base), site, and page.

Accent CSS variables include --accent, --accent-dim, --accent-glow, and --accent-fg.

Dialogs (Message, Get Alerts, Share, Subscribe, Write Review) render under themed chrome so theme CSS can style them, for example:

[data-harborfm-dialog="feedback"] { /* Message */ }
[data-harborfm-dialog="alerts"] { /* Get Alerts */ }
[data-harborfm-dialog="share"] { /* Share */ }
[data-harborfm-dialog-overlay="feedback"],
[data-harborfm-dialog-overlay="alerts"] { /* backdrop */ }

Theme partials (templates/_nav.liquid, etc.) use {% render %} with an isolated scope. Pass context explicitly:

{% render '_nav', urls: urls, podcast: podcast, site: site, page: page %}

Who Can Import Themes

  • defaultCanImportTheme (Settings > Default Limits) - whether newly registered users can import and edit themes. Default is on.
  • canImportTheme (Users admin) - per-user flag. When off, that user cannot import, download, or edit theme files (403). Selecting a built-in or server theme on a show they manage still works when the theme is available.

See Admin and settings.

See Also