Skip to content

Commit a5d72d0

Browse files
bpamiriclaude
andauthored
feat(web): phase 0 static site monorepo foundation
Adds a pnpm workspace under web/ containing four Astro 5 static sites (landing, blog, guides+Starlight, api+Starlight) sharing a @wheels-dev/ui package for Header, Footer, and design tokens. Each site deploys to its own Cloudflare Pages project via a matrix GitHub Actions workflow triggered on web/** changes. Live placeholder pages: - blog.wheels.dev → wheels-blog - guides.wheels.dev → wheels-guides (Starlight) - api.wheels.dev → wheels-api (Starlight) - wheels.dev apex unchanged — cutover deferred to Phase 4. Commitlint scope-enum extended with web, web/ui, web/landing, web/blog, web/guides, web/api, web/starlight for the new monorepo. Phase 0 of the wheels.dev static-site migration. See full plan at docs/superpowers/plans/2026-04-17-phase-0-foundation.md in the wheels.dev repo. Subsequent phases migrate blog content from DB, generate API reference from docs/api/*.json, migrate guides from docs/src/, and retire the CFWheels wheels.dev app. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 9cd068c commit a5d72d0

40 files changed

Lines changed: 5949 additions & 2 deletions

.github/workflows/web-deploy.yml

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
name: Deploy static sites
2+
3+
on:
4+
push:
5+
branches: [develop]
6+
paths:
7+
- 'web/**'
8+
- '.github/workflows/web-deploy.yml'
9+
pull_request:
10+
branches: [develop]
11+
paths:
12+
- 'web/**'
13+
- '.github/workflows/web-deploy.yml'
14+
15+
jobs:
16+
deploy:
17+
name: Deploy ${{ matrix.site }}
18+
runs-on: ubuntu-latest
19+
concurrency:
20+
group: web-deploy-${{ matrix.site }}-${{ github.ref }}
21+
cancel-in-progress: true
22+
permissions:
23+
contents: read
24+
deployments: write
25+
pull-requests: write
26+
strategy:
27+
fail-fast: false
28+
matrix:
29+
site: [landing, blog, guides, api]
30+
31+
steps:
32+
- name: Checkout
33+
uses: actions/checkout@v4
34+
35+
- name: Set up pnpm
36+
uses: pnpm/action-setup@v4
37+
with:
38+
version: 10.23.0
39+
40+
- name: Set up Node.js
41+
uses: actions/setup-node@v4
42+
with:
43+
node-version: 22
44+
cache: pnpm
45+
cache-dependency-path: web/pnpm-lock.yaml
46+
47+
- name: Install dependencies
48+
working-directory: web
49+
run: pnpm install --frozen-lockfile
50+
51+
- name: Build ${{ matrix.site }}
52+
working-directory: web
53+
run: pnpm --filter @wheels-dev/site-${{ matrix.site }} build
54+
55+
- name: Deploy to Cloudflare Pages
56+
uses: cloudflare/wrangler-action@v3
57+
env:
58+
# Untrusted inputs — pass via env to prevent command injection
59+
DEPLOY_BRANCH: ${{ github.head_ref || github.ref_name }}
60+
with:
61+
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
62+
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
63+
command: pages deploy web/sites/${{ matrix.site }}/dist --project-name=wheels-${{ matrix.site }} --branch="$DEPLOY_BRANCH" --commit-hash="$GITHUB_SHA"

.gitignore

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,12 @@ tests/_output/
4949
/playwright-report/
5050
/blob-report/
5151
/playwright/.cache/
52-
/playwright/.auth/
52+
/playwright/.auth/
53+
54+
# Node / Astro (web/)
55+
web/**/node_modules/
56+
web/**/.astro/
57+
web/**/dist/
58+
web/**/.wrangler/
59+
web/**/.turbo/
60+
web/.pnpm-store/

.nvmrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
22

commitlint.config.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,15 @@ export default {
3232
'plugin',
3333
'sse',
3434
'seed',
35-
'docs'
35+
'docs',
36+
// Static-site monorepo under web/ (wheels.dev sites)
37+
'web',
38+
'web/ui',
39+
'web/landing',
40+
'web/blog',
41+
'web/guides',
42+
'web/api',
43+
'web/starlight'
3644
]
3745
],
3846
// Allow empty scope (scope is optional)

web/.prettierignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Generated output — never format
2+
**/dist/
3+
**/.astro/
4+
**/node_modules/
5+
**/pnpm-lock.yaml
6+
**/pagefind/
7+
8+
# Lockfiles and binaries
9+
*.svg

