# @meowlnir/landing-editor

A modern React 18 + TypeScript library powered by Vite and Craft.js for building beautiful landing page editors.  
Simple integration, full type safety, and flexible components for your projects.

---

## Features

- **Editor Mode**: Full-featured Craft.js editor with drag-and-drop, properties panel, and save functionality
- **Preview Mode**: Read-only display for rendering editor content
- **Render Mode**: Display components with simulated API data (WYSIWYG demo mode)
- **React 18**: Built using the latest React API
- **TypeScript**: Full type definitions for IntelliSense and safety
- **Ready for Production**: UMD and ES modules, TypeScript declarations included

---

## Installation

Install via pnpm (recommended):

```bash
pnpm add @meowlnir/landing-editor
```

> **Peer Dependencies**:  
> Make sure you have React 18 and React DOM installed in your project:
>
> ```bash
> pnpm add react@^18.0.0 react-dom@^18.0.0
> ```

### CDN Usage (CSS only)

If you only need the compiled CSS file, you can use a CDN without installing the full package:

```html
<!-- jsDelivr CDN -->
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/@meowlnir/landing-editor@latest/dist/style.css"
/>

<!-- or Unpkg CDN -->
<link
  rel="stylesheet"
  href="https://unpkg.com/@meowlnir/landing-editor@latest/dist/style.css"
/>
```

This exposes only the compiled styles, not the source code.

---

## Usage

### Editor Component

```tsx
import { Editor } from "@meowlnir/landing-editor";

const handleSave = (data: string) => {
  // Save data to your backend or localStorage
};

export default function MyEditorApp() {
  return (
    <Editor
      initialData={savedData} // Optional: load previously saved data
      onSave={handleSave} // Optional: callback when user saves
    />
  );
}
```

### Preview Component

```tsx
import { Preview } from "@meowlnir/landing-editor";

export default function MyPreview() {
  return (
    <Preview
      data={savedData} // Optional: data to display
      className="my-preview" // Optional: CSS class
      style={{ padding: "20px" }} // Optional: inline styles
    />
  );
}
```

### Render Component

The Render component displays your landing page with simulated API data, showing how it would look when consuming real backend data.

```tsx
import { Render } from "@meowlnir/landing-editor";

export default function MyRender() {
  return (
    <Render
      data={savedData} // Optional: editor data to render
      className="my-render" // Optional: CSS class
      style={{ padding: "20px" }} // Optional: inline styles
    />
  );
}
```

---

## API Reference

### Editor

| Prop          | Type                     | Description                    |
| ------------- | ------------------------ | ------------------------------ |
| `initialData` | `string`                 | Serialized editor data to load |
| `onSave`      | `(data: string) => void` | Callback when user saves       |

### Preview

| Prop            | Type                           | Description                |
| --------------- | ------------------------------ | -------------------------- |
| `data`          | `string`                       | Serialized data to display |
| `className`     | `string`                       | CSS class for styling      |
| `style`         | `React.CSSProperties`          | Inline styles              |
| `onButtonClick` | `(buttonText: string) => void` | Button click handler       |

### Render

| Prop        | Type                  | Description                                     |
| ----------- | --------------------- | ----------------------------------------------- |
| `data`      | `string`              | Serialized editor data to render with mock data |
| `className` | `string`              | CSS class for styling                           |
| `style`     | `React.CSSProperties` | Inline styles                                   |

---

## Available Components

- **Container**: Layout container, customizable background
- **Text**: Editable text with font size
- **Button**: Interactive button with color options

### Hero Sections

- **Hero Simple**: Clean profile-style hero with avatar
- **Hero Gradient**: Hero with gradient background
- **Hero Banner**: Hero with banner image
- **Hero Card**: Card-style hero presentation

### Content Blocks

- **Services Block**: Display services with pricing, ratings, and booking
- **Social Links Block**: Social media icons and links
- **Rich Text Block**: HTML content editor
- **Video Block**: Embed videos (YouTube, Vimeo, etc.)

You can easily extend built-in components using Craft.js resolver.

## Editor Modes

The editor includes three distinct modes accessible via tabs:

