# WHP Site Builder v2 (Craft.js) - Project Documentation
## Overview
A visual drag-and-drop website builder rebuilt from the ground up using Craft.js, React 18, and TypeScript. Replaces the legacy GrapesJS-based editor (`/workspace/site-builder/`). Users create multi-page websites without writing code, with server-side storage through WHP's PHP API layer.
Opens at `http://localhost:5173`. The Vite dev server proxies `/api` requests to `http://192.168.1.105:8080` (the WHP staging server) for save/load during development.
In standalone mode (no WHP_CONFIG on `window`), the editor runs fully client-side without save/load functionality.
## Building
```bash
npm run build
```
Runs `tsc && vite build`. Output goes to `dist/`:
-`dist/index.html` - HTML shell
-`dist/js/editor.js` - Single JS bundle
-`dist/css/editor.css` - All styles
-`dist/assets/` - Static assets (if any)
## Deploying to WHP
Copy the built `dist/` contents into the WHP site-builder web directory:
The PHP wrapper (`/docker/whp/web/site-builder/index.php`) injects `WHP_CONFIG` into the HTML before serving it, so the editor gets the current user's session, CSRF token, site ID, etc.
## Architecture
### Key Decisions
1.**No iframe** - The canvas renders directly in the DOM (unlike GrapesJS which uses an iframe). This simplifies drag-and-drop and avoids cross-origin issues but means editor CSS must not leak into user content.
2.**Inline styles** - All component styling uses React `CSSProperties` (inline styles). No class-based CSS for user content. This makes HTML export trivial and avoids stylesheet management.
3.**Single Frame, multi-page** - Craft.js `<Frame>` holds one page at a time. Page switching serializes the current state, stores it, and deserializes the new page's state.
4.**Header/Footer as separate pages** - Header and Footer are stored as independent Craft.js states (like pages) that render above and below every page. Editing them uses the same canvas but with a distinct editing mode. This provides site-wide shared navigation and footer.
5.**API compatibility** - The save endpoint sends data in the same format as the GrapesJS version (`{ site_id, name, html, css, grapesjs: serializedJson }`), so the PHP backend doesn't need changes.
6.**Component-based architecture** - Each visual element is a React component that doubles as a Craft.js `UserComponent`. Rendering and HTML export are co-located in one file; style editing is handled by a shared per-type `StylePanel` in `src/panels/right/styles/` rather than a per-component settings panel.
7.**Site Design Tokens** - A `SiteDesignContext` provides 17 design properties (colors, fonts, radii, nav style) that components can reference. Templates import their own design tokens when loaded.
### Component Architecture
Every component in `src/components/` follows this pattern:
```typescript
import{UserComponent,useNode}from'@craftjs/core';
// 1. Props interface
interfaceMyComponentProps{
text?: string;
style?: CSSProperties;
}
// 2. The component itself (renders in editor canvas)
Style editing for the new type is added separately as a `StylePanel` under `src/panels/right/styles/` (or reuses an existing generic one), and wired into `GuidedStyles.tsx`'s type dispatch -- components no longer carry their own settings UI.
All components must be registered in `src/components/resolver.ts`. This map is passed to `<Editor resolver={componentResolver}>` so Craft.js can serialize/deserialize the node tree.
| Personal | Resume/CV, Blog, Wedding, Coming Soon |
| Community | Church, Non-Profit, Fitness/Gym |
Each template includes:
- Site design tokens (color palette, fonts)
- Header content (Navbar)
- Footer content
- One or more pages with pre-built content
- SVG thumbnail preview
Templates are loaded via the Template Modal (opened from TopBar). Loading a template replaces all pages, header, footer, and optionally imports the design tokens.
- Each page has: `id`, `name`, `slug`, `craftState` (`headCode` is site-wide only, on `SiteDesignContext`/`SiteDesign`, edited via the TopBar's Head Code modal -- not a per-page field)
- Header and Footer are stored as separate "page" entries with fixed IDs (`__header__`, `__footer__`)
- Page switching serializes the current canvas, stores it, then deserializes the target page
- Header/Footer editing puts the canvas in a distinct mode
- The PagesPanel provides add, rename, delete, reorder, and header/footer edit buttons
## Keyboard Shortcuts
| Shortcut | Action |
|----------|--------|
| Ctrl/Cmd + Z | Undo |
| Ctrl/Cmd + Shift + Z | Redo |
| Ctrl/Cmd + Y | Redo (alternative) |
| Delete / Backspace | Delete selected element |
Shortcuts are disabled when focus is on input, textarea, select, or contentEditable elements.
## Context Menu (Right-Click)
The context menu appears on right-click within the canvas and provides:
- Duplicate element
- Copy / Paste
- Move Up / Move Down
- Select Parent
- Delete (with danger styling)
Items are disabled contextually (e.g., cannot delete ROOT, cannot move if already first/last).
## Layers Panel
The Layers panel shows a hierarchical tree of all components on the current page. Clicking a layer selects the corresponding component. The tree displays component display names and nests children with indentation.
## Asset Management
The Assets panel (`AssetsPanel.tsx`) provides:
- Upload button and drag-and-drop zone
- Thumbnail grid of uploaded assets
- Copy URL to clipboard
- Delete asset
- Integration with WHP API for server-side storage
Image and video fields elsewhere in the editor (ImageStylePanel, MediaStylePanel, HeroStylePanel, NavStylePanel, BackgroundSectionStylePanel, and array-editor cards like FeaturesEditor) use the shared `AssetPicker` (`src/ui/AssetPicker.tsx`) for upload / browse-uploaded / paste-URL, in a `full` or `compact` variant depending on space.
4. Add or extend a `StylePanel` in `src/panels/right/styles/` and wire it into `GuidedStyles.tsx`'s type dispatch so the new component is editable when selected
5. Implement the `toHtml` static for HTML export
6. Build and test: `npm run dev`, drag the block onto the canvas, verify the style panel, verify HTML export
Style presets are defined in `src/constants/presets.ts`:
-`TEXT_COLORS` - 8 text color swatches
-`BG_COLORS` - 8 background color swatches
-`FONT_FAMILIES` - 8 Google Fonts
-`TEXT_SIZES` - XS through 2XL
-`FONT_WEIGHTS` - Light through Bold
-`SPACING_PRESETS` - None through XL
-`RADIUS_PRESETS` - None through Full (9999px)
-`GRADIENTS` - 12 gradient presets
-`DEVICE_WIDTHS` - Desktop (100%), Tablet (768px), Mobile (375px)
## HTML Export
Every component has a static `toHtml(props, childrenHtml)` method. The `html-export.ts` utility recursively walks the Craft.js node tree and calls each component's `toHtml` to produce a complete HTML document. Export includes:
-`GuidedStyles` shows the selected component type and dispatches to a shared `StylePanel` in `src/panels/right/styles/` (components no longer carry their own settings UI)