diff --git a/README.md b/README.md new file mode 100644 index 0000000..d8c5b0c --- /dev/null +++ b/README.md @@ -0,0 +1,67 @@ +# dbtlr.com + +Personal site for [dbtlr.com](https://dbtlr.com) — a calm, typography-led dark-mode +portfolio and blog. Built as a fully static site with **Astro 6** and **Tailwind 4**, +deployed to **Cloudflare Workers** static assets. + +No client framework ships: the only browser JS is a ⌘K search palette and code-copy +buttons (`src/scripts/`). Code blocks are highlighted at build time with Shiki using a +custom theme mapped to the design tokens. + +## Requirements + +- **Node 24** +- **pnpm** (the package manager — never npm; pinned via `packageManager` in `package.json`) + +## Development + +```sh +pnpm install +pnpm dev # local dev server with HMR +pnpm build # static build to ./dist +pnpm preview # serve the built ./dist locally +pnpm check # astro check (type checking) +``` + +## Workflow + +Work happens on feature branches and lands through pull requests: + +``` +feature branch → PR to main → preview deploy → merge to main → production +``` + +- **PR previews** (`.github/workflows/preview.yml`): every PR against `main` runs + `pnpm check` + `pnpm build`, then `wrangler versions upload` publishes an ephemeral + version of the `dbtlr-com` Worker **without** touching production. The preview URL is + posted (and kept updated) as a comment on the PR. +- **Production** (`.github/workflows/deploy.yml`): pushing to `main` runs the same + checks and `wrangler deploy`, publishing the `dbtlr-com` Worker that serves + [dbtlr.com](https://dbtlr.com). + +Both workflows use Node 24 + pnpm and require `CLOUDFLARE_API_TOKEN` and +`CLOUDFLARE_ACCOUNT_ID` repository secrets. + +## Checks + +Run before pushing — these are exactly what CI runs: + +```sh +pnpm check && pnpm build +``` + +## Project structure + +``` +astro.config.mjs Astro config — Shiki theme + code-block chrome transformer +wrangler.jsonc Cloudflare Worker (static assets from ./dist) +src/ + pages/ routes — home, about, projects, writing, feed.xml, search.json, 404 + layouts/Base.astro shared page shell + components/ SectionHead, PostRow + content/ Markdown content collections (projects/ populated; writing/ pending) + content.config.ts collection schemas (zod) — writing + projects + scripts/ vanilla JS — search.js (⌘K palette), copy.js (code copy) + styles/global.css Tailwind 4 theme tokens + component CSS +.github/workflows/ deploy.yml (production), preview.yml (PR previews) +``` diff --git a/src/pages/about.astro b/src/pages/about.astro index 2071d2a..9133e76 100644 --- a/src/pages/about.astro +++ b/src/pages/about.astro @@ -14,9 +14,9 @@ const elsewhere = [ ---
-
+

Hi, I’m Drew.

-
+

I’m a product-focused engineer and engineering leader. Twenty years in, I’ve never stopped writing code — I think the best technical leaders keep their hands on the work, and it keeps me honest about the trade-offs. Lately I’m focused on agentic engineering: building the open-source tooling and workflows for how software gets made next.

I care about why something is being built, not just how. My best work happens close to the problem — talking to users, learning the workflow, making architectural calls that serve the product rather than the tech. I’ve led distributed teams since before remote was normal, and I’d still rather reach for the right boring tool than the trendy one.

Right now that’s norn, mimir, saga, and skald — a Norse-named family of terminal tools for agentic development. (I’ve named a few products in my time; the habit stuck.) I’m based in Brooklyn.

diff --git a/src/pages/index.astro b/src/pages/index.astro index a25b1e6..17fc9c6 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -9,7 +9,7 @@ const projects = (await getCollection('projects')).sort((a, b) => a.data.order -

I build tools for AI-native development.

-

+

I’m Drew Butler — a product-focused engineer and engineering leader, twenty years in and still shipping code every day. Lately that means open-source tooling for agentic development — norn, mimir, @@ -21,10 +21,12 @@ const projects = (await getCollection('projects')).sort((a, b) => a.data.order - {projects.map((project) => ( - + {project.data.name} - {project.data.blurb} - {project.data.lang} + + {project.data.blurb} + {project.data.lang} + ))}

diff --git a/src/pages/projects/[slug].astro b/src/pages/projects/[slug].astro index d0ddf22..0107c17 100644 --- a/src/pages/projects/[slug].astro +++ b/src/pages/projects/[slug].astro @@ -18,15 +18,15 @@ const buttons = [ ---
-
-
+
+

{project.data.name}

{meta}
-

{project.data.tagline}

+

{project.data.tagline}

{buttons.length > 0 && (
{buttons.map((b) => @@ -50,7 +50,7 @@ const buttons = [
{project.data.facts.map((fact) => ( -
+
{fact.label}
{fact.value}
diff --git a/src/pages/projects/index.astro b/src/pages/projects/index.astro index d79b557..0c6c921 100644 --- a/src/pages/projects/index.astro +++ b/src/pages/projects/index.astro @@ -6,14 +6,14 @@ const projects = (await getCollection('projects')).sort((a, b) => a.data.order - ---
-
+

Projects

-

A Norse-named family of terminal tools for agentic development. norn keeps knowledge, mimir holds work, saga weaves them into a session — and skald writes your git prose. Open-source, built in the open.

+

A Norse-named family of terminal tools for agentic development. norn keeps knowledge, mimir holds work, saga weaves them into a session — and skald writes your git prose. Open-source, built in the open.

{projects.map((project) => ( -
+
{project.data.demo}