# Modyo Site Components - Deep Dive

**Version**: 1.0.0
**Last Updated**: 2025-01-09
**Module**: Channels

> This document is part of the [Site Architecture Guide](./site-architecture.md). See also [Content Flow, Patterns & Best Practices](./site-patterns.md).

## Component Deep Dive

### 1. Site (Container)

**What it is**: The top-level container for your entire web application with a unique domain.

**Key Characteristics**:
- Unique domain name (e.g., `www.mycompany.com` or `myapp.modyo.me`)
- Can exist in three states: **Enabled**, **Pending Changes**, **Disabled**
- Supports multiple deployment stages (development, staging, production)

**Configuration Options**:

#### General Settings
```yaml
name: "Corporate Website"
host: "www.mycompany.com"
language: "en"
time_zone: "America/New_York"
theme: "208"
```

#### Progressive Web App (PWA)
- Manifest generation
- Service worker configuration
- Offline capabilities
- Install prompts

#### Security
- Custom security headers
- CORS configuration
- Content Security Policy (CSP)
- HTTPS enforcement

#### Performance
- Custom redirects (301/302)
- Sitemap generation
- robots.txt configuration
- Caching strategies

#### Site Variables
Global variables accessible throughout the site:
```liquid
{{ site.name }}
{{ site.base_url }}
{{ site.time_zone }}
```

**Real-World Example**:
```
Site: E-Commerce Platform
Domain: shop.example.com
Language: English
PWA: Enabled
Security: HTTPS enforced, CSP configured
Variables:
  - brand_color: "#FF5733"
  - support_email: "support@example.com"
  - analytics_id: "GA-XXXXXXX"
```

---

### 2. Pages (Routes/URLs)

**What they are**: Individual routes that define what users can access at specific URLs.

**⚠️ CRITICAL: Modyo has THREE distinct page types with different capabilities:**

#### 1. Widget Pages (Layout Pages)
- **page_type**: `"default"` or `"home"`
- **Purpose**: Modular pages built with grid layouts and custom widgets
- **Accepts**: ✅ Custom widgets, ✅ Liquid templates, ✅ Grid layouts
- **Does NOT have**: Automatic Content API connection
- **Use Cases**: Landing pages, dashboards, marketing pages, homepages, **Single Page Applications (SPAs)**
- **Structure**: Flexible grid layout with positioned widgets
- **`has_router: true`**: Enables **client-side JS routing** - Same widgets render for all sub-routes, widgets handle navigation
- **Example - Static Widget Page**:
  ```typescript
  {
    name: "Dashboard",
    path: "/dashboard",
    page_type: "default",
    grid_type: "full_three_cols_grid",  // Defines columns available
    has_router: false
  }
  // Can add custom widgets via page-add-widgets tool
  ```
- **Example - SPA with Client-Side Routing**:
  ```typescript
  {
    name: "Banking App",
    path: "/app",
    page_type: "default",
    grid_type: "full_grid",
    has_router: true  // Same widgets handle /app/*, JS routing
  }
  // Widgets use React Router/Vue Router to handle:
  // /app/dashboard, /app/accounts, /app/transfers
  ```

#### 2. Content Pages
- **page_type**: `"content"` or `"entry"` (verify in API docs)
- **Purpose**: Display content from Content module with automatic Liquid drops
- **Accepts**: ✅ Liquid templates only (server-side rendering)
- **Does NOT accept**: ❌ Custom widgets
- **Automatic Features**:
  - **Index view**: Automatic `entries` drop with list of content
  - **Show view**: Automatic `entry` drop with single content item
  - Dynamic routing for entry slugs
