Skip to content

Apply Butter & Maple to homepage, login, docs, workspace#179

Merged
hackerwins merged 5 commits into
mainfrom
homepage-butter-maple-redesign
May 3, 2026
Merged

Apply Butter & Maple to homepage, login, docs, workspace#179
hackerwins merged 5 commits into
mainfrom
homepage-butter-maple-redesign

Conversation

@hackerwins

@hackerwins hackerwins commented May 3, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Rebuild the landing page (/) around the locked Butter & Maple design
    (cream-and-syrup palette, Fraunces + Inter + JetBrains Mono, ruler-motif
    backdrop): sticky NavBar, single-column hero, tabbed live-demo card with
    spreadsheet + word-processor iframes (lazy-mounted), feature grid with
    waffle-pocket SVG glyphs, Use Cases / Why / dev-tools / Open Source CTA
    with BigWaffle illustration / Footer.
  • Extend the same identity to /login, /docs (VitePress), and the
    authenticated workspace shell so /, /login, /docs, /w/...,
    Sheet (/s/...) and Doc (/d/...) routes share one visual language.
  • Remap shadcn --primary / --ring / --sidebar-* to the new tokens so
    every default <Button> becomes a syrup pill and the workspace sidebar
    goes cream + WaffleLogo + Fraunces wordmark.
  • Sheet engine: amber active-cell + header swapped to syrup + butter; two
    yellow peer-cursor slots replaced with rose / lavender so collaborator
    labels stop clashing with the syrup-amber accent.
  • Drop deprecated --homepage-* tokens (no remaining callers).

Test plan

  • pnpm verify:self passes locally (8 lanes — already green at the
    tip commit, ~63s).
  • Visit http://localhost:5173/ in light + dark; confirm the hero
    ruler backdrop fades smoothly with no rectangular box artifact.
  • Tab between Spreadsheet / Word processor in the demo card and
    confirm both iframes render with theme sync (no reload).
  • Visit /login, confirm logo lines up at the same x-position as the
    home NavBar (both left=48px on a 1280px viewport).
  • Visit /docs, confirm h1–h4 use Fraunces and brand color is syrup.
  • Sign into a workspace; confirm sidebar is cream + WaffleLogo,
    + New is a syrup pill, the active nav item has the butter glow.
    Toggle dark mode; verify continuity across pages.
  • Open a sheet; confirm the active cell ring is syrup, the active
    column/row header is butter, and the Sheet1 tab underline is
    syrup. Repeat in dark mode (ring → maple amber).
  • Open a doc; confirm sidebar/header are themed. With a second
    collaborator joined, confirm peer labels are no longer bright
    yellow (now rose / lavender / one of the existing distinct hues).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Redesigned homepage with the new “Butter & Maple” visual system, updated palette and typography
    • Demo section now tabbed (spreadsheet + document) with lazy loading and persistent previews; theme changes propagate into demos
    • New Use Cases, Developer, and Open Source sections plus illustrative waffle graphics and UI primitives
  • Style

    • Global design token overhaul and refreshed component styling (including updated login and navbar with theme toggle)

Why: the design handoff in ~/Downloads/design_handoff_wafflebase_landing
locked a cream-and-syrup palette (Fraunces + Inter + JetBrains Mono,
ruler-motif backdrop) for the landing page. Apply it consistently so
the unauthenticated path (/, /login, /docs) and the authenticated
workspace shell share one visual identity.

Scope:
- Homepage: full rebuild around the new tokens — sticky NavBar, focused
  single-column hero with ruler backdrop, tabbed live-demo card with
  spreadsheet + word-processor iframes (lazy-mounted), 3+4 feature grid
  with waffle-pocket SVG glyphs, Use Cases section, restyled Why
  comparison, dark dev-tools card with REST/CLI tabs, Open Source CTA
  with BigWaffle illustration, restyled Footer.
- Login: new header layout matching NavBar geometry, paper card with
  "Welcome back" Fraunces heading, syrup pill GitHub CTA.
- Docs (VitePress): map --vp-c-* tokens to Butter & Maple, load Fraunces
  for headings.
- Workspace shell: remap shadcn --primary / --ring / --sidebar-* to the
  Butter & Maple tokens so the same syrup pill, butter active-nav glow,
  and cream sidebar reach Documents, Data Sources, Settings, Sheet, and
  Doc routes. Swap the sidebar Grid2x2Plus icon for the WaffleLogo
  primitive.
- Sheet engine theme: replace amber active-cell ring + header chip with
  syrup + butter, swap two yellow peer-cursor slots for rose / lavender
  so collaborator labels stop competing with the system accent.
- Drop deprecated --homepage-* tokens (no remaining callers).

Verification: pnpm verify:self passes (8 lanes, ~63s) — sheets / docs /
frontend / backend / cli builds, verify:fast (40 files, 686 tests, lint
0), chunk gate, and entropy checks all green. Frontend chunk count
limit bumped 70 → 80 to absorb the new primitives + section.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@coderabbitai

coderabbitai Bot commented May 3, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@hackerwins has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 27 minutes and 48 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 28228051-5d22-455a-8448-9d30a9574fb5

📥 Commits

Reviewing files that changed from the base of the PR and between b78074b and cda8a75.

