Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a4df9ed
feat(quick-start): implement QuickStartSection and CodeBlock components
May 7, 2026
8f2dd51
chore(scenario): backend fallback commit for "Quick-Start Guide Section"
May 7, 2026
986f04e
feat(roadmap): implement RoadmapSection with full feature display
May 7, 2026
ad6b9df
feat(demo): add interactive demo section with terminal animation
May 7, 2026
1acbe05
feat(homepage): implement responsive desktop layout with E2E tests
May 7, 2026
ad40022
test(a11y): add WCAG 2.1 AA accessibility e2e tests
May 7, 2026
0ff14b5
feat(mobile): add mobile navigation overlay and responsive E2E tests
May 7, 2026
5c4b435
test(cross-browser): add Playwright projects for Chrome, Firefox, Saf…
May 7, 2026
4d20238
feat(theme): add dark mode support with system preference and persist…
May 7, 2026
86316bb
test(static-generation): add e2e tests verifying Next.js static export
May 7, 2026
d1d484e
chore(scenario): backend fallback commit for "Dark Mode Support"
May 7, 2026
38e81da
Merge remote-tracking branch 'origin/feature/product-homepage-design-…
May 7, 2026
364a05e
chore(scenario): backend fallback commit for "Cross-Browser Compatibi…
May 7, 2026
dc3d6d3
Merge remote-tracking branch 'origin/feature/product-homepage-design-…
May 7, 2026
8bfe0f2
feat(navigation): add smooth-scroll header, scroll spy, and hash routing
May 7, 2026
3d398c4
chore(scenario): backend fallback commit for "Responsive Design - Mob…
May 7, 2026
3ac05c9
Merge remote-tracking branch 'origin/feature/product-homepage-design-…
May 7, 2026
5bc5125
feat(seo): add comprehensive SEO meta tags and structured data
May 7, 2026
0cf91b0
chore(scenario): backend fallback commit for "Static Site Generation"
May 7, 2026
0689936
chore(scenario): backend fallback commit for "Navigation and Smooth S…
May 7, 2026
7198279
Merge remote-tracking branch 'origin/feature/product-homepage-design-…
May 7, 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
7 changes: 7 additions & 0 deletions .claude/skills/css-feature-detection-with-fallbacks/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
name: css-feature-detection-with-fallbacks
description: Runtime CSS feature detection that defends against missing CSS.supports, normalizes the -webkit-backdrop-filter prefix for Safari, and exposes a hasCriticalSupport predicate that treats scroll-behavior and backdrop-filter as optional. Use when a component needs to branch on browser CSS support or a test must enforce graceful fallbacks.
scope: project
---

See [README.md](references/README.md) for full documentation.
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# CSS Feature Detection With Fallbacks

A small TypeScript module that wraps `CSS.supports()` for the homepage's cross-browser strategy. Used both at runtime (when a component wants to branch on engine support) and from Jest unit tests (to validate that the global stylesheet declares fallback chains).

## Lives at

`homepage/tests/unit/cross-browser/cssFeatureDetection.ts`

(It currently lives in the test folder because only tests and one runtime utility consume it. Promote to `homepage/src/lib/` if a non-test caller starts importing it.)

## API

```ts
supportsCSSFeature(property: string, value: string): boolean
supportsCSSVariables(): boolean
supportsFlexbox(): boolean
supportsGrid(): boolean
supportsScrollBehavior(): boolean
supportsBackdropFilter(): boolean // probes both standard and -webkit-
checkCriticalCSSFeatures(): CriticalFeatureSupport
hasCriticalSupport(support): boolean
```

## Three rules baked into the implementation

1. **Defensive `CSS.supports` call.** Old browsers and SSR may not expose `CSS` or `CSS.supports`. We type-check both, then call inside try/catch because some engines throw on malformed property/value strings:

```ts
if (typeof CSS === 'undefined' || typeof CSS.supports !== 'function') return false;
try { return CSS.supports(property, value); } catch { return false; }
```

2. **`-webkit-backdrop-filter` is a valid yes.** Safari shipped this without dropping the prefix. `supportsBackdropFilter` returns true if either property reports support, so a Safari-style partial-support shape is treated as supported:

```ts
return (
supportsCSSFeature('backdrop-filter', 'blur(10px)') ||
supportsCSSFeature('-webkit-backdrop-filter', 'blur(10px)')
);
```

