# 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.

**Stack:** Vite 6 + React 18 + TypeScript 5 + @craftjs/core 0.2.x
**Bundle:** ~460KB JS + ~15KB CSS
**Version:** 2.0.0

## File Structure

```
craft/
├── index.html                          # HTML shell (loads fonts, FA icons, mounts React)
├── package.json                        # Dependencies and scripts (v2.0.0)
├── tsconfig.json                       # TypeScript config (ES2020, strict, path aliases)
├── vite.config.ts                      # Vite config (builds to dist/js/editor.js + dist/css/editor.css)
├── CLAUDE.md                           # This file
├── README.md                           # Brief project readme
├── FEATURES.md                         # User-facing features list
├── dist/                               # Build output (not committed)
│   ├── index.html
│   ├── js/editor.js
│   ├── css/editor.css
│   └── assets/
├── src/
│   ├── main.tsx                        # Entry point: reads WHP_CONFIG, mounts <App>
│   ├── App.tsx                         # Wraps <Editor> with providers, passes resolver
│   │
│   ├── types/
│   │   └── index.ts                    # WhpConfig, PageData, AssetData, StyleProps, DeviceMode
│   │
│   ├── state/
│   │   ├── EditorConfigContext.tsx      # React context for WHP_CONFIG (useEditorConfig hook)
│   │   ├── PageContext.tsx             # Multi-page state (pages, header, footer, CRUD, switching)
│   │   └── SiteDesignContext.tsx       # Site-wide design tokens (17 properties, Basic/Advanced)
│   │
│   ├── editor/
│   │   ├── EditorShell.tsx             # 3-panel layout: TopBar + LeftPanel + Canvas + RightPanel + ContextMenu
│   │   └── Canvas.tsx                  # Craft.js <Frame> with device-width switching
│   │
│   ├── components/
│   │   ├── resolver.ts                 # Component map for Craft.js serialization (39 components)
│   │   ├── layout/
│   │   │   ├── Container.tsx           # Generic container (div/section/article/header/footer/main)
│   │   │   ├── Section.tsx             # Full-width section with centered inner container
│   │   │   ├── ColumnLayout.tsx        # Flex columns (1-6, with split ratios)
│   │   │   └── BackgroundSection.tsx   # Section with background image/gradient overlay
│   │   ├── basic/
│   │   │   ├── Heading.tsx             # Inline-editable heading (h1-h6)
│   │   │   ├── TextBlock.tsx           # Inline-editable paragraph
│   │   │   ├── ButtonLink.tsx          # Styled <a> with color presets
│   │   │   ├── Navbar.tsx              # Navigation bar (text/image logo, page links, external links, CTA)
│   │   │   ├── Footer.tsx              # Footer component (links, copyright, social)
│   │   │   ├── Divider.tsx             # Horizontal rule (color, thickness)
│   │   │   └── Spacer.tsx              # Vertical spacing element
│   │   ├── media/
│   │   │   ├── ImageBlock.tsx          # Image with placeholder, upload, browse, sizing
│   │   │   └── VideoBlock.tsx          # Video embed (YouTube, Vimeo, direct files, background mode)
│   │   ├── sections/
│   │   │   ├── HeroSimple.tsx          # Pre-built hero section with heading, subtext, CTA
│   │   │   ├── FeaturesGrid.tsx        # 3-column feature cards grid
│   │   │   └── CTASection.tsx          # Call-to-action banner section
│   │   └── forms/
│   │       ├── FormContainer.tsx       # Form wrapper with action/method
│   │       ├── InputField.tsx          # Input field with label and placeholder
│   │       ├── TextareaField.tsx       # Textarea field with label
│   │       └── FormButton.tsx          # Submit button with styling
│   │
│   ├── panels/
│   │   ├── topbar/
│   │   │   ├── TopBar.tsx              # Back button, domain badge, device switcher, undo/redo, save, templates
│   │   │   ├── TemplateModal.tsx       # Template browser with categories and one-click loading
│   │   │   └── HeadCodeModal.tsx       # Edits SiteDesign.headCode (site-wide, not per-page)
│   │   ├── left/
│   │   │   ├── LeftPanel.tsx           # Tabs: Blocks | Pages | Layers | Assets
│   │   │   ├── BlocksPanel.tsx         # Draggable block toolbox with categories
│   │   │   ├── PagesPanel.tsx          # Multi-page CRUD, header/footer editing
│   │   │   ├── LayersPanel.tsx         # Component hierarchy tree view
│   │   │   └── AssetsPanel.tsx         # Asset browser with upload, drag-drop, thumbnails
│   │   ├── right/
│   │   │   ├── RightPanel.tsx          # Single "Styles" tab -- renders GuidedStyles only
│   │   │   ├── GuidedStyles.tsx        # Context-aware dispatcher: picks a StylePanel by selected type
│   │   │   ├── SiteDesignPanel.tsx     # Site-wide design tokens editor (Basic/Advanced tabs)
│   │   │   └── styles/                 # Per-type StylePanels (Text, Button, Image, Container, Nav, Form, etc.)
│   │   └── context-menu/
│   │       └── ContextMenu.tsx         # Right-click context menu (duplicate, copy, paste, delete, etc.)
│   │
│   ├── hooks/
│   │   ├── useWhpApi.ts               # Save/load/deploy via WHP API (with auto-save)
│   │   ├── useAssets.ts               # Asset upload, browse, delete via WHP API
│   │   ├── useContextMenu.ts          # Right-click menu state management
│   │   └── useKeyboardShortcuts.ts    # Keyboard shortcut handler (undo, redo, delete, etc.)
│   │
│   ├── templates/
│   │   ├── index.ts                   # Template exports
│   │   └── definitions.ts            # 16 template definitions across 4 categories
│   │
│   ├── ui/
│   │   ├── AssetPicker.tsx             # Reusable image/video source picker (upload/browse-uploaded/URL), full+compact variants
│   │   └── Modal.tsx                   # Reusable modal dialog shell
│   │
│   ├── constants/
│   │   └── presets.ts                  # Color, font, spacing, radius, gradient, device width presets
│   │
│   ├── utils/
│   │   ├── style-helpers.ts            # cssPropsToString(), mergeStyles()
│   │   └── html-export.ts             # Recursive node-to-HTML renderer, full page export
│   │
│   └── styles/
│       └── editor.css                  # Dark theme, CSS variables
```