1. **Edición (Editor Mode)**: Full editing capabilities with drag-and-drop, component settings, and customization
2. **Vista previa (Preview Mode)**: Read-only view showing exactly what was configured in editor mode
3. **Render Mode**: Displays components with simulated API data, demonstrating how the page would look when consuming real backend services

This "What You See Is What You Get" (WYSIWYG) approach ensures your designs match production output.

---

## Data Services & Backend Integration

### Environment Configuration

Configure your backend connection via `.env` file:

```env
# Data mode: 'fake' for demo data, 'real' for production API
VITE_DATA_MODE=fake

# Backend API base URL (only required for real mode)
VITE_API_BASE_URL=https://api.dashflow.com

# Default tenant slug for demo mode
VITE_DEFAULT_TENANT=roger-maldonado
```

### API Endpoints (Production Mode)

When `VITE_DATA_MODE=real`, the editor expects these endpoints on your backend:

#### 1. Fetch Landing Settings

```
GET /api/v1/landing/{tenantSlug}/settings
```

**Response**: `LandingSettings` object containing profile, services, social links, and theme.

#### 2. Fetch User Profile

```
GET /api/v1/users/{tenantSlug}/profile
```

**Response**: `UserProfile` object with user details.

#### 3. Fetch Services

```
GET /api/v1/users/{tenantSlug}/services
```

**Response**: Array of `Service` objects.

#### 4. Fetch Social Links

```
GET /api/v1/users/{tenantSlug}/social-links
```

**Response**: Array of `SocialLink` objects.

#### 5. Save Editor Customizations

```
PUT /api/v1/landing/{tenantSlug}/editor-data
```

**Request Body**:

```json
{
  "editorData": {
    /* serialized CraftJS editor state */
  },
  "updatedAt": "2025-10-23T10:30:00Z"
}
```

#### 6. Book a Service

```
POST /api/v1/users/{tenantSlug}/services/{serviceId}/book
```

**Request Body**: Service booking details (custom structure).

### Auto-Injection of Backend Data

When users drag components from the toolbar, the editor **automatically injects backend data** into those components at creation time. This ensures seamless integration between editor and backend without manual steps.

#### How It Works

1. **User drags component** (e.g., "Tarjeta de Presentación") from toolbar
2. **Editor detects component type** and fetches corresponding backend data
3. **Component is created with backend data** as initial props
4. **User sees data immediately** - no placeholder phase

#### Components with Auto-Injection

| Component        | Backend Data Source | Props Injected                                     |
| ---------------- | ------------------- | -------------------------------------------------- |
| HeroSimple       | UserProfile         | `name`, `role`, `description`, `profileImage`      |
| HeroCard         | UserProfile         | `name`, `role`, `description`, `profileImage`      |
| HeroGradient     | UserProfile         | `title`, `subtitle`                                |
| HeroBanner       | UserProfile         | `title`, `subtitle`, `description`, `profileImage` |
| ServicesBlock    | Service[]           | `services`                                         |
| SocialLinksBlock | SocialLink[]        | `links`                                            |
| VideoBlock       | Video[]             | `videoUrl`, `title`                                |

#### Example: Dragging a Hero

```typescript
// When user drags HeroCard from toolbar:
// 1. Toolbar detects HeroCard is a Hero component
// 2. Gets backendSettings.profile: { fullName: "Roger Maldonado", profession: "Senior Engineer", ... }
// 3. Creates component with these props:
//
//   <HeroCard
//     name="Roger Maldonado"
//     role="Senior Engineer"
//     description="10+ years of experience..."
//     profileImage="https://..."
//   />
//
// 4. User sees "Roger Maldonado" immediately
```

#### Customization

Users can still customize injected data:

- Edit component properties in the sidebar
- Changes are saved to the editor state
- User customizations take priority over backend data when rendering

#### UserProfile

```typescript
interface UserProfile {
  id: string;
  slug: string;
  fullName: string;
  email: string;
  bio?: string;
  profession?: string;
  profileImage?: string;
  coverImage?: string;
  phone?: string;
  location?: string;
}
```

#### Service

