diff --git a/.github/workflows/nextjs.yml b/.github/workflows/nextjs.yml index 772c052..4ab3434 100644 --- a/.github/workflows/nextjs.yml +++ b/.github/workflows/nextjs.yml @@ -2,7 +2,7 @@ name: CI / Deploy on: push: - branches: ["main"] + branches: ["main", "redesign"] # TEMP(redesign): "redesign" is fork-preview only — revert to ["main"] before upstream merge pull_request: branches: ["main"] workflow_dispatch: @@ -82,6 +82,11 @@ jobs: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}- - run: npm ci - run: npm run build + # TEMP(redesign): basePath for fork Pages preview at /mellea-website. + # On main this resolves to empty, so it is a no-op there. Remove this + # env block before upstream merge. + env: + NEXT_PUBLIC_BASE_PATH: ${{ github.ref == 'refs/heads/redesign' && '/mellea-website' || '' }} - uses: actions/upload-artifact@v7 with: name: website @@ -113,12 +118,17 @@ jobs: path: playwright-report/ retention-days: 7 + # TEMP(redesign): preview deploy for the fork. Gated on build only — + # test-e2e and link-check still run and report status on the PR, but they + # assume root-path serving / a live URL and so don't fit an in-progress + # basePath preview. Before upstream merge, revert BOTH lines below to: + # needs: [test-unit, test-e2e, link-check] + # if: | + # github.ref == 'refs/heads/main' && + # (needs.link-check.result == 'success' || needs.link-check.result == 'skipped') deploy: - needs: [test-unit, test-e2e, link-check] - # Allow deploy when link-check was skipped via the override mechanisms above. - if: | - github.ref == 'refs/heads/main' && - (needs.link-check.result == 'success' || needs.link-check.result == 'skipped') + needs: [test-unit, build] + if: github.ref == 'refs/heads/redesign' runs-on: ubuntu-latest environment: name: github-pages diff --git a/AGENTS.md b/AGENTS.md index 9750963..858f0b6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -10,8 +10,6 @@ This is the **Next.js website** for Mellea — the landing page and developer bl **Adding or editing a blog post** → go to [§ Adding Blog Posts](#8-adding-blog-posts). No dev environment, no code changes needed. -**Adding a news highlight** → go to [§ Adding News Items](#9-adding-news-items). No dev environment, no code changes needed. - **Changing the site** (UI, components, CI, dependencies) → read everything below. --- @@ -40,8 +38,9 @@ npm run build # Static export to ./out/ | `src/lib/` | Server-side utilities (blog parsing, etc.) | | `src/config/` | Site-wide configuration (`site.ts`) | | `content/blogs/` | Markdown blog posts with YAML front matter | -| `content/news/` | Markdown news/highlights items with YAML front matter | -| `public/` | Static assets (images, CNAME) | +| `public/css/` | Global stylesheets | +| `public/js/` | Vanilla ES-module landing-page interactions | +| `public/` | Static assets (fonts, images, CNAME) | | `tests/unit/` | Vitest unit tests | | `tests/e2e/` | Playwright E2E tests | | `.github/workflows/` | CI pipeline | @@ -51,19 +50,32 @@ npm run build # Static export to ./out/ - TypeScript throughout — no `any` without a comment explaining why - Server Components by default; add `'use client'` only when needed - `src/lib/blogs.ts` uses Node.js `fs` — never import it in Client Components -- `params` in Next.js 15 page components is a `Promise` — always `await params` -- No CSS modules, no Tailwind — all styles in `src/app/globals.css` +- `params` in page components is a `Promise` — always `await params` +- Plain CSS only — no CSS modules, no Tailwind; global styles live in `public/css/` - `src/config/site.ts` is the single source of truth for URLs and repo slug -## 4. Attribution +## 4. AI Coding Assistants + +AI-assisted development is welcome. You are responsible for reviewing and understanding every change before submitting. + +AI coding assistants following project guidelines add an `Assisted-by:` trailer to commit messages by default, identifying which tool was used: + +```text +Assisted-by: Claude Code +Assisted-by: IBM Bob +``` -Do **not** add AI assistant attribution to commits, PRs, code, or documentation unless explicitly asked. No `Co-Authored-By` lines, no AI-generated footers. +Add one line per tool used, using its common name (GitHub Copilot, Cursor, etc.). Do not add `Co-Authored-By` lines for AI tools. ## 5. Commits -Plain descriptive messages: `fix: nav link selector in E2E tests`, `feat: add tags filter to blog listing`, `docs: update CONTRIBUTING.md`. +Follow [Angular commit format](https://github.com/angular/angular/blob/main/CONTRIBUTING.md#commit), matching the [mellea repo](https://github.com/generative-computing/mellea): `: `, with an optional body and footer. -No Angular-style mandatory types required, but keep messages short and imperative. +**Types:** `feat`, `fix`, `docs`, `test`, `refactor`, `ci`, `chore`, `release`. + +Examples: `fix: nav link selector in E2E tests`, `feat: add tags filter to blog listing`, `docs: update CONTRIBUTING.md`. + +**Sign off every commit** with `git commit -s` (DCO is enforced in CI). ## 6. Pre-commit Checklist (mandatory — do not skip) @@ -88,27 +100,32 @@ If you rename or remove a CSS class, check `tests/e2e/` for selectors that refer ## 7. Architecture -**Next.js 15 App Router, fully static** (`output: 'export'`). Nothing runs at request time — all pages are pre-rendered at build time or handled client-side. +**Next.js App Router, fully static** (`output: 'export'`). Nothing runs at request time — all pages are pre-rendered at build time or handled client-side. ### Key constraints - No `next/headers`, no route handlers, no server actions - `Image` component uses `unoptimized: true` (required for static export) - `trailingSlash: true` is set in `next.config.mjs` -- `params` in page components is a `Promise` in Next.js 15 — always `await params` +- `params` in page components is a `Promise` — always `await params` - `src/lib/blogs.ts` uses Node.js `fs` — **Server Components only**, never import in Client Components ### Data flow -- **Build-time** (Server Components): `getAllBlogs()` → landing page + blog listing; `getAllBlogSlugs()` + `getBlog(slug)` → individual post pages; `getAllNews()` → landing page news highlights -- **Client-side** (Client Components): GitHub API stats via `useGitHubStats` hook on mount; image compare slider via `react-compare-slider` +- **Build-time** (Server Components): `getAllBlogs()` → landing page + blog listing; `getAllBlogSlugs()` + `getBlog(slug)` → individual post pages +- **Client-side**: GitHub star count via the `GitHubStarsInit` component on mount; landing-page interactions (cursor, hero, compare slider, code panel) via vanilla ES modules in `public/js/` ### Styling -- Single global CSS file: `src/app/globals.css` -- IBM Plex Sans + IBM Plex Mono (Google Fonts) -- Dark/light theme via CSS custom properties + `@media (prefers-color-scheme: light)` -- No CSS modules, no Tailwind +- Global stylesheets in `public/css/`: `styles.css` (site) + `code-theme.css` (syntax highlighting), linked from `layout.tsx` +- Self-hosted **Aileron** (sans) + **JetBrains Mono** via `public/assets/fonts.css` +- Light theme via CSS custom properties on `:root` +- Landing-page interactions (cursor, hero, compare slider, code panel) are vanilla ES modules in `public/js/` +- Plain CSS only — no CSS modules, no Tailwind + +### Landing-page JS (`public/js/`) + +These are plain browser ES modules — served statically and loaded via a `