Releases: vhscom/emdash-theme-bravada
Release list
v0.10.0 – tiered edge caching, self-hosted build fix, route rules
Pages are now cached in front of the site rather than inside it, so a reader is answered from their nearest data centre and the site never runs.
Heads up
- The self-hosted build was broken in 0.9.0 and works again here.
node ./dist/server/entry.mjsexited immediately with a type error, because 0.9.0 moved the theme to a newer Astro without moving the Node server alongside it. If you are on 0.9.0 and self-hosting, this is the reason to upgrade. The Cloudflare deploy was unaffected. - Purging no longer needs Cloudflare API credentials. If you set up
CF_ZONE_IDand a cache-purge token for this theme, nothing reads them any more — delete the worker secrets and revoke the token after you deploy, not before. - Set Browser Cache TTL to "Respect Existing Headers" in Cloudflare, under your domain → Caching → Configuration, if you have not already. The theme states how long a browser may keep each page, and the zone serves whichever value is higher.
Changed
- Pages are cached in front of the site, not inside it. Two tiers sit ahead of the Worker, so a hit is answered at the reader's nearest data centre without the site running at all. On a sister site the same change took a cached page from roughly 400ms to 95ms for a reader on the other side of the world.
- Pages are held for an hour, with ten days of stale-while-revalidate behind it. Publishing still clears the pages an entry appears on, so the longer window bounds only what tags cannot see.
- Cache policy is declared in
routeRulesinastro.config.mjs, next to the routes it applies to, rather than in site code. - The editing toolbar is assembled in the browser on every build, not just the Cloudflare one. A cache that answers before the site runs cannot inject one.
Fixed
- Search results are kept out of the cache properly. They were being offered to it with no lifetime at all, which a cache is free to read as roughly two hours — for the one page built from whatever the reader typed.
Documentation
- The README explains how the theme caches pages, what to set in Cloudflare before deploying, and why a page you have just deployed can still look old.
Full changelog: v0.9.0...v0.10.0
v0.9.0 – browser cache policy, EmDash 0.35.0, caching guide
Public pages now tell browsers how long to keep them, search results stay out of the cache, and the README explains how the theme's caching actually works.
Known issue
The self-hosted build does not start in this release. node ./dist/server/entry.mjs exits immediately with TypeError: Cannot read properties of undefined (reading 'getLogger'). This release raised the Astro floor without moving @astrojs/node alongside it, and 11.0.2 reads an internal that Astro 7.2 relocated. The Cloudflare deploy is unaffected. Fixed in 0.10.0 — or pin @astrojs/node to ^11.1.4 yourself.
Heads up
- Set Browser Cache TTL to "Respect Existing Headers" in Cloudflare, under your domain → Caching → Configuration. The theme now sends a
Cache-Controlon every page, but where the zone holds its own fixed value Cloudflare serves whichever is higher, so a four-hour default silently replaces the theme's five minutes. Neither half works without the other, and the override shows only on cached responses, so a cache-busted request looks correct. - EmDash 0.35.0 runs database migrations the first time you start the site after updating.
- Astro 7.2.5 or newer is now required. Older versions could cache a signed-in visitor's page for everyone.
Fixed
- Pages tell browsers how long to keep them, and missing pages say one minute. Without a header the host decided, so an edit stayed invisible to returning readers for four hours with no way to clear it. A browser cache cannot be purged.
- Search results are no longer cached. They are built from whatever the reader typed, so they belong to nobody else.
Changed
- EmDash 0.34.0 to 0.35.0, Astro 7.0.7 to 7.2.9. The declared floors move with them, not just the lockfile, so a fresh scaffold cannot resolve below the versions this release depends on.
Documentation
- The README explains how the theme caches pages, what to set in Cloudflare before deploying, and why a page you have just deployed can still look old.
Full changelog: v0.8.0...v0.9.0
v0.8.0 – structured product editing, review dates, derived ratings
Product content gets a real editing surface: reviews are a structured list rather than hand-written JSON, and the rating behind them is worked out instead of typed.
Heads up
-
Three product fields change type, and EmDash will not alter a field's type in place. On a site that already has products, migrate them from Content Types in the admin:
- Reviews — delete it, then add it back as a Repeater with sub-fields
author(Short Text, required),rating(Number),date(Date & Time) andtext(Long Text, required). Putauthorfirst: the editor titles each collapsed row from the first text sub-field. - Button label — delete it, then add it back as a Select with options
Add to basketandSelect options, defaultAdd to basket. - Rating — delete it. A product's stars are averaged from its reviews now, so nothing needs keeping in step by hand.
Stored values survived the delete-and-recreate as long as the field slug stayed the same — that is how this release's demo was migrated — but take a backup first.
- Reviews — delete it, then add it back as a Repeater with sub-fields
-
Do not migrate with
emdash schema remove-fieldalone. The CLI can delete a field but cannot recreate one carrying a repeater's sub-fields or a select's options, so it will leave you with no way to rebuild them. Applying the new seed only works on a local SQLite site; a deployed site cannot have a seed applied remotely. -
Database migrations run on first start after the EmDash 0.34.0 update.
Added
- Each customer review is described to search engines individually, not just as an average. Results can show a star rating with the number of reviews behind it, which search engines ask for before they will display either.
- Products can carry an availability note. It replaces the generic out-of-stock message when the product is unavailable, so you can say when it is coming back, and sits above the buy button when the product is in stock.
- The content lists in the admin show more at a glance — pages carry their layout, and products their price, SKU and stock state.
Fixed
- The two out-of-stock demo products now show a price. Both were seeded without one, so their pages had no price at all and search engines were told nothing about what they cost.
Changed
- Product reviews are edited as a proper list, with a row per review carrying its own author, rating, date and body, and rows that can be dragged into a new order.
- A product's star rating is worked out from its reviews instead of being typed in separately. The two could drift apart, and adding a review in the new editor would have done exactly that. Every product shows the rating it showed before.
- Customer reviews carry a real date. They all read "7th June" before, with no year, so search engines got no review date at all.
- The product button label is chosen from a list rather than typed, so a typo cannot put wording on a product that appears nowhere else. Its default now applies to new products, which it never did.
- Every product has its own SKU. Six had none and three shared placeholders, which search engines read as one product listed several times.
- Portfolio project dates are real dates, picked from a calendar instead of typed as free text. They read the same on the site as before, but the admin can sort and filter projects by them.
- Category, tag, project-type and project-tag archives ask search engines to index the posts they list rather than the list itself, so thin copies stop competing with the real pages.
- EmDash 0.33.0 to 0.34.0.
Documentation
- The README explains how to keep uploaded images visible to search engines. EmDash's stock robots.txt blocks the path its media proxy serves uploads from, so link previews are hidden from crawlers until you replace that file.
Full changelog: v0.7.0...v0.8.0
v0.7.0 – mobile gutter fidelity, breadcrumb structured data, safe JSON-LD
Mobile fidelity work against the Bravada theme source, plus breadcrumb structured data and a JSON-LD escaping fix.
Added
- Breadcrumb structured data. The trail above a page title is now described to search engines as a
BreadcrumbList, so results can show where a page sits in the site rather than just its address. Emitted on pages, posts, the blog archive, products and projects; skipped on 404 and search, which aren't real positions in the hierarchy.
Fixed
- Structured data can no longer be broken by page content. Project and product pages serialized their JSON-LD straight into the page, so an entry containing
</script>could cut the block short. The data is now escaped on its way in. - Posts use the full width of a phone screen. The article sat inside a margin and then indented its text again, running the words in a column about three quarters as wide as the theme gives them.
- The sidebar under a post lines up with the article above it. Where it drops below the white card, its search box and recent-post thumbnails ran flush to the right edge instead of keeping the article's margin.
- The portfolio and testimonial sections keep their proportions on a phone. Both held their desktop indent at every width, leaving them noticeably narrower than the sections above and below.
- Section headings sit over their large faded title again. The two drifted apart as the screen narrowed until the heading cleared the faded title almost entirely, losing the overlap the pairing is built on.
Full changelog: v0.6.0...v0.7.0
v0.6.0 – SEO audit pass, canonical redirects, EmDash 0.33.0
An SEO audit of the port against the original Bravada WordPress theme, plus a move to EmDash 0.33.0. Each item below was checked against the theme's own behaviour rather than assumed.
Heads up
Two URL behaviours change. Addresses written with a trailing slash now redirect to the slashless form instead of serving a second copy of the page, and the landing page's own slug (/home) redirects to the site root. Both are permanent redirects, and both match what WordPress does in redirect_canonical, so links from a migrated WordPress site keep working.
One manual step after seeding. Open the Home page in the admin and tick hide from search engines. The landing page is a real page entry, so the sitemap, which is built from content rather than routes, lists its slug as a URL that only redirects. The flag removes it and leaves / indexable. There is no seed field for it, so it cannot ship pre-set; the README covers this.
Fixed
- Blog posts can show a large preview image in search results. Posts were the only page type emitting no robots directive at all, so the one page type built around a photograph was the one shown with a small thumbnail.
- The landing page has a top-level heading again, the site title, where the original theme puts it. Its headings previously started one level down, leaving the site's most important page without one.
- The landing page is no longer served at a second address.
/homeredirects to the site root instead of answering with the same page. - Posts name their author in the structured data. The byline was on the page but missing from the JSON-LD and
article:author, the one piece of the theme's own schema markup the port had dropped. Sites that turn author attribution off stay anonymous there too. - Trailing-slash addresses redirect rather than serving the page a second time under its own canonical.
- The admin SEO panel takes effect on pages, projects and products, not just posts. A custom title, description, social image or canonical set there was ignored. Hide from search engines was worse than ignored: it dropped the page from the sitemap while the page itself kept inviting search engines in.
- Later pages of the blog archive no longer present themselves as copies of page one, and their titles say which page you are on.
Changed
- EmDash 0.31.1 → 0.33.0. Two database migrations run on the first start after updating. Taxonomy terms keep the order they appear in today, now stored explicitly, so they can be rearranged from the Taxonomies screen instead of renamed to sort them.
- Start the dev server with
pnpm dev. EmDash 0.33.0 deprecatesnpx emdash dev; it still runs, but warns. - The comment components now come from
emdash/ui/comments, the import path that survives EmDash 1.0.
Documentation
- The README documents the one-time noindex step for the home page entry.
AGENTS.mdrecords the changelog conventions this project follows.
Full changelog: v0.5.0...v0.6.0
v0.5.0 – accessibility pass, pagination, EmDash 0.31.1
An accessibility and correctness pass over the theme, plus a move to EmDash 0.31.1.
Heads up
This release requires Node 22 or newer. The pinned pnpm already refused to run on Node 20, so the previous "Node 20+" claim could not be honoured — engines now says what is actually true.
Added
- A "Skip to content" link — the first stop when you tab into any page, so reaching the article no longer means tabbing the entire header and menu.
- The blog archive is paginated, ten per page, using the same numbered pager as search. Previously every post on the site rendered on a single page.
Fixed
- The fullscreen search overlay and the burger menu now keep the keyboard inside them while open. Tabbing off the end used to walk invisibly into the page behind the layer.
- The sidebar tabs widget and the product page tabs respond to arrow, Home and End keys, and the tab strip is a single tab stop rather than one per tab. Screen readers are now told which tab belongs to which panel.
- The footer's light/dark/system buttons announce which one is active; they previously sounded like three identical buttons.
- Reduce motion now also calms in-page scrolling, the back-to-top jump, the header slide-down, and the burger menu's item-by-item entrance.
- Post dates no longer shift by a day depending on where the site is hosted.
- Editing a page or publishing a post now refreshes the footer navigation and recent-posts widgets instead of leaving stale copies on cached pages.
- Products whose options or reviews were saved in an unexpected shape no longer take the product page down.
- Archive pages no longer nest one
<main>inside another, and widget areas no longer render a stray heading for widget types the theme does not handle. - Restored the intended hover colour on portfolio meta links in dark mode.
Changed
- emdash 0.29.0 → 0.31.1, and the Cloudflare adapter alongside it. No template changes were needed.
- The theme plugin version was declared as
0.4.0in two places against a0.4.5package; all version numbers are now synced.
Documentation
- The README carries the design-token cheat sheet and the note that the palette deliberately reproduces the original Bravada demo rather than meeting WCAG contrast — previously only in the agent-facing
AGENTS.md. - Documented the Cloudflare Workers deployment path and the bundler pin it depends on.
- Added EmDash version, Node, CI, and licence badges.
- CI now runs typecheck and the test suite on every push and pull request.
Note for Safari users
Safari only tabs to links once "Press Tab to highlight each item on a webpage" is enabled in its Advanced settings. Without it, Option+Tab reaches them. This affects the skip link on every site, not just this one.
Full changelog: v0.4.5...v0.5.0
v0.4.5 – mobile spacing and layout fixes
Fixed
- The light/dark mode toggle in the footer now actually switches the
site's colors instead of silently doing nothing and leaving it on
whatever the system preference was. - Hero text now matches the original theme's width and proportions on
mobile and desktop — it was running noticeably narrower than
intended. - Hero buttons now stay side-by-side at their natural size until the
screen is narrow enough to stack, matching the original theme
instead of stacking too early. - Stacked hero buttons on mobile no longer stretch edge-to-edge;
they match the original theme's proportions. - The large translucent section headings (e.g. "A glorious title") now
wrap and space themselves against their description the way the
original theme does on mobile, and reveal with the same subtle
animation on scroll. - Photos that overlap the card above them no longer crowd the section
edge — restored the breathing room the original theme gives them. - Text inside image/text cards no longer runs narrower than the
original theme on mobile.
v0.4.0 – burger menu and search page fidelity pass
Changed
- Burger menu fidelity pass against the original Bravada theme:
layout, spacing, and animations now match the source, the search bar
uses the original's own magnifier icon and type metrics, and the
header hides on scroll and slides back on mobile like the original.
One deliberate improvement: parent menu items without a link toggle
their submenu instead of doing nothing. - Webfonts trimmed to the faces the theme actually renders: Playfair
Display ships regular and bold only (no italics), JetBrains Mono a
single regular face. Mulish is unchanged — all its weights and
italics are in use. - The burger-menu search is a plain search form again, submitting to
the results page — the live-suggestions dropdown didn't suit the
fullscreen menu. - The search results page now matches the original theme: the title
reads "Search Results for: …", the breadcrumb names the query, the
form is the theme's white square input with a gold square submit
button, and results display as the same article cards the blog uses
— on phones and desktop, paginated ten to a page with the theme's
numeric page links. A fruitless search gets the theme's Nothing
Found page: the message, a search form, and fallback columns of
recent posts, recent comments (a tag cloud when comments are off or
silent), and categories. - Inner-page headers now show the theme's bouncing chevron that
scrolls readers down to the content; the homepage chevron adopts the
theme's exact glyph and placement too. - The fixed navigation bar slides in from above once you scroll past
the header, at the theme's own scroll threshold. - Archive pages share the same sidebar as single posts instead of
carrying their own variant.
Fixed
- Text no longer clips in the burger-menu search field while typing (a
display bug the original theme also has; not ported). - Two section-library entries linked to a demo post that no longer
exists; they now point at live content, matching the home page.
v0.3.0 – product gallery, structured data, real photography
Added
- Product gallery interactions: hover zoom, a full-size lightbox, and
slide transitions between images. - Structured data for search engines: product pages emit
schema.org/Product(with price, availability, and ratings) and
portfolio pages emitschema.org/CreativeWork. - Product pages now always have a meta description — when there's no
excerpt, one is derived from the product's description.
Changed
- The sitemap now covers every content type. Pages were missing
entirely, and every product URL in the sitemap pointed at a route
that didn't exist. Sites created from an earlier seed need a
one-time schema update (seeds don't re-apply to existing
databases): give each collection the URL pattern and SEO flag it has
inseed/seed.json, via the admin's content-type settings or the
schema API. - Page titles use one separator everywhere (a compact
|by default),
and it's now editable under Settings → SEO in the admin. - Demo imagery is now real photography (CC0/CC BY, credited in
CREDITS.md) instead of placeholder artwork, with AVIF/WebP
variants for the heavy images. Shop products each get distinct
photos — several previously shared one. README and screenshots
refreshed to match.
Fixed
- The demo post "Throught the lens" is now "Through the lens" — title,
URL, and every link to it. Existing databases need the same rename
applied to their content. - Product gallery glitches: a slide getting stuck when revisiting an
image, plus zoom, keyboard, and lightbox-focus issues. - Several homepage links pointed at posts that don't exist in this
seed. - Long unbroken words or URLs in blockquotes could overflow the screen
on narrow viewports. - Injected content (embeds, ads, third-party widgets) pasted into
posts/pages could carry fixed, oversized dimensions with no theme
sizing constraint. Added a genericmax-width: 100%+
overflow: hiddenguard oniframe/embed/objectinside content
areas — no ad-network-specific selectors, so it holds regardless of
provider. Documented the existinghtml, body { overflow-x: clip }
rule as an intentional last-resort backstop for the same class of
bug.
v0.2.0 – theme settings plugin, minimal seed, route caching
Added
- Theme settings plugin (
src/plugins/bravada-theme/): editors toggle
post-author attribution and the docked prev/next buttons from a Block
Kit settings page in the admin (sidebar → Bravada Theme). Changes
apply live, no restart. seed/seed.minimal.json: structure-only seed (collections,
taxonomies, menus, widget areas, sections) for starting a clean site.- Route-cache support:
src/middleware.tsopts public pages into
Astro's route cache (maxAge 300, swr 3600) wherever a cache provider
is configured; the theme'sAstro.cache.set(cacheHint)tags enable
purge-by-tag on content edits. No-op without a provider. - Vitest suite covering the utility modules (35 tests);
pnpm test. - Live demo at bravada.comfus.io.
Changed
- emdash 0.28.1 → 0.29.0.
- Post comments render only when the collection has comments enabled
(previously the form always rendered). - The setup wizard's "Include sample content" option is now the
documented first-run path; Node 20+ declared viaengines. - Footer Contact Info matches the contact page (Ratsada, Phuket).
Fixed
- Mobile: boxes bands run flush edge-to-edge like the demo (tint
strips no longer show between stacked cards); animated boxes reveal
Read More on hover instead of overflowing the card; text-band
buttons stack with a real gap; hero buttons stretch full width. - Mobile: text bands with a right-side image stack the image above the
card (it previously climbed over the last lines of text or the
buttons). - Ghost section headers: the description's overlap pull now applies
only when a ghost title exists and eases at small viewports —
description-only headers no longer escape the section top. The dark
icon-blocks band regained its "Amazing feedback" ghost title from
the demo. - Footer About Us spacing: the image no longer double-gaps below the
widget title.