Live demo: bravada.comfus.io
A port of the Bravada WordPress theme (Cryout Creations) to Astro, powered by EmDash and built on the EmDash blog template. Runs on any Node.js server with SQLite and local file storage.
The port carries Bravada's visual language — Playfair Display headings over
Mulish body text, the teal/gold palette, the gold-ribbon wordmark, highlighter
title sweeps, ghost section headers, the slow zoom-under-teal image hover, the
dark footer — and rebuilds its landing page as EmDash sections: reusable
blocks editors drop into any Portable Text field with the /section command.
Every demo image — heroes, headers, shop and portfolio photography — is real
CC0/CC BY photography rather than placeholder art; see
CREDITS.md for the full attribution table. Local images ship
with pre-built AVIF/WebP siblings served through <picture> for the hero,
page headers, portfolio, and project-grid images.
Bravada's front-page elements map to four custom Portable Text block types, each seeded as a section:
Section (/section) |
Block type | Bravada original |
|---|---|---|
| Hero banner | bravada.hero |
LP slider / static slider |
| Icon blocks | bravada.blocks |
LP blocks |
| Featured boxes | bravada.boxes |
LP boxes (animated) |
| Text band | bravada.text |
LP text areas |
The homepage renders the page with slug home full-width above the latest
posts — the seed ships one assembled from the four sections. Edit, reorder or
delete bands there like any other content; delete the page to fall back to a
plain blog front page. Sections work in posts and pages too, on any site the
schema grows into (the CMS content model is data, so extra collections scale
without theme changes).
Block components live in src/components/blocks/ and are registered in
src/components/RichText.astro (use it wherever editor content renders).
Image fields on hero/boxes blocks take a URL — a media-library file URL or an
external one.
seed/seed.minimal.json— the same structure with no demo content, for starting a clean site (see First run).seed/seed.json— collections (posts, pages), category/tag taxonomies, primary + social menus, sidebar/footer widget areas, the Bravada sections, and sample content (ahomelanding page + demo posts).src/styles/theme.css— the Bravada design tokens and signature styles. All colors uselight-dark(); dark mode is automatic.src/styles/tokens.css— template defaults (don't edit; override in theme.css).
| Page | Route |
|---|---|
| Homepage (landing + latest) | / |
| All posts | /posts |
| Single post | /posts/:slug |
| Category / tag archive | /category/:slug, /tag/:slug |
| Portfolio project | /portfolio/:slug |
| Project type / tag archive | /project-type/:slug, /project-tag/:slug |
| Product | /product/:slug (zoomable gallery: hover lens, click for a magnifier lightbox) |
| Search | /search |
| Static pages (about, contact, shop, …) | /:slug |
RSS lives at /rss.xml; sitemap.xml and robots.txt are served by the
EmDash integration.
Everything is server-rendered (output: "server"): content lives in SQLite
and pages query it per request, so edits in the admin are live immediately —
no rebuilds.
flowchart LR
V[Visitor] --> P["src/pages/*"] --> Q[EmDash] --> DB[(SQLite)]
P --> B["bravada.* blocks"]
E[Editor] --> A["/_emdash/admin"] --> DB
The theme layer is deliberately thin: routes in src/pages/ query EmDash and
hand Portable Text to RichText.astro, which dispatches the four
bravada.* block types; design tokens in src/styles/theme.css restyle the
base template without touching its layout primitives.
Start from a clean copy — either click Use this template on GitHub, or:
npm create astro@latest -- --template vhscom/emdash-theme-bravadaRequires Node 20+ and pnpm (fonts are fetched from Google at build time, so the first build needs network access).
pnpm install
npx emdash dev # localhost:4321 — migrations run, but the site starts EMPTYThen visit http://localhost:4321/_emdash/admin — the setup wizard creates
your first admin account and offers "Include sample content", which
applies the full Bravada demo seed for you. Prefer the command line?
npx emdash seed seed/seed.json # same thing, without the wizard checkboxPrefer to skip the demo content? Seed the structure only (collections, taxonomies, menus, widget areas, sections — no posts, shop, or portfolio):
npx emdash seed seed/seed.minimal.jsonTo start over at any point: stop the dev server, rm data.db*, and run
npx emdash dev again.
Full-text search, RSS, sitemap/robots, SEO/JSON-LD, comments-ready routes, dark/light mode and the audit-log plugin come from EmDash and the underlying blog template.
- Site title, tagline, logo live in the CMS, not the code: admin → Settings. The header wordmark, footer, RSS feed, and meta titles all follow.
- Menus and widgets are admin-editable (Appearance → Menus / Widgets);
the seed's
primary,social, andmobilemenus are starting points. - Colours and fonts: override tokens in
src/styles/theme.css(see the notes at the top of that file); webfonts are configured inastro.config.mjs. Don't editsrc/styles/tokens.css. - Post-page furniture: admin → Plugins → Bravada Theme toggles the post author attribution and the docked prev/next buttons (see Theme settings below).
The template builds to a self-hosted Node server:
pnpm build
node ./dist/server/entry.mjs # honours HOST / PORT env varsProduction checklist:
- Set the Site URL (admin → Settings) — canonicals, Open Graph URLs, the sitemap, and the RSS feed all derive absolute URLs from it.
- Generate an encryption key:
npx emdash secrets generateand setEMDASH_ENCRYPTION_KEYin the server environment (encrypts plugin secrets at rest). - Persist
data.db*anduploads/— both live on disk; put them on a volume that survives restarts and back them up together.
For other targets (Cloudflare, Postgres, S3 storage) see the EmDash deployment docs.
Post-page display toggles live in a template-local plugin
(src/plugins/bravada-theme/) and are edited in the admin:
Plugins → Bravada Theme. Changes apply immediately — no restart, no
seed edits.
- Show post author (default on) — post pages attribute content to the byline in three places: the avatar + name chip in the post hero, the byline in the article meta line, and the author card below the article. For a single-author site where attribution is noise, turn all three off. The hero excerpt (the entry's Excerpt field, which is also the search-engine description) is independent of author display — it keeps rendering, exactly as Bravada treats its excerpt and author-meta options as separate toggles.
- Show prev/next buttons (default on) — the docked buttons that fade
in beside the article on scroll (demo
#nav-fixed). Turning them off leaves the full-bleed previous/next image band above the footer intact.
- EmDash docs — querying content, schema, menus, widgets, plugins, deployment.
- EmDash docs MCP — this repo ships
.mcp.json/.cursor/mcp.json/.vscode/mcp.json, so Claude Code, Cursor, and VS Code can search the EmDash docs while you work. - Astro docs — the underlying framework.
- Bravada — the upstream WordPress theme this port is matched against.
© 2026 vhs. A port of Bravada, © 2020–25 Cryout Creations. Licensed under GPL-3.0-or-later — see LICENSE for the full text and CREDITS.md for attribution details.
Maintained by vhs at Comfusion.