⛔ Files ignored due to path filters (76)
  • packages/frontend/tests/visual/baselines/harness-visual.browser.chart-area.desktop.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.chart-area.mobile.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.chart-area.mobile.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.chart-area.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.chart-bar.desktop.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.chart-bar.mobile.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.chart-bar.mobile.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.chart-bar.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.chart-line.desktop.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.chart-line.mobile.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.chart-line.mobile.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.chart-line.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.desktop.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.format-alignment.desktop.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.format-alignment.mobile.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.format-alignment.mobile.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.format-alignment.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.format-borders.desktop.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.format-borders.mobile.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.format-borders.mobile.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.format-borders.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.format-number.desktop.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.format-number.mobile.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.format-number.mobile.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.format-number.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.format-text-bg-colors.desktop.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.format-text-bg-colors.mobile.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.format-text-bg-colors.mobile.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.format-text-bg-colors.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.format-text-decoration.desktop.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.format-text-decoration.mobile.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.format-text-decoration.mobile.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.format-text-decoration.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.mobile.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.mobile.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-dimensions-freeze.desktop.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-dimensions-freeze.mobile.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-dimensions-freeze.mobile.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-dimensions-freeze.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-formula-errors.desktop.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-formula-errors.mobile.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-formula-errors.mobile.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-formula-errors.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-freeze-selection.desktop.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-freeze-selection.mobile.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-freeze-selection.mobile.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-freeze-selection.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-merge-layout.desktop.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-merge-layout.mobile.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-merge-layout.mobile.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-merge-layout.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-mobile-column-menu.desktop.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-mobile-column-menu.mobile.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-mobile-column-menu.mobile.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-mobile-column-menu.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-mobile-context-menu.desktop.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-mobile-context-menu.mobile.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-mobile-context-menu.mobile.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-mobile-context-menu.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-mobile-edit-panel.desktop.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-mobile-edit-panel.mobile.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-mobile-edit-panel.mobile.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-mobile-edit-panel.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-mobile-row-menu.desktop.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-mobile-row-menu.mobile.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-mobile-row-menu.mobile.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-mobile-row-menu.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-mobile-selection-handles.desktop.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-mobile-selection-handles.mobile.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-mobile-selection-handles.mobile.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-mobile-selection-handles.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-overflow-clip.desktop.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-overflow-clip.mobile.dark.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-overflow-clip.mobile.png is excluded by !**/*.png
  • packages/frontend/tests/visual/baselines/harness-visual.browser.sheet-overflow-clip.png is excluded by !**/*.png
📒 Files selected for processing (4)
  • docs/design/homepage.md
  • packages/frontend/src/app/home/demo-section.tsx
  • packages/frontend/src/app/home/developer-section.tsx
  • packages/frontend/src/index.css
📝 Walkthrough

Walkthrough

Implements the "Butter & Maple" design system and applies it across the homepage: new CSS tokens, typography, primitives, SVG assets, redesigned sections (demo, hero, features, developer, use-cases, why, OSS, footer, nav), a two-tab lazy iframe demo with theme postMessage sync, and related docs/config updates.

Changes

Butter & Maple design system & homepage redesign

