# MultiPortal — Templates Guide

This folder holds all portal templates. Each template is a standalone HTML file
that the portal renderer fetches, fills in with real data, and injects into an
iframe for public display.

---

## Folder Structure

```
templates/
├── t001/
│   └── template.html      ← Modern Business  (free)
├── t002/
│   └── template.html      ← Community Hub    (free)
├── t003/
│   └── template.html      ← Edu Portal       (free)
├── t004/
│   └── template.html      ← Township Connect (paid)
├── t005/                  ← (reserved — Boutique Shop)
└── t006/                  ← (reserved — Restaurant & Café)
```

Place this entire `templates/` folder in the **same directory** as
`multiportal.html` and `admin.html`.

---

## How Templates Work

When a visitor opens `multiportal.html?portal=your-portal-slug`, the renderer:

1. Loads the portal record from the database (localStorage in dev, REST API in prod).
2. Fetches `templates/{templateId}/template.html` via HTTP.
3. Replaces all `{{TAG}}` placeholders with real portal data.
4. Injects the final HTML into an `<iframe srcdoc="...">` for display.

> **Offline / local file:// fallback** — If the fetch fails (e.g. you open
> the file directly without a web server), the renderer automatically uses the
> identical inline copy baked into `multiportal.html`. Both copies must be kept
> in sync if you edit a template.

---

## Available Template Tags

These placeholders are replaced automatically. Use them anywhere in your
`template.html`.

| Tag | Replaced with |
|-----|---------------|
| `{{PORTAL_NAME}}` | Portal display name |
| `{{PORTAL_TAGLINE}}` | Portal description / tagline |
| `{{PRIMARY_COLOR}}` | Hex colour, e.g. `#4f6ef7` |
| `{{SECONDARY_COLOR}}` | Hex colour, e.g. `#00d4a8` |
| `{{FONT_FAMILY}}` | Google Font name, e.g. `Poppins` |
| `{{FONT_FAMILY_URL}}` | Same name with spaces as `+`, e.g. `DM+Sans` |
| `{{PORTAL_LOGO_HTML}}` | `<img>` tag for the portal logo, or empty string |
| `{{NAV_ITEMS_HTML}}` | Rendered `<li>` tags for the navigation menu |
| `{{SECTIONS_HTML}}` | All page sections as `<div class="page-section ...">` blocks |
| `{{CONTACT_EMAIL}}` | Contact email address |
| `{{CONTACT_PHONE}}` | Contact phone number |
| `{{CONTACT_ADDRESS}}` | Physical address |
| `{{SOCIAL_LINKS_HTML}}` | Rendered social media links with emoji icons |
| `{{FOOTER_TEXT}}` | Footer copyright / tagline text |
| `{{CURRENT_YEAR}}` | Current 4-digit year |

### How `{{SECTIONS_HTML}}` works

Each published page in the portal becomes a `<div>` like this:

```html
<!-- Home page (type="home") -->
<div class="page-section t1-hero active" id="page-home">
  ... page content HTML ...
</div>

<!-- Any other page -->
<div class="page-section t1-section" id="page-about">
  ... page content HTML ...
</div>
```

Only the **first** section gets the `active` class on load. The `showPage(slug)`
JavaScript function (which you must include in your template) toggles visibility.

### How `{{NAV_ITEMS_HTML}}` works

Each published page with `in_menu: true` becomes:

```html
<li>
  <a href="#" class="active" data-slug="home"
     onclick="showPage('home');return false;">Home</a>
</li>
```

Wire these into any `<ul>` in your template navbar.

---

## Adding a New Template

### Step 1 — Pick an ID

Templates are numbered sequentially: `t005`, `t006`, `t007`, ...  
The next available free IDs are `t005` and `t006` (reserved in `data/db.json`
for Boutique Shop and Restaurant & Café). Use `t007` onwards for custom ones.

### Step 2 — Create the folder and file

```
templates/
└── t007/
    └── template.html
```

### Step 3 — Write `template.html`

Start from a copy of the closest existing template and customise it.
Key rules:

1. **Every CSS class must use a unique prefix** to avoid clashes between
   templates rendered side-by-side in the admin previewer.  
   Use your template ID as the prefix: `.t7-nav`, `.t7-hero`, `.t7-card`, etc.

2. **Include all required tags** — at minimum:
   `{{PORTAL_NAME}}`, `{{NAV_ITEMS_HTML}}`, `{{SECTIONS_HTML}}`, `{{CURRENT_YEAR}}`.