```typescript
interface Service {
  id: string;
  name: string;
  description: string;
  price: number;
  currency: string;
  duration: number;
  durationUnit: string;
  rating?: number;
  reviews?: number;
  icon?: string;
  color?: string;
  available: boolean;
  popular?: boolean;
  category?: string;
}
```

#### SocialLink

```typescript
interface SocialLink {
  platform: string; // e.g., 'twitter', 'linkedin', 'instagram'
  url: string;
  enabled: boolean;
  icon?: string;
  order?: number;
}
```

#### LandingSettings (Complete Response)

```typescript
interface LandingSettings {
  profile: UserProfile;
  services: Service[];
  socialLinks: SocialLink[];
  theme?: {
    primaryColor?: string;
    secondaryColor?: string;
    accentColor?: string;
    backgroundColor?: string;
    fontFamily?: string;
  };
  seo?: {
    title?: string;
    description?: string;
    keywords?: string[];
    ogImage?: string;
  };
  customData?: Record<string, any>;
}
```

### Authentication

The API client automatically includes:

- **Authorization Header**: `Authorization: Bearer {AUTH_TOKEN}` (when available)
- **Tenant Header**: `X-Tenant-Slug: {tenantSlug}`

Configure auth token via environment or provide it when initializing the data provider.

### Data Merge Strategy

When rendering, backend data is merged with editor customizations:

- **Backend** provides dynamic content: profiles, services, social links
- **Editor** provides layout, styling, and component configuration
- **Editor customizations take precedence** for specific field overrides

Example: If a user customizes the hero title in the editor, that value is used. Otherwise, the backend profile name is displayed.

---

## TypeScript Support

Type definitions are included for all exported components and props.

```tsx
import {
  EditorProps,
  PreviewProps,
  RenderProps,
} from "@meowlnir/landing-editor";
```

---

## Example

A minimal example to get you started:

```tsx
import { Editor, Preview, Render } from "@meowlnir/landing-editor";

function App() {
  const [data, setData] = React.useState("");

  return (
    <>
      <Editor onSave={setData} />
      <Preview data={data} />
      <Render data={data} />
    </>
  );
}
```

The Editor component includes built-in tabs for switching between editor, preview, and render modes, so you typically only need to use the Editor component in your application.

---

## Publishing and Releases

This package is automatically published to GitHub Packages when a new release is created. The GitHub Actions workflow will:

1. Install dependencies with pnpm
2. Build the library using `pnpm run build:lib`
3. Publish the package to GitHub Packages

### Creating a Release from GitHub Web Interface

1. Go to the [GitHub repository](https://github.com/meowlnir/landing-editor)
2. Click on "Releases" in the right sidebar or go to `/releases`
3. Click "Create a new release"
4. Choose or create a new tag (e.g., `v1.0.0`, `v1.1.0`)
5. Add a release title and description
6. Click "Publish release"

### Creating a Release from Terminal

```bash
# Create and push a tag
git tag v1.0.0
git push origin v1.0.0

# Or create a release using GitHub CLI
gh release create v1.0.0 --title "v1.0.0" --notes "Release notes here"
```

The workflow will automatically trigger when:

- A release is published with any tag
- A tag matching the pattern `v*` is pushed (e.g., `v1.0.0`, `v2.1.3`)

---

## License

MIT

## Support

If you have questions or issues, please open an issue in the [GitHub repository](https://github.com/meowlnir/landing-editor/issues).

## Documentation

The detailed implementation and setup guides have been moved to the `docs/` directory. Useful files:

- [Index / overview](./docs/INDEX.md)
- [Getting started guide (EN)](./docs/GETTING_STARTED.md)
- [Quick start (ES)](./docs/QUICK_START_ES.md)
- [Setup guide (ES)](./docs/SETUP_GUIDE_ES.md)
- [Implementation summary (ES)](./docs/IMPLEMENTATION_SUMMARY_ES.md)
- [Troubleshooting](./docs/TROUBLESHOOTING.md)
- [Changes made / changelog](./docs/CHANGES_MADE.md)
- [Implementation README](./docs/README_IMPLEMENTATION.md)
- [Implementation complete notes](./docs/IMPLEMENTATION_COMPLETE.md)

If you can't find a specific document, check the `docs/` folder or open an issue in the repository.