Layer / File(s) Summary
Design spec & tasks
docs/design/homepage.md, docs/tasks/*, docs/tasks/archive/*
Spec bumped to 0.4.0 and expanded into Butter & Maple visual system; documents phased rollout, accessibility, iframe theme-sync via postMessage, and archived task files added/updated.
Font loading (docs & app)
packages/documentation/.vitepress/config.ts, packages/frontend/index.html
Google Fonts preconnect and stylesheet links injected for Fraunces / Inter / JetBrains Mono.
CSS token foundation
packages/frontend/src/index.css, packages/documentation/.vitepress/theme/style.css
Introduces --wb-* Butter & Maple palette (light/dark), updates semantic tokens (--primary, --ring, --chart-*, --sidebar-*), and applies display typography rules.
UI primitives & illustrations
packages/frontend/src/app/home/primitives/* (wb-button.tsx, waffle-logo.tsx, feature-glyph.tsx, big-waffle.tsx, ruler-backdrop.tsx, section-head.tsx, theme-toggle.tsx)
Adds button primitives, logo and waffle SVGs, feature glyphs, ruler backdrop, section heading, and theme toggle components with aria-hidden/accessibility considerations.
Homepage sections & layout
packages/frontend/src/app/home/* (demo-section.tsx, developer-section.tsx, features-section.tsx, hero-section.tsx, footer.tsx, nav-bar.tsx, opensource-section.tsx, why-section.tsx, use-cases-section.tsx, page.tsx)
Redesigned hero (stats + ruler), sticky navbar with ThemeToggle, DemoSection → two-tab Sheet/Doc with lazy-mount doc iframe and postMessage theme forwarding, DeveloperSection tabbed/token-typed highlighting, feature/use-case/OSS/why/footer rewrites, section reorder and main background token.
Homepage primitives consumption
packages/frontend/src/components/*, packages/frontend/src/components/app-sidebar.tsx, packages/frontend/src/components/login-form.tsx
Sidebar and login form updated to use WaffleLogo, WbButton, RulerBackdrop, and ThemeToggle; login page layout rewritten to match visual system.
Sheet theme & config
packages/sheets/src/view/theme.ts, harness.config.json
Updated Light/Dark sheet palette values (active/selection/header/reference/peer cursors) and increased frontend chunk budget maxChunkCount from 70→80 with reason field added.
Docs theme tweaks
packages/documentation/.vitepress/theme/style.css
VitePress doc theme variables adjusted to use Butter & Maple tokens and Fraunces headings.

Sequence Diagram

sequenceDiagram
    participant User
    participant DemoSection
    participant SheetIframe as Sheet Iframe
    participant DocIframe as Doc Iframe
    participant ThemeProvider

    User->>DemoSection: Click "Word processor" tab
    DemoSection->>DemoSection: Check docIframe mounted?
    alt not mounted
        DemoSection->>DocIframe: Mount iframe (lazy)
        DocIframe->>DocIframe: Load & initialize
    end
    DemoSection->>SheetIframe: Toggle visibility (hide)
    DemoSection->>DocIframe: Toggle visibility (show)
    User->>ThemeProvider: Toggle theme
    ThemeProvider->>DemoSection: Notify theme change
    DemoSection->>SheetIframe: postMessage({ type: 'theme-change', theme })
    DemoSection->>DocIframe: postMessage({ type: 'theme-change', theme })
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~65 minutes

Possibly related PRs

Poem

🐰 nibble, hop, and hum with glee,
Butter & Maple colors free,
Waffles, glyphs, and iframes two—
Tabs that lazy-load for you,
CSS syrup, fonts that sing 🧇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.76% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Apply Butter & Maple to homepage, login, docs, workspace' directly and accurately summarizes the main change: applying the Butter & Maple design system across multiple pages and components.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch homepage-butter-maple-redesign

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 27 minutes and 48 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented May 3, 2026

Copy link
Copy Markdown
Contributor

Verification: verify:self

Result: ✅ PASS in 129.9s

Lane Status Duration
sheets:build ✅ pass 13.7s
docs:build ✅ pass 10.9s
verify:fast ✅ pass 63.9s
frontend:build ✅ pass 17.7s
verify:frontend:chunks ✅ pass 0.3s
backend:build ✅ pass 4.8s
cli:build ✅ pass 1.8s
verify:entropy ✅ pass 16.6s

Verification: verify:integration

Result: ✅ PASS

@codecov

codecov Bot commented May 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🧹 Nitpick comments (5)
harness.config.json (1)

5-5: ⚡ Quick win

Verify remaining headroom against the new limit.

The limit has now been raised twice (60 hard default → 70 → 80). The gate's value as a regression guard depends on how tightly it tracks the actual count. If the build already lands at, e.g., 78–79 chunks, the next incremental change will trip it again. Knowing the exact post-build count (and baking it + a small buffer into the comment or a reason field here) would make future bumps more deliberate.

Run the following after a local pnpm build to see the real count and remaining headroom:

#!/bin/bash
# Description: Count .js chunks in the frontend build output and compare against the configured limit.
# Expects the frontend dist/assets directory to exist after a build.

ASSETS_DIR=$(fd -t d "assets" --search-path . | head -n 1)
if [ -z "$ASSETS_DIR" ]; then
  echo "Could not locate an assets directory. Run pnpm build first."
  exit 1
fi

COUNT=$(find "$ASSETS_DIR" -maxdepth 1 -name "*.js" -type f | wc -l)
LIMIT=$(python3 -c "import json,sys; print(json.load(open('harness.config.json'))['frontend']['chunkBudgets']['maxChunkCount'])")

echo "Actual JS chunk count : $COUNT"
echo "Configured limit      : $LIMIT"
echo "Remaining headroom    : $((LIMIT - COUNT))"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@harness.config.json` at line 5, Update the harness.config.json
frontend.chunkBudgets.maxChunkCount entry to include a documented reason and
realistic headroom: run a local pnpm build, count the produced .js chunks
(frontend assets) and record the measured count plus a small buffer in a new
"reason" field next to "maxChunkCount" (or in a comment in the file metadata if
comments are supported); ensure the value of maxChunkCount (currently 80) is set
to that measured count plus buffer so the gate has intentional headroom and
include the exact measured count and chosen buffer in the reason for future
reviewers.
packages/frontend/src/app/home/primitives/feature-glyph.tsx (1)

1-1: 💤 Low value

Consider exporting GlyphKind for downstream type safety.

GlyphKind is used in the exported component's prop but is not itself exported. Consumers that want to type their feature data arrays — like features-section.tsx — must use React.ComponentProps<typeof FeatureGlyph>['kind'] instead of the more readable GlyphKind.

♻️ One-word fix
-type GlyphKind = "reactive" | "formulas" | "embed" | "sync" | "io";
+export type GlyphKind = "reactive" | "formulas" | "embed" | "sync" | "io";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/frontend/src/app/home/primitives/feature-glyph.tsx` at line 1, The
type alias GlyphKind is currently internal but used in the exported FeatureGlyph
props; export it so downstream consumers can import GlyphKind for typing instead
of deriving it via ComponentProps. Modify the declaration of GlyphKind (the type
alias named GlyphKind) to be exported (e.g., export type GlyphKind = ...) and
update any index/re-export barrels if this file's types are re-exported
elsewhere so consumers like features-section.tsx can import GlyphKind directly.
packages/frontend/src/app/home/primitives/ruler-backdrop.tsx (1)

28-113: ⚡ Quick win

Hardcoded SVG id will collide if two RulerBackdrop instances appear in the same document.

id="wb-ruler-pat" is a global DOM identifier. Although the two current call sites (hero-section.tsx and login/page.tsx) are on separate routes, a second instance in the same document (e.g., added to a shared layout or a multi-section page) would cause both fill="url(#wb-ruler-pat)" references to resolve against whichever <pattern> the browser encounters first, potentially applying the wrong tile dimensions. Use useId() (React 18+, available in this project's React 19 baseline) to generate a per-instance unique ID.

🔧 Proposed fix
-import { cn } from "@/lib/utils";
+import { useId } from "react";
+import { cn } from "@/lib/utils";

 export function RulerBackdrop({ className }: RulerBackdropProps) {
+  const patternId = useId();
   return (
     <div
       ...
     >
       <svg width="100%" height="100%">
         <defs>
           <pattern
-            id="wb-ruler-pat"
+            id={patternId}
             ...
           >
             ...
           </pattern>
         </defs>
-        <rect width="100%" height="100%" fill="url(`#wb-ruler-pat`)" />
+        <rect width="100%" height="100%" fill={`url(#${patternId})`} />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/frontend/src/app/home/primitives/ruler-backdrop.tsx` around lines 28
- 113, Replace the hardcoded SVG id "wb-ruler-pat" with a per-instance unique id
using React's useId(); inside the RulerBackdrop component (function
RulerBackdrop) call useId(), build a patternId (e.g., `${id}-wb-ruler-pat`), set
the <pattern id={patternId}> and update every reference to that id (the rect
fill="url(#...)" and any other url(...) usages) to use the generated id string;
also add the import for useId from 'react' if missing.
packages/frontend/src/components/login-form.tsx (1)

3-3: 💤 Low value

WbButton is used outside app/home/ — consider relocating it to src/components/.

login-form.tsx lives in src/components/ (shared layer) but imports from src/app/home/primitives/ (page layer). Now that WbButton is consumed by a non-homepage route, it effectively belongs in the shared components layer alongside other design-system primitives.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/frontend/src/components/login-form.tsx` at line 3, WbButton is a
design primitive imported from app/home/primitives into a shared component
(login-form.tsx); move the WbButton component file (identified as WbButton) from
app/home/primitives into the shared components directory (e.g., src/components/
or the existing design-system primitives folder), update its module export if
needed, then update all imports that reference app/home/primitives/WbButton
(including in login-form.tsx) to the new shared path so the primitive is
accessible from non-page code.
packages/frontend/src/app/home/developer-section.tsx (1)

197-240: ⚡ Quick win

Missing ARIA tab pattern degrades screen-reader navigation.

The tab strip and code panel have no semantic tab role structure. Screen readers will announce them as plain buttons with no indication that they control the panel below.

♿ Proposed fix — add ARIA tab roles
  <div
-   className="flex items-center px-2 border-b"
+   role="tablist"
+   aria-label="Developer API examples"
+   className="flex items-center px-2 border-b"
    style={{ ... }}
  >
    {TABS.map((t) => (
      <button
        key={t.key}
        type="button"
+       role="tab"
+       id={`tab-${t.key}`}
+       aria-selected={tab === t.key}
+       aria-controls={`panel-${t.key}`}
        onClick={() => setTab(t.key)}
        ...
      >
- <pre className="m-0 px-6 md:px-8 py-7 overflow-x-auto font-code text-[14px] leading-7 whitespace-pre">
+ <pre
+   role="tabpanel"
+   id={`panel-${active.key}`}
+   aria-labelledby={`tab-${active.key}`}
+   className="m-0 px-6 md:px-8 py-7 overflow-x-auto font-code text-[14px] leading-7 whitespace-pre"
+ >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/frontend/src/app/home/developer-section.tsx` around lines 197 - 240,
The tab strip and code panel need ARIA tab pattern markup: wrap the TABS.map
container div with role="tablist" (preserving its classes), render each button
(the one using key t.key, onClick setTab and checking tab === t.key) with
role="tab", an id like `tab-${t.key}`, aria-selected set to (tab === t.key),
aria-controls pointing to a matching panel id `panel-${t.key}`, and include
keyboard focusability as needed; then mark the code container (the pre that
renders highlightCode(active.code)) as role="tabpanel" with id
`panel-${active.key}` and aria-labelledby pointing to `tab-${active.key}`, and
set hidden (or aria-hidden) when it is not the active panel to ensure screen
readers know which tab is active.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/design/homepage.md`:
- Line 225: The fenced code block showing the file structure (the triple
backticks around the "packages/frontend/src/app/home/ ├── page.tsx ..." snippet)
lacks a language identifier; update that opening fence to include a language
specifier such as ```text or ```plain so the block becomes ```text (or ```plain)
to satisfy markdownlint MD040 and avoid the warning.
- Line 88: Update the summary table entry for DemoSection to match the detailed
spec: replace the phrase "Doc tab renders `<DocPreview>`" with wording that
indicates the Doc tab is a live iframe serving
/shared/{VITE_DEMO_DOC_SHARED_TOKEN} (or similar live iframe token URL). Locate
the DemoSection mention in the summary row (reference symbol: DemoSection) and
ensure the text references the live iframe endpoint instead of DocPreview so the
table aligns with the detailed spec and revision `#3`.

In `@docs/tasks/archive/2026/05/20260503-homepage-redesign-todo.md`:
- Around line 9-11: The document contains a committed macOS home-directory path
string (the design handoff directory name) that leaks a username; open
docs/tasks/archive/2026/05/20260503-homepage-redesign-todo.md and replace the
absolute path occurrences with a neutral project-relative reference or short
descriptive note (e.g., "design_handoff_wafflebase_landing in project assets" or
"see design handoff bundle in /designs/") so the username is not recorded;
update both instances of the referenced design handoff mention and keep the note
clear about where contributors can find the design within the repo.

In `@packages/documentation/.vitepress/theme/style.css`:
- Around line 55-58: Remove unnecessary quotes from single-word font family
names and suppress the false-positive keyword-case lint errors: update the
font-family declarations referenced by the CSS custom properties (e.g.,
--vp-font-family-mono and the other --vp-font-family-... declarations that
include "Inter" and "Fraunces") to use unquoted single-word names (Inter,
Fraunces) and either add a preceding /* stylelint-disable-next-line
value-keyword-case */ comment for the affected font-family lines or adjust the
stylelint config to ignore font-family values so proprietary family names like
Roboto, Arial, SFMono-Regular, Menlo, Monaco, and Consolas are not forced to
lowercase.

