# Создание шаблонов Celena CMS

Шаблон в Celena — это набор `.tpl`-файлов в каталоге `templates/<slug>/`. **PHP в `.tpl` запрещён**: используются только теги шаблонизатора. Это безопасно, удобно для вёрстки и легко документируется для ИИ-агентов.

---

## Быстрый старт

```
templates/
└── mytheme/
    ├── theme.json          # манифест темы
    ├── home.tpl            # главная страница
    ├── news_list.tpl       # список новостей
    ├── news_full.tpl       # полная новость
    ├── page.tpl            # обычная страница
    ├── search.tpl          # страница поиска
    ├── 404.tpl
    ├── _partials/          # переиспользуемые куски
    │   ├── head.tpl
    │   └── foot.tpl
    ├── async/              # шаблоны для тегов {async}
    │   └── latest_news.tpl
    └── assets/             # CSS/JS темы
        └── theme.css
```

`theme.json`:
```json
{
  "name": "My Theme",
  "slug": "mytheme",
  "version": "1.0.0",
  "author": "Имя автора",
  "description": "Краткое описание",
  "regions": ["header", "main", "sidebar", "footer"]
}
```

Активировать в админке: **Настройки → Шаблоны** → выбрать `mytheme`.

---

## Синтаксис

### 1. Переменные

```html
{title}                <!-- $vars['title'] -->
{user.name}            <!-- $vars['user']['name'] -->
{site.url}
```

Значения **автоматически экранируются**. Чтобы вывести «как есть» (доверенный HTML):

```html
{news.body|raw}
```

### 2. Inline-теги (с параметрами)

Если у тега есть параметры — это вызов обработчика:

```html
{include file="_partials/head.tpl"}
{lang key="hello.world"}
{csrf}                          <!-- скрытое поле -->
{csrf format="meta"}            <!-- <meta name="csrf-token"> -->
{csrf format="token"}           <!-- только сам токен -->
{async block="latest_news" url="/api/blocks/latest_news" placeholder="Загрузка…"}
```

В параметрах разрешена интерполяция `{var}`:

```html
{lang key="greeting" name="{user.name}"}
```

### 3. Условия

```html
[if {user.role}="admin"]
  Привет, начальник.
[else if {user.role}="editor"]
  Привет, редактор.
[else]
  Гость.
[/if]

[if {comments_count}>"0"]
  Комментариев: {comments_count}
[/if]

[if {is_published}]            <!-- truthy-проверка -->
  Опубликовано
[/if]
```

Поддерживаются операторы: `=`, `!=`, `>`, `<`, `>=`, `<=`. Сравнения с `>`, `<` — числовые, остальные — строковые.

### 4. Циклы

```html
[foreach var="news" as="n"]
  <article>
    <h2><a href="{n.url}">{n.title}</a></h2>
    <p>{n.short}</p>
    <small>{n.date} · {n.author}</small>
  </article>
[/foreach]
```

Внутри цикла доступны служебные переменные:

- `{_index}` — 0-based номер итерации
- `{_total}` — всего элементов
- `{_first}`, `{_last}` — `"1"` если первый/последний, иначе `""`

Если массив пустой — тело не рендерится. Для пустого состояния передайте отдельный флаг из контроллера/блока:

```html
[if {news_empty}="1"]
  <p class="muted">Пока нет новостей.</p>
[/if]
```

### 4a. Сравнение двух переменных

Кроме сравнения переменной со строковым литералом работает и сравнение двух переменных:

```html
[if {product.category_id}={current.id}]
  ...
[/if]
```

Используется в select'ах админки: `<option [if {row.status}={value}]selected[/if]>`.

### 5. Async-блоки (как в React/Facebook)

Любой блок может загружаться отдельным запросом после рендера страницы. Это делает страницу мгновенно отзывчивой, а тяжёлые секции догружаются позже.

```html
{async block="recent_comments" url="/api/blocks/recent_comments" placeholder="<em>Загружаем…</em>"}
```

Параметры:

| Параметр | Назначение | По умолчанию |
|---|---|---|
| `block` | Имя зарегистрированного блока (см. PLUGIN_SDK.md) | — |
| `url` | URL ручки. Если не задан — `/api/blocks/{block}` | автоген |
| `placeholder` | HTML, показываемый до загрузки | пусто |
| `trigger` | `load` (сразу), `visible` (когда в зоне видимости), `manual` | `load` |
| `poll` | Интервал авто-обновления: `30s`, `5m`, `500ms` | нет |
| `class` | CSS-класс контейнера | `celena-async` |

После загрузки контейнер получает класс `is-loaded` и кидает событие `celena:loaded`. Клиентский JS можно вызывать через `Celena.refresh('#my-block')`.

### 6. Специальные теги

```html
{plugin_assets}                 <!-- подключает CSS всех активных плагинов -->
{csrf}                          <!-- <input type="hidden" name="_csrf" value="..."> -->
{csrf format="meta"}            <!-- <meta name="csrf-token" content="..."> для AJAX -->
{async block="widget_name"}     <!-- async-подгрузка блока (см. ниже) -->
```

### 7. Комментарии

```html
{* Этот текст в выводе не появится *}
```

### 8. Запреты

- `<?php`, `<?=` — экранируются как текст. Нельзя писать PHP в шаблонах.
- Прямая работа с БД, сессиями, файлами — только через зарегистрированные теги или async-блоки.
- Не использовать сторонние CDN — все ассеты темы кладите в `templates/<slug>/assets/`.

---

## Кеширование

При первом обращении `.tpl` компилируется в PHP-файл в `storage/cache/tpl/{hash}.php`. Последующие рендеры мгновенные. Инвалидация:

- автоматически при изменении исходного файла (по mtime),
- автоматически при сохранении шаблона из визуального редактора,
- вручную: `php bin/celena cache:clear` или **Настройки → Производительность → Очистить кеш**,
- временно отключить: `Настройки → Производительность → Не кешировать шаблоны` (для разработки).

---

## Темы и тёмный режим

Все темы наследуют CSS-переменные ядра (`--bg`, `--surface`, `--text`, `--accent` и т.д.). Тёмный режим переключается атрибутом `data-theme="dark"` на `<html>`. Авто-режим (по локальному времени браузера 18:00–07:00) включён по умолчанию.

Кнопки переключения:

```html
<button data-celena-theme="light">☀</button>
<button data-celena-theme="dark">☾</button>
<button data-celena-theme="auto">A</button>
```

---

## Стандартные шаблоны темы

Минимальный комплект, который должна предоставлять тема:

| Файл | Когда вызывается |
|---|---|
| `home.tpl` | главная страница |
| `page.tpl` | статическая страница |
| `news_list.tpl` | список новостей категории/поиска |
| `news_full.tpl` | страница одной новости |
| `search.tpl` | результаты поиска |
| `404.tpl` | страница «не найдено» |

Переменные, которые ядро всегда передаёт в каждый шаблон:

```
{site.name}      название сайта
{site.url}       базовый URL
{user.name}      имя текущего пользователя ("" если не залогинен)
{user.role}
{page.title}     заголовок страницы
```

В шаблонах списков (`news_list`, `search`):
```
{news}            массив новостей для [foreach var="news" as="n"]
{pagination}      объект пагинации: {pagination.current}, {pagination.total}, {pagination.next}, {pagination.prev}
```

В шаблоне `news_full`:
```
{news.title}, {news.body}, {news.date}, {news.author},
{news.category.name}, {news.fields.<custom_field_slug>}
```

---

## Чек-лист «своя тема за час»

1. Скопировать `templates/default/` → `templates/mytheme/`.
2. Поправить `theme.json`.
3. Заменить стили в `assets/theme.css`.
4. Изменить `_partials/head.tpl` и `_partials/foot.tpl` под свою вёрстку.
5. При необходимости переопределить `home.tpl`, `news_list.tpl`, `news_full.tpl`, `page.tpl`.
6. Активировать тему в **Настройки → Шаблоны**.
7. Проверить адаптивность и тёмную тему.