3. **The `showPage(slug)` function is mandatory.** It must toggle
   `.active` on `.page-section` elements and update your nav link active state.
   Minimal version:

   ```html
   <script>
   function showPage(slug) {
     document.querySelectorAll('.page-section').forEach(s => s.classList.remove('active'));
     var el = document.getElementById('page-' + slug);
     if (el) el.classList.add('active');
     // also update your nav active link here
     window.scrollTo(0, 0);
   }
   </script>
   ```

4. **Home page section uses `.tN-hero`** (or your preferred hero class),
   inner pages use `.tN-section`. The renderer wraps content in:

   ```html
   <!-- home page -->
   <div class="page-section tN-hero active" id="page-home">...</div>

   <!-- other pages -->
   <div class="page-section tN-section" id="page-about">...</div>
   ```

   Make sure both classes are styled in your CSS.

5. **Use Bootstrap 5** via CDN — it's already loaded by all templates:

   ```html
   <link rel="stylesheet"
     href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
   ```

6. **Google Fonts** — use `{{FONT_FAMILY_URL}}` in the font URL and
   `{{FONT_FAMILY}}` in CSS `font-family`:

   ```html
   <link href="https://fonts.googleapis.com/css2?family={{FONT_FAMILY_URL}}:wght@400;600;700&display=swap" rel="stylesheet">
   <style>
   * { font-family: '{{FONT_FAMILY}}', sans-serif; }
   </style>
   ```

### Step 4 — Register the template in `data/db.json`

Add a record to the `templates.seed` array:

```json
{
  "id": "t007",
  "name": "My Custom Template",
  "slug": "my-custom-template",
  "description": "A short description shown in the template gallery.",
  "thumbnail_color": "#e11d48",
  "thumbnail_icon": "🎨",
  "path": "templates/t007/",
  "category": "custom",
  "tags": ["creative", "bold"],
  "is_free": true,
  "price": 0,
  "created_by": null,
  "status": "active",
  "created_at": "2026-01-01T00:00:00Z"
}
```

### Step 5 — Register in `multiportal.html` (for offline fallback)

Open `multiportal.html` and find the `const TEMPLATES = { ... }` block inside
the `<script>` tag. Add a new entry:

```js
// ── TEMPLATE 7: My Custom Template ──────────────────────────
t007: `<!DOCTYPE html>...full template HTML...`,
```

Copy the exact content of your `template.html` file, paste it as a JS template
literal (backtick string), and escape any backtick characters inside it as
`` \` ``. Also escape `</script>` tags as `<\/script>`.

### Step 6 — Register in `admin.html` template gallery

Find the `SEED_TEMPLATES` array in `admin.html` and add your template following
the same structure as the existing entries (id, name, description,
thumbnail_color, thumbnail_icon, tags, is_free, price).

---

## Installing a Bought / Third-Party Template

If you purchased a template (e.g. from a marketplace):

1. Get the template HTML file and rename it to `template.html`.
2. Replace the seller's hardcoded content with `{{TAG}}` placeholders
   (see the tag table above). At minimum you need:
   - Portal name → `{{PORTAL_NAME}}`
   - Nav links → `{{NAV_ITEMS_HTML}}` inside a `<ul>`
   - Page content → `{{SECTIONS_HTML}}`
   - Year in footer → `{{CURRENT_YEAR}}`
3. Add `.page-section { display:none; }` and `.page-section.active { display:block; }`
   to the CSS.
4. Add the `showPage(slug)` function (see Step 3 above).
5. Follow Steps 2–6 to register it.

---

## Template Naming Conventions

| Range | Purpose |
|-------|---------|
| `t001`–`t006` | Built-in system templates (do not modify IDs) |
| `t007`–`t099` | Your custom or purchased templates |
| `t100`+        | Reserved for future system templates |

---

## Tips

- Test your template by creating a portal in the admin, assigning your new
  template ID to it, and previewing via `multiportal.html?portal=your-slug`.
- Keep CSS class prefixes unique — conflicts between templates can cause layout
  bugs in the admin live-preview panel.
- If you use external JS libraries (e.g. Swiper, GSAP), load them from
  `https://cdnjs.cloudflare.com` to keep templates self-contained.
- The renderer strips nothing — anything in your `template.html` is rendered as-is
  inside the iframe, so custom fonts, animations, and third-party widgets all work.