## Running Locally

```bash
cd /workspace/site-builder/craft
npm install
npm run dev
```

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:

```bash
# Build
cd /workspace/site-builder/craft && npm run build

# Deploy to WHP Docker container
cp dist/index.html /docker/whp/web/site-builder/editor.html
cp -r dist/js/ /docker/whp/web/site-builder/js/
cp -r dist/css/ /docker/whp/web/site-builder/css/
```

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
interface MyComponentProps {
  text?: string;
  style?: CSSProperties;
}

// 2. The component itself (renders in editor canvas)
export const MyComponent: UserComponent<MyComponentProps> = ({ text, style }) => {
  const { connectors: { connect, drag } } = useNode();
  return <div ref={(r) => { if (r) connect(drag(r)); }} style={style}>{text}</div>;
};

// 3. Craft config (displayName, default props, rules)
MyComponent.craft = {
  displayName: 'My Component',
  props: { text: 'Default text', style: {} },
  rules: { canDrag: () => true, canMoveIn: () => false, canMoveOut: () => true },
};

// 4. HTML export (static method for serializing to HTML string)
(MyComponent as any).toHtml = (props: MyComponentProps, childrenHtml: string) => {
  return { html: `<div style="...">${childrenHtml}</div>` };
};
```

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.

### Component Resolver

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.

```typescript
export const componentResolver = {
  Container, Section, ColumnLayout, BackgroundSection,
  Heading, TextBlock, ButtonLink, Navbar, Footer, Divider, Spacer,
  ImageBlock, VideoBlock,
  HeroSimple, FeaturesGrid, CTASection,
  FormContainer, InputField, TextareaField, FormButton,
};
```

## WHP Integration

### PHP Wrapper

The WHP control panel serves the editor through `index.php`, which:
1. Verifies user authentication
2. Validates the `site_id` parameter
3. Generates a CSRF token
4. Injects a `WHP_CONFIG` object into the HTML as a `<script>` tag before the app bundle

```javascript
window.WHP_CONFIG = {
  user: "username",
  apiUrl: "/panel/api/site-builder",
  csrfToken: "abc123...",
  siteId: 42,
  siteDomain: "example.com",
  siteName: "My Site",
  backUrl: "/panel/sites",
  isRoot: false
};
```

### API Endpoints

The editor communicates with WHP through these endpoints (all require CSRF token):

| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | `/panel/api/site-builder?action=save` | Save project (JSON body with site_id, html, css, craft state) |
| GET | `/panel/api/site-builder?action=load&site_id=N` | Load project for a site |
| POST | `/panel/api/site-builder?action=upload` | Upload asset (multipart) |
| GET | `/panel/api/site-builder?action=assets&site_id=N` | List assets for a site |
| DELETE | `/panel/api/site-builder?action=delete_asset` | Delete an asset |
| POST | `/panel/api/site-builder?action=deploy&site_id=N` | Deploy/publish site to document root |

### Auto-Save

The editor auto-saves every 30 seconds when running inside WHP. The save status is displayed in the top bar.

### EditorConfigContext

`useEditorConfig()` provides access to `WHP_CONFIG` throughout the React tree:
- `whpConfig` - The full config object (or null in standalone mode)
- `isWHP` - Boolean shorthand for whether we're running inside WHP

## All Components (39)

| # | Component | Type | File | Features |
|---|-----------|------|------|----------|
| 1 | Container | Layout | `layout/Container.tsx` | Generic wrapper, tag selector (div/section/article/header/footer/main), bg color, padding, radius |
| 2 | Section | Layout | `layout/Section.tsx` | Full-width with centered inner container, bg color/gradient, vertical padding, inner max-width |
| 3 | ColumnLayout | Layout | `layout/ColumnLayout.tsx` | 1-6 columns, split ratios (50-50, 30-70, 70-30, 33-33-33, 25-25-25-25, etc.), gap control |
| 4 | BackgroundSection | Layout | `layout/BackgroundSection.tsx` | Section with background image, gradient overlay, parallax-ready |
| 5 | Heading | Basic | `basic/Heading.tsx` | Inline-editable, h1-h6 level, color, font family/size/weight, text align |
| 6 | TextBlock | Basic | `basic/TextBlock.tsx` | Inline-editable paragraph, color, font family/size/weight, text align, line height |
| 7 | ButtonLink | Basic | `basic/ButtonLink.tsx` | Link text/URL/target, 8 color presets (auto text contrast), radius, padding, font size |
| 8 | Logo | Basic | `basic/Logo.tsx` | Text or image logo, link href, font family/size/weight, image width |
| 9 | Menu | Basic | `basic/Menu.tsx` | Link list with optional CTA styling, horizontal/vertical orientation, alignment, hover colors |
| 10 | Navbar | Basic | `basic/Navbar.tsx` | Text or image logo, page links, external links, CTA buttons, light/dark nav style |
| 11 | Footer | Basic | `basic/Footer.tsx` | Footer with links, copyright, social links |
| 12 | Divider | Basic | `basic/Divider.tsx` | Horizontal rule with color and thickness controls |
| 13 | Spacer | Basic | `basic/Spacer.tsx` | Vertical spacing element with height control |
| 14 | Icon | Basic | `basic/Icon.tsx` | Font Awesome icon, size/color, background shape, optional link |
| 15 | ImageBlock | Media | `media/ImageBlock.tsx` | SVG placeholder, URL input, upload, browse assets, alt text, width/height, object-fit, radius |
| 16 | VideoBlock | Media | `media/VideoBlock.tsx` | YouTube, Vimeo, direct files (.mp4/.webm/.ogg), background mode, autoplay, loop |
| 17 | MapEmbed | Media | `media/MapEmbed.tsx` | Embedded map by address, zoom level, height |
| 18 | HeroSimple | Section | `sections/HeroSimple.tsx` | Pre-built hero with heading, subtext, CTA button, gradient/color background |
| 19 | FeaturesGrid | Section | `sections/FeaturesGrid.tsx` | 3-column feature cards with icons, titles, descriptions |
| 20 | CTASection | Section | `sections/CTASection.tsx` | Call-to-action banner with heading, text, button |
| 21 | Countdown | Section | `sections/Countdown.tsx` | Countdown timer to a target date, heading, digit/label colors |
| 22 | Testimonials | Section | `sections/Testimonials.tsx` | Grid or single-layout testimonial cards, star color, card background |
| 23 | FormContainer | Form | `forms/FormContainer.tsx` | Form wrapper with action URL and method |
| 24 | InputField | Form | `forms/InputField.tsx` | Text input with label, placeholder, type (text/email/tel/password/number) |
| 25 | TextareaField | Form | `forms/TextareaField.tsx` | Textarea with label and placeholder |
| 26 | FormButton | Form | `forms/FormButton.tsx` | Submit button with color and style controls |
| 27 | ContactForm | Form | `forms/ContactForm.tsx` | Configurable field list, recipient email, success message or thank-you URL redirect |
| 28 | StarRating | Basic | `basic/StarRating.tsx` | Star rating display, rating/max stars, filled/empty color |
| 29 | SocialLinks | Basic | `basic/SocialLinks.tsx` | Social icon links, size/color/shape, gap, alignment |
| 30 | CallToAction | Section | `sections/CallToAction.tsx` | Heading/description with 1-2 buttons, color/gradient/image background with overlay |
| 31 | Accordion | Section | `sections/Accordion.tsx` | Expand/collapse item list, header/content colors |
| 32 | Tabs | Section | `sections/Tabs.tsx` | Tabbed content panels, active/inactive tab colors |
| 33 | PricingTable | Section | `sections/PricingTable.tsx` | Pricing plan cards, featured plan highlight, bullet list |
| 34 | Gallery | Section | `sections/Gallery.tsx` | Image grid gallery, configurable columns/gap, optional lightbox |
| 35 | ContentSlider | Section | `sections/ContentSlider.tsx` | Auto-playing image/content slider, dots/arrows, configurable interval |
| 36 | NumberCounter | Section | `sections/NumberCounter.tsx` | Animated stat counters, columns, number/label colors |
| 37 | SubscribeForm | Form | `forms/SubscribeForm.tsx` | Inline/stacked email signup form, heading, button color |
| 38 | SearchBar | Basic | `basic/SearchBar.tsx` | Search input with optional button, placeholder text |
| 39 | HtmlBlock | Basic | `basic/HtmlBlock.tsx` | Raw/custom HTML embed block, sanitized on export |

## Site Design Tokens

The `SiteDesignContext` provides 17 design properties organized into Basic and Advanced tabs:

### Basic Tab (6 properties)
| Property | Default | Description |
|----------|---------|-------------|
| primaryColor | `#3b82f6` | Primary brand color |
| secondaryColor | `#8b5cf6` | Secondary brand color |
| accentColor | `#10b981` | Accent/highlight color |
| headingFont | `Inter, sans-serif` | Font for headings |
| bodyFont | `Inter, sans-serif` | Font for body text |
| linkColor | `#3b82f6` | Default link color |

