No description https://hallowedtales.com
Find a file
Brian Ladner f39d2f3918 fix: improve favicon contrast in light and dark browser tabs
Base color was too low-contrast against both light and dark tab
backgrounds. Adds prefers-color-scheme overrides for browsers that
honor them (Chrome, Firefox, Edge); Safari ignores the media query
for favicons, so the base stroke color is a compromise tuned for
readability in both themes. Regenerates the raster fallbacks to match.
2026-11-05 04:42:27 +00:00
.claude/skills/proofread Point proofread reports at catholic-research instead of context/Notes 2026-10-09 01:12:47 -05:00
.github fix: clamp leap-day feasts, guard localStorage, pin CI actions to SHAs 2026-11-03 14:15:28 -06:00
context feature: add about page and footer navigation 2026-11-03 14:26:13 -06:00
docs docs: rewrite README for portfolio review with screenshots 2026-11-03 13:03:47 -06:00
public fix: improve favicon contrast in light and dark browser tabs 2026-11-05 04:42:27 +00:00
scripts chore: small cleanups (symbols heading, slug humanizers, unused font, list-content dash) 2026-10-09 17:23:07 -05:00
src feature: add about page and footer navigation 2026-11-03 14:26:13 -06:00
tests fix: clamp leap-day feasts, guard localStorage, pin CI actions to SHAs 2026-11-03 14:15:28 -06:00
.gitignore chore: regenerate backlog, split and ignore security backlog 2026-11-03 13:03:47 -06:00
astro.config.mjs fix: allow per-image focal-point crop through CSP 2026-10-20 01:11:24 +00:00
CLAUDE.md Update CLAUDE.md: Helena/Kateri duplication resolved, scope the tone model (#28) 2026-11-02 16:21:36 -06:00
LICENSE docs: switch to MIT + CC BY 4.0 content split, standardize README 2026-11-03 20:38:45 +00:00
package-lock.json Pin transitive deps to resolve Dependabot alerts 2026-11-02 05:13:45 +00:00
package.json docs: switch to MIT + CC BY 4.0 content split, standardize README 2026-11-03 20:38:45 +00:00
README.md docs: switch to MIT + CC BY 4.0 content split, standardize README 2026-11-03 20:38:45 +00:00
tsconfig.json Initial scaffold: Astro base, legends content collection schema, CLAUDE.md 2026-10-03 17:24:21 +00:00
vitest.config.ts feature: shared schema fragments, new content checks, and calendar tests 2026-10-10 17:17:17 -05:00
wrangler.jsonc Add previews.kv_namespaces block to wrangler.jsonc for SESSION binding 2026-10-05 01:30:09 +00:00

HallowedTales

CI License: MIT Content: CC BY 4.0

Live site: hallowedtales.com

A content-driven site of Catholic saint and miracle lore - legends, folk traditions, relics, symbols and saint biographies - built with Astro on Cloudflare Workers. Nearly 60 entries, no database, full-text search, and a liturgical calendar computed from first principles.

HallowedTales home page, light theme HallowedTales home page, dark theme

Liturgical feast-day calendar with season color bands Folk Traditions listing, dark theme

Designed, built and written solo.

Why this project exists

HallowedTales is the companion to The Miracle Register, a site that holds itself to a Vatican-documentation and medical-verification standard. Lore cannot meet that bar, and mixing the two would erode the Register's core promise, so this is a separate site with its own data shape, tone and audience. The two cross-link wherever a story overlaps a verified case.

Engineering Highlights

  • No database, by design. Cross-links, back-links, same-saint sections, tags and the saint index are all derived at build time from the content files. The relational needs are small and read-only, so a DB would add cost and failure modes for no benefit. If a runtime need appears, D1 is the planned option.
  • Content treated as code. Frontmatter is validated by Zod schemas at build time (feast dates, image indexes, alt text, cross-references), and Vitest enforces editorial rules on the prose itself: plain hyphens, "Saint" spelled out, no entry referring to the site around it, and every relatedLegends / saint / Register reference resolving. A typo fails CI instead of silently dropping an entry.
  • Computed liturgical calendar. Easter, Easter-relative feasts, fixed feasts and liturgical seasons (including Advent start detection) are calculated in src/lib/liturgical/ and unit tested. They drive a /calendar page and a "today in the Church calendar" banner that stays live on prerendered pages as an Astro server island.
  • Search without a backend. Pagefind indexes only published entry pages at build time, so drafts never reach the index. The UI is a dialog calling the static index directly.
  • Security headers on every response. A hashed Content-Security-Policy generated by Astro, plus nosniff, Referrer-Policy and frame protections applied through public/_headers for static assets and src/middleware.ts for on-demand responses, with one shared header definition.
  • Vendored reference data with drift detection. Published Register slugs and the feast-day master list are synced into generated files from a sibling research repo, with a --check mode that reports drift. They stay vendored copies rather than runtime dependencies.
  • Accessible UI. Skip link, keyboard-dismissible menus and dialogs, tracked focus, contrast-tuned dark mode tokens, and screen-reader text on calendar season bands.
  • Edge deployment. Cloudflare Workers with static assets; CI runs typecheck, tests and the full build on every push and PR.

Design decisions

  • Files over rows. The content model is narrative pieces with variants, not one verified record per case. Markdown in the repo gives review via pull request, version history and zero operational overhead.
  • Two kinds of "related" story. variants[] (inline) holds the same story with changed details, such as the Saint Nicholas window, chimney and pawnbroker versions. relatedLegends[] links distinct stories that share a motif, such as the Hubert and Eustace stags. Back-links are derived, so a reference only has to be authored once.
  • Same-saint links are computed, not curated. Entries sharing a saint slug surface each other automatically, which keeps unrelated stories about one saint out of relatedLegends.
  • Separate site, not a feature of the Register. Different sourcing standard, different audience, different tone. Keeping them apart protects the Register's guarantee.

Content

Six collections, each an Astro Content Collection with its own Zod schema in src/content.config.ts:

Collection Covers
Legends Saint-and-creature stories, patronage origins, founding and shrine legends
Traditions Feast-day customs, liturgical-object and food traditions, naming and weather folklore
Relics Biblical artifacts and legendary relics (True Cross, Holy Lance, Crown of Thorns)
Phenomena Mystical phenomena from saints' lives (bilocation, levitation, luminosity)
Symbols Chi-Rho, scallop shell, pelican, Tau cross, and how their use shifted across eras
Biographies Condensed cradle-to-grave saint lives

Every entry separates the legend as told from what the historical record supports, rather than presenting tradition as documented fact.

Tech Stack

  • Astro with the Cloudflare adapter, deployed to Cloudflare Workers
  • TypeScript, Markdown/MDX content, Zod-validated frontmatter
  • Tailwind v4
  • Pagefind for static full-text search
  • Vitest for unit and content-level tests
  • GitHub Actions for CI

Local Development

npm install
npm run dev         # http://localhost:4321
npm run typecheck
npm test
npm run build       # astro build + pagefind indexing

Deploying requires a CLOUDFLARE_API_TOKEN in a local .env (gitignored, not required for dev, build or test).

The Miracle Register - the evidentiary counterpart, for documented and medically reviewed cases.

Licensing

  • Code: MIT.
  • Content (saint and miracle lore write-ups, and other text published on the site): CC BY 4.0. Attribute as "HallowedTales, hallowedtales.com, CC BY 4.0". Provided without warranty.