Supplement
Mudlej.com's Codebase Structure
Where content, routes, components, styling, runtime code, Markdown plugins, and tests live.
Mudlej.com is an Astro static site. The codebase is organized so content, presentation, Markdown processing, browser runtimes, styling, and tests stay separated.
That separation is the main maintenance trick. If a change feels hard, first ask: is this content, routing, rendering, styling, runtime behavior, or test coverage?
Top-Level Files#
The most important root files are:
| File | Job |
|---|---|
astro.config.mjs | Astro integrations, Markdown processor, and Tailwind Vite plugin. |
ec.config.mjs | Expressive Code configuration. |
tsconfig.json | TypeScript strict settings and path aliases. |
vitest.config.ts | Vitest configuration and test aliases. |
src/content.config.ts | Content collection schemas. |
src/env.d.ts | Ambient module declarations for untyped imports. |
package.json | Scripts, dependencies, and project metadata. |
Most day-to-day content work happens under src/content/. Most visual work happens under src/components/ and src/styles/. Test coverage lives under tests/.
Content Collections#
Content lives here:
src/content/├── articles/├── projects/├── series/└── supplements/Each folder maps to an Astro content collection. The schema in src/content.config.ts validates frontmatter before pages are built.
That validation catches mistakes such as a missing publishedAt, a bad project link kind, missing project image alt text, or a supplement that does not point to exactly one parent.
Routes#
Routes live under src/pages/.
| Route file | Public output |
|---|---|
src/pages/index.astro | Landing page. |
src/pages/articles/index.astro | Article archive and series cards. |
src/pages/articles/[...slug].astro | Article detail pages. |
src/pages/articles/series/[slug].astro | Series roadmap pages. |
src/pages/articles/[article]/supplements/[...slug].astro | Article supplement pages. |
src/pages/projects/index.astro | Project archive. |
src/pages/projects/[...slug].astro | Project detail pages. |
src/pages/projects/[project]/supplements/[...slug].astro | Project supplement pages. |
src/pages/styleguide.astro | Design-system fixture page. |
Routes should mostly orchestrate data and choose the correct page shell. If a route becomes a large UI component, reusable pieces should move into src/components/.
Shared Rich Content Layer#
Articles, projects, and supplements render Markdown through shared rich-content components:
src/components/content/├── ContentImageLightbox.astro├── RichContentPage.astro├── RichContentBoundary.astro├── RichContentDivider.astro├── RichContentRuntimes.astro└── SupplementContentPage.astroThis layer owns the common reading shell: title, subtitle, metadata slot, optional table of contents, body separators, Mermaid runtime inclusion, content tabs, image lightbox inclusion, and body layout.
The article, project, and supplement routes keep their own semantics, but they share this rendering surface so Markdown features behave consistently everywhere.
Components#
Component folders are grouped by purpose:
src/components/├── articles/├── bootstrap/├── content/├── icons/├── landing/├── projects/├── styleguide/└── ui/Use ui/ for generic primitives. Use articles/ and projects/ for composite pieces that only make sense in those sections. Use content/ for behavior shared by articles, projects, supplements, and future rich pages.
The goal is to keep page files as orchestration and keep reusable rendering decisions in components.
Styles#
Global styling is split by responsibility:
src/styles/├── global.css├── theme.css├── semantic.css├── prose.css├── prose/└── utilities.cssThe important rule is token discipline. Shared spacing, type, colors, radii, and measures belong in the design system. Component-private geometry can stay local.
Markdown body styles belong in src/styles/prose/, not inside individual article, project, or supplement routes.
Runtime Code#
Browser behavior lives under src/runtime/:
src/runtime/├── anchor-scroll.ts├── content-image-lightbox.ts├── mermaid-runtime.ts├── reader-settings.ts├── styleguide.ts└── theme.tsThe site is static, but small runtime enhancements are still useful. Theme and reader settings support user preferences. Mermaid, content tabs, and image lightbox behavior are included only when the page content needs them.
Markdown Plugins#
Markdown enrichment lives under src/markdown/:
src/markdown/├── rehype-content-tabs-a11y.mjs├── rehype-external-links.mjs├── rehype-heading-anchors.mjs├── remark-abbreviations.mjs├── remark-content-tabs.mjs├── remark-inline-formatting.mjs├── remark-internal-links.mjs├── remark-mermaid.mjs└── remark-reading-time.mjsThese plugins add local syntax and HTML post-processing such as Mermaid rewriting, internal links, reading time, content tabs, abbreviations, highlight, underline, keyboard shortcuts, accessible tabs, external-link attributes, and heading anchors.
The order matters. For example, Mermaid fences are rewritten before Expressive Code can treat them as ordinary code blocks.
Data Helpers#
Shared data helpers live close to the domain they support:
| File | Job |
|---|---|
src/articles/index.ts | Article summaries, series grouping, article visibility, dates, URLs, and article index data. |
src/projects/index.ts | Project summaries, project visibility, lifecycle labels, URLs, and project index data. |
src/content-pages/index.ts | Shared rich-content helpers such as date formatting, TOC filtering, Mermaid detection, tabs detection, and image detection. |
src/site/metadata.ts | Page titles, canonical URLs, robots metadata, Open Graph metadata, and schema types. |
src/site/rss.ts | RSS filtering, dates, and feed item mapping. |
src/site/sitemap-rules.mjs | Sitemap exclusions for draft and unlisted content. |
These helpers keep route files and components from reimplementing content rules in several places.
Tests#
Tests live under tests/:
tests/├── dist/├── helpers/├── markdown/├── stubs/└── unit/tests/unit/ covers pure helpers and small runtime modules. tests/markdown/ covers the custom Markdown plugins and combined rendering fragments. tests/dist/ inspects built HTML, feeds, metadata, links, runtimes, accessibility details, and normalized snapshots. tests/helpers/ and tests/stubs/ support those test categories.
The test suite is intentionally split this way so regressions fail close to the layer that owns them.
Path Aliases#
Use path aliases instead of long relative imports:
import RichContentPage from '@components/content/RichContentPage.astro';import { formatContentDate } from '@src/content-pages';This keeps files easier to move and read.
Maintenance Rule#
Before editing, identify the layer:
| Change | Start here |
|---|---|
| Add or edit article text | src/content/articles/ |
| Add or edit project text | src/content/projects/ |
| Add long supporting material | src/content/supplements/ |
| Add or edit series metadata | src/content/series/ |
| Change article, project, or supplement page layout | src/components/content/ plus the relevant route file. |
| Change archive cards or section-specific UI | src/components/articles/ or src/components/projects/ |
| Change Markdown typography | src/styles/prose/ |
| Change shared tokens | src/styles/theme.css or src/styles/semantic.css |
| Change reader settings | src/runtime/reader-settings.ts and the bootstrap/control components. |
| Change Markdown syntax | src/markdown/ and tests/markdown/ |
| Change generated output rules | src/site/, route helpers, and tests/dist/ |
The simplest maintenance path is usually to make the change in the narrowest layer that owns it, then add or update the matching test if the behavior should stay stable.