### Advanced Tab (11 properties)
| Property | Default | Description |
|----------|---------|-------------|
| successColor | `#10b981` | Success state color |
| warningColor | `#f59e0b` | Warning state color |
| errorColor | `#ef4444` | Error state color |
| backgroundColor | `#ffffff` | Page background |
| textColor | `#1f2937` | Default text color |
| mutedTextColor | `#6b7280` | Muted/secondary text |
| borderColor | `#e5e7eb` | Default border color |
| borderRadius | `8px` | Global border radius |
| buttonFont | `Inter, sans-serif` | Button font family |
| buttonRadius | `8px` | Button border radius |
| navStyle | `light` | Navbar style (light/dark) |

Design tokens are imported from templates and can be edited via the Site Design panel. Components can read these tokens via `useSiteDesign()`.

## Templates

16 pre-built templates organized into 4 categories:

| Category | Templates |
|----------|-----------|
| Business | Restaurant, Small Business, SaaS Landing, Agency, Medical |
| Creative | Portfolio, Photography, Content Creator, Event/Conference |
| 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.

## Multi-Page System

Pages are managed through `PageContext`:
- 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.

## Adding New Components

1. Create `src/components/<category>/<ComponentName>.tsx` following the pattern above
2. Add the component to `src/components/resolver.ts`
3. Add a block entry in `src/panels/left/BlocksPanel.tsx` under the appropriate category
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

