Releases: Mariatta/hugo-theme-popular
Release list
Popular v0.11.0
Added
- Every page says which generator built it, via
<meta name="generator">
(hugo.Generatoron Hugo,Astro.generatoron Astro). Astro does not inject
this itself, and it is what the Astro theme catalogue's reviewers look for
when verifying that a demo really is an Astro site. [module.hugoVersion]in the Hugo theme'shugo.toml, declaring the
0.146.0 floor where themes.gohugo.io's build actually reads it.theme.toml's
min_versionis the older field, from the retiredhugoThemesrepo; both are
kept in step. A site built with an older Hugo now says so, rather than the
floor being a claim nothing checked.npm create popular-site@latest, a scaffolder for Astro sites (packaging
phase 3). It writes a small project that depends on the theme rather than
containing a copy of it, so the site updates withnpm updateinstead of by
diffing tags and re-copying files. Pick the neutral starter or any of the
four demos as a fuller example to edit down.- The templates are collected from
demos/*at pack time, so the demos stay
the single source of truth and there is no committed copy to drift. The
demo switcher bar is stripped on the way, and CI fails if it ever reaches
a scaffolded site. - A project-page URL like
https://you.github.io/my-community/is split into
Astro'ssiteandbasefor you, the same splitscripts/setup.pydoes. - Releases now publish two npm packages:
astro-theme-popularand
create-popular-site, versioned in lockstep so a scaffolded site always pins
the theme release that shipped with it.
- The templates are collected from
Changed
-
A Popular deployment now loads nothing from a third party at all. The
superfan demo was the last exception: it pulled Cinzel from Google Fonts
throughcustomCSSfor its display face. It uses the bundled Quantico like
the other demos now, so no page of the theme, its demos or its docs sends a
visitor's IP anywhere.customCSSitself is unchanged and still takes any
stylesheet URL you want, including a CDN. -
npm create popular-site@latestrenders the same project templates the
setup wizard does (scripts/templates/), instead of carrying its own copies
ofastro.config.mjs,package.jsonandcontent.config.ts. Two generators
writing the same file two ways is how they drift, and one had already started:
the wizard's template still defaulted to an older theme version. -
The release smoke-tests what it published: after both packages reach the
registry it scaffolds a site from them and builds it. The scaffolder's own CI
installs the theme from the checkout, which is right for a pull request but
cannot catch a mismatch between two published versions. That gap is exactly
what brokecreate-popular-site@0.10.0, whose templates needed a newer theme
than it pinned; it is deprecated. -
The Astro README and the quick start lead with the scaffolder. The README
still describednpm run demo:aquariumas switching the active demo set into
src/, which stopped being true when the demos became workspaces, and the
quick start still told Astro users to use the repo as a template. -
The Astro demo deployment serves the neutral starter at its root, with the
four flavored demos still at their subpaths and the gallery landing page moved
to/demos/. The root used to be the gallery, a hand-written HTML page that is
not an Astro build at all, so the URL people are given demonstrated nothing and
could not be verified as an Astro site. It is now exactly what
npm create popular-site@latestwrites.- The gallery gets its icons and fonts from the deployment instead of cdnjs and
Google Fonts, so the landing page stops being the one page that loads a third
party.
- The gallery gets its icons and fonts from the deployment instead of cdnjs and
-
Astro: the demos are now real consumers of the npm package (packaging
phase 3). The repo is an npm workspace, and each of the five demos is a
project with its ownpackage.json,astro.config.mjs,popular.config.ts,
src/content/andpublic/images/, installing the theme the way an adopter
does.scripts/use-demo.mjsand the copy-a-demo-into-src/step are gone;
npm run dev --workspace demos/aquariumreplaces activation.- The demo deployment and the image-alt job became integration tests.
Both now build five real consumers against the packaged theme instead of
one copied-together site, so a package regression fails CI rather than
surfacing after publish. - Nothing changes for anyone using the theme. The template model (
src/)
keeps working until the cutover, and the Hugo side is untouched.
- The demo deployment and the image-alt job became integration tests.
-
Web fonts are served by the site itself, not fetched from
fonts.googleapis.com. Inter and Quantico now ship in the theme
(static/fonts/⇄src/styles/fonts/), 716KB of woff2 under their SIL Open
Font Licences. Nothing about the rendering changes: the vendored files are
exactly the subsets and weight ranges Google was serving.- This removes a GDPR exposure. Embedding Google Fonts sends every
visitor's IP address to Google, which a German court held to violate the
GDPR (LG München I, 3 O 17493/20). A community site should not have to
think about that. - It is also faster, not slower. The partitioned browser cache has meant no
cross-site reuse since 2020, and the old@importadded a DNS lookup, a
TLS handshake and a round trip before any font could start downloading. - Every face keeps its
unicode-range, so all seven Inter subsets ship but a
latin-only page still downloads about 150KB of them. Greek, Cyrillic and
Vietnamese sites now render in Inter instead of falling back. - Sites that prefer a CDN, or a different family entirely, override
fonts.cssthe same way as before.
- This removes a GDPR exposure. Embedding Google Fonts sends every
-
Font Awesome is served by the site itself, not fetched from cdnjs. A
Popular site now renders its icons offline, keeps working when a CDN has an
outage or changes a URL, and no longer hands every visitor's IP address to a
third party the community never chose. Font Awesome Free 7.3.1 ships in
the theme (static/fontawesome/⇄public/fontawesome/), about 364KB of
woff2 and one stylesheet, under its ownLICENSE.txt.params.fontAwesome/SITE.fontAwesomeis now optional: leave it
unset for the bundled copy, or set it to a URL to use a CDN as before.
Existing sites that set it keep working unchanged.- The version moves from 6.5.2 to 7.3.1. Every icon the theme and its demos
use exists in 7.3.1 in the same style, but an adopter naming an icon that
7.x removed would see a blank square, so check any icon you named yourself. - Sites generated by
scripts/setup.pyno longer pin the CDN URL in their
config, so they follow the theme.
Fixed
- Astro package model: an adopter's
SITE.fontAwesomenow resolves against
the base, so a site-relative path survives a subpath install. It was
written to the page raw, unlike every other URL the theme emits. The subpath
guard in CI could not see it because leaving the key unset renders no link at
all; a smoke variant now sets it. - The demo configs no longer pin
fontAwesometo/fontawesome/…. That
path is the template model's default and does not exist in the package model,
which bundles the stylesheet instead, so every page of every demo requested a
stylesheet that 404'd. Icons rendered anyway, from the bundled copy, which is
why it went unnoticed. Leaving the key unset is and was the correct setting.
Popular v0.10.0
Added
scripts/starter-content.py, the companion to the setup wizard: it copies
the theme's starter content (a post, an event, an organizer, a speaker, a
venue, the handbook and runbooks) into a new site, never overwriting anything
that is already there.- The wizard can write an Astro site that consumes the npm package, not only
one that vendors this repo:--astro-model packagewrites
popular.config.ts, apackage.jsonpinned to the current release, a
one-linesrc/content.config.ts, and anastro.config.mjsusing the
integration. The result is a small repo that updates withnpm updaterather
than by re-copying files.--astro-model template(the default, and what an
existing site detects as) is unchanged. - The setup wizard asks for a brand colour, optionally. One hex is enough:
the theme derives badges, tags, hovers and link states from it, so answering
#fa023cwrites[params.brand].primary(Hugo) orBRAND.primary(Astro)
and the whole site follows. Skipping it writes nothing at all and leaves the
default palette in place, which keeps a first run adoptable without--force.
Answers are validated as#rgbor#rrggbb, a newcolorquestion type in
the shared schema. - A preview banner for generators (
partials/preview-bar.html⇄
components/PreviewBar.astro). Setparams.previewMode/SITE.previewMode
and the page carries a fixed "this is a preview" bar, with an optionalnote
for things like an expiry. It is meant for a tool that renders a site on
someone's behalf and shows it in an iframe. Nothing the setup wizard writes
into a real site's config sets the flag, and CI in both repos fails if the
banner turns up in a build that did not ask for it. - The setup wizard now writes everything a GitHub Pages deployment needs.
Answer the site-URL question with a project-page URL
(https://you.github.io/my-community/) andscripts/setup.pywrites a site
that works there:- Astro gains a generated
astro.config.mjscarryingsiteandbase.
Astro needs the origin and the subpath as separate keys and nothing wrote
basebefore, so a project-page site 404'd every internal link. They are
derived from the singlebase_urlanswer, so the schema is unchanged and
no one is asked the same thing twice. - Both frameworks gain
.github/workflows/deploy.yml, a parameterless
GitHub Pages workflow (everything that varies lives in the config the
wizard already wrote). It is skipped when the site already has workflows
of its own, so it never fights an existing deployment. Set Settings ->
Pages -> Source: GitHub Actions once, and pushes tomainpublish.
- Astro gains a generated
- Astro:
popular-markdown.mjs, the markdown hooks (lazy images, base-aware
links) as a proper integration in the template model, matching what the npm
package already does. Because an integration receives the resolved config,
astro build --base /elsewhere/now applies to markdown bodies too, where the
old config-file hook silently kept the old base.
Changed
- The Astro demo deployment builds each demo with Astro's
baseinstead of
rewriting the built HTML withsed. The rewrite predated base support and
could never reach the absolute URLs, so a deployed demo's canonical,
og:imageand JSON-LD all pointed at the site root. Both the Pages workflow
and the Netlify preview build now runscripts/build-sites.mjs, so a preview
cannot differ from production. - The preview banner can be switched on from the environment, for a
generator that owns the build but not the config:HUGO_PARAMS_PREVIEWMODE_NOTE
(Hugo) orPOPULAR_PREVIEW_NOTE(Astro). Setting either enables the banner and
supplies its note.
Popular v0.9.1
Fixed
- The docs sidebar scrolls when it outgrows the window. On a long page the
current entry nests every heading beneath it, which makes the sticky sidebar
taller than the viewport, and a sticky element taller than the viewport
cannot be scrolled: the entries below the fold, including the links to the
other docs pages, were unreachable until you had scrolled through the whole
article. The sidebar now stops at the bottom of the window and scrolls on its
own, and the scroll-spy keeps the highlighted entry in view as you read.
Popular v0.9.0
Added
- Base-aware URL helpers, as public surface. Astro:
withBase()and
absoluteUrl()fromsrc/lib/url.ts, exported by the package as
astro-theme-popular/url. Hugo:rel-src.html(images and assets) and
abs-url.html(absolute URLs) join the existingrel-href.html. Use them
for any URL your own components, overrides or templates emit, and a subpath
install keeps working. The Astro template repo'sastro.config.mjsgained a
baseconstant at the top: leave it'/'for a site at a domain root.
Fixed
- Sites served from a subpath now work in both themes. A site deployed to
user.github.io/repo/(Astrobase, HugobaseURLwith a path) built and
styled correctly but every internal link and image stayed at the server root
and 404'd. Both frameworks rewrite the asset URLs they generate themselves,
and neither touches the paths a template writes, so those had to be resolved
explicitly.- Astro: new
withBase()/absoluteUrl()helpers (lib/url.ts, exported
from the package asastro-theme-popular/url) now resolve every URL the
theme emits: navigation, cards, tags, pagination, the brand link, images
from config and front matter, the shared behaviour scripts, and the
absolute URLs in canonical,og:image, JSON-LD, RSS,llms.txt,
robots.txtand the iCalendar feed. Markdown bodies are handled by a hook
the integration registers on the active Markdown processor. - Hugo:
rel-href.htmlnow has a sibling,rel-src.html, for images and
assets, plusabs-url.htmlfor absolute URLs. Front matter written the
Astro way (image = "/images/x.png") previously lost the subpath, because
relURL/absURLtreat a leading slash as the server root. Card, hero,
logo, favicon, avatar and body images, the JSON-LDurl/logo/image
fields andog:imageall go through them now. - Adopter configs and content need no changes: the helpers pass external
URLs,mailto:,tel:and#fragmentthrough untouched, and accept
paths written with or without a leading slash. - Both repos build a subpath site in CI and fail on any internal
hrefor
srcleft at the root (PARITY.md, "Subpath deployments").
- Astro: new
- Astro package: markdown images regained
loading="lazy" decoding="async".
Astro 7's default Markdown processor does not run rehype plugins, and a
plugin added by an integration after config validation was dropped silently
(Astro warned on every build). The theme's hooks are now registered on the
active processor, in that processor's own plugin shape.
Popular v0.8.1
Changed
- The setup wizard now adopts an unedited starter file automatically. On a fresh
site (copied fromexampleSiteor a demo, or the Astro template), it writes
the config and Code of Conduct seed page without--force, because their bytes
still match what the theme shipped. The moment you hand-edit either one, the
wizard protects it again and asks for--force. First-time setup no longer
needs a flag.
Popular v0.8.0
Added
- Setup wizard (
scripts/setup.py): a stdlib, zero-dependency script that reads
the shared question schema (setup-questions.json) and writes a site's config,
a Code of Conduct seed page, aDECISIONS.mdaudit trail (what was decided,
with handbook citations, and what is still open) and a.popular-setup.json
answer record. Sugar, never a gate: skip every question and you get the clean
starter config. Runs interactively or non-interactively (--answers file.json)
for the agent and CI paths, detects Hugo vs Astro, and never overwrites an
existing file without--force(--dry-runshows the diff). Works by
placeholder substitution on templates, so it never parses or re-serializes
your config. - "Before you build" worksheet (
/docs/before-you-build/): a docs page that
renders the same question schema as a persistent checklist (decisions to
settle first, then values to have ready), so the worksheet cannot drift from
the wizard. The quick-start is rewritten around the wizard, and both repos'
AGENTS.mdgain a "Setting up a new site for a user" interview protocol.
Popular v0.7.0
Changed
- The footer shows the theme version (e.g.
v0.7.0) next to the Popular
credit, on the demos and the docs site.
Fixed
- The "no upcoming events" empty state no longer renders on event-less sites
such as the docs site; it appears only on a community that has an events
section but nothing upcoming.
Added
- Recaps toolkit:
gallery+photoandpullquoteshortcodes (Hugo) /
Gallery+PhotoandPullquotecomponents (Astro). The gallery is a
CSS-grid figure list with no JavaScript and no lightbox (each photo links to
its full-size image);altis required and a missing one fails the build.
A recap is a blog post taggedrecapthat uses both, with a worked example
in the KDrama demo. llms.txt: a build-time plain-text summary for AI agents at/llms.txt,
naming the next upcoming event, how to join, and links to the key pages and
the calendar feed. Always generated on Astro; on Hugo the site addsLLMS
to its home outputs (the demos, exampleSite, and docs site do).- Docs: the deliberate non-features list (job board, member directory,
comments, photo lightbox) and the stats strip as the social-proof pattern.
Added
- Talk archive. Events gain optional
recording/slides(single-talk
meetups) and atalks[]array (titlerequired;speaker,recording,
slidesoptional); whentalks[]is present it wins over the event-level
fields. The event page renders a Talks section (or inline links for the
simple case), and past-event rows show a recording cue. An opt-in/talks/
archive aggregates every talk newest-first, filterable by the parent event's
tags: enable it withcontent/talks/_index.md(Hugo) orSITE.talks = true
(Astro). New UI stringswatchRecording,viewSlides,hasRecording,
talks,talksLead.
Changed
- Speaker, organizer, and author profile pages no longer repeat the bio: the
page hero is now a compact banner (eyebrow, name, back link) and the bio
lives only in the persona card below it.
Added
- Community chat bridge and speaker pipeline.
params.community.chat = { url, label }adds a "Join the chat" CTA to the home hero, the footer, and
the no-events empty state (platform-agnostic: Discord, Slack, Matrix, Zulip).
The starter ships a "Start here" first-timer page (/start/) and a "Speak
with us" call-for-speakers page (/speak/).params.speakers.invite = true
appends a "Your name here?" card to the speakers list (new strings
speakerInviteTitle,speakerInviteBody), off by default.
Fixed
- Astro: the speakers and venues list pages (
/speakers/,/venues/) were
missing, so the "All speakers" / "All venues" back links on detail pages led
to 404s. Both list pages now exist, mirroring the Hugo templates.
Added
- Notice banner and designed empty states.
params.notice = { text, url? }
renders a static, non-dismissible banner above the header (inline-markdown
text, an optional link, no JavaScript). When there are no upcoming events,
the home page and the events list now render a designed empty state (a
message, the community chat CTA if configured, and the calendar-subscribe
link) instead of a blank section. New UI stringslearnMore,joinChat.
Added
- Venue access & logistics fields:
wheelchair(a badge on the venue and on
events held there),transit,parking, and a freeformaccessnote,
shown as a "Getting there & access" section. Inclusion as a data-model
concern. Matching spreadsheet-importer columns. New UI strings
gettingThere,wheelchairAccessible,transit,parking.
Added
- Calendar feed: an iCalendar (
.ics) feed of events at
/events/calendar.ics, so members subscribe once and every future meetup
appears in their calendar app. Reuses the eventtimeparsing (so the feed
and the Event structured data agree), marks cancelled events, and adds a
"Subscribe to calendar" link to the events list.scripts/check-ics.py
validates it in CI. Hugo: addCalendarto the events section outputs.
Fixed
- Speaker, venue and organizer profile pages now show a back link to their
list (matching blog posts and events); the organizer link follows the
renamed team section. New UI stringsallSpeakers,allVenues,
allOrganizers.
Added
- Astro package: component overrides.
popular({ overrides: { Header: './src/overrides/Header.astro' } })replaces any of Header, Footer, Hero,
EventRow, PostCard, OrganizerCard, AuthorBox, PageHero without forking the
theme. (Hugo adopters already override via native template lookup.)
Popular v0.6.0
Search-engine optimisation: structured data, crawl plumbing, Core Web Vitals,
and an FAQ block. Zero client JavaScript added.
Added
- Structured data (JSON-LD, byte-identical across both frameworks):
schema.org/Eventon event pages (rich-result eligible, with best-effort
timeparsing; see PARITY.md for the contract),Organizationon home
pages,BlogPostingon blog posts, andFAQPagefrom FAQ blocks. - New event fields:
cancelled(a visible danger badge and the structured
status, so they never disagree),online(virtual location), and
price/currency/cost(paid-event offers). - FAQ block:
{{< faq >}}/{{< question >}}shortcodes (Astro<FAQ>/
<FAQItem>), native<details>with zero JavaScript, answers in the DOM
for indexing and AI answer engines. Gated FAQPage JSON-LD via
seo.faqJsonLd(default true). - Crawl plumbing:
robots.txtadvertising the sitemap,og:locale,
og:image:alt(optionalimageAltfield), and an opt-innoindexon
taxonomy pages (seo.noindexTaxonomies). Astro adds@astrojs/sitemap. - Core Web Vitals: markdown and card/list images lazy-load with async
decoding (hero and event lead stay eager); apreconnectto the Font
Awesome CDN when the default URL is used. - New SEO and FAQ documentation pages;
scripts/check-jsonld.pyvalidates
every built JSON-LD block in CI.
Popular v0.5.0
Added
- Computed home-page stats:
@count:<section>(and@count:<section>:rounded)
render a live entry count for any section, generalizing@pastEventCount.
Factored into a reusable resolver (Hugopartials/stat-value.html, Astro
src/lib/stats.ts). - Organizer profile pages: each organizer entry renders a bio-card profile
page (Hugoorganizers/single.html, Astroorganizers/[slug]), and
organizer cards link to it. NeweyebrowOrganizerUI string. - Back link to the parent section on nested pages, labeled by the parent's
optionalshortTitlefront-matter field or its title. Astro serves pages
through a rest-param route to support nested page ids. - Renameable content sections:
[params.sections](Hugo) /SECTIONS_MAP
(Astro) point post-author bylines (authors) and the homepage team grid
(team) at differently-named sections, for communities whose people are
not "organizers" or whose blog is not written by "authors". No template
overrides needed.
Fixed
- Post cards on date-less pages no longer render "Jan 0001" or a stray
eyebrow separator (affects sections of static pages rendered through the
default list).
Popular v0.4.0
Added
- Astro package:
popular({ routes: { speakers: false, ... } })disables
any injected route group, the supported way to replace part of the
content model or provide your own/or/rss.xml. - Astro package: injected slug routes use rest params, so folder-organized
content ids (2019-pycon-us/cooper-lees) build.
Changed
- Astro: theme pages tolerate undefined or empty collections, rendering no
pages instead of failing the build. - Theme-only CI workflows (deploys, releases, parity checks and reminders)
no longer run in forks of either repo.