Шаблоны: API

Техническая документация для разработчиков шаблонов. Описывает API internal/templateviews — обёртки моделей для Jet-шаблонов.

Архитектура

Jet-шаблон
    ↓
templateviews (Note, NVS, Meta, NoteQuery)
    ↓
model.NoteView, model.NoteViews
    ↓
База данных

templateviews изолирует шаблоны от внутренних изменений модели. Шаблоны работают со стабильным API.


Note

Обёртка над model.NoteView. Представляет одну заметку в шаблоне.

Методы

Метод Возвращает Описание
Title() string Заголовок из frontmatter
HTMLString() string Отрендеренный HTML контент
ContentString() string Сырой markdown
PathID() int64 ID для data-атрибутов
Permalink() string URL страницы
CreatedAt() time.Time Дата создания
ReadingTime() int Время чтения в минутах
ReadingComplexity() int Сложность (0-2)
IsHomePage() bool Является ли домашней страницей подграфа
Description() string SEO-описание
PartialRenderer() NoteViewPartialRenderer Рендерер для разбивки контента
TOC() NoteViewHeadings Оглавление
M() *Meta Доступ к frontmatter

Пример

<article>
  <h1>{{ note.Title() }}</h1>
  <time>{{ note.CreatedAt().Format("02.01.2006") }}</time>
  <span>{{ note.ReadingTime() }} мин</span>

  {{ note.HTMLString() | unsafe }}
</article>

NVS (NoteViewService)

Сервис доступа к заметкам. Доступен в шаблоне как nvs.

Методы доступа

Метод Описание
ByPath(path) Заметка по пути файла ("/_sidebar.md", "docs/intro.md")
ByPermalink(url) Заметка по URL ("/docs", "/about")
List() Все видимые заметки (без системных /_*)

Методы для навигации

Метод Описание
Sidebars(note) Сайдбары для заметки
HomePages(note) Домашние страницы подграфов
BackLinks(note) Обратные ссылки (кто ссылается на эту заметку)
ResolveURL(note) Полный URL с версией

Методы запросов

Метод Описание
ByGlob(pattern) Query builder с glob-фильтром
Query() Query builder без фильтра

Примеры

{* Загрузить заметку по пути *}
{{ sidebar := nvs.ByPath("/docs/_sidebar.md") }}
{{ if sidebar }}
  {{ sidebar.HTMLString() | unsafe }}
{{ end }}

{* Загрузить по URL *}
{{ about := nvs.ByPermalink("/about") }}

{* Обратные ссылки *}
{{ range i, link := nvs.BackLinks(note) }}
  <a href="{{ link.Permalink() }}">{{ link.Title() }}</a>
{{ end }}

NoteQuery

Ленивый query builder. Операции накапливаются и выполняются при вызове терминального метода.

Фильтрация

nvs.ByGlob("blog/*.md")           {* Все .md в папке blog *}
nvs.ByGlob("docs/**/*.md")        {* Рекурсивно все .md в docs *}
nvs.ByGlob("projects/**/README.md") {* Все README.md *}
nvs.Query()                        {* Все заметки без фильтра *}

Поддерживаемые glob-паттерны:

  • * — любые символы кроме /
  • ** — любая вложенность
  • ? — один символ

Сортировка

.SortBy("Title")       {* По заголовку *}
.SortBy("CreatedAt")   {* По дате создания *}
.SortBy("Permalink")   {* По URL *}
.SortBy("created_at")  {* snake_case тоже работает *}

.SortByMeta("order")   {* По полю frontmatter *}
.SortByMeta("weight")

Направление

.Desc()   {* Последний критерий — по убыванию *}
.Asc()    {* Последний критерий — по возрастанию (по умолчанию) *}

Множественная сортировка

{* Сначала по категории, внутри — по заголовку *}
nvs.ByGlob("blog/*.md").SortByMeta("category").SortBy("Title")

Пагинация

.Limit(10)              {* Первые 10 *}
.Offset(5)              {* Пропустить 5 *}
.Offset(10).Limit(10)   {* Вторая страница *}

Терминальные методы

Метод Возвращает Описание
All() []*Note Все результаты
First() *Note Первый результат или nil
Last() *Note Последний результат или nil