### Checklist for a new component:
- [ ] Props interface with `style?: CSSProperties`
- [ ] `useNode()` with `connect(drag(ref))` on the root element
- [ ] `StylePanel` entry (new or reused) wired into `GuidedStyles.tsx`
- [ ] `.craft` config with `displayName`, default `props`, `rules`
- [ ] `.toHtml()` static method using `cssPropsToString()`
- [ ] Registered in `resolver.ts`
- [ ] Block added to `BlocksPanel.tsx`

## CSS / Theme

The editor uses a dark theme defined via CSS custom properties in `src/styles/editor.css`:
- **Base:** `#16161a`
- **Surface:** `#1c1c24`
- **Accent:** `#3b82f6` (blue)
- **Text:** `#e4e4e7`
- **Border:** `#2d2d3a`
- **Font:** Inter

All editor chrome (panels, topbar, style panels) is styled via `editor.css`. User content on the canvas uses inline styles exclusively.

## Presets

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:
- Full `<!DOCTYPE html>` document structure
- Google Fonts preload links (optional)
- Inline styles throughout
- Header and footer wrapping each page

## Testing Approach

- **Manual testing:** Run `npm run dev`, drag components, edit props, verify style panels
- **Type checking:** `tsc --noEmit` (part of build step)
- **HTML export:** Verify `toHtml()` output matches expected HTML structure
- **Device preview:** Switch between desktop/tablet/mobile and verify responsive behavior
- **WHP integration:** Deploy to staging, verify save/load, verify PHP wrapper injection

## Development Notes

- Path alias `@/` maps to `./src/` (configured in both tsconfig.json and vite.config.ts)
- `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)
- Text components (Heading, TextBlock) use `contentEditable` for inline editing when selected
- Button/link navigation is prevented in the editor via `e.preventDefault()`
- Image upload integrates with WHP API; in standalone mode falls back to local `blob:` URLs
- Auto-save runs every 30 seconds when connected to WHP API
- `AssetPicker` (`src/ui/AssetPicker.tsx`) is the shared upload/browse/URL control reused across StylePanels for every image and video field