web/.prettierrc.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"printWidth": 100,
3+
"singleQuote": true,
4+
"semi": true,
5+
"trailingComma": "es5",
6+
"plugins": ["prettier-plugin-astro"],
7+
"overrides": [{ "files": "*.astro", "options": { "parser": "astro" } }]
8+
}

web/README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# wheels.dev Static Sites
2+
3+
Monorepo for the four static sites served under the `wheels.dev` apex and subdomains:
4+
5+
| Site | Path | Domain |
6+
| ------- | ---------------- | ------------------- |
7+
| Landing | `sites/landing/` | `wheels.dev` |
8+
| Guides | `sites/guides/` | `guides.wheels.dev` |
9+
| API | `sites/api/` | `api.wheels.dev` |
10+
| Blog | `sites/blog/` | `blog.wheels.dev` |
11+
12+
Shared UI lives in `packages/ui/` (imported as `@wheels-dev/ui`).
13+
14+
## Local development
15+
16+
```bash
17+
pnpm install
18+
pnpm dev:blog # or dev:landing, dev:guides, dev:api
19+
```
20+
21+
## Build
22+
23+
```bash
24+
pnpm build # builds all four sites
25+
```
26+
27+
## Deploy
28+
29+
Cloudflare Pages watches this repo and builds each site when files under its
30+
path change. See the project dashboard for per-site build settings.

web/package.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "@wheels-dev/web",
3+
"version": "0.0.0",
4+
"private": true,
5+
"description": "wheels.dev static sites monorepo",
6+
"packageManager": "pnpm@10.23.0",
7+
"engines": {
8+
"node": ">=22.0.0"
9+
},
10+
"scripts": {
11+
"build": "pnpm -r --filter './sites/*' build",
12+
"dev:landing": "pnpm --filter @wheels-dev/site-landing dev",
13+
"dev:blog": "pnpm --filter @wheels-dev/site-blog dev",
14+
"dev:guides": "pnpm --filter @wheels-dev/site-guides dev",
15+
"dev:api": "pnpm --filter @wheels-dev/site-api dev",
16+
"format": "prettier --write \"**/*.{astro,ts,tsx,md,json,css}\"",
17+
"format:check": "prettier --check \"**/*.{astro,ts,tsx,md,json,css}\""
18+
},
19+
"devDependencies": {
20+
"prettier": "^3.4.2",
21+
"prettier-plugin-astro": "^0.14.1",
22+
"typescript": "^5.7.2"
23+
}
24+
}

web/packages/ui/package.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "@wheels-dev/ui",
3+
"version": "0.0.0",
4+
"type": "module",
5+
"private": true,
6+
"exports": {
7+
"./components/Header.astro": "./src/components/Header.astro",
8+
"./components/Footer.astro": "./src/components/Footer.astro",
9+
"./styles/tokens.css": "./src/styles/tokens.css"
10+
},
11+
"peerDependencies": {
12+
"astro": "^5.0.0"
13+
}
14+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
---
2+
const year = new Date().getFullYear();
3+
---
4+
5+
<footer class="wd-footer">
6+
<div class="wd-footer__inner">
7+
<p>&copy; {year} Wheels contributors. MIT licensed.</p>
8+
<nav class="wd-footer__nav">
9+
<a href="https://github.com/wheels-dev/wheels">GitHub</a>
10+
<a href="https://guides.wheels.dev/">Guides</a>
11+
<a href="https://api.wheels.dev/">API</a>
12+
</nav>
13+
</div>
14+
</footer>
15+
16+
<style>
17+
.wd-footer {
18+
border-top: 1px solid var(--color-border);
19+
padding: 2rem 1.5rem;
20+
background: var(--color-bg);
21+
color: var(--color-muted);
22+
font-family: var(--font-sans);
23+
font-size: 0.875rem;
24+
}
25+
.wd-footer__inner {
26+
max-width: var(--max-width);
27+
margin: 0 auto;
28+
display: flex;
29+
justify-content: space-between;
30+
align-items: center;
31+
gap: 1rem;
32+
flex-wrap: wrap;
33+
}
34+
.wd-footer__nav {
35+
display: flex;
36+
gap: 1rem;
37+
}
38+
.wd-footer__nav a {
39+
color: var(--color-muted);
40+
text-decoration: none;
41+
}
42+
.wd-footer__nav a:hover {
43+
color: var(--color-fg);
44+
}
45+
</style>

0 commit comments

Comments
 (0)