Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
cc0fd28
ci(redesign): set up fork Pages preview from redesign branch
ajbozarth Jun 26, 2026
9447782
ci(redesign): gate preview deploy on build, not e2e/link-check
ajbozarth Jun 26, 2026
f786ad1
Initial Migration
Jun 27, 2026
4abc762
Design Fixes
Jun 29, 2026
792e864
Update to style.css
Jun 29, 2026
0c025d8
Updated style.css
Jun 30, 2026
f2878ba
Header Nav Links
Jul 6, 2026
b16b96a
fix: redesign review β€” remove news, dedupe stars, fix code/image rend…
ajbozarth Jul 10, 2026
2cc6b66
fix: prefix blog markdown image URLs with basePath
ajbozarth Jul 10, 2026
086daf2
refactor: rename cursor sprites, repoint OG image, drop unused logo
ajbozarth Jul 10, 2026
2ba45cc
refactor: use CSS variables for repeated colors
ajbozarth Jul 10, 2026
02ec5c7
docs: refresh AGENTS.md and README for redesigned site
ajbozarth Jul 13, 2026
559c428
refactor: add ESLint gate for public/js and remove dead code
ajbozarth Jul 13, 2026
9d4a190
refactor: flatten src/components/redesign into src/components
ajbozarth Jul 13, 2026
c93c57e
refactor: clean up landing-page comments and dev config
ajbozarth Jul 13, 2026
b620554
refactor: reduced-motion safety net, color-scheme, dotField comments
ajbozarth Jul 13, 2026
6ab725d
Merge remote-tracking branch 'upstream/main' into redesign
ajbozarth Jul 13, 2026
b135357
refactor: dedupe homepage metadata and section containers
ajbozarth Jul 13, 2026
d4793aa
-s
Jul 14, 2026
5dc2b2e
chore
Jul 14, 2026
9b39fbd
fix: mobile layout and menu bugs from device testing
ajbozarth Jul 15, 2026
b0db54c
fix: restore Get Started in mobile menu, anchor hamburger top-right
ajbozarth Jul 15, 2026
a9acfa2
fix: style mobile menu Get Started as a text link with arrow
ajbozarth Jul 15, 2026
5c04e67
test: harden e2e suite against timing flakiness
ajbozarth Jul 15, 2026
75f5c56
Merge branch 'main' into redesign
ajbozarth Jul 17, 2026
3ffb756
fix: add missing space after year in footer copyright
ajbozarth Jul 17, 2026
ff25e69
fix: use div role=tab in future-panel to keep HTML valid
ajbozarth Jul 17, 2026
0dce46d
fix: restore skip link and harden keyboard accessibility
ajbozarth Jul 17, 2026
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
22 changes: 16 additions & 6 deletions .github/workflows/nextjs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
87 changes: 37 additions & 50 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

---
Expand Down Expand Up @@ -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 |
Expand All @@ -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): `<type>: <subject>`, 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)

Expand All @@ -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 `<script type="module">` tag, not bundled or transpiled. They are JavaScript, not TypeScript, and are intentionally outside `tsconfig`, so `npm run typecheck` does not cover them. The JSDoc `@param`/`@returns` annotations are for editor hints and readability only; they are **not** enforced by `tsc`, so do not assume these files are type-checked because they carry JSDoc. ESLint is the quality gate here β€” the flat config lints `public/js/**/*.js` with `eslint:recommended` plus `no-unused-vars`/`no-undef` and browser globals.

### Deployment

Expand Down Expand Up @@ -158,41 +175,11 @@ A workflow runs daily at ~9am Eastern and posts a reminder comment on the PR onc

Verify with `npm run build` β€” no config changes or code edits needed.

## 9. Adding News Items

Drop a `.md` file in `content/news/`. News items appear in the "Latest News" highlights strip on the landing page hero section, sorted by date descending. Unlike blog posts, news items link to an external URL (opened in a new tab) β€” they do not have their own page on the site.

Required front matter:

```md
---
title: "Short Headline"
date: "YYYY-MM-DD"
category: "Release"
excerpt: "One sentence description shown on the card."
url: "https://example.com/full-link"
source: "GitHub"
---
```