- **REQUIRED**: Must specify `content_type_id` to connect to Content API
- **Use Cases**: Blogs, news, documentation, product catalogs
- **Structure**: Two views (Index list + Show detail)
- **`has_router: true`**: Required for **show view** to enable **server-side dynamic routing** for content entry slugs
- **Example**:
  ```typescript
  {
    name: "Blog",
    path: "/blog",
    page_type: "content",  // Index view
    content_type_id: 5756,  // REQUIRED!
    has_router: false  // Index doesn't need routing
  }
  // Creates: /blog (lists all posts)

  {
    name: "Blog Post",
    path: "/blog",
    page_type: "entry",  // Show view
    content_type_id: 5756,  // REQUIRED!
    has_router: true  // Enable dynamic routing for /{slug}
  }
  // Creates: /blog/{slug} (displays single post)
  ```

**Index View Liquid (automatic `entries` drop)**:
```liquid
{% for entry in entries %}
  <article>
    <h2>{{ entry.meta.name }}</h2>
    <p>{{ entry.fields['Description'] }}</p>
    <a href="/blog/{{ entry.meta.slug }}">Read more</a>
  </article>
{% endfor %}
```

**Show View Liquid (automatic `entry` drop)**:
```liquid
<article>
  <h1>{{ entry.meta.name }}</h1>
  <div>{{ entry.fields['Content'] }}</div>
  <time>{{ entry.meta.published_at | date: "%B %d, %Y" }}</time>
</article>
```

#### 3. Origination Pages
- **page_type**: `"origination"`
- **Purpose**: Multi-step form workflows and data collection
- **Accepts**: ✅ Form workflows, ✅ Task-based navigation
- **Does NOT accept**: ❌ Custom widgets
- **Use Cases**: Loan applications, account openings, surveys, onboarding
- **Structure**: Multi-step process with stepper/progress indicators
- **Example**:
  ```typescript
  {
    name: "Loan Application",
    path: "/apply/loan",
    page_type: "origination",
    origination_uuid: "uuid-of-origination-config",
    options: {
      show_stepper: true,
      stepper_position: "top",
      show_sidebar: true
    }
  }
  ```

**Page Type Comparison**:

| Feature | Widget Page | Content Page | Origination Page |
|---------|------------|--------------|------------------|
| **Custom Widgets** | ✅ Yes | ❌ No | ❌ No |
| **Liquid Templates** | ✅ Yes | ✅ Yes | ✅ Yes |
| **Grid Layout** | ✅ Yes | ❌ No | ❌ No |
| **Content API Connection** | ❌ Manual | ✅ Automatic | ❌ No |
| **Automatic Drops** | ❌ No | ✅ Yes (`entries`, `entry`) | ❌ No |
| **Index/Show Views** | ❌ No | ✅ Yes | ❌ No |
| **Form Workflows** | Manual | ❌ No | ✅ Yes |
| **Dynamic Routing** | Manual | ✅ Automatic | Task-based |

**📖 See [MODYO_PAGE_TYPES.md](./MODYO_PAGE_TYPES.md) for comprehensive page type documentation.**

**Page Properties**:

```typescript
{
  id: 456,
  uuid: "page-uuid-123",
  name: "Product Catalog",
  path: "/products",
  page_type: "default",
  grid_type: "standard",
  private: false,              // Public or requires authentication
  has_router: true,           // Dynamic routing (/:slug)
  restriction_enabled: false, // Segment restrictions
  excerpt: "Browse our products",
  content_type_id: 45,        // Linked content type
  parent_uuid: null,          // Parent page for nesting
  status: "published",        // draft | published | archived
}
```

**Page Routing**:

- **Static Routes**: `/about`, `/contact`, `/services`
- **Dynamic Routes**: `/products/:slug`, `/blog/:category/:slug`
- **Nested Routes**: `/products/electronics/laptops`
- **Reserved Paths**: Some paths like `/admin`, `/api` are reserved

**Page Privacy**:

```yaml
public_page:
  private: false
  # Accessible to everyone

private_page:
  private: true
  # Requires authentication

segmented_page:
  private: true
  restriction_enabled: true
  segments: ["premium", "enterprise"]
  # Only specific user segments
```

---

