Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 12 additions & 18 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,40 +17,34 @@ concurrency:

jobs:
lint-format:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
- uses: actions/checkout@v6.0.2
- uses: volta-cli/action@615a78f6c83e116339c53b94f3f82b4d6c0b7d18 # v5.0.0
- run: npm ci
- run: npm run prettier
- run: npx astro sync
- run: npm run fmt:check
- run: npm run lint
- run: npx astro sync

build:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/configure-pages@v4
- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
- uses: actions/checkout@v6.0.2
- uses: actions/configure-pages@v6
- uses: volta-cli/action@615a78f6c83e116339c53b94f3f82b4d6c0b7d18 # v5.0.0
- run: npm ci
- run: npm run build
- uses: actions/upload-pages-artifact@v3
- uses: actions/upload-pages-artifact@v5
with:
path: ./dist

deploy:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
needs: [lint-format, build]
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- uses: actions/deploy-pages@v4
- uses: actions/deploy-pages@v5
id: deployment
5 changes: 5 additions & 0 deletions .oxfmtrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"printWidth": 120,
"trailingComma": "es5",
"ignorePatterns": ["dist/**", ".astro/**", ".claude/**", ".vscode/**"]
}
13 changes: 13 additions & 0 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"plugins": ["typescript"],
"categories": {
"correctness": "off"
},
"options": {
"typeAware": true
},
"rules": {
"typescript/consistent-type-imports": ["error", { "fixStyle": "inline-type-imports" }]
},
"ignorePatterns": ["dist/**", ".astro/**", ".claude/**", ".vscode/**"]
}
2 changes: 1 addition & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"recommendations": ["astro-build.astro-vscode"],
"recommendations": ["astro-build.astro-vscode", "oxc.oxc-vscode"],
"unwantedRecommendations": []
}
File renamed without changes.
File renamed without changes.
24 changes: 11 additions & 13 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
{
"eslint.validate": ["javascript", "javascriptreact", "astro", "typescript", "typescriptreact"],
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
"oxc.fmt.configPath": ".oxfmtrc.json",
"oxc.configPath": ".oxlintrc.json",
"oxc.path.tsgolint": "node_modules/.bin/tsgolint",
"editor.formatOnSave": false,
"[javascript][typescript][javascriptreact][typescriptreact][json][jsonc]": {
"editor.defaultFormatter": "oxc.oxc-vscode"
},
"[astro]": {
"editor.defaultFormatter": "astro-build.astro-vscode"
},
"editor.codeActionsOnSave": {
"source.format.oxc": "always",
"source.fixAll.oxc": "always"
}
}
}
4 changes: 2 additions & 2 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
{
"label": "New Post",
"type": "shell",
"command": "node .vscode/new-post.mjs \"${input:newPostSlug}\"",
"command": "node .vscode/new-post.mts \"${input:newPostSlug}\"",
"presentation": {
"reveal": "always",
"panel": "shared"
Expand All @@ -31,7 +31,7 @@
{
"label": "New Comment",
"type": "shell",
"command": "node .vscode/new-comment.mjs \"${input:postSlug}\" \"${input:authorName}\"",
"command": "node .vscode/new-comment.mts \"${input:postSlug}\" \"${input:authorName}\"",
"presentation": {
"reveal": "always",
"panel": "shared"
Expand Down
76 changes: 22 additions & 54 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,65 +1,33 @@
# AGENTS.md
See [ARCHITECTURE.md](ARCHITECTURE.md) to understand the project. See [CONVENTIONS.md](CONVENTIONS.md) for naming, formatting, and other conventions.

This file provides guidance to AI agents working with code in this repository.
Oxfmt used for JS/TS code formatting. Oxfmt + Prettier used for Astro code formatting.

## Commands

```sh
npm run dev # Start dev server at localhost:4321
npm run build # Build production site to ./dist/
npm run preview # Preview production build locally
npm run astro ... # Run Astro CLI commands (e.g. astro add, astro check)
npm run lint # Run ESLint
npm run lint:fix # Auto-fix ESLint issues
npm run prettier # Check formatting
npm run prettier:fix # Auto-fix formatting
```

## Architecture

This is an [Astro](https://astro.build) blog site using the minimal template with strict TypeScript.

- `src/pages/` — File-based routing. `.astro` and `.md` files become routes based on filename.
- `src/components/` — Astro components: `BlogPost.astro`, `Comment.astro`, `Comments.astro`, `Footer.astro`, `Header.astro`, `Navigation.astro`, `Social.astro`, `ThemeIcon.astro`.
- `src/layouts/` — Page layouts: `BaseLayout.astro`, `MarkdownPostLayout.astro`.
- `src/blog/` — Markdown blog post content files.
- `src/content/comments/` — Markdown comment files linked to blog posts.
- `src/styles/` — Global CSS (`global.css`).
- `src/assets/` — Static assets imported by components.
- `src/utils/` — Utility functions (e.g. `date.ts`).
- `src/content.config.ts` — Content collection schema for the blog.
- `public/` — Static assets served at root (e.g. `public/favicon.svg` → `/favicon.svg`).
- `astro.config.mts` — Astro configuration.
## Content creation

Astro pages use a frontmatter fence (`---`) at the top for server-side JavaScript, followed by HTML/component markup. TypeScript is configured in strict mode via `astro/tsconfigs/strict`.
Use these scripts (not manual file creation) — they set correct paths, timestamps, and frontmatter:

## Content Schemas

**Blog post** (`src/blog/*.md`) frontmatter (all required):

```yaml
title: "Post Title"
date: 2026-01-01
description: "Short description"
tags: ["tag1", "tag2"]
```

**Comment** (`src/content/comments/*.md`) frontmatter:

```yaml
author: "Name" # required
date: 2026-01-01 # required
url: "https://..." # optional
```sh
node .vscode/new-post.mts <post-slug> # creates src/blog/<slug>.md
node .vscode/new-comment.mts <post-slug> <author-name> # creates src/content/comments/<postSlug>/<ts>-<authorSlug>.md
```

## Tooling

- **ESLint** — `eslint-plugin-astro`, `typescript-eslint` (strictTypeChecked), `eslint-config-prettier`
- **Prettier** — `prettier-plugin-astro`, 120-character print width
- **TypeScript** — strict mode via `astro/tsconfigs/strict`
Also available as VS Code tasks: **New Post** / **New Comment** (prompts for inputs).

## Deployment & CI

- Hosted on GitHub Pages at `https://truman.mulholland.nz`
- CI runs lint + build on every push and PR
- Merges to `main` deploy to production; PRs get a deploy preview
- Merges to `main` deploy to production

## Commands

```sh
npm run dev # Start dev server at localhost:4321
npm run build # Build production site to ./dist/
npm run preview # Preview production build locally
npm run astro ... # Run Astro CLI commands (e.g. astro add, astro check)
npm run lint # Run oxlint
npm run lint:fix # Auto-fix oxlint issues
npm run fmt:check # Check formatting
npm run fmt # Auto-fix formatting
```
17 changes: 17 additions & 0 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Architecture

An [Astro](https://astro.build) blog site using minimal template.

- `src/pages/` — File-based routing. `.astro`, `.md`, and `.js` files become routes. Includes `posts/`, `tags/` subdirs and `rss.xml.js` endpoint.
- `src/components/` — Astro components: `BlogPost.astro`, `Comment.astro`, `Comments.astro`, `Footer.astro`, `Header.astro`, `Navigation.astro`, `Social.astro`, `ThemeIcon.astro`.
- `src/layouts/` — Page layouts: `BaseLayout.astro`, `MarkdownPostLayout.astro`.
- `src/blog/` — Markdown blog post content files.
- `src/content/comments/` — Markdown comment files. Organized as `src/content/comments/<postSlug>/<unixTimestamp>-<authorSlug>.md`.
- `src/styles/` — Global CSS (`global.css`).
- `src/assets/` — Static assets imported by components.
- `src/utils/` — Utility functions (e.g. `date.ts`).
- `src/content.config.ts` — Content collection schema for the blog.
- `public/` — Static assets served at root (e.g. `public/favicon.svg` → `/favicon.svg`).
- `astro.config.mts` — Astro configuration.

Astro pages use a frontmatter fence (`---`) at the top for server-side JavaScript, followed by HTML/component markup. TypeScript is configured in strict mode via `astro/tsconfigs/strict`.
6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# CLAUDE.md

Read AGENTS.md for guidance on working with this repository.
@AGENTS.md
@ARCHITECTURE.md
@CONVENTIONS.md
74 changes: 74 additions & 0 deletions CONVENTIONS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Conventions

## File naming

### TS/JS

- Source files: `kebab-case.ts` or `kebab-case.mts` for ESM modules, configs, and scripts.
- Astro component/layout files: `PascalCase.astro` or `kebab-case.astro` for other Astro files.

## Naming

### TS/JS

- Types, interfaces, classes: `PascalCase`
- Functions, variables, properties: `camelCase`

## File layout

Higher-level functions should come before lower-level ones e.g. public before private. Ideally topologically sorted meaning each function appears before any it calls into.

## Formatting

Code formatting enforced automatically by project formatters.

- **TS/JS**: Oxfmt
- **Astro**: Oxfmt + Prettier

Run `npm run fmt` to apply formatting fixes.

## Spelling

**US English** spelling throughout all code, comments, and documentation.

## Error handling

Categorize errors into one of:

### User error

- Propagate by return value not exception
- Shown to user

### External error

E.g. network error, file system error.

- Propagate by return value, not exception. Means catching exceptions from external function calls.
- Retried if possible

### Unexpected error

Bugs caused by developer.

- Propagate by exception
- Caught at top level

## Content Schemas

**Blog post** (`src/blog/*.md`) frontmatter (all required):

```yaml
title: "Post Title"
date: 2026-01-01
description: "Short description"
tags: ["tag1", "tag2"]
```

**Comment** (`src/content/comments/*.md`) frontmatter:

```yaml
author: "Name" # required
date: 2026-01-01 # required
url: "https://..." # optional
```
36 changes: 0 additions & 36 deletions eslint.config.mjs

This file was deleted.

Loading