| Field | Required | Notes |
| ---------- | -------- | ---------------------------------------------------------------------------- |
| `title` | Yes | Short headline for the card |
| `date` | Yes | `YYYY-MM-DD`, used for sorting |
| `category` | Yes | One of: `Release`, `Event`, `Integration`, `Community`, `Feature` |
| `excerpt` | Yes | One sentence shown on the card |
| `url` | Yes | External link (must be a full URL) |
| `source` | No | Display label for the link (e.g. "GitHub", "PyCon"); defaults to "Read more" |

The `category` field controls the visual styling β€” each category gets a distinct accent color on the card's left border and category badge. No markdown body content is needed (only frontmatter is used).

Verify with `npm run build` β€” no config changes or code edits needed.

## 10. Common Issues
## 9. Common Issues

| Problem | Fix |
| --- | --- |
| `params` type error in page component | `params` is `Promise<{slug: string}>` in Next.js 15 β€” use `await params` |
| `params` type error in page component | `params` is `Promise<{slug: string}>` β€” use `await params` |
| E2E test strict mode violation | Scope selector (e.g. `page.getByRole('banner').getByRole('link', ...)`) |
| `fs` import error in client bundle | Move the import to a Server Component; never import `src/lib/blogs.ts` client-side |
| ESLint config error | Uses ESLint 9 flat config (`eslint.config.mjs`) β€” no legacy `.eslintrc` |
74 changes: 4 additions & 70 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# Contributing

There are three ways to contribute:
There are two ways to contribute:

