Шаблоны
Шаблон — HTML-файл, который определяет внешний вид страницы. Один файл в папке _layouts/ — и готово.
Быстрый старт
Шаг 1. Создайте файл _layouts/my-page.html:
<!DOCTYPE html>
<html>
<head>
<title>{{ note.Title() }}</title>
</head>
<body>
<h1>{{ note.Title() }}</h1>
{{ note.HTMLString() | unsafe }}
</body>
</html>
Шаг 2. Укажите шаблон в заметке:
---
layout: my-page
title: Моя страница
---
Текст страницы в markdown.
Готово. Страница использует ваш шаблон.
Что доступно в шаблоне
note — текущая заметка
{{ note.Title() }} — заголовок из frontmatter
{{ note.HTMLString() }} — весь контент как HTML
{{ note.Permalink() }} — URL страницы
{{ note.ReadingTime() }} — время чтения в минутах
{{ note.PathID() }} — уникальный ID для data-атрибутов
note.M() — доступ к frontmatter
{{ note.M().GetString("author", "Unknown") }}
{{ note.M().GetInt("version", 1) }}
{{ note.M().GetBool("featured", false) }}
{{ note.M().Has("custom_field") }}
nvs — доступ к другим заметкам
{{ sidebar := nvs.ByPath("/_sidebar.md") }}
{{ if sidebar }}
{{ sidebar.HTMLString() | unsafe }}
{{ end }}
{{ about := nvs.ByPermalink("/about") }}
asset() — подключение файлов
<link rel="stylesheet" href="{{ asset("style.css") }}">
<script src="{{ asset("app.js") }}"></script>
PartialRenderer — контент по частям
PartialRenderer разбирает markdown на логические блоки. Полезно для лендингов, FAQ, карточек.
Introduce() — вступление
Возвращает контент до первого заголовка:
{{ intro := note.PartialRenderer().Introduce() }}
<div class="intro">
{{ intro.ContentHTML | unsafe }}
</div>
Sections(level) — секции по уровню заголовков
Собирает секции под заголовками нужного уровня. Каждая секция содержит:
TitleHTML— текст заголовка (без тега<h3>)ContentHTML— контент до следующего заголовка того же или выше уровня
Пример: FAQ из markdown
Часто задаваемые вопросы о сервисе.
### Как начать работу?
Зарегистрируйтесь и создайте первый проект.
### Сколько стоит?
Базовый тариф бесплатный.
### Есть ли API?
Да, документация на сайте.
Шаблон:
{{ intro := note.PartialRenderer().Introduce() }}
<p class="lead">{{ intro.ContentHTML | unsafe }}</p>
<div class="faq">
{{ range s := note.PartialRenderer().Sections(3) }}
<details>
<summary>{{ s.TitleHTML | unsafe }}</summary>
<div>{{ s.ContentHTML | unsafe }}</div>
</details>
{{ end }}
</div>
Section(title) — секция по заголовку
Находит конкретную секцию по тексту заголовка:
{{ faq := note.PartialRenderer().Section("FAQ") }}
{{ if faq }}
<div class="faq-section">
{{ faq.ContentHTML | unsafe }}
</div>
{{ end }}
Пример: карточки фич
<div class="features-grid">
{{ range s := note.PartialRenderer().Sections(3) }}
<div class="feature-card">
<h3>{{ s.TitleHTML | unsafe }}</h3>
{{ s.ContentHTML | unsafe }}
</div>
{{ end }}
</div>
Фильтр unsafe
HTML экранируется по умолчанию. Чтобы вывести разметку — добавьте | unsafe:
{{ note.HTMLString() | unsafe }}
{{ b.ContentHTML | unsafe }}
Без фильтра теги отобразятся как текст: <p>...
Вложенные asset-зависимости
Если шаблон импортирует другой файл с asset(), движок может не увидеть зависимость. Обходное решение — добавить комментарий:
{{ import "blocks" }}
<!-- {{ asset("style.css") }} -->
{{ yield main_layout() content }}
...
{{ end }}
Комментарий не попадает в HTML, но зависимость подхватится.
Синтаксис Jet
Шаблоны используют движок Jet:
{{ переменная }} — вывод
{{ if условие }}...{{ end }} — условие
{{ range item := список }}...{{ end }} — цикл
{{ block имя() }}...{{ end }} — определение блока
{{ yield имя() }} — вызов блока
{{ include "путь" данные }} — вставка шаблона
Подробнее — в документации Jet.
Выборка и сортировка заметок — в запросах к заметкам.
Продвинутые паттерны организации шаблонов — в лучших практиках.