N1 Nex1on

Виды на тегах: как переделать страницу без PHP

Любой вид сайта (главную, вход, регистрацию, поиск, кабинет, страницу) можно заменить файлом тегов. Это обычная HTML-разметка, в которую вставляются теги {имя}, условия … и повторы [each:список]…[/each] (общий язык тегов, тот же…

Любой вид сайта (главную, вход, регистрацию, поиск, кабинет, страницу) можно заменить файлом тегов. Это обычная HTML-разметка, в которую вставляются теги {имя}, условия [if:имя]…[/if] и повторы [each:список]…[/each] (общий язык тегов, тот же, что в «Новости → Шаблоны записей»).

Как включить

В вашей теме положите файл по пути вида с окончанием .tpl.html вместо .php:

Что заменяетеФайл в теме
главная разметка (шапка, места, содержимое, подвал)themes/<имя>/views/layouts/main.tpl.html
страница сайтаthemes/<имя>/views/pages/show.tpl.html
входthemes/<имя>/views/auth/login.tpl.html
регистрация, восстановление пароля, сброс, второй фактор, подтверждение почты, правилаauth/register.tpl.html, auth/forgot.tpl.html, auth/reset.tpl.html, auth/two-factor.tpl.html, auth/verify.tpl.html, auth/rules.tpl.html
поискsearch.tpl.html
кабинет, безопасность, сеансы, приватностьauth/profile.tpl.html, auth/profile-security.tpl.html, auth/profile-sessions.tpl.html, auth/profile-privacy.tpl.html
публичный профильauth/public-profile.tpl.html

Нет файла тегов или он сломан (например, не закрыт блок) — работает обычный PHP-вид, страница не ломается. Файл тегов в общей папке темы главнее вида модуля, как и PHP-файл.

Главная разметка: пример в 15 строк

<header class="my-head">
  <a href="{home}">{site_name}</a>
  [each:menu]<a href="{item.url}">{item.title}</a> [/each]
  {languages} {search}
  [if:user.logged]<a href="{user.url}">{user.name}</a>[else]<a href="{user.login_url}">Войти</a>[/if]
</header>
<main>{content}</main>
<aside>{region:sidebar}</aside>
<footer>© {year} {site_name}</footer>

Положите это в themes/<имя>/views/layouts/main.tpl.html — и страница получит вашу шапку с меню, выбором языка, поиском и входом, содержимое, боковую колонку и подвал. <head>, скрипты движка и кнопка «наверх» остаются от движка; стили и шрифты подключаются через theme.json и assets — в файле тегов их писать не нужно.

Общие теги любой страницы

ТегЧто выводит
{site_name}название сайта
{locale}язык страницы
{year}текущий год
{home}адрес главной
{canonical}основной адрес этой страницы
{theme}путь к папке темы
{user.logged}условие: посетитель вошёл ([if:user.logged]…[/if])
{user.name}, {user.url}имя вошедшего и адрес его профиля
{user.login_url}адрес страницы входа
{user.avatar}адрес аватара; пусто, если аватара нет (для вёрстки [if:user.avatar]…[/if])
{user.role}название роли вошедшего
{user.pm_unread}число непрочитанных личных сообщений; пусто, если модуль «Сообщения» выключен
{user.favorites_count}число закладок
{user.pm_url}, {user.favorites_url}адреса личных сообщений и закладок
{user.admin_url}, [if:user.can_admin]…[/if]адрес панели и условие «в панель пускают» (пусто, если нет)
{user.register_url}, {user.forgot_url}адреса регистрации и восстановления пароля
{logout_button}готовая кнопка «Выйти» с ключом защиты (выход у нас — форма, ссылкой нельзя из-за ключа)
{menu_toggle}кнопка «Меню» и меню разделов (то, что на телефоне открывается кнопкой)
{user_menu}меню участника: профиль, сообщения, панель, выход
{login}готовый блок входа и регистрации
{content}содержимое страницы в контейнере движка (не вылезает за ширину экрана); для кабинета, форума и форм берите его
{content_raw}содержимое без обёртки и без ограничения ширины, только для своих полностраничных раскладок
{languages}выбор языка
{search}строка поиска
{poll}текущий опрос
{region:header}, {region:before_content}, {region:sidebar}, {region:after_content}, {region:footer}, {region:head_actions}блоки модулей, поставленные в это место темы
[each:menu]…[/each]пункты меню сайта; внутри {item.title}, {item.url}, {item.active}

Теги из данных вида, условия, повторы

Дальше идут данные, которые вид получил от движка: {имя}, {a.b}, [each:список] с {item}, {item.ключ}, {index}, условия [if:имя], [if:имя=значение], [ifnot:имя], опция limit=N. Секретное (ключи защиты форм, пароли, токены, сеансы) и объекты через теги не отдаются.

Виды ядра на тегах

ВидЧто доступно (кроме общих тегов)
auth/login{form} — готовая форма входа; слова {t.eyebrow}, {t.title}, {t.lead}, {t.forgot}, {t.no_account}, {t.submit} и другие; {forgot_url}, {register_url}; условие [if:can_register]
auth/register{form}, слова {t.…} (приставка auth.register), {forgot_url}
auth/forgot, auth/reset, auth/two-factor, auth/verify, auth/rulesу каждого {form} и слова {t.…} (приставки auth.forgot, auth.reset, auth.2fa, auth.verify, auth.rules)
search{form} (строка поиска), {query}, [each:results] ({item.title}, {item.url}, {item.excerpt}…), [each:popular], {found.*}, [if:tooShort], {minimum}, слова {t.…} (search.*)
auth/profile, auth/profile-security, auth/profile-sessions, auth/profile-privacy{form} (и {form:2}, {form:3} — остальные формы вида по порядку), {identity} (шапка кабинета), {profile_nav} (меню кабинета), слова {t.…} (profile.*)
auth/public-profile{identity} и данные профиля
pages/show{title}, {page.title}, {page.excerpt}, {page.body} (текст страницы, разметка движка), {cover}, [each:trail], [each:children], [each:siblings]

Форма по частям

В видах с формой (вход, регистрация, восстановление, сброс пароля, второй фактор, подтверждение почты, правила, поиск, кабинет) форму можно вывести целиком тегом {form} — это безопасный путь, или собрать по частям, чтобы расставить поля в нужном порядке:

ТегЧто выводит
{form_open}открытие формы с её адресом и скрытыми полями; ключ защиты — там
{field:имя}поле целиком: подпись, подсказка, ошибка, как построил движок; имя — это name у поля ввода
{field:captcha}проверка «не робот»
{submit}кнопка отправки
{form_close}закрытие формы
{form_open}
  {field:email}
  {field:password}
  {field:captcha}
  {submit}
{form_close}

Поле, которого нет в вашем шаблоне, в форме не появится: расстановка — выбор темы. Обязательные поля и проверку «не робот» не опускайте — без них форма не пройдёт проверку.

Слово {t.хвост} даёт подпись интерфейса «<приставка вида>.<хвост>» на языке посетителя, поэтому тексты в шаблоне на разные языки не дублируются.

Обсуждение (комментарии) на тегах

Файл views/comments/thread.tpl.html темы заменяет вид обсуждения под записью, страницей и другими материалами. Нет файла или он не прошёл проверку — работает обычный вид.

ТегЧто выводит
[each:comments] … [/each]комментарии плоским списком в порядке показа: ответ идёт сразу за своим комментарием, глубину даёт {item.level} (0 — корень)
{item.id} {item.name} {item.avatar} {item.profile} {item.date}номер (для якоря), имя автора, адрес аватара, адрес профиля (пусто, если закрыт), дата
{item.text}текст участника: разметка движка, очищенная (скриптов и чужих тегов нет); у спрятанного человеком из «Кого я не вижу» пуст
{item.likes} {item.minus} {item.rating} {item.verified} {item.op}«Полезно» (число) или оценка «+ / −» (число «за» минус «против»; {item.minus} — оценка отрицательная), звёзды отзыва, «проверенный покупатель», «автор записи»
{item.place} {item.group} {item.online} {item.signature}поля карточки автора, если их включил владелец (место, группа, «на сайте», подпись)
{item.image1} {item.image2} {item.image3}картинки комментария (миниатюры)
{item.actions}готовые кнопки движка: «Полезно», «Ответить», «Цитата», «Изменить», «Удалить», «Не видеть», «Пожаловаться» — правила показа те же, что в обычном виде
{compose}форма комментария целиком (поля, ловушка для роботов, ключ защиты) и скрипт ответа
{form_open} {field:body} {field:author_name} {field:author_email} {submit} {form_close}та же форма по частям — вёрстка ваша, ключ защиты и скрытые поля остаются у движка
{follow}кнопка «Следить за комментариями» (вошедший с подтверждённой почтой — сразу, гость называет почту и подтверждает письмом); пусто, если подписку выключил владелец
{comments_script}скрипт «Ответить»/«Цитата»/звёзды отдельно (внутри {compose} и {form_close} он уже есть)
{pager} {report} {notice}постраничная навигация, «Пожаловаться на запись», сообщение вместо формы (обсуждение закрыто, предел, нужен вход)
{comments.total} [if:closed] [if:can_write]число комментариев; обсуждение закрыто; писать можно

Пример:

<section id="comments"><h2>{comments.word}: {comments.total}</h2>
[each:comments]
<article id="comment-{item.id}" class="c c-l{item.level}"><b>{item.name}</b> <time>{item.date}</time>
<div>{item.text}</div><footer>{item.actions}</footer></article>
[/each]
{pager}
[if:can_write]{compose}[else]{notice}[/if]
</section>

Списки с отбором, архив, метки, рубрики и числа сайта (модуль «Новости»)

Эти теги работают в любом файле тегов: в главной рамке, на странице, в ленте. Отбор записан в самом имени списка парами «ключ:значение» через двоеточие; несколько значений — через «_». Ключи защиты, почта и закрытое в списки не попадают; записи отбираются тем же запросом, что и лента (права, пароль, язык, срок действия).

СписокЧто даётОтбор в имени
[each:news_list category=films,3 limit=5 sort=views] … [/each] (или привычно [each:news_list:cat:3_5:limit:5:sort:views])записи
[each:comments_list limit=5 category=3] (или [each:comments_list:limit:5:cat:3])последние комментарии к записям (у вошедшего в {item.name} его имя)limit, category, not_category, author (номера или логины), days, post (номера записей)
[each:news_archive:limit:12]месяцы архиваlimit
[each:news_tags:limit:30]облако метокlimit
[each:news_categories]рубрики деревом (родитель, затем вложенные)category (какие рубрики; номер, адрес, список), not_category (кроме), subcat — yes с вложенными, no только названные, only только вложенные, depth — сколько уровней, limit

В элементе news_list: {item.id} {item.title} {item.url} {item.excerpt} {item.date} {item.cover} {item.cover_large} {item.category} {item.category_url} {item.by} (автор, если сайт показывает авторов) {item.views} {item.rating} {item.rating_count} {item.comments} {item.pinned} {item.locked} (запись под паролем: видно только название) {item.first} {index}. В comments_list: {item.name} {item.text} (до 160 знаков, без разметки) {item.url} {item.date} {item.title} (название записи) {item.avatar}. В news_archive: {item.title} {item.url} {item.count}. В news_tags: {item.title} {item.url} {item.count} {item.weight} (1–5, для размера шрифта). В news_categories: {item.title} {item.url} {item.count} {item.active} (текущая рубрика) {item.level} (0 — верхний уровень) {item.parent} {item.id} [if:item.has_children].

Числа сайта: {stat.news} {stat.news_day} {stat.news_week} {stat.news_month}, то же для comments и users ({stat.comments_week}, {stat.users_month}).

Пример «Рубрики с числом записей» и «Популярное за месяц»:

<nav><ul>
[each:news_categories]<li class="l{item.level}"><a href="{item.url}">{item.title}</a> <small>{item.count}</small></li>[/each]
</ul></nav>
<h3>Популярное</h3>
[each:news_list:days:30:sort:views:limit:5]<p><a href="{item.url}">{item.title}</a> · {item.views}</p>[/each]
<p>Записей: {stat.news}, за неделю: {stat.news_week}</p>

«Загрузки» на тегах

Шаблон под рубрику. Новости, «Загрузки», форум (раздел) и магазин (категория) называют рубрику страницы движку (адрес рубрики латиницей, цифрами и дефисом, до 40 знаков). Тогда файл <вид>.<адрес-рубрики>.tpl.html (например, views/news/show.tech.tpl.html или views/forum/section.api.tpl.html) берётся раньше общего <вид>.tpl.html; для остальных рубрик остаётся общий. Описание рубрики страницы (без разметки) модуль тоже отдаёт в общие данные страницы; тег {category.description} подключает ядро. Обрезка текста в тегах записи: limit=N знаков, words=N слов, wordsafe=1 — по границе слова.

Файлы views/downloads/index.tpl.html (каталог и рубрика) и views/downloads/show.tpl.html (страница релиза) темы заменяют PHP-виды модуля. Скачивание идёт обычными адресами движка: счётчик, ограничение доступа и пароли работают как раньше.

ВидТегЧто выводит
каталог[each:cards]релизы: {item.title} {item.url} {item.description} {item.version} {item.date} {item.cover} {item.category} {item.category_url} {item.hits} {item.first}
каталог[each:rubrics]рубрики: {item.title} {item.url} {item.count} {item.active}
каталог{category.title} {category.url} {category_description} {pager} {t.empty}рубрика страницы (от рамки), её описание, листание, слово «пусто»
релиз{item.title} {item.description} {item.version} {item.hits} {item.changelog} {item.requirements} {date} {cover} {cover_large}сам релиз
релиз{category.title} {category.url} {files.count} [if:allow_download]рубрика, число файлов, «есть что скачать»
релиз[each:files]файлы: {item.name} {item.url} (адрес скачивания) {item.platform} {item.arch} {item.size} {item.ext} {item.hits} {item.primary} {item.external} (хост внешней ссылки)
релиз[each:sums]контрольные суммы: {item.name} {item.checksum} — чтобы проверить скачанное

Пример страницы релиза:

<h1>{item.title}</h1><p>v{item.version} · {date} · скачано {item.hits}</p>
[if:allow_download]
[each:files]<p><a href="{item.url}">{item.name}</a> {item.platform} {item.arch} {item.size} ↓{item.hits}</p>[/each]
[/if]
<h2>Что нового</h2><p>{item.changelog}</p>
<h2>Требования</h2><p>{item.requirements}</p>
[each:sums]<code>{item.name}: {item.checksum}</code>[/each]

Баннеры на тегах

В любом файле тегов баннер ставится по номеру или целым местом. Правила показа те же, что у обычных баннеров: срок, расписание, устройство, страницы, роли, страны, «только первая страница».

ТегЧто выводит
{banner:5}баннер с номером 5 (номер — в списке баннеров панели)
{banner_place:sidebar}все баннеры места целиком; места: topbar, header, before_content, sidebar, after_content, footer, between_feed (между записями ленты), between_comments (между комментариями)

Места between_feed и between_comments рисуют сами виды новостей и комментариев: баннер идёт после каждой третьей записи ленты и после каждого пятого комментария. У баннера в панели отмечаются роли (guest — гость), страны (RU, UA — только в них; -BY — везде, кроме) и «только на первой странице раздела». Страница, где есть такой баннер, не уходит в общий кэш: ответ зависит от зрителя.

Каталог вставок: любой элемент модуля — одним тегом

Каждый модуль объявляет всё, что можно вынести на любую страницу и вставить в любое место файла тегов темы: готовые блоки, списки для своей вёрстки, числа, формы и кнопки. Это единый каталог: из него строятся вкладка «Вывод на сайте» в панели модуля (таблица элементов, параметры, пример и кнопка «Копировать», файлы видов), подсказки редактора шаблонов и эта таблица.

Как вставляется:

  • блок, форма, кнопка, число — {block:модуль.имя параметр=значение}: {block:news.count what=news period=week}; параметров до четырёх;
  • список для своей вёрстки — [each:list:модуль_имя:параметр:значение:…] … {item.поле} … [/each]: [each:list:news_latest:cat:3:sort:views:limit:5]; несколько значений — через «_», в имени списка «модуль_имя» (точка в имени тега не годится).

Правило для модуля: элемент вида block, button и form сам отвечает за экранирование своего вывода (через e() и виды движка, как любой вид); число и текст (value) — только экранированный текст без разметки; список отдаёт строки, они экранируются тегами. Каталог проверяет параметры, но чужую разметку не чистит. Параметры проверяются по описанию элемента: число — в границах, выбор — только из списка, номера — только цифры; лишнее отбрасывается. Сбой, право, которого нет, превышение времени или размера — пустая вставка, страница цела. Старые теги (news_list…, {banner:5}, [each:comments]) продолжают работать.

Как модуль объявляет элемент (фильтр theme.blocks, запись «модуль.имя» → module, kind (block, list, value, form, button), title, description, params, items, example, works_in, permission, render) — описано в core/Themes/BlockCatalog.php. Готовые блоки раскладки модулей (то, что модуль кладёт в места темы) попадают в каталог сами — их вид в таблице помечен «блок». Таблица ниже собирается скриптом php dev/katalog-spravka.php из каталога, руками не пишется.

МодульЭлементВидЧто выводитВставкаПараметры
bannersbanners.after_contentблокБаннеры под содержимым{block:banners.after_content}—
bannersbanners.bannerблокОдин баннер{block:banners.banner}id
bannersbanners.before_contentблокБаннеры над содержимым{block:banners.before_content}—
bannersbanners.footerблокБаннеры в подвале{block:banners.footer}—
bannersbanners.headerблокБаннеры в шапке{block:banners.header}—
bannersbanners.placeблокБаннеры места{block:banners.place place=sidebar}place (topbar/header/before_content/sidebar/after_content/footer/between_feed/between_comments)
bannersbanners.sidebarблокБаннеры в боковой колонке{block:banners.sidebar}—
bannersbanners.topbarблокБаннеры в полосе над шапкой{block:banners.topbar}—
commentscomments.threadблокОбсуждение под записью{block:comments.thread}—
contentcontent.factsблокДетали{block:content.facts}—
contentcontent.vakansii_homeблокВакансии{block:content.vakansii_home}—
downloadsdownloads.homeблокФайлы на главной{block:downloads.home}—
downloadsdownloads.latestблокПоследние файлы{block:downloads.latest}—
downloadsdownloads.releasesсписокПоследние релизы[each:list:downloads_releases:limit:5]{item.title}[/each]limit
eventsevents.homeблокБлижайшие события{block:events.home}—
favoritesfavorites.starблокЗакладка{block:favorites.star}—
formsforms.formформаФорма{block:forms.form}id
forumforum.homeблокОбсуждения на главной{block:forum.home}—
forumforum.latestблокПоследние обсуждения{block:forum.latest}—
forumforum.topicsсписокПоследние темы[each:list:forum_topics:limit:5]{item.title}[/each]limit
gallerygallery.homeблокИз галереи{block:gallery.home}—
highlighthighlight.scriptблокПодсветка кода{block:highlight.script}—
newsnews.archiveсписокАрхив по месяцам[each:list:news_archive:limit:12]{item.title}[/each]limit
newsnews.archive_boxблокБлок «Архив»{block:news.archive_box}—
newsnews.categoriesсписокРубрики деревом[each:list:news_categories]{item.title}[/each]—
newsnews.commentsсписокПоследние комментарии[each:list:news_comments:limit:5]{item.name}[/each]limit, cat
newsnews.countчисло/текстЧисло{block:news.count what=news period=all}what (news/comments), period (all/day/week/month)
newsnews.feed_boxблокБлок «Лента»{block:news.feed_box}—
newsnews.latestсписокЗаписи с отбором[each:list:news_latest:limit:5:start:0:sort:new]{item.id}[/each]limit, start, cat, user, days, tag, main, sort (new/old/title/views/rating/rand)
newsnews.latest_boxблокБлок «Последние новости»{block:news.latest_box}—
newsnews.rssкнопкаКнопка RSS{block:news.rss}—
newsnews.suggestкнопкаКнопка «Предложить запись»{block:news.suggest}—
newsnews.tagsсписокОблако меток[each:list:news_tags:limit:30]{item.title}[/each]limit
pagespages.listблокСтраницы{block:pages.list}—
pollspolls.currentблокОпрос{block:polls.current}—
pollspolls.oneблокОдин опрос{block:polls.one}id
registryregistry.latestблокПоследняя версия движка{block:registry.latest}—
reviewsreviews.homeблокОтзывы клиентов{block:reviews.home}—
shareshare.afterблокКнопки «поделиться»{block:share.after}—
shopshop.cartкнопкаКорзина{block:shop.cart}—
shopshop.cart_iconблокЗначок корзины{block:shop.cart_icon}—
shopshop.categories_tilesблокКатегории плитками{block:shop.categories_tiles}—
shopshop.latestблокНовинки{block:shop.latest}—
shopshop.productsсписокНовые товары[each:list:shop_products:limit:4]{item.title}[/each]limit
shopshop.showcaseблокВитрина магазина{block:shop.showcase}—
subscribesubscribe.compactблокПодписаться на новости{block:subscribe.compact}—
subscribesubscribe.formблокРассылка{block:subscribe.form}—
tagstags.cloudблокМетки{block:tags.cloud}—
tagstags.subjectблокМетки{block:tags.subject}—

Безопасность

  • Формы рисует только движок: в файле тегов тег <form> вычищается, поэтому ключ защиты и поля всегда на месте. Форму выводит {form}.
  • Разметка шаблона очищается по белому списку: без script, style, iframe, обработчиков событий и атрибутов data-*; адреса только http(s)://, /путь, #.
  • Значения экранируются по месту (в тексте, в атрибуте, в адресе по-разному).
  • Пределы те же, что у языка тегов: размер шаблона 20000 знаков, 400 тегов, вложенность 6, повторов 200.
  • Письма в файлах тегов не нужны: их тексты правятся в «Почта → тексты писем».

Доп. поля новостей: где работают (после переноса в «Доп. поля»)

Поля заводятся в разделе «Доп. поля» (хозяин «Новости», можно ограничить рубриками). Пустое поле нигде не показывается: ни значение, ни подпись.

ГдеЧто писатьУсловие
Полная запись{field:имя}, {fieldlabel:имя}, [if:field:имя], {fieldurl:имя}поле видно этому читателю
Карточка ленты (index.tpl.html, [each:cards]){item.field:имя}, {item.fieldlabel:имя}, {item.fieldurl:имя}, [if:item.field:имя]галочка «в списке»; закрытой записи (под паролем) полей нет
Списки и блоки ([each:news_list …], [each:list:news_latest], {block:news.latest_box})те же теги с item.то же
Отбор записей[each:news_list field:год>2000 field:жанр=драма], custom=имя (заполнено), custom=имя is=значениеполе с галочкой «фильтр» (иначе список пуст, а не вся лента)
Значение ссылкой («Режиссёр: Нолан» → все записи с этим значением)автоматически на странице записи; в списках — <a href="{item.fieldurl:имя}">{item.field:имя}</a>; адрес вида /news/рубрика?field=имя&value=значениегалочки «фильтр» и «значение ссылкой»; виды: строка, список-выбор, число, дробь
Поиск в панелистрока поиска по списку записей находит значения полейгалочка «поиск»
RSSк описанию записи добавляется «Подпись: значение»галочка «отдавать в RSS»; только публичные поля
Замена по сайту«Поиск и замена» видит значения полей новостейправо на замену

Адрес с field=…&value=… показывает над лентой плашку «Подпись: значение» и кнопку «Сбросить отбор». Закрытые поля (только для персонала, по ролям) тегами и в RSS не отдаются.

«Предложить запись» на тегах (модуль «Новости»)

Файлы темы: views/news/suggest.tpl.html (форма для вошедшего) и views/news/suggest-login.tpl.html (гостю: пояснение и кнопки входа). Нет файла — страница как раньше.

Форма пишется движком (ключ защиты, ловушка от роботов, проверка): целиком — {form}, либо по частям {form_open} … {form_close}:

ТегЧто это
{field:title}, {field:excerpt}, {field:category}, {field:tags}, {field:body}основные поля; поле, которого нет в шаблоне, в форме не окажется (заголовок и текст обязательны — без них форма не пройдёт)
{field:f_имя}своё дополнительное поле: только то, которое владелец отметил в «Доп. поля» галочками «в форме сайта» и «заполняет посетитель»; привязанное к рубрике показывается, когда выбрана она; картинки, файлы и видео посетителю не даются
{submit}кнопка отправки
{t.title} {t.lead} {t.note} {t.send} {t.mine} {t.too_many}слова страницы на языке посетителя
{left}, [if:can_send]сколько предложений осталось за сутки; можно ли ещё отправлять
{mine_url}адрес «Мои предложения»
[each:categories]рубрики для выбора: {item.id} {item.title}

Страница для гостя: {login_url}, {register_url}, [if:can_register], слова {t.guest_title} {t.guest_text} {t.guest_login} {t.guest_register}.

Обновлено 16.10.2026

На этой странице
Поделиться: Telegram WhatsApp
Откладывать можно и без входа: закладки сохранятся в этом браузере, а после входа их можно перенести в учётную запись. Вход
Обсуждение

Комментарии

Обсуждение ещё не началось

Пока никто не высказался. Будьте первым.

Пожаловаться на запись