3. **`scroll-behavior` and `backdrop-filter` are optional.** `hasCriticalSupport` only requires `cssVariables`, `flexbox`, and `grid`. The other two have natural degradations: missing `scroll-behavior` becomes instant scroll; missing `backdrop-filter` falls back to the solid `background-color` we set on the header.

## Companion test pattern (static CSS analysis)

The Jest suite for this module also reads `globals.css`, `postcss.config.js`, and `tailwind.config.ts` and asserts contracts that would be hard to lint:

```ts
expect(globalsCss).toMatch(/var\(--/); // variables in use
expect(globalsCss).toMatch(/(monospace|sans-serif|serif)/); // generic family fallback
expect(globalsCss).toMatch(/scroll-behavior:\s*smooth/); // smooth declared
expect(postcssConfig).toMatch(/autoprefixer/); // autoprefixer wired
```

A risky-selector guard requires `@supports` whenever `:has()`, `color-mix()`, or `@property` appear:

```ts
const risky = [/:has\(/, /color-mix\(/, /@property\s/];
for (const re of risky) {
if (re.test(globalsCss)) {
expect(globalsCss).toMatch(/@supports/);
}
}
```

This keeps progressive-enhancement enforced as a unit test rather than a code-review checklist.

## Mocking pattern in unit tests

The Jest tests replace `global.CSS` with a Jest mock in `beforeEach` and restore it in `afterEach`. Avoid polluting other suites by always pairing the override:

```ts
let originalCSS: typeof CSS | undefined;
beforeEach(() => {
originalCSS = (global as unknown as { CSS?: typeof CSS }).CSS;
(global as unknown as { CSS: { supports: jest.Mock } }).CSS = { supports: jest.fn() };
});
afterEach(() => { (global as unknown as { CSS?: typeof CSS }).CSS = originalCSS; });
```

The Safari shape test is worth keeping as a regression: it makes `CSS.supports` return false for the standard property and true for `-webkit-backdrop-filter`, then asserts `checkCriticalCSSFeatures().backdropFilter === true`.
8 changes: 8 additions & 0 deletions .claude/skills/nextjs-public-asset-bootstrap/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
name: nextjs-public-asset-bootstrap
description: Copy shared assets from the workspace's /assets/ folder into homepage/public/ so the Next.js dev server serves them at runtime. Use when an image at src=/foo.gif returns 404 in dev/test, when e2e tests need real (not placeholder) images, or when scaffold rule 6 (Asset References) is in play.
metadata:
scope: project
---

See [README.md](references/README.md) for full documentation.
60 changes: 60 additions & 0 deletions .claude/skills/nextjs-public-asset-bootstrap/references/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Next.js Public Asset Bootstrap

## Overview

