7.4 KiB

Landing Pages (Page Builder)

The Landing Pages feature provides a complete page building system with WYSIWYG editing, custom blocks, MkDocs export, and public rendering. Build custom landing pages without code.

Overview

The Landing Pages system consists of four integrated components:

  1. Page Builder - Page CRUD and management
  2. GrapesJS Editor - WYSIWYG editor
  3. Block Library - Reusable content blocks
  4. MkDocs Export - Export to Jinja2 templates

Features

WYSIWYG Editor

  • GrapesJS integration
  • Drag-and-drop interface
  • Visual editing
  • Component customization
  • CSS styling
  • Responsive preview
  • Desktop-only (mobile warning)

Block Library

Pre-built components:

  • Hero sections - Large header with CTA
  • Feature grids - Multi-column features
  • Call-to-action - Button sections
  • Text blocks - Rich text content
  • Image galleries - Photo grids
  • Forms - Contact forms (future)
  • Custom HTML - Raw HTML blocks

Page Management

  • Create/edit/delete pages
  • Slug management (URL-friendly)
  • Meta tags (title, description)
  • Published/draft status
  • Page settings (layout, scripts)
  • Search and filtering

MkDocs Export

  • Export to Jinja2 Material theme templates
  • Custom overrides directory
  • Static page generation
  • SEO optimization
  • Template inheritance

User Flow

Admin Experience

  1. Create Page (/app/pages)

    • Click "New Page"
    • Enter title and slug
    • Set meta description
    • Save draft
  2. Edit Page (/app/pages/:id/edit)

    • Full-screen GrapesJS editor
    • Drag blocks from sidebar
    • Customize components
    • Ctrl+S to save
    • Preview changes
  3. Publish Page

    • Set status to "Published"
    • Page appears at /p/:slug
    • Listed in page table
  4. Export to MkDocs (/app/services/docs)

    • Select pages to export
    • Click "Export"
    • Pages saved to MkDocs overrides
    • Rebuild MkDocs site

Public Experience

  1. View Landing Page (/p/:slug)
    • Rendered HTML/CSS
    • Custom styling
    • Responsive design
    • SEO metadata

Architecture

Backend Components

Module:

  • api/src/modules/pages/pages-admin.routes.ts - Admin CRUD
  • api/src/modules/pages/pages-public.routes.ts - Public renderer
  • api/src/modules/pages/blocks.routes.ts - Block library API
  • api/src/modules/pages/pages.service.ts - Business logic
  • api/src/modules/pages/pages.schemas.ts - Zod validation

Database Models:

  • Page - Page definitions (title, slug, html, css, settings)
  • PageBlock - Reusable block library

Frontend Components

Admin Pages:

  • admin/src/pages/LandingPagesPage.tsx - Page management table
  • admin/src/pages/PageEditorPage.tsx - Full-screen editor

Public Pages:

  • admin/src/pages/public/LandingPage.tsx - Page renderer

Editor Component:

  • admin/src/components/GrapesJSEditor.tsx - GrapesJS wrapper

Configuration

Environment Variables

# MkDocs export directory (inside Docker)
MKDOCS_EXPORT_DIR=/mkdocs/docs/overrides

Page Settings

Each page can configure:

  • Meta title - Browser title tag
  • Meta description - SEO description
  • Custom CSS - Page-specific styles
  • Custom JS - Page-specific scripts
  • Layout - Template wrapper (future)

GrapesJS Integration

Editor Setup

import grapesjs from 'grapesjs';

const editor = grapesjs.init({
  container: '#gjs',
  fromElement: true,
  height: '100vh',
  storageManager: false,  // Save via API
  canvas: {
    styles: [...],         // Custom styles
    scripts: [...],        // Custom scripts
  },
  blockManager: {
    blocks: customBlocks,  // Block library
  },
});

Custom Blocks

Blocks defined in GrapesJSEditor.tsx:

const customBlocks = [
  {
    id: 'hero-section',
    label: 'Hero Section',
    content: '<div class="hero">...</div>',
    category: 'Basic',
  },
  {
    id: 'feature-grid',
    label: 'Feature Grid',
    content: '<div class="features">...</div>',
    category: 'Content',
  },
  // ... more blocks
];

Save Handler

Ctrl+S keyboard shortcut:

editor.on('run:core:save', () => {
  const html = editor.getHtml();
  const css = editor.getCss();
  onSave({ html, css });
});

MkDocs Export

Export Process

  1. Select Pages - Admin selects pages to export
  2. Generate Jinja2 - Wrap HTML in Material theme template
  3. Save to Overrides - Write to mkdocs/docs/overrides/
  4. Configure Front Matter - Set template, title, description
  5. Rebuild Site - MkDocs regenerates static site

Jinja2 Template Wrapper

{% extends "main.html" %}

{% block content %}
<style>
{{ page_css }}
</style>

{{ page_html }}
{% endblock %}

Front Matter

---
template: custom-page.html
title: Page Title
description: Page description for SEO
---

Database Schema

Page Model

model Page {
  id          Int      @id @default(autoincrement())
  title       String
  slug        String   @unique
  html        String   @db.Text
  css         String?  @db.Text
  settings    Json?
  published   Boolean  @default(false)
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt
}

PageBlock Model

model PageBlock {
  id          Int      @id @default(autoincrement())
  name        String
  category    String
  html        String   @db.Text
  css         String?  @db.Text
  thumbnail   String?
  createdAt   DateTime @default(now())
  updatedAt   DateTime @updatedAt
}

API Endpoints

Admin Endpoints

GET    /api/pages                       # List pages
POST   /api/pages                       # Create page
GET    /api/pages/:id                   # Get page
PATCH  /api/pages/:id                   # Update page
DELETE /api/pages/:id                   # Delete page
POST   /api/pages/export-mkdocs         # Export to MkDocs
GET    /api/pages/blocks                # Get block library
POST   /api/pages/blocks                # Create block

Public Endpoints

GET    /api/pages/public/:slug          # Get published page by slug

Desktop-Only Editor

GrapesJS editor requires desktop browser:

const screens = Grid.useBreakpoint();
const isMobile = !screens.md;

if (isMobile) {
  return (
    <Alert
      message="Desktop Required"
      description="Page editor requires desktop browser"
      type="warning"
    />
  );
}

Best Practices

Slug Management

  • Auto-generate from title
  • URL-friendly (lowercase, hyphens)
  • Unique constraint
  • Update URL on slug change

SEO Optimization

  • Meta title (50-60 chars)
  • Meta description (150-160 chars)
  • Semantic HTML structure
  • Alt text for images
  • Heading hierarchy

Performance

  • Minify CSS
  • Lazy load images
  • Async scripts
  • Cache rendered pages

Responsive Design

  • Mobile-first CSS
  • Flexible grids
  • Responsive images
  • Touch-friendly buttons