Полный пример

{* Последние 5 постов блога *}
{{ range i, post := nvs.ByGlob("blog/*.md").SortBy("CreatedAt").Desc().Limit(5).All() }}
  <article>
    <h2><a href="{{ post.Permalink() }}">{{ post.Title() }}</a></h2>
    <time>{{ post.CreatedAt().Format("02.01.2006") }}</time>
  </article>
{{ end }}

{* Документация с ручным порядком *}
{{ range i, doc := nvs.ByGlob("docs/*.md").SortByMeta("order").All() }}
  <a href="{{ doc.Permalink() }}">{{ doc.Title() }}</a>
{{ end }}

{* Последний пост *}
{{ latest := nvs.ByGlob("blog/*.md").SortBy("CreatedAt").Desc().First() }}
{{ if latest }}
  <a href="{{ latest.Permalink() }}">{{ latest.Title() }}</a>
{{ end }}

Meta

Типобезопасный доступ к frontmatter.

Методы

Метод Описание
Has(key) Проверка наличия ключа
Get(key) Сырое значение (interface{})
GetString(key, default) Строка или default
GetInt(key, default) Число или default
GetBool(key, default) Булево или default
GetStringSlice(key) Массив строк или nil

Приведение типов

GetBool понимает:

  • true, false (bool)
  • "true", "yes", "1" (string → true)
  • 1, 0 (int → bool)

GetInt понимает:

  • int, int64, float64

Примеры

{* Проверка наличия *}
{{ if note.M().Has("featured") }}
  <span class="badge">Featured</span>
{{ end }}

{* Получение значений *}
{{ author := note.M().GetString("author", "Anonymous") }}
{{ order := note.M().GetInt("order", 999) }}
{{ published := note.M().GetBool("published", false) }}

{* Теги *}
{{ range i, tag := note.M().GetStringSlice("tags") }}
  <span class="tag">{{ tag }}</span>
{{ end }}

PartialRenderer

Разбивает markdown на блоки. Доступен через note.PartialRenderer().

Методы

Метод Описание
Introduce() Контент до первого заголовка
Sections(level) Секции под заголовками уровня level
Section(title) Секция по тексту заголовка

Структура секции

type Section struct {
    TitleHTML   string  // Текст заголовка (без тега)
    ContentHTML string  // Контент до следующего заголовка
}

Примеры

{* Вступление *}
{{ intro := note.PartialRenderer().Introduce() }}
<div class="lead">{{ intro.ContentHTML | unsafe }}</div>

{* FAQ из H3 *}
{{ range i, q := note.PartialRenderer().Sections(3) }}
  <details>
    <summary>{{ q.TitleHTML | unsafe }}</summary>
    <div>{{ q.ContentHTML | unsafe }}</div>
  </details>
{{ end }}

{* Конкретная секция *}
{{ faq := note.PartialRenderer().Section("FAQ") }}
{{ if faq }}
  {{ faq.ContentHTML | unsafe }}
{{ end }}

Jet-синтаксис

Краткая справка. Подробнее — в Синтаксис Jet.

Переменные

{{ x := "value" }}              {* Объявление *}
{{ x = "new value" }}           {* Присваивание *}
{{ x }}                         {* Вывод *}

Условия

{{ if condition }}
  ...
{{ else if other }}
  ...
{{ else }}
  ...
{{ end }}

Циклы

{* range возвращает индекс и значение *}
{{ range i, item := list }}
  {{ i }}: {{ item }}
{{ end }}

{* Только значение — НЕПРАВИЛЬНО, item будет индексом! *}
{{ range item := list }}  {* item = 0, 1, 2... *}

Блоки и наследование

{* blocks.html *}
{{ block header() }}
  <header>Default header</header>
{{ end }}

{* page.html *}
{{ import "blocks" }}

{{ yield header() }}  {* Вызов блока *}

Переопределение блоков

{* page.html *}
{{ import "blocks" }}

{{ block header() }}
  <header>Custom header</header>
{{ end }}

{{ yield main_layout() content }}
  ...
{{ end }}

Фильтры

{{ value | unsafe }}          {* Вывод HTML без экранирования *}
{{ value | html }}            {* Экранирование (по умолчанию) *}