Astro + Tailwind v4 + MDX, styled with the slim.tf design system (light theme, single teal accent). Built as a static site, deploys to Cloudflare Pages.
- Astro 5: static site generator, ships zero JS by default
- Tailwind v4: via
@tailwindcss/vite; tokens live insrc/styles/global.cssunder@theme - MDX: Markdown + JSX for blog posts, via Astro content collections
- Cloudflare Pages: static hosting
npm install
npm run dev # http://localhost:4321
npm run build # outputs to dist/
npm run preview # serve the production build locallysrc/
styles/
global.css Design tokens (@theme) + components. Edit colors here.
prose.css Styles for MDX blog-post body content (.sl-prose)
layouts/
BaseLayout.astro Head, fonts, nav, footer
BlogPost.astro Wraps MDX posts in themed prose
components/
Nav.astro Sticky pill navbar
Hero.astro Hero band + animated teal grid (canvas)
Card.astro, PostCard.astro
content/
blog/ Your .mdx posts live here
content.config.ts Blog frontmatter schema (title, description, pubDate, tags, draft)
pages/
index.astro Home (hero, work, latest posts, about)
blog/index.astro Post list
blog/[...slug].astro Renders each post
rss.xml.ts RSS feed
public/
favicon.svg
Create src/content/blog/my-post.mdx:
---
title: "My post title"
description: "One-line summary for cards and SEO."
pubDate: 2025-06-27
tags: ["tag-one", "tag-two"]
draft: false
---
Markdown content here. Import and use components when you need them:
import Card from "../../components/Card.astro";
<Card title="Inline component">Works inside MDX.</Card>The frontmatter is type-checked against the schema in content.config.ts.
Set draft: true to hide a post from listings, the RSS feed, and builds.
All design decisions are tokens in src/styles/global.css:
- Colors: the
@themeblock (--color-sl-*) generates Tailwind utilities likebg-sl-accent,text-sl-accent-ink,border-sl-border. - Component classes:
.sl-btn,.sl-card,.sl-nav,.sl-hero, etc. read plain CSS vars (--sl-*) defined in the:rootblock below@theme. - Blog typography:
src/styles/prose.css.
Change --color-sl-accent (and its --sl-accent mirror) in one place and the
whole site follows.
This is a static build (output: "static" in astro.config.mjs), so no
adapter is required.
- Push the repo to GitHub/GitLab.
- In the Cloudflare dashboard: Workers & Pages → Create → Pages → Connect to Git.
- Build settings:
- Framework preset: Astro
- Build command:
npm run build - Build output directory:
dist
- Deploy. Cloudflare gives you a
*.pages.devURL.
Before going live, set your real domain in astro.config.mjs (site:), which
feeds the sitemap, RSS, and canonical URLs.
If you later add server-rendered routes or Cloudflare Workers functions, install
@astrojs/cloudflare, setoutput: "server", and add the adapter. For a portfolio/blog you almost certainly don't need this.