# Phase 3: Custom Component Porting

## Goal
Convert the website's existing hardcoded React components (e.g., Hero sections, About Us sections, Legal text) into drag-and-drop blocks inside the Puck Editor, without altering their visual design.

## Requirements

### 1. Wrap, Don't Rewrite (Crucial Rule)
* **DO NOT** rewrite the CSS, HTML, or Tailwind classes of the original React components.
* You must import the existing live component and "wrap" it in a Puck configuration object. 
* This guarantees that the component rendered in the editor looks 100% identical to the one rendered on the live frontend.
* **CRITICAL CONTAINER BUG:** If you extract a section from a hardcoded page, check if it was originally sitting inside a page-level `<div className="container mx-auto max-w-[1280px]">`. If so, you MUST include that container wrapper *inside* your new component's JSX. Otherwise, the component will stretch to full browser width when Puck renders it.
* **DON'T FORGET UTILITIES:** When extracting components from a page, don't just extract the "big" cards. You must also extract and wrap small utility components (like Breadcrumbs, Dividers, or Spacers) so the editor has all the necessary building blocks to recreate the original page layout.

### 2. Map the Fields Properly
Examine the props of the original component and expose them as editable fields in Puck:
*   Use `type: "text"` for short titles or names.
*   Use `type: "textarea"` for paragraphs or long descriptions.
*   **Media Uploads:** You must use the custom `<MediaUploadField>` component for any image or media fields so the user gets a visual upload button instead of a plain text input.

### 3. Register in the Puck Config
* Add the newly wrapped component to the central `lib/puck/config.tsx` file.
* Organize the components into clean, logical categories in the left sidebar (e.g., "About Components", "Legal Components") to keep the UI easy to navigate.

### 4. Register for Live Rendering (CRITICAL!)
Because we do NOT use Puck's default `<Render>` component for the live website (to improve SSR and fix hydration issues), **you must manually register your component to be rendered on the live frontend.**
* Open `app/page.tsx` and `components/puck/PageRenderer.tsx`.
* Add your component to the `COMPONENT_MAP` object in **both** files.
* If your component relies on client-side browser hooks (like `useState`, `window`, etc.), you must also add its string name to the `CLIENT_ONLY_COMPONENTS` Set in both files so it gets safely hydrated on the client.

## Implementation Pattern
Here is the standard pattern for wrapping an existing component for the agent to follow:

```tsx
// 1. Import the original, untouched UI component
import { OriginalAboutHero } from "@/components/about/OriginalAboutHero";
import { MediaUploadField } from "@/components/editor/MediaUploadField";

// 2. Define the Puck configuration wrapper
export const AboutHeroPuck = {
  fields: {
    title: { type: "text" },
    subtitle: { type: "textarea" },
    bgImage: {
      type: "custom",
      render: ({ value, onChange }: any) => (
        <MediaUploadField value={value || ''} onChange={onChange} accept="image" />
      ),
    },
  },
  defaultProps: {
    title: "About Us",
    subtitle: "We are a great company.",
    bgImage: "/images/default-bg.jpg",
  },
  // 3. Render the original component passing the Puck props
  render: (props: any) => {
    return <OriginalAboutHero title={props.title} subtitle={props.subtitle} bgImage={props.bgImage} />;
  },
};
```

## Testing Steps
1. Open the `/page_editor_admin` interface.
2. Look at the left sidebar and confirm the new components are listed under their correct categories.
3. Drag the component onto the canvas.
4. Verify that the component renders perfectly and its styling matches the live site exactly.
5. Edit the text and upload a new image via the right-side properties panel, and confirm the component updates instantly on the canvas.

## Advanced: The Anchor ID (`anchorId`) System

When configuring fields for components like `RankedTopList` or `SectionHeading`, you will often see a `Section ID (for TOC/Nav anchor)` field. This is internally named `anchorId`.

**You do NOT need to manually add `id={anchorId}` inside your wrapped React component!**

To ensure Table of Contents (TOC) and Sticky Navigation links work globally without duplicating code:
1. In `lib/puck/config.tsx`, the `withAnchor` higher-order component handles wrapping the element in the editor preview.
2. In the live frontend (`PageRenderer.tsx` and `app/page.tsx`), the custom rendering loop automatically extracts the `anchorId` prop.
3. It then wraps your rendered component in a `<div id={anchorId} className="scroll-mt-24">` container.

This guarantees that Sticky Navigation links will always successfully scroll to the component, regardless of how complex the internal HTML of the component is.

---

## ? Phase 3 Completion Verification

Run this checklist to confirm Phase 3 is fully implemented:

- [ ] `npx tsc --noEmit` passes with 0 errors
- [ ] All existing hardcoded components are registered in `lib/puck/config.tsx`
- [ ] Components appear in the correct Puck sidebar categories
- [ ] Drag a component onto the canvas ? it renders correctly in the editor preview
- [ ] Publish ? live site renders the component with correct styling and layout
- [ ] All components enforce `max-w-7xl` (1280px) content width
- [ ] `anchorId` prop works for scroll-to navigation (`scroll-mt-24` wrapper applied)

> **Phase 3 is complete when ALL boxes above are checked.**
