diff --git a/docs/superpowers/plans/2026-07-21-creeer-landing-additions.md b/docs/superpowers/plans/2026-07-21-creeer-landing-additions.md new file mode 100644 index 0000000..a168602 --- /dev/null +++ b/docs/superpowers/plans/2026-07-21-creeer-landing-additions.md @@ -0,0 +1,462 @@ +# creeer Landing Additions — Header + Cómo empezar + Footer — Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Add a minimal sticky Header, a new "Cómo empezar" on-ramp section (section 07), and a slim Footer to the existing 7-section `creeer` landing page. + +**Architecture:** Three additive pieces reusing the existing primitives (`Wordmark`, `CTA`, `Container`), tokens, the `motion` + `motionProps(reduced)` pattern, and the copy-in-`lib/content.ts` convention. Header and Footer are static server components wrapping `
`; `ComoEmpezar` is a client section following the exact pattern of `Mecanismo.tsx`/`Disciplinas.tsx`. Cierre becomes section 08. No backend, no forms — the site stays a static export. + +**Tech Stack:** Next.js 14 (App Router, `output: export`), React 18, TypeScript, Tailwind CSS 3.4, Framer Motion 11. Tests: Vitest + @testing-library/react. + +## Global Constraints + +(Copied from the spec `docs/superpowers/specs/2026-07-21-creeer-landing-additions-design.md` — apply to every task.) + +- **Wordmark** always via the `Wordmark` primitive — never re-implemented, never uppercased. +- **Paleta (tokens):** `ink #0A1F44` · `gold #B8901f` (accents on LIGHT) · `gold-bright #D4AF37` (accents on DARK) · `base #FBFAF7` (light bg, class `bg-base`) · dark bg class `bg-bg-dark` · `cream` (text on dark) · `muted`/`muted-dark`. +- **Tipografía:** Georgia italic (`font-serif italic`) = wordmark + section titles; Inter = body/UI. +- **Sin backend, sin formularios** — contacto solo por enlaces directos (WhatsApp/mailto/LinkedIn). +- **Un único `

`** en toda la página — vive en el Hero. New pieces use `

`/`

` or no heading. +- **Todo el copy** vive en `lib/content.ts` (nuevas claves `header`, `comoEmpezar`, `footer`). +- **Voz** en segunda persona, español. +- **Reduced motion:** every Framer Motion element gets `{...motionProps(reduced)}` after its `initial`/`whileInView`/`viewport` props (`reduced = usePrefersReducedMotion()`). Header/Footer are static (no motion). +- **`tsconfig.json` has no `target`** → avoid ES2018+ regex flags (`s`/dotAll) or `tsc --noEmit` fails. + +## File Structure + +``` +components/ +├── layout/ +│ ├── Header.tsx # Task 1 — sticky bar (server component) +│ ├── Footer.tsx # Task 3 — slim footer strip (server component) +│ └── __tests__/ +│ ├── Header.test.tsx # Task 1 +│ └── Footer.test.tsx # Task 3 +└── sections/ + ├── ComoEmpezar.tsx # Task 2 — section 07 (client, motion pattern) + └── __tests__/ + └── ComoEmpezar.test.tsx # Task 2 +lib/content.ts # Tasks 1/2/3 append `header` / `comoEmpezar` / `footer` +app/page.tsx # Tasks 1/2/3 wire the pieces; Task 4 anchor offset +components/sections/Cierre.tsx # Task 4 — add scroll-mt to the #contacto anchor +``` + +Each component task also wires itself into `app/page.tsx` (matching the repo's established incremental-compose pattern), so the page stays working after every task. + +--- + +### Task 1: Header (minimal sticky) + +**Files:** +- Create: `components/layout/Header.tsx` +- Create: `components/layout/__tests__/Header.test.tsx` +- Modify: `lib/content.ts` (append `header`) +- Modify: `app/page.tsx` (place `
` before `
`) + +**Interfaces:** +- Consumes: `Wordmark` (`size`, `onDark`), `CTA` (`href`, `label`, `variant`), `Container`, and `header.cta` from content. +- Produces: `Header()` at `components/layout/Header.tsx` — no props. Consumed by `app/page.tsx`. + +- [ ] **Step 1: Append the `header` copy to `lib/content.ts`** + +Add at the end of `lib/content.ts`: + +```ts +export const header = { + cta: 'Hablemos', // short nav CTA → #contacto (the full CTA lives in Hero/Cierre) +}; +``` + +- [ ] **Step 2: Write the failing test `components/layout/__tests__/Header.test.tsx`** + +```tsx +import { render, screen } from '@testing-library/react'; +import { describe, it, expect } from 'vitest'; +import { Header } from '../Header'; + +describe('
', () => { + it('renders the wordmark', () => { + const { container } = render(
); + expect(container.textContent).toContain('creeer'); + }); + it('renders a persistent CTA linking to the contact section', () => { + render(
); + const cta = screen.getByRole('link', { name: /Hablemos/i }); + expect(cta).toHaveAttribute('href', '#contacto'); + }); +}); +``` + +- [ ] **Step 3: Run the test to verify it fails** + +Run: `npm test -- Header` +Expected: FAIL with "Cannot find module '../Header'". + +- [ ] **Step 4: Write `components/layout/Header.tsx`** + +```tsx +import { Wordmark } from '@/components/primitives/Wordmark'; +import { CTA } from '@/components/primitives/CTA'; +import { Container } from '@/components/primitives/Container'; +import { header } from '@/lib/content'; + +export function Header() { + return ( +
+ + + + + + +
+ ); +} +``` + +Notes: server component (no `'use client'`, no motion — `position: sticky` is pure CSS). `#top` is the special top-of-document fragment (no element with that id is required). The `CTA` primitive appends the `→`, so `header.cta` holds just the word. + +- [ ] **Step 5: Run the test to verify it passes** + +Run: `npm test -- Header` +Expected: PASS, 2 tests. + +- [ ] **Step 6: Wire `
` into `app/page.tsx`** + +Add the import after the existing section imports (top of the file): + +```tsx +import { Header } from '@/components/layout/Header'; +``` + +Then insert `
` between the JSON-LD `