- **Writing a blog post** β€” add a Markdown file and verify it renders. [Jump to that section.](#adding-a-blog-post)
- **Adding a news highlight** β€” add a short Markdown file to surface events, releases, or features. [Jump to that section.](#adding-a-news-item)
- **Changing the site** β€” UI, CI, or dependencies. Requires a full dev setup. [Jump to that section.](#development-setup)

All contributions must be signed off under the [Developer Certificate of Origin](#developer-certificate-of-origin-dco) β€” use `git commit -s` on every commit.
Expand Down Expand Up @@ -80,74 +79,9 @@ No config changes or code edits are needed β€” just the Markdown file and any im

---

## Adding a news item

News items are short highlights that appear on the landing page to draw attention to things that matter to users β€” upcoming events (conferences, meetups, webinars), new releases, notable integrations or features, community milestones, or any other timely announcement. Unlike blog posts, news items link out to an external URL and do not have their own page on the site.

### Steps

1. Fork the repository.

2. Create a new file in `content/news/news-n.md`.
The filename is internal only (not a public URL), to make it easier and only update the frontmatter content, keep the name pattern to `news-n.md`.

3. Fill in the YAML front matter:

```md
---
title: "Short Headline"
date: "YYYY-MM-DD"
category: "Release"
excerpt: "One sentence description shown on the card."
url: "https://example.com/full-link"
source: "GitHub"
---
```

No markdown body content is needed β€” only the front matter is used.

4. Verify locally:

```bash
npm install
npm run build # must succeed with no errors
npm run dev # check the landing page at http://localhost:4000
```

5. Open a PR against `main`. A member of the **mellea-maintainers** team must approve before merge.

6. Once merged, the news item will appear in the "Latest News" section on the landing page within a few minutes.

### News front matter fields

| Field | Required | Description |
| ---------- | -------- | ---------------------------------------------------------------------------- |
| `title` | Yes | Short headline for the card |
| `date` | Yes | Date (`YYYY-MM-DD`), used for sort order |
| `category` | Yes | One of: `Release`, `Event`, `Integration`, `Community`, `Feature` |
| `excerpt` | Yes | One sentence shown on the card |
| `url` | Yes | External link target (must be a full URL starting with `https://`) |
| `source` | No | Label shown on the link (e.g. "GitHub", "PyCon"); defaults to "Read more" |

### Categories

Each category gets a distinct accent color on the card to help users scan at a glance:

| Category | Color | Use for |
| ------------- | ------ | ---------------------------------------------- |
| `Release` | Blue | New versions, changelogs |
| `Event` | Green | Conferences, meetups, webinars |
| `Integration` | Purple | New framework or tool integrations |
| `Community` | Cyan | Community milestones, spotlights |
| `Feature` | Blue | Notable new capabilities |

No config changes or code edits are needed β€” just the Markdown file.

---

## Developer Certificate of Origin (DCO)

All contributions to this repository β€” blog posts, news items, and code changes β€”
All contributions to this repository β€” blog posts and code changes β€”
must be signed off under the [Developer Certificate of Origin](https://developercertificate.org/),
which certifies that you have the right to submit your work under the project's
license. By signing off on a commit, you are agreeing to the terms of the DCO
Expand Down Expand Up @@ -311,7 +245,7 @@ On E2E failure, a `playwright-report` artifact is uploaded to the GitHub Actions
### Key constraints

- No `next/headers`, no route handlers, no server actions
- `Image` component uses `unoptimized: true` (required for static export)
- `images.unoptimized: true` is set in `next.config.mjs` (required for static export); components use plain `<img>` rather than `next/image`
- `trailingSlash: true` is set in `next.config.mjs`
- Blog data fetching uses Node.js `fs` inside Server Components only β€” `src/lib/blogs.ts` is **not** safe to import in Client Components

Expand All @@ -321,4 +255,4 @@ On E2E failure, a `playwright-report` artifact is uploaded to the GitHub Actions

### Styling

Single global CSS file: `src/app/globals.css`. IBM Plex fonts via Google Fonts. Dark/light theme via CSS custom properties and `@media (prefers-color-scheme: light)`. No CSS modules, no Tailwind.
Stylesheets under `public/css/` (`styles.css` plus `code-theme.css` for syntax highlighting), linked from `src/app/layout.tsx`. Self-hosted fonts (Aileron + JetBrains Mono) via `public/assets/fonts.css`. Light theme only (no dark mode / `prefers-color-scheme`). No CSS modules, no Tailwind. Landing-page interactions are plain ES modules in `public/js/`.
31 changes: 7 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Mellea Website

Landing page and developer blog for **[Mellea](https://github.com/generative-computing/mellea)** β€” a composable, multi-agent framework for building reliable AI agents at production scale.
Landing page and developer blog for **[Mellea](https://github.com/generative-computing/mellea)** β€” a Python library for writing generative programs: control LLMs with code, not prompts.

Built with Next.js 15, statically exported, and deployed to GitHub Pages at [mellea.ai](https://mellea.ai).
Built with Next.js, statically exported to GitHub Pages at [mellea.ai](https://mellea.ai).

---

Expand All @@ -18,30 +18,13 @@ Built with Next.js 15, statically exported, and deployed to GitHub Pages at [mel

## Contributing

There are two distinct ways to contribute β€” pick the one that applies:
Two ways to contribute β€” both covered in full by [CONTRIBUTING.md](CONTRIBUTING.md):

### Writing a blog post

No development environment needed. Copy [`templates/blog-post.md`](templates/blog-post.md) to
`content/blogs/your-slug.md`, fill in the front matter, and open a PR against `main`. A maintainer
will review and merge it β€” the post goes live automatically on merge.

See [CONTRIBUTING.md](CONTRIBUTING.md) for the full submission steps and front matter reference.

### Changing the site (UI, CI, dependencies)

```bash
npm install
npm run dev # http://localhost:4000
```

See [CONTRIBUTING.md](CONTRIBUTING.md) for the full development guide β€” commands, testing, and CI pipeline.
- **Writing a blog post** β€” no dev environment needed; add a Markdown file and open a PR. β†’ [Adding a blog post](CONTRIBUTING.md#adding-a-blog-post)
- **Changing the site** (UI, CI, dependencies) β€” `npm install && npm run dev`. β†’ [Development setup](CONTRIBUTING.md#development-setup)

---

## Tech Stack
## License

- [Next.js 15](https://nextjs.org/) β€” App Router, static export (`output: 'export'`)
- [react-markdown](https://github.com/remarkjs/react-markdown) β€” Markdown rendering
- [gray-matter](https://github.com/jonschlinkert/gray-matter) β€” Frontmatter parsing
- IBM Plex Sans & IBM Plex Mono β€” typography
[Apache License 2.0](LICENSE)
Loading
Loading