The MirDB project keeps shared image assets at `/workspace/assets/` (referenced by scaffold rule #6, "Asset References"), but the Next.js app at `homepage/` only serves files placed under `homepage/public/`. This skill captures the bootstrap step: copying the shared assets into the homepage public folder so the dev server, e2e tests, and production build all see the real images.

## When to Use This Skill

Use this skill when:

- An `<img src="/foo.gif">` 404s in the dev server but the file exists under `/workspace/assets/foo.gif`
- An e2e test inspects images and the page returns a broken image (no `naturalWidth`, axe `image-alt`/`image-redundant-alt` flapping)
- You are scaffolding a new homepage scenario and need to be sure the scenario's component can actually render its image
- Scaffold rule #6 (Asset References) is in play

## Core Capabilities

### 1. Identify which public/ assets the page references

Grep the homepage source for `src="/"` and `url(/...)`:

```bash
grep -rn 'src="/' homepage/src/
grep -rn 'url(/' homepage/src/
```

Each unique `/foo.gif` / `/bar.png` is a candidate that must exist under `homepage/public/`.

### 2. Copy from shared `/workspace/assets/`

```bash
cp /workspace/assets/logo.gif homepage/public/logo.gif
cp /workspace/assets/usage.gif homepage/public/usage.gif
```

This is intentionally a copy, not a symlink — the homepage Next.js build (especially the `output: 'export'` static path) needs concrete files under `public/`.

### 3. Verify the dev server serves them

```bash
curl -sI http://localhost:3000/usage.gif | head -1 # expect 200, not 404
```

If the dev server is already running, no restart is needed — Next.js serves `public/` files dynamically.

## Best Practices

- Treat `homepage/public/` as **bootstrap territory**, not a per-scenario folder. Copying an asset here is appropriate even if your scenario only owns `tests/`.
- Do not modify or rename the original under `/workspace/assets/`. Other scenarios reference it by name.
- After copying, commit both the copy and any test that depends on it in the same commit so reviewers see the dependency in one diff.

## Reference Implementation

`homepage/public/usage.gif`, `homepage/public/logo.gif` (copies of `/workspace/assets/usage.gif`, `/workspace/assets/logo.gif`).

## Resources

### references/

- `README.md` — This documentation
8 changes: 8 additions & 0 deletions .claude/skills/playwright-axe-a11y-testing/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
name: playwright-axe-a11y-testing
description: Run WCAG 2.1 AA audits inside Playwright tests using @axe-core/playwright with a Lighthouse-style pass-rate gate. Use when adding accessibility tests for a Next.js homepage, when a scenario requires zero critical violations plus a 90 or higher score, or when you need an axe audit that produces assertable JSON instead of a Lighthouse HTML report.
metadata:
scope: project
---

See [README.md](references/README.md) for full documentation.
82 changes: 82 additions & 0 deletions .claude/skills/playwright-axe-a11y-testing/references/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Playwright Axe A11y Testing

## Overview

This skill captures the pattern used in `homepage/tests/e2e/accessibility.spec.ts` for running an in-test WCAG 2.1 AA audit using `@axe-core/playwright`. Instead of spinning up the Lighthouse CLI (heavy, HTML report, requires headful Chrome), we run the same WCAG rule set inside a Playwright test, return a structured violations array, and reproduce Lighthouse's rule-pass-rate scoring with assertable JSON.

## When to Use This Skill

Use this skill when:

- A scenario or PRD asks for "Lighthouse accessibility score >= 90 with zero critical violations"
- You need a deterministic, sub-second accessibility check that runs in CI without extra browser binaries
- You want to filter axe violations by impact level (`minor` / `moderate` / `serious` / `critical`) to scope a gate
- A page has color-contrast issues owned by other components/teams that you do not want to block on, but still want logged

## Core Capabilities

### 1. Tagged WCAG audit via AxeBuilder

```ts
import AxeBuilder from '@axe-core/playwright';

const results = await new AxeBuilder({ page })
.withTags(['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa'])
.analyze();
```

The four tags select WCAG 2.0 Level A + AA and WCAG 2.1 Level A + AA — the exact surface called out by PRD NFR-3.

### 2. Critical-only gate

```ts
const critical = results.violations.filter((v) => v.impact === 'critical');
expect(critical).toHaveLength(0);
```

`critical` issues are the ones that actually block assistive tech (missing accessible names, broken landmark structure). `serious` issues like color-contrast are real WCAG failures but often live in design-token territory owned by other scenarios — log them but do not gate on them here.

### 3. Lighthouse-style rule pass-rate

```ts
const totalRulesEvaluated =
results.violations.length + results.passes.length + results.incomplete.length;
const violationCount = results.violations.length;
const passRate =
totalRulesEvaluated === 0
? 100
: ((totalRulesEvaluated - violationCount) / totalRulesEvaluated) * 100;
expect(passRate).toBeGreaterThanOrEqual(90);
```

Counts rule TYPES (not flagged DOM nodes). One failing rule with 12 nodes is one failed audit, mirroring how Lighthouse computes its 0–100 score. A single offending rule cannot tank the score, but multiple distinct accessibility problems will.

### 4. Surfacing failures in the test log

Always print the violations summary before asserting so a failing CI run includes the offending rule IDs:

```ts
if (critical.length > 0) {
console.log('Critical violations:', JSON.stringify(
critical.map((v) => ({ id: v.id, impact: v.impact, help: v.help })),
null, 2,
));
}
```

## Best Practices

- Always `await page.waitForLoadState('networkidle')` in `beforeEach` so axe sees the final DOM.
- Filter on `impact === 'critical'` only when the test_case wording uses that word — if the wording is "AA conformance", consider including `serious` too.
- Prefer the rule-pass-rate formula above over a flagged-node penalty: it matches Lighthouse semantics and is more stable across runs.
- Add `@axe-core/playwright` and `axe-core` as **devDependencies** of the homepage package, not the root.

## Reference Implementation

`homepage/tests/e2e/accessibility.spec.ts` lines 10–46 (Test Case 1).

## Resources

### references/

- `README.md` — This documentation
7 changes: 7 additions & 0 deletions .claude/skills/playwright-cross-browser-projects/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
name: playwright-cross-browser-projects
description: Configure Playwright projects for Chrome, Firefox, Safari (WebKit), and Edge with selective testMatch scoping so cross-browser tests run on all engines while other suites stay on chromium. Use when adding cross-browser coverage to a Next.js or web project that already uses Playwright.
scope: project
---

See [README.md](references/README.md) for full documentation.
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Playwright Cross-Browser Projects

How the MirDB homepage runs cross-browser e2e tests on Chrome, Firefox, Safari (WebKit), and Edge while keeping the rest of the e2e suite scoped to chromium for CI cost.

## When to use

- Adding a new e2e spec that must validate engine-specific behavior (CSS, layout, font fallbacks).
- Verifying that cross-browser regressions show up in CI without quadrupling the runtime of unrelated specs.

## The pattern

In `homepage/playwright.config.ts`:

```ts
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
{
name: 'firefox',
testMatch: /cross-browser\.spec\.ts/,
use: { ...devices['Desktop Firefox'] },
},
{
name: 'webkit',
testMatch: /cross-browser\.spec\.ts/,
use: { ...devices['Desktop Safari'] },
},
{
name: 'edge',
testMatch: /cross-browser\.spec\.ts/,
use: { ...devices['Desktop Edge'] },
},
]
```

Key points:

1. **`chromium` has no `testMatch`** so it runs every spec under `tests/e2e/` (the default). All non-cross-browser tests still execute.
2. **Firefox / WebKit / Edge each set `testMatch: /cross-browser\.spec\.ts/`** which restricts that project to a single file.
3. **Edge uses `Desktop Edge`** rather than a separate channel install. Modern Edge is Chromium-based and Playwright's Desktop Edge device exercises that engine through the Edge channel — matches reality, keeps CI hermetic.
4. **Run all four engines on the cross-browser file**: `npx playwright test tests/e2e/cross-browser.spec.ts` runs the spec on each project (~72 tests for the suite documented here).
5. **Run a single engine for debugging**: `npx playwright test --project=webkit tests/e2e/cross-browser.spec.ts`.

## Browser install (for fresh hosts)

Firefox and WebKit need system libs. The flow that worked on this Ubuntu 22.04 host:

```bash
npx playwright install chromium # ok without sudo
sudo -n npx playwright install-deps chromium # apt deps
sudo -n npx playwright install --with-deps firefox webkit
```

The `--with-deps` form of `install` runs `apt-get install` for the required X/GTK libraries before downloading the browser binaries. Without sudo, Firefox/WebKit downloads still succeed but launching fails with the host validation banner.

## Test patterns that worked across all four engines

In the cross-browser spec, every assertion includes `${browserName}` in the message so a CI failure tells you which engine regressed:

```ts
expect(consoleErrors, `${browserName}: page should load without console errors`).toEqual([]);
```

For features with engine-specific prefixes (e.g. `backdrop-filter`), accept either the standard property OR a documented graceful fallback (background-color), so the test stays green on engines that lawfully lack the property without weakening the contract on engines that have it.

## Reference: this scenario

- `homepage/playwright.config.ts` lines 20–40
- `homepage/tests/e2e/cross-browser.spec.ts` (18 tests, all engines)
- All 4 projects pass: chromium 18/18, firefox 18/18, webkit 18/18, edge 18/18.
8 changes: 8 additions & 0 deletions .claude/skills/status-tagged-list-section/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
name: status-tagged-list-section
description: Render a homepage section that splits a single tagged data array (e.g. status='implemented'|'planned') into two visually distinct columns - implemented in green with checkmark icons, planned in amber with clock icons - in the MirDB Next.js homepage. Use whenever a section needs to compare "shipped" vs "upcoming" items sourced from src/lib/constants.ts.
metadata:
scope: project
---

See [README.md](references/README.md) for full documentation.
Loading