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).
  4. Optionally set a Meta Pixel ID. Public podcast and episode pages load the pixel; when the site consent banner is enabled, it loads only after analytics consent.

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