Configuration reference
Every knob the theme exposes. Hugo reads hugo.toml [params]; Astro reads src/config.ts, same keys, same meaning.
Site identity
title, tagline, description, brandName + brandSub (the two-line wordmark in the header), logo, ogImage, and landAcknowledgement (footer slot, leave empty to hide).
[params]
tagline = "A friendly coding meetup"
brandName = "Rocky Cove"
brandSub = "Aquarium Club"
logo = "images/logo.png"
landAcknowledgement = "…"
export const SITE = {
title: 'Rocky Cove Aquarium Club',
tagline: 'A friendly coding meetup',
brandName: 'Rocky Cove',
brandSub: 'Aquarium Club',
logo: '/images/logo.png',
landAcknowledgement: '…',
};
Brand tokens
The whole visual identity, one block. Only primary is required to re-brand; the rest have sensible defaults. See Theming for how derived tints work.
| Key | What it controls |
|---|---|
primary / primaryHover / primaryActive | buttons, links, accents |
link / linkHover | prose link color, when the default (derived from primaryActive) lacks contrast against body text |
secondary | secondary buttons, persona accents |
accent | occasional highlights |
accentHover | accent-button hover (defaults to a darkened accent) |
ink | headings & dark text |
surfaceWash / surfaceWashSoft | hero wash & soft bands |
surfaceInk | footer / dark strips |
fontSans / fontDisplay | body & display faces |
radiusCard, containerMax | card corners, page width |
surfacePage / surfaceCard / surfaceTertiary / textBody / textMuted / textOnBrand / borderSubtle | dark-palette keys: page & card backgrounds, body/muted text, filled-button text, borders. Set these (plus the surfaces above) to run the theme on a dark background |
Navigation & CTA
Top menu = standard Hugo menu ([[menu.main]]). Header button = [params.cta] (label, url, icon).
Top menu = NAV array. Header button = CTA (label, url, icon).
Footer, socials, support box
footer.tagline+footer.columns: link columns (they lay out side by side and wrap on small screens)social: icon links in the footer. Any Font Awesome class works, so adding a channel is one entry:
[[params.social]]
label = "YouTube"
icon = "fa-brands fa-youtube"
url = "https://youtube.com/@yourcommunity"
[[params.social]]
label = "TikTok"
icon = "fa-brands fa-tiktok"
url = "https://tiktok.com/@yourcommunity"
[[params.social]]
label = "Mastodon"
icon = "fa-brands fa-mastodon"
url = "https://fosstodon.org/@yourcommunity"
[[params.social]]
label = "RSS"
icon = "fa-solid fa-rss"
url = "/blog/index.xml"
export const SOCIAL = [
{ label: 'YouTube', icon: 'fa-brands fa-youtube', url: 'https://youtube.com/@yourcommunity' },
{ label: 'TikTok', icon: 'fa-brands fa-tiktok', url: 'https://tiktok.com/@yourcommunity' },
{ label: 'Mastodon', icon: 'fa-brands fa-mastodon', url: 'https://fosstodon.org/@yourcommunity' },
{ label: 'RSS', icon: 'fa-solid fa-rss', url: '/rss.xml' },
];
support: optional box at the end of every blog post (badge, text, CTAs). Omit / setnullto hide.
Feeds & sharing defaults
These work out of the box, nothing to configure:
- Open Graph / Twitter-card meta tags on every page (title, description, URL, and
ogImageor the page’s ownimage), so links unfurl nicely on social platforms and chat apps. - RSS feed for the blog, advertised via a
<link rel="alternate">tag (feed readers auto-discover it) and a “Subscribe via RSS” link on the blog page. Tell your members they can follow new posts in any feed reader, no account needed.
Hugo generates the feed at /blog/index.xml.
The feed is served at /rss.xml.
Section headers & home page
The home page composition (hero, stats, features, team heading, testimonials, closing CTA) lives in:
content/_index.md front matter: [hero], [[stats]], [featuresHead] + [[features]], [team], [testimonialsHead] + [[testimonials]], [getInvolved].
HOME in src/config.ts (same shape), plus SECTIONS for the blog/events/organizers list-page headers.
Each [[testimonials]] entry takes a quote, name, optional role, and optional photo; delete the block to hide the section.
Beyond those, the home page auto-populates the next upcoming event, the latest three posts, and your organizers from content, no config.
Calendar feed (iCal)
Add Calendar to your events section’s outputs and the theme publishes an
iCalendar feed at /events/calendar.ics that people subscribe to once and
see every future meetup in Google, Apple or Outlook Calendar:
# content/events/_index.md
outputs = ["HTML", "RSS", "Calendar"]
The events list gains a “Subscribe to calendar” link automatically. Timed
events (a parseable time) get a start and a 2-hour default end
([params.events] defaultDurationMinutes); date-only events are all-day.
Cancelled events carry STATUS:CANCELLED. To subscribe, most apps take the
feed URL under “add calendar from URL”. On Astro the feed is always at
/events/calendar.ics, no opt-in needed.
Search-engine basics
The theme emits a robots.txt pointing at your sitemap, plus og:locale
and (when a page has an image) og:image:alt. Optional knobs:
imageAlton any page’s front matter sets theog:image:alttext (defaults to the page title).[params.seo]noindexTaxonomies = trueaddsnoindex,followto tag pages (Astro:SITE.seo.noindexTaxonomies).
A fuller SEO reference (structured data, event rich results) lives on the SEO docs page.
Live counts in the home page stats
The stats strip is the theme’s social-proof pattern: a running “events hosted”
or “years running” count is the quiet evidence that a group is real and
regular. A stat’s value is shown verbatim unless it is one of these computed
tokens, which stay true on their own as your history grows:
@pastEventCount: the number of past events, rounded down to a “70+” style once there are ten or more.@count:<section>: the live number of entries in a section, for example@count:blogor@count:events.@count:<section>:rounded: the same count, rounded down to “70+” at ten or more (podcast-style exact counts stay exact without:rounded).
[[stats]]
value = "@count:blog"
label = "posts"
On Hugo the resolver is partials/stat-value.html, reusable from any
template; on Astro it is formatStat in src/lib/stats.ts.
Renaming content sections
If your community’s people are not “organizers” and your blog is not written
by “authors”, rename the sections the theme reads, without overriding any
template. In hugo.toml:
[params.sections]
authors = "hosts" # resolve post-author bylines against content/hosts/
team = "hosts" # show the content/hosts/ people in the homepage team grid
Both default to the theme’s own names (authors, organizers). authors
drives the byline links and author bio cards on posts; team drives the
homepage team grid and its “All organizers” button. Rename the matching
content directory to suit (content/authors/ becomes content/hosts/).
On the Astro side the equivalent lives in config.ts as SECTIONS_MAP
({ authors: 'hosts', team: 'hosts' }); the value names a collection that
must exist in your content.config.ts.
Extra head markup (analytics and friends)
The theme core ships no analytics. To add a tracking snippet, verification
tag, or any other head-level markup, create layouts/partials/head-extra.html
in your site: the theme includes it at the end of <head> and ships it empty,
so your version wins without overriding the whole head partial.
Translating the UI
All template strings (section headings, buttons, badges, empty states, dates) are translatable; content is whatever language you write it in.
Set defaultContentLanguage in hugo.toml, at the top level above any
[section]: it drives both <html lang> and date formatting. Then create
i18n/<lang>.toml in your site root and override any key from the theme’s
i18n/en.toml; you only need the keys you want to change.
Set SITE.locale in src/config.ts (drives <html lang> and date
formatting), then edit the values in the STRINGS block. Keys match the Hugo
theme’s i18n/en.toml one to one.
One site, one language: multilingual sites (several languages with a language switcher) are not supported yet.
Demo bar
demoBar (Hugo) / DEMO_BAR (Astro) renders the floating demo switcher on the theme’s own demo builds. Never set it on a real site and it never appears.