In `@packages/frontend/src/app/home/demo-section.tsx`:
- Around line 29-30: The current code recomputes sheetUrl and docUrl on every
render using resolvedTheme, causing iframe src changes and full reloads; fix
this by initializing two state variables (e.g., initialSheetUrl and
initialDocUrl) with a lazy useState initializer that builds the URLs once from
the initial resolvedTheme, then use those state values as the iframe src props
instead of sheetUrl/docUrl; continue to send theme changes via the existing
postMessage path (do not change that logic) so the iframe updates without
resetting its src.

In `@packages/frontend/src/app/home/developer-section.tsx`:
- Around line 191-202: The container and tab-bar in developer-section.tsx are
using the foreground token --wb-ink as a background which inverts colors in dark
mode; add terminal-specific CSS tokens (--wb-terminal-bg and --wb-terminal-fg)
in index.css (with stable dark values under .dark) and replace usages in
developer-section.tsx (the outer container style and the inline tab-bar
background) to use --wb-terminal-bg/--wb-terminal-fg; also update TOKEN_CLASSES
(or any places deriving text colors for the terminal) to derive from
--wb-terminal-fg instead of --wb-paper so syntax tokens and text keep proper
contrast in both light and dark modes.

In `@packages/frontend/src/app/home/features-section.tsx`:
- Line 6: Remove the duplicate GlyphKind definition in features-section.tsx and
instead import the exported type from the feature-glyph component; add an export
of the GlyphKind type in FeatureGlyph (feature-glyph.tsx) if it's not already
exported, then update HeroFeature.glyph and any local usages in
features-section.tsx to reference the imported GlyphKind type so all components
(FeatureGlyph and HeroFeature) share a single source of truth.

In `@packages/frontend/src/app/home/primitives/big-waffle.tsx`:
- Around line 55-75: The SVG defs in BigWaffle use fixed ids (wb-waffle-body,
wb-pocket-shade, wb-butter-face, wb-soft-shadow) which will collide across
multiple mounts; fix this by generating a per-instance prefix via React's
useId() inside the BigWaffle component and append it to each def id and every
reference to them (e.g., url(`#wb-waffle-body-`{id}), url(`#wb-pocket-shade-`{id}),
url(`#wb-butter-face-`{id}), url(`#wb-soft-shadow-`{id})); update all places that
reference these ids (fill, filter, xlink:href or other url() usages) so each
rendered SVG uses the unique ids.

In `@packages/frontend/src/app/home/primitives/wb-button.tsx`:
- Around line 41-47: The WbButton currently renders a plain <button> (Comp)
without a default type, causing unintended form submissions; update the
component (wb-button.tsx, around the Comp render) to ensure it supplies
type="button" for the rendered button element unless the consumer explicitly
provides a type or asChild is true (i.e., when Comp === Slot do not inject
type). Implement this by preferring an incoming props.type if present, otherwise
setting type="button" when rendering the native button.

In `@packages/frontend/src/index.css`:
- Around line 52-54: The stylelint `value-keyword-case` rule is falsely flagging
font-family names in the CSS vars (--font-display, --font-body, --font-code);
suppress the rule around these declarations by adding a stylelint disable/enable
comment (e.g. place a /* stylelint-disable-next-line value-keyword-case */
immediately before each problematic variable or wrap the `@theme` inline block
with /* stylelint-disable value-keyword-case */ and then /* stylelint-enable
value-keyword-case */ after) so the font-family names (Fraunces, Georgia, Inter,
SFMono-Regular, Menlo, JetBrains Mono) are allowed without changing the values.

---

Nitpick comments:
In `@harness.config.json`:
- Line 5: Update the harness.config.json frontend.chunkBudgets.maxChunkCount
entry to include a documented reason and realistic headroom: run a local pnpm
build, count the produced .js chunks (frontend assets) and record the measured
count plus a small buffer in a new "reason" field next to "maxChunkCount" (or in
a comment in the file metadata if comments are supported); ensure the value of
maxChunkCount (currently 80) is set to that measured count plus buffer so the
gate has intentional headroom and include the exact measured count and chosen
buffer in the reason for future reviewers.

In `@packages/frontend/src/app/home/developer-section.tsx`:
- Around line 197-240: The tab strip and code panel need ARIA tab pattern
markup: wrap the TABS.map container div with role="tablist" (preserving its
classes), render each button (the one using key t.key, onClick setTab and
checking tab === t.key) with role="tab", an id like `tab-${t.key}`,
aria-selected set to (tab === t.key), aria-controls pointing to a matching panel
id `panel-${t.key}`, and include keyboard focusability as needed; then mark the
code container (the pre that renders highlightCode(active.code)) as
role="tabpanel" with id `panel-${active.key}` and aria-labelledby pointing to
`tab-${active.key}`, and set hidden (or aria-hidden) when it is not the active
panel to ensure screen readers know which tab is active.

In `@packages/frontend/src/app/home/primitives/feature-glyph.tsx`:
- Line 1: The type alias GlyphKind is currently internal but used in the
exported FeatureGlyph props; export it so downstream consumers can import
GlyphKind for typing instead of deriving it via ComponentProps. Modify the
declaration of GlyphKind (the type alias named GlyphKind) to be exported (e.g.,
export type GlyphKind = ...) and update any index/re-export barrels if this
file's types are re-exported elsewhere so consumers like features-section.tsx
can import GlyphKind directly.

In `@packages/frontend/src/app/home/primitives/ruler-backdrop.tsx`:
- Around line 28-113: Replace the hardcoded SVG id "wb-ruler-pat" with a
per-instance unique id using React's useId(); inside the RulerBackdrop component
(function RulerBackdrop) call useId(), build a patternId (e.g.,
`${id}-wb-ruler-pat`), set the <pattern id={patternId}> and update every
reference to that id (the rect fill="url(#...)" and any other url(...) usages)
to use the generated id string; also add the import for useId from 'react' if
missing.

In `@packages/frontend/src/components/login-form.tsx`:
- Line 3: WbButton is a design primitive imported from app/home/primitives into
a shared component (login-form.tsx); move the WbButton component file
(identified as WbButton) from app/home/primitives into the shared components
directory (e.g., src/components/ or the existing design-system primitives
folder), update its module export if needed, then update all imports that
reference app/home/primitives/WbButton (including in login-form.tsx) to the new
shared path so the primitive is accessible from non-page code.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9253e9fa-9c45-4357-a531-841bc4aa4d92

📥 Commits

Reviewing files that changed from the base of the PR and between 4a3315e and f2284a0.

📒 Files selected for processing (30)
  • docs/design/homepage.md
  • docs/tasks/README.md
  • docs/tasks/archive/2026/05/20260503-homepage-redesign-todo.md
  • docs/tasks/archive/README.md
  • harness.config.json
  • packages/documentation/.vitepress/config.ts
  • packages/documentation/.vitepress/theme/style.css
  • packages/frontend/index.html
  • packages/frontend/src/app/home/demo-section.tsx
  • packages/frontend/src/app/home/developer-section.tsx
  • packages/frontend/src/app/home/features-section.tsx
  • packages/frontend/src/app/home/footer.tsx
  • packages/frontend/src/app/home/hero-section.tsx
  • packages/frontend/src/app/home/nav-bar.tsx
  • packages/frontend/src/app/home/opensource-section.tsx
  • packages/frontend/src/app/home/page.tsx
  • packages/frontend/src/app/home/primitives/big-waffle.tsx
  • packages/frontend/src/app/home/primitives/feature-glyph.tsx
  • packages/frontend/src/app/home/primitives/ruler-backdrop.tsx
  • packages/frontend/src/app/home/primitives/section-head.tsx
  • packages/frontend/src/app/home/primitives/theme-toggle.tsx
  • packages/frontend/src/app/home/primitives/waffle-logo.tsx
  • packages/frontend/src/app/home/primitives/wb-button.tsx
  • packages/frontend/src/app/home/use-cases-section.tsx
  • packages/frontend/src/app/home/why-section.tsx
  • packages/frontend/src/app/login/page.tsx
  • packages/frontend/src/components/app-sidebar.tsx
  • packages/frontend/src/components/login-form.tsx
  • packages/frontend/src/index.css
  • packages/sheets/src/view/theme.ts

Comment thread docs/design/homepage.md Outdated
Comment thread docs/design/homepage.md Outdated
Comment thread docs/tasks/archive/2026/05/20260503-homepage-redesign-todo.md Outdated
Comment on lines +55 to +58
"Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
"Helvetica Neue", Arial, sans-serif;
--vp-font-family-mono:
"JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Stylelint reports errors on font-family declarations.

The static analysis tool flags two distinct rule violations:

  1. font-family-name-quotes (line 111): "Fraunces" is a single-word family name; the project's stylelint config expects it unquoted (Fraunces). Single-word names like "Inter" in index.css line 53 have the same issue.

  2. value-keyword-case (lines 55–58): Roboto, Arial, SFMono-Regular, Menlo, Monaco, and Consolas are flagged as requiring lowercase. These are proprietary font-family names rather than CSS keywords, so these are likely false positives from an overly broad rule configuration, but they are still reported as errors by stylelint.

CI currently passes (the docs CSS may not be in the lint pipeline), but these will block if linting scope is extended.

🛠️ Proposed fix for the quotes violation
 .vp-doc h1,
 .vp-doc h2,
 .vp-doc h3,
 .vp-doc h4,
 .VPHero .name,
 .VPHero .text {
   font-family:
-    "Fraunces", ui-serif, Georgia, "Times New Roman", Times, serif;
+    Fraunces, ui-serif, Georgia, "Times New Roman", Times, serif;
   font-feature-settings: "ss01" on, "ss02" on;
   letter-spacing: -0.01em;
 }

For the value-keyword-case false positives, the cleanest resolution is to add a /* stylelint-disable-next-line value-keyword-case */ comment before each affected declaration, or configure the rule to ignore font-family values in the stylelint config.

Also applies to: 110-113

🧰 Tools
🪛 Stylelint (17.9.0)

[error] 55-55: Expected "Roboto" to be "roboto" (value-keyword-case)

(value-keyword-case)


[error] 56-56: Expected "Arial" to be "arial" (value-keyword-case)

(value-keyword-case)


[error] 58-58: Expected "SFMono-Regular" to be "sfmono-regular" (value-keyword-case)

(value-keyword-case)


[error] 58-58: Expected "Menlo" to be "menlo" (value-keyword-case)

(value-keyword-case)


[error] 58-58: Expected "Monaco" to be "monaco" (value-keyword-case)

(value-keyword-case)


[error] 58-58: Expected "Consolas" to be "consolas" (value-keyword-case)

(value-keyword-case)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/documentation/.vitepress/theme/style.css` around lines 55 - 58,
Remove unnecessary quotes from single-word font family names and suppress the
false-positive keyword-case lint errors: update the font-family declarations
referenced by the CSS custom properties (e.g., --vp-font-family-mono and the
other --vp-font-family-... declarations that include "Inter" and "Fraunces") to
use unquoted single-word names (Inter, Fraunces) and either add a preceding /*
stylelint-disable-next-line value-keyword-case */ comment for the affected
font-family lines or adjust the stylelint config to ignore font-family values so
proprietary family names like Roboto, Arial, SFMono-Regular, Menlo, Monaco, and
Consolas are not forced to lowercase.

Comment thread packages/frontend/src/app/home/demo-section.tsx Outdated
Comment thread packages/frontend/src/app/home/developer-section.tsx Outdated
Comment thread packages/frontend/src/app/home/features-section.tsx Outdated
Comment thread packages/frontend/src/app/home/primitives/big-waffle.tsx Outdated
Comment thread packages/frontend/src/app/home/primitives/wb-button.tsx
Comment thread packages/frontend/src/index.css
Why: CodeRabbit flagged a few real bugs and accessibility gaps in the
homepage redesign. Folding the fixes here so the PR is mergeable.

- WbButton now defaults `type="button"` for the native-button path so it
  never accidentally submits a parent form. asChild mode still defers to
  the underlying element's own type.
- DemoSection iframe URLs are now lazy-init via useState so theme changes
  no longer mutate the `src` prop and force a full reload — theme
  updates flow through postMessage as intended.
- DeveloperSection swapped from `--wb-ink` (which inverts to cream in
  dark mode) to dedicated `--wb-terminal-bg` / `--wb-terminal-fg` tokens
  that stay locked across themes; the dark code card finally renders
  dark in both light and dark.
- DeveloperSection tabs got the proper ARIA tablist / tab / tabpanel
  roles + tabindex roving so screen readers announce the relationship.
- RulerBackdrop and BigWaffle now derive SVG `id` values via React's
  `useId()` so multiple instances on the same document can't collide.
- FeatureGlyph exports `GlyphKind`; FeaturesSection imports it instead
  of redeclaring the union (single source of truth).
- harness.config.json captures the chunk-count bump rationale next to
  the limit, with the measured count + buffer for future reviewers.
- Sanitized the archived task doc — replaced the absolute
  `/Users/<name>/Downloads/...` handoff path with a neutral reference to
  the shared bundle.
- Design doc table row for DemoSection no longer says "DocPreview" —
  both tabs are live iframes now.

Verification: pnpm verify:self passes (8 lanes, ~65s). Visual baselines
left untouched here — they need a Docker (linux/amd64) refresh, which
the next commit / CI artifact will produce.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
packages/frontend/src/index.css (1)

52-54: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Stylelint value-keyword-case errors on font-family names remain unresolved.

Georgia, SFMono-Regular, and Menlo are font-family names, not CSS keywords, so the errors are false positives — but they are still reported as [error] by stylelint and will break a lint gate. Adding inline disable/enable comments around the affected declarations is the standard suppression approach.

✏️ Proposed fix
+  /* stylelint-disable value-keyword-case */
   --font-display: "Fraunces", ui-serif, Georgia, serif;
   --font-body: "Inter", ui-sans-serif, system-ui, sans-serif;
   --font-code: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
+  /* stylelint-enable value-keyword-case */
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/frontend/src/index.css` around lines 52 - 54, The stylelint false
positives for font-family names are coming from the CSS custom properties
--font-display, --font-body, and --font-code in index.css; wrap those specific
declarations with inline stylelint suppression comments to disable and then
re-enable the value-keyword-case rule (i.e., add a /* stylelint-disable
value-keyword-case */ immediately before the three --font-... declarations and a
matching /* stylelint-enable value-keyword-case */ immediately after) so linting
ignores these font-family identifiers while leaving the rest of the file
checked.
🧹 Nitpick comments (1)
packages/frontend/src/app/home/developer-section.tsx (1)

211-240: ⚡ Quick win

Arrow key navigation missing from the role="tablist" — the roving tabindex pattern is only half-implemented.

The tabIndex values are correctly set (0 for active, -1 for inactive), but without an onKeyDown handler for ArrowRight/ArrowLeft, keyboard users cannot cycle between tabs using the arrow keys. The WAI-ARIA Tab Panel pattern requires this. Instead they'd have to Tab out and back in, which breaks expected tab-widget behavior.

♻️ Proposed addition

Add a shared handler and pass it to each tab button:

+  const handleTabKeyDown = (e: React.KeyboardEvent, currentKey: TabKey) => {
+    const idx = TABS.findIndex((t) => t.key === currentKey);
+    let next: typeof TABS[number] | undefined;
+    if (e.key === "ArrowRight") next = TABS[(idx + 1) % TABS.length];
+    if (e.key === "ArrowLeft")  next = TABS[(idx - 1 + TABS.length) % TABS.length];
+    if (next) {
+      setTab(next.key);
+      // Move DOM focus to the newly active tab button
+      document.getElementById(`dev-tab-${next.key}`)?.focus();
+    }
+  };

  {TABS.map((t) => (
    <button
      key={t.key}
      type="button"
      role="tab"
      id={`dev-tab-${t.key}`}
      aria-selected={tab === t.key}
      aria-controls={`dev-panel-${t.key}`}
      tabIndex={tab === t.key ? 0 : -1}
      onClick={() => setTab(t.key)}
+     onKeyDown={(e) => handleTabKeyDown(e, t.key)}
      className={...}
    >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/frontend/src/app/home/developer-section.tsx` around lines 211 - 240,
The tablist is missing ArrowLeft/ArrowRight keyboard support; implement an
onKeyDown handler (e.g., handleTabKeyDown) that listens for ArrowRight and
ArrowLeft, computes the next/previous index within TABS (wrapping at ends),
calls setTab(TABS[newIndex].key) and moves focus to the corresponding button
(use the button ids like `dev-tab-${key}` or refs), and attach this handler to
each tab button (the elements using role="tab" and tabIndex logic). Ensure the
handler prevents default for arrow keys and preserves the existing
aria-selected/tabIndex behavior so keyboard users can rove focus correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/design/homepage.md`:
- Around line 257-259: The risk table incorrectly claims a static screenshot
fallback exists; update the table entry to reflect the real behavior (the
DemoFrame component renders an inline error message "Demo unavailable. Try
refreshing the page.") or alternatively implement the documented fallback by
adding a static screenshot under public/images and wiring DemoFrame to use it on
iframe errors; reference the DemoFrame component when making the change so the
doc and implementation stay consistent.

In `@packages/frontend/src/app/home/demo-section.tsx`:
- Around line 74-94: The tab UI lacks ARIA tab semantics: update the DemoSection
container div to include role="tablist" and generate stable IDs for tabs/panels;
modify DemoTab (and its type DemoTabProps) to accept id, panelId, role="tab",
aria-selected (true for the active tab), aria-controls (panelId) and a roving
tabIndex (0 for active, -1 otherwise) and ensure onClick/focus set active;
update DemoFrameProps and the DemoFrame outer div to role="tabpanel", id
(panelId) and aria-labelledby (tab id) and pass the new id/panelId props from
DemoSection when rendering DemoTab and DemoFrame so tabs and panels are properly
linked.

---

Duplicate comments:
In `@packages/frontend/src/index.css`:
- Around line 52-54: The stylelint false positives for font-family names are
coming from the CSS custom properties --font-display, --font-body, and
--font-code in index.css; wrap those specific declarations with inline stylelint
suppression comments to disable and then re-enable the value-keyword-case rule
(i.e., add a /* stylelint-disable value-keyword-case */ immediately before the
three --font-... declarations and a matching /* stylelint-enable
value-keyword-case */ immediately after) so linting ignores these font-family
identifiers while leaving the rest of the file checked.

---

Nitpick comments:
In `@packages/frontend/src/app/home/developer-section.tsx`:
- Around line 211-240: The tablist is missing ArrowLeft/ArrowRight keyboard
support; implement an onKeyDown handler (e.g., handleTabKeyDown) that listens
for ArrowRight and ArrowLeft, computes the next/previous index within TABS
(wrapping at ends), calls setTab(TABS[newIndex].key) and moves focus to the
corresponding button (use the button ids like `dev-tab-${key}` or refs), and
attach this handler to each tab button (the elements using role="tab" and
tabIndex logic). Ensure the handler prevents default for arrow keys and
preserves the existing aria-selected/tabIndex behavior so keyboard users can
rove focus correctly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bf6b3541-550a-41ae-8cb3-7338e15aaa15

📥 Commits

Reviewing files that changed from the base of the PR and between f2284a0 and b78074b.

📒 Files selected for processing (11)
  • docs/design/homepage.md
  • docs/tasks/archive/2026/05/20260503-homepage-redesign-todo.md
  • harness.config.json
  • packages/frontend/src/app/home/demo-section.tsx
  • packages/frontend/src/app/home/developer-section.tsx
  • packages/frontend/src/app/home/features-section.tsx
  • packages/frontend/src/app/home/primitives/big-waffle.tsx
  • packages/frontend/src/app/home/primitives/feature-glyph.tsx
  • packages/frontend/src/app/home/primitives/ruler-backdrop.tsx
  • packages/frontend/src/app/home/primitives/wb-button.tsx
  • packages/frontend/src/index.css
✅ Files skipped from review due to trivial changes (1)
  • harness.config.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/frontend/src/app/home/primitives/feature-glyph.tsx
  • packages/frontend/src/app/home/primitives/big-waffle.tsx

Comment thread docs/design/homepage.md Outdated
Comment thread packages/frontend/src/app/home/demo-section.tsx
hackerwins and others added 3 commits May 3, 2026 19:36
Why: the Butter & Maple migration recolored the sheet engine — active
cell ring (amber → syrup), header chip (amber → butter), and two
peer-cursor slots (yellow → rose / lavender). Every browser visual
baseline that touches those pixels needs a refresh.

Source: CI workflow run 25276627500's `browser-visual-actual` artifact
(linux/amd64, Docker). Baselines must come from CI's environment, not a
local Apple Silicon machine, so the comparison stays pixel-stable.

76 actual.png files downloaded; 75 differed from existing baselines.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Why: CodeRabbit's follow-up flagged a few accessibility + lint loose
ends from the first review pass. Tightening them so the PR doesn't
carry forward known gaps.

- DemoSection tabs now expose the full WAI-ARIA tab pattern: outer
  `role="tablist"`, each `<DemoTab>` renders `role="tab"` with id /
  aria-selected / aria-controls / roving tabindex, and `<DemoFrame>`
  renders `role="tabpanel"` with aria-labelledby + hidden. ArrowLeft /
  ArrowRight cycle focus between tabs (with wrap-around).
- DeveloperSection tabs got the same ArrowLeft / ArrowRight handler so
  the tablist/tab semantics added last round can actually be navigated
  by keyboard alone.
- index.css wraps the three `--font-*` declarations with
  `stylelint-disable value-keyword-case` so the false positives on
  Georgia / SFMono-Regular / Menlo stop blocking the lint gate.
- homepage.md risk row no longer claims a static-screenshot iframe
  fallback; it now describes the actual behavior — `<DemoFrame>` swaps
  to an inline "Demo unavailable" message on iframe error.

Verification: pnpm verify:self passes (8 lanes, ~60s).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Why: Wafflebase Docs is a word processor, not a formula-bearing doc, so
the hint promised behavior the iframe doesn't actually have. The phrase
was a holdover from the design prototype's static DocPreview, which
demonstrated inline ƒ formula tokens — the live iframe doesn't render
those. Replaced with a copy that matches what users will actually see
("changes sync in real time").

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@hackerwins
hackerwins merged commit 331a4b2 into main May 3, 2026
4 checks passed
@hackerwins
hackerwins deleted the homepage-butter-maple-redesign branch May 3, 2026 11:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant