From 913d7a88329cf1a835aec4fb526ebaa9075aa1de Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 12 Oct 2026 15:00:38 +0000 Subject: [PATCH] feat(web): marketing Button, Nav (with mobile menu) and Footer from Figma, test-first Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_014SdXCbrN5PtGExkpvMaMHx --- web/__tests__/marketing/Button.test.tsx | 20 ++++ web/__tests__/marketing/Footer.test.tsx | 42 ++++++++ web/__tests__/marketing/Nav.test.tsx | 60 +++++++++++ web/app/(marketing)/page.tsx | 11 +- web/public/marketing/README.md | 11 ++ web/public/marketing/brand-mark-dark.svg | 6 ++ web/public/marketing/brand-mark-light.svg | 6 ++ web/public/marketing/icons/chevron-right.svg | 5 + web/public/marketing/icons/menu.svg | 5 + web/src/marketing/BrandMark.tsx | 11 ++ web/src/marketing/Button.tsx | 20 ++++ web/src/marketing/Footer.tsx | 37 +++++++ web/src/marketing/Icon.tsx | 16 +++ web/src/marketing/Nav.tsx | 72 +++++++++++++ web/src/marketing/content.ts | 45 ++++++++ web/src/styles/marketing.css | 105 +++++++++++++++++++ 16 files changed, 471 insertions(+), 1 deletion(-) create mode 100644 web/__tests__/marketing/Button.test.tsx create mode 100644 web/__tests__/marketing/Footer.test.tsx create mode 100644 web/__tests__/marketing/Nav.test.tsx create mode 100644 web/public/marketing/README.md create mode 100644 web/public/marketing/brand-mark-dark.svg create mode 100644 web/public/marketing/brand-mark-light.svg create mode 100644 web/public/marketing/icons/chevron-right.svg create mode 100644 web/public/marketing/icons/menu.svg create mode 100644 web/src/marketing/BrandMark.tsx create mode 100644 web/src/marketing/Button.tsx create mode 100644 web/src/marketing/Footer.tsx create mode 100644 web/src/marketing/Icon.tsx create mode 100644 web/src/marketing/Nav.tsx create mode 100644 web/src/marketing/content.ts diff --git a/web/__tests__/marketing/Button.test.tsx b/web/__tests__/marketing/Button.test.tsx new file mode 100644 index 0000000..6ce9fed --- /dev/null +++ b/web/__tests__/marketing/Button.test.tsx @@ -0,0 +1,20 @@ +import { render, screen } from '@testing-library/react'; +import { describe, expect, it } from 'vitest'; +import { Button } from '../../src/marketing/Button.tsx'; + +describe('Button', () => { + it('renders a link with its label and destination', () => { + render(); + expect(screen.getByRole('link', { name: 'Get started' })).toHaveAttribute('href', '/signup'); + }); + + it('is the primary (inverse) pill by default', () => { + render(); + expect(screen.getByRole('link', { name: 'Get started' })).toHaveClass('btn', 'btn-primary', 'btn-md'); + }); + + it('supports the ghost variant and the large size', () => { + render(); + expect(screen.getByRole('link', { name: 'See how it works' })).toHaveClass('btn-ghost', 'btn-lg'); + }); +}); diff --git a/web/__tests__/marketing/Footer.test.tsx b/web/__tests__/marketing/Footer.test.tsx new file mode 100644 index 0000000..c1d1090 --- /dev/null +++ b/web/__tests__/marketing/Footer.test.tsx @@ -0,0 +1,42 @@ +import { render, screen, within } from '@testing-library/react'; +import { describe, expect, it } from 'vitest'; +import { Footer } from '../../src/marketing/Footer.tsx'; + +describe('Footer', () => { + it('shows the brand and tagline', () => { + render(