### 3. Page Layouts (Structure Templates)

**What they are**: Master templates that define the overall HTML structure of pages.

**Predefined Layouts**:

#### Base Layout
- **Purpose**: Default site-wide structure
- **Contains**: Header, footer, navigation, service worker
- **Usage**: Most standard pages use Base Layout
- **Example Structure**:
```liquid
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>{{ page.title }} - {{ site.name }}</title>
  {% snippet 'head-meta' %}
  {{ 'application' | stylesheet_tag }}
</head>
<body>
  {% snippet 'site-header' %}
  {% menu 'main-navigation' %}

  <main>
    {{ content_for_layout }}
  </main>

  {% snippet 'site-footer' %}
  {{ 'application' | script_tag }}
</body>
</html>
```

#### Home Layout
- **Purpose**: Homepage-specific template
- **Contains**: Special header, hero sections, custom navigation
- **Usage**: Only for homepage (/)
- **Example**:
```liquid
<!DOCTYPE html>
<html>
<head>
  <title>{{ site.name }} - Welcome</title>
</head>
<body class="home-page">
  {% snippet 'home-hero' %}

  <main>
    {{ content_for_layout }}
  </main>

  {% snippet 'site-footer' %}
</body>
</html>
```

#### Error Layout
- **Purpose**: Error page templates
- **Types**:
  - 404 (Page Not Found)
  - 500 (Server Error)
  - Site Disabled
  - Privacy Restricted
  - Template Syntax Error
- **Example**:
```liquid
<!DOCTYPE html>
<html>
<head>
  <title>Page Not Found - {{ site.name }}</title>
</head>
<body>
  <h1>404 - Page Not Found</h1>
  <p>The page you're looking for doesn't exist.</p>
  <a href="/">Go Home</a>
</body>
</html>
```

**Custom Layouts**:
You can create custom layouts for specific page types:
```
- Product Layout (for product pages)
- Blog Layout (for blog posts)
- Landing Layout (for marketing campaigns)
- Documentation Layout (for help docs)
```

**Layout Selection**:
When creating a page, you choose which layout to use:
```
Page: /products/laptop-x
Layout: Product Layout
```

---

### 4. Templates (Code Organization)

**What they are**: The broader category containing all reusable code elements.

**Template Types**:

#### Snippets (System-Level)
- **Purpose**: Reusable HTML/Liquid code blocks managed by administrators
- **Scope**: Available site-wide
- **Examples**: Headers, footers, meta tags, analytics
- **Usage in Pages**:
```liquid
{% snippet 'site-header' %}
{% snippet 'analytics' %}
{% snippet 'breadcrumbs' %}
```

#### Custom Snippets (User-Level)
- **Purpose**: User-created reusable components
- **Scope**: Often site-specific or feature-specific
- **Examples**: Product cards, testimonial sections, CTAs
- **Usage in Pages**:
```liquid
{% snippet 'product-card' %}
{% snippet 'testimonial-section' %}
{% snippet 'newsletter-signup' %}
```

**Difference: Snippets vs Custom Snippets**:
| Aspect | Snippets | Custom Snippets |
|--------|----------|-----------------|
| **Created By** | Administrators | Content editors/developers |
| **Management** | System-level | User-level |
| **Common Use** | Site infrastructure | Feature components |
| **Examples** | Header, Footer, Analytics | Product Card, Testimonial Widget |

#### CSS Templates
- **Purpose**: Site-wide or page-specific styles
- **Features**:
  - Import external libraries
  - Use Liquid filters: `{{ 'styles.css' | asset_url }}`
  - Support for SASS/SCSS via preprocessors
- **Example**:
```css
/* Global Styles */
:root {
  --primary-color: {{ site.brand_color }};
  --font-family: 'Inter', sans-serif;
}

body {
  font-family: var(--font-family);
  color: #333;
}

.container {
  max-width: 1200px;
  margin: 0 auto;
}
```

#### JS Templates
- **Purpose**: Site-wide or page-specific JavaScript
- **Features**:
  - Import external libraries
  - Use Liquid filters: `{{ 'script.js' | asset_url }}`
  - Access to Modyo SDK
- **Example**:
```javascript
// Global Scripts
(function() {
  // Initialize analytics
  if (typeof ga !== 'undefined') {
    ga('create', '{{ site.analytics_id }}', 'auto');
    ga('send', 'pageview');
  }

  // Mobile menu toggle
  document.querySelector('.menu-toggle').addEventListener('click', function() {
    document.querySelector('.main-nav').classList.toggle('open');
  });
})();
```

**Template Versioning**:
- Supports up to **20 backup versions**
- Can compare versions side-by-side
- Rollback to previous versions
- Activity history tracking

---

### 5. Snippets & Custom Snippets (Reusable Code)

**Why Snippets Matter**:
Snippets solve the **DRY (Don't Repeat Yourself)** principle at the template level.

**Without Snippets** (Bad):
```liquid
<!-- Page 1 -->
<header>
  <nav>
    <a href="/">Home</a>
    <a href="/about">About</a>
    <a href="/contact">Contact</a>
  </nav>
</header>

<!-- Page 2 -->
<header>
  <nav>
    <a href="/">Home</a>
    <a href="/about">About</a>
    <a href="/contact">Contact</a>
  </nav>
</header>

<!-- Problem: Update navigation = update every page -->
```

**With Snippets** (Good):
```liquid
<!-- snippet: 'site-header' -->
<header>
  <nav>
    <a href="/">Home</a>
    <a href="/about">About</a>
    <a href="/contact">Contact</a>
  </nav>
</header>

<!-- Page 1 -->
{% snippet 'site-header' %}

<!-- Page 2 -->
{% snippet 'site-header' %}

<!-- Update once, reflects everywhere -->
```

**Common Snippet Types**:

| Snippet Name | Purpose | Typical Body |
|--------------|---------|--------------|
| `site-header` | Site navigation | `<header><nav>...</nav></header>` |
| `site-footer` | Footer content | `<footer>&copy; {{ site.name }}</footer>` |
| `head-meta` | SEO meta tags | `<meta name="description" content="...">` |
| `analytics` | Tracking scripts | `<script>ga('...')</script>` |
| `breadcrumbs` | Navigation path | `<nav>{% for item in path %}...</nav>` |
| `social-share` | Share buttons | `<div class="share">...</div>` |

**Custom Snippet Example** (Product Card):
```liquid
<!-- snippet: 'product-card' -->
<div class="product-card">
  <img src="{{ product.image }}" alt="{{ product.name }}">
  <h3>{{ product.name }}</h3>
  <p class="price">${{ product.price }}</p>
  <a href="/products/{{ product.slug }}" class="btn">View Details</a>
</div>

<!-- Usage in page -->
<div class="products-grid">
  {% for product in products %}
    {% snippet 'product-card' with product %}
  {% endfor %}
</div>
```

**Liquid Markup in Snippets**:
Snippets can use Liquid for dynamic content:
```liquid
{% if user.logged_in %}
  <a href="/account">My Account</a>
  <a href="/logout">Logout</a>
{% else %}
  <a href="/login">Login</a>
  <a href="/register">Register</a>
{% endif %}
```

---

### 6. Widgets (Micro Frontends)

**What they are**: Self-contained, reusable UI components that function as **micro frontends**.

**Widget Architecture**:
```
Widget: "Product Showcase"
├── HTML (Structure)
├── CSS (Styles)
├── JavaScript (Behavior)
├── Variables (Configuration)
│   ├── category (text)
│   ├── limit (number)
│   └── show_price (boolean)
└── i18n (Translations)
    ├── en: "Featured Products"
    ├── es: "Productos Destacados"
    └── pt: "Produtos em Destaque"
```

**Widget vs Snippet**:

| Aspect | Widget | Snippet |
|--------|--------|---------|
| **Scope** | Page-level | Site-wide |
| **Structure** | HTML + CSS + JS | HTML/Liquid only |
| **Configuration** | Has variables | No variables |
| **Placement** | Drag-and-drop | Liquid tag |
| **Use Case** | Interactive components | Static reusable code |

**Widget Example** (Hero Banner):

**HTML Tab**:
```html
<section class="hero-banner">
  <div class="hero-content">
    <h1>{{ title }}</h1>
    <p>{{ subtitle }}</p>
    <a href="{{ cta_link }}" class="btn-primary">{{ cta_text }}</a>
  </div>
  <div class="hero-image">
    <img src="{{ image_url }}" alt="{{ title }}">
  </div>
</section>
```

**CSS Tab**:
```css
.hero-banner {
  display: flex;
  align-items: center;
  padding: 80px 20px;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}

.hero-content {
  flex: 1;
  color: white;
}

.hero-content h1 {
  font-size: 48px;
  margin-bottom: 20px;
}

.btn-primary {
  background: white;
  color: #667eea;
  padding: 15px 30px;
  border-radius: 5px;
  text-decoration: none;
}
```

**JavaScript Tab**:
```javascript
(function() {
  // Animate hero on scroll
  const hero = document.querySelector('.hero-banner');

  window.addEventListener('scroll', function() {
    const scrolled = window.pageYOffset;
    hero.style.transform = `translateY(${scrolled * 0.5}px)`;
  });
})();
```

**Variables Configuration**:
```json
{
  "title": {
    "type": "text",
    "default": "Welcome to Our Site",
    "label": "Hero Title"
  },
  "subtitle": {
    "type": "text",
    "default": "Discover amazing products",
    "label": "Hero Subtitle"
  },
  "cta_text": {
    "type": "text",
    "default": "Shop Now",
    "label": "Button Text"
  },
  "cta_link": {
    "type": "text",
    "default": "/products",
    "label": "Button Link"
  },
  "image_url": {
    "type": "asset",
    "default": "",
    "label": "Background Image"
  }
}
```

**Widget Loading Options**:
- **Synchronous**: Loads with page (blocks rendering)
- **Asynchronous**: Loads after page (non-blocking)

**Widget States**:
- **Draft**: Unpublished changes
- **Published**: Live version
- **Pending Changes**: Has unpublished edits

**Accessing Widget Variables in JS**:
```javascript
(function() {
  // Access Liquid variables in JavaScript
  const config = {
    title: '{{ title }}',
    ctaLink: '{{ cta_link }}',
    showPrice: {{ show_price }}  // Boolean
  };

  console.log('Widget config:', config);
})();
```

---

### 7. Navigation / Menus (Site Structure)

**What they are**: Hierarchical navigation structures that define site organization.

**Menu Structure**:
- Supports **three levels of depth**:
  - Level 1: Main menu items
  - Level 2: Sub-items
  - Level 3: Sub-sub-items

**Menu Configuration**:

```yaml
Main Navigation:
  - Home
    Link: /
    Target: _self
    Private: false

  - Products
    Link: /products
    Target: _self
    Private: false
    Children:
      - Electronics
        Link: /products/electronics
        Target: _self
        Children:
          - Laptops
            Link: /products/electronics/laptops
          - Phones
            Link: /products/electronics/phones

      - Clothing
        Link: /products/clothing
        Target: _self

  - About
    Link: /about
    Target: _self
    Private: false

  - Contact
    Link: /contact
    Target: _self
    Private: false

  - My Account
    Link: /account
    Target: _self
    Private: true  # Only visible to logged-in users
```

**Menu Display in Templates**:

Using the `{% menu %}` tag:

**Basic Menu**:
```liquid
{% menu 'main-navigation' %}
```

**Custom Menu Rendering**:
```liquid
<nav class="main-nav">
  <ul>
    {% for item in menu.items %}
      <li class="{% if item.active %}active{% endif %}">
        <a href="{{ item.url }}"
           {% if item.target == '_blank' %}target="_blank"{% endif %}>
          {{ item.label }}
        </a>

        {% if item.children %}
          <ul class="submenu">
            {% for child in item.children %}
              <li>
                <a href="{{ child.url }}">{{ child.label }}</a>

                {% if child.children %}
                  <ul class="submenu-level-2">
                    {% for grandchild in child.children %}
                      <li>
                        <a href="{{ grandchild.url }}">{{ grandchild.label }}</a>
                      </li>
                    {% endfor %}
                  </ul>
                {% endif %}
              </li>
            {% endfor %}
          </ul>
        {% endif %}
      </li>
    {% endfor %}
  </ul>
</nav>
```

**Menu Display Styles**:
- **Dropdown**: Hover reveals sub-items
- **List**: All items expanded
- **Three-Level**: Full hierarchy visible

**Menu Features**:
- **External Links**: Link to external URLs
- **New Tab**: Open links in new window
- **Private Items**: Show only to authenticated users
- **Segment Restrictions**: Show only to specific user segments
- **Active State**: Highlight current page

**Menu Publication Workflow**:
```
Draft → Submit for Review → Approved → Published
```

**Breadcrumbs**:
Automatically generated based on page hierarchy:
```liquid
<nav class="breadcrumbs">
  <a href="/">Home</a>
  {% if page.parent %}
    <a href="{{ page.parent.url }}">{{ page.parent.name }}</a>
  {% endif %}
  <span>{{ page.name }}</span>
</nav>
```

---

### 8. Site Settings (Configuration)

**What they are**: Global configuration options that control site behavior.

**Settings Categories**:

#### General
```yaml
name: "Corporate Website"
logo: /assets/logo.png
description: "Leading provider of..."
language: en
time_zone: America/New_York
```

#### Domain
```yaml
primary_domain: www.example.com
aliases:
  - example.com
  - www.example.org
ssl_enabled: true
force_https: true
```

#### SEO
```yaml
meta_title: "Example Corp - Leading Provider"
meta_description: "We provide innovative solutions..."
meta_keywords: "technology, innovation, solutions"
og_image: /assets/og-image.png
twitter_card: summary_large_image
sitemap_enabled: true
robots_txt: |
  User-agent: *
  Allow: /
  Disallow: /admin/
```

#### Progressive Web App (PWA)
```yaml
pwa_enabled: true
manifest:
  name: "Example App"
  short_name: "Example"
  theme_color: "#667eea"
  background_color: "#ffffff"
  display: standalone
  icons:
    - src: /assets/icon-192.png
      sizes: 192x192
      type: image/png
    - src: /assets/icon-512.png
      sizes: 512x512
      type: image/png
service_worker:
  enabled: true
  cache_strategy: network_first
web_push:
  enabled: true
  vapid_public_key: "..."
```

#### Security Headers
```yaml
content_security_policy: "default-src 'self'; script-src 'self' 'unsafe-inline'"
x_frame_options: SAMEORIGIN
x_content_type_options: nosniff
referrer_policy: strict-origin-when-cross-origin
permissions_policy: "geolocation=(self)"
```

#### Custom Redirects
```yaml
redirects:
  - from: /old-page
    to: /new-page
    type: 301  # Permanent

  - from: /promo
    to: /products/sale
    type: 302  # Temporary
```

#### Search
```yaml
search_enabled: true
search_scope:
  - pages
  - content_entries
search_excluded_paths:
  - /admin
  - /private
```

#### Team & Permissions
```yaml
team_review_enabled: true
approval_workflow:
  - reviewer
  - approver
member_roles:
  - admin
  - editor
  - contributor
```

#### Privacy
```yaml
site_visibility: public  # public | private | disabled
authentication_required: false
segment_restrictions:
  enabled: false
  allowed_segments: []
```

---
