upd
This commit is contained in:
parent
d14a3f95a7
commit
423468a50b
@ -13,6 +13,6 @@
|
|||||||
* `vk-toot <https://git.nxhs.cloud/ge/vk-toot>`_ -- кросспостер VK -> Mastodon
|
* `vk-toot <https://git.nxhs.cloud/ge/vk-toot>`_ -- кросспостер VK -> Mastodon
|
||||||
* `piglet <https://git.hxhs.cloud/ge/piglet>`_ -- клиент DNS API Porkbun
|
* `piglet <https://git.hxhs.cloud/ge/piglet>`_ -- клиент DNS API Porkbun
|
||||||
* roadwarrior -- менеджер подключений к VPN и прокси
|
* roadwarrior -- менеджер подключений к VPN и прокси
|
||||||
* `n! <https://git.nxhs.cloud/ge/n>` -- консольный менеджер заметок
|
* `n! <https://git.nxhs.cloud/ge/n>`_ -- консольный менеджер заметок
|
||||||
|
|
||||||
Остальное есть в `Gitea <https://git.nxhs.cloud/ge/>`_.
|
Остальное есть в `Gitea <https://git.nxhs.cloud/ge/>`_.
|
||||||
|
@ -1,339 +0,0 @@
|
|||||||
:title: Как я написал этот блог
|
|
||||||
:date: 5 Aug 22
|
|
||||||
:type: page
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Статья малось устарела и не соответсвует текущей действительности.
|
|
||||||
|
|
||||||
=======================
|
|
||||||
Как я написал этот блог
|
|
||||||
=======================
|
|
||||||
|
|
||||||
Я очень давно планировал написать блог. Именно что написать CMS для ведения
|
|
||||||
блога. Если погуглить, то CMS для этих целей сотни на разных языках с разным
|
|
||||||
позиционированием и фичами. Но мне хотелось своего.
|
|
||||||
|
|
||||||
Первые попытки создать сайт были на `Flask`_, особым успехом не увенчались,
|
|
||||||
но это была хорошая практика и я немного прокачал свой уровень программирования.
|
|
||||||
|
|
||||||
Для блога я не хотел использовать базу данных. Вместо этого я хранил статьи в
|
|
||||||
исходном Markdown, а метаданные по каждой статье писал в отдельный JSON, который
|
|
||||||
заменял мне БД. С тем же успехом я мог бы использовать SQLite, но мне нужно было
|
|
||||||
хранить контент в text/plain.
|
|
||||||
|
|
||||||
Блог даже работал, но мне хотелось сделать админку, чтобы можно было писать
|
|
||||||
прямо в браузере. На этой части разработка заглохла и я окончательно запутался в
|
|
||||||
импортах в Python)
|
|
||||||
|
|
||||||
Прошло ещё много времени, я вернулся к идее, но решил сделать ставку на простоту
|
|
||||||
и начал писать на `Bottle`_. Здесь разработка остановилась не дойдя даже до
|
|
||||||
варианта хоть как-то работающей системы. Причины скорее всего надо искать в
|
|
||||||
лени.
|
|
||||||
|
|
||||||
Устав я взял `CMS Bludit`_ и стал вести свои редкие заметки в нём. Решение не
|
|
||||||
самое плохое, но и не супер отличное. Для простой кастомизации футера пришлось
|
|
||||||
городить костыли.
|
|
||||||
|
|
||||||
.. _Flask: https://flask.palletsprojects.com/
|
|
||||||
.. _Bottle: https://bottlepy.org/
|
|
||||||
.. _CMS Bludit: https://www.bludit.com/ru/
|
|
||||||
|
|
||||||
Статика VS динамика
|
|
||||||
===================
|
|
||||||
|
|
||||||
Преимуществ у статических сайтов много. Об этом уже много написано. Мне больше
|
|
||||||
всего в статических сайтах нравится то, что:
|
|
||||||
|
|
||||||
* роутингом запросов не управляет какой-либо скрипт, я могу свободно
|
|
||||||
распоряжаться тем, что у меня есть в DocumentRoot;
|
|
||||||
* не нужно настраивать application-сервер и реверс-прокси на него.
|
|
||||||
|
|
||||||
С редактированием сайта чуть сложнее, так как сперва надо внести изменения
|
|
||||||
локально, а затем заменить изменившиеся файлы на сервере. Но и тут есть
|
|
||||||
какие-то решения.
|
|
||||||
|
|
||||||
Я рассматривал уже готовые генераторы статических сайтов, но у них всех были
|
|
||||||
фатальные недостатки:
|
|
||||||
|
|
||||||
* они сложные и требуют изучения документации чтобы начать писать;
|
|
||||||
* написать собственную тему задача весьма непростая;
|
|
||||||
* они написаны не мной.
|
|
||||||
|
|
||||||
Здесь и рождается мой велосипед, которому я не придумал названия. Буду называть
|
|
||||||
его `генератором`.
|
|
||||||
|
|
||||||
*re*\ **Structured**\ *Text*
|
|
||||||
============================
|
|
||||||
|
|
||||||
Я очень долго писал на Markdown, но в один момент понял, что возможностей языка
|
|
||||||
стало нехватать. Тут пришёлся очень кстати `Python-Markdown`_ к которому можно
|
|
||||||
было прикручивать `расширения`_. Одно даже сам `написал`_.
|
|
||||||
|
|
||||||
Постепенно я пришёл к `reStructuredText`_. Все приколюхи, которые в нём есть
|
|
||||||
существуют не за счёт расширения синтаксиса плагинами, а заложены в спецификации.
|
|
||||||
Функциональности из коробки хватает чтобы писать даже `формулы`_.
|
|
||||||
|
|
||||||
Такие вещи делаются через `роли` и `директивы`. Некоторые готовые директивы есть
|
|
||||||
в системе документации `Sphinx`_. Их я собираюсь потихоньку скопировать к себе.
|
|
||||||
|
|
||||||
Ещё одно большое преимущество перед Markdown состоит в том, что reStructuredText
|
|
||||||
поддерживает атрибуты. Вот как это выглядит:
|
|
||||||
|
|
||||||
.. code-block:: rst
|
|
||||||
|
|
||||||
:title: Как я написал этот блог
|
|
||||||
:date: 5 Aug 2022
|
|
||||||
|
|
||||||
Это нативная фича, которую можно использовать в статьях для добавления метаданных.
|
|
||||||
|
|
||||||
По сути это место, где можно сделать настройки, касающиеся отдельно взятой статьи.
|
|
||||||
|
|
||||||
Большинство генераторов статических сайтов колхозят нечно подобное в Markdown, делая
|
|
||||||
исходник статьи непригодным для парсинга другими инструментами. Это причина по
|
|
||||||
которой в старой реализации блога мне пришлось использовать JSON для метаданных.
|
|
||||||
|
|
||||||
.. _Sphinx: https://www.sphinx-doc.org/en/master/index.html
|
|
||||||
.. _Python-Markdown: https://python-markdown.github.io/
|
|
||||||
.. _расширения: https://python-markdown.github.io/extensions/
|
|
||||||
.. _написал: https://pypi.org/project/markdown-alerts/
|
|
||||||
.. _rST: https://docutils.sourceforge.io/rst.html
|
|
||||||
.. _формулы: https://docutils.sourceforge.io/docs/ref/rst/mathematics.html
|
|
||||||
|
|
||||||
Обзор
|
|
||||||
=====
|
|
||||||
|
|
||||||
Сайт состоит из следующих частей.
|
|
||||||
|
|
||||||
rst_blg.py
|
|
||||||
Непосредственно код генератора. Сейчас там всего около 200 строк без учёта
|
|
||||||
комментариев.
|
|
||||||
|
|
||||||
requirements.txt
|
|
||||||
Список зависимостей. Стараюсь держать минимум. Пока что там: `docutils`,
|
|
||||||
`jinja2`, `toml` и `pygments`.
|
|
||||||
|
|
||||||
settings.toml
|
|
||||||
Файл с настройками. Здесь можно переопределить практически всё.
|
|
||||||
|
|
||||||
Makefile
|
|
||||||
Через него запускаются команды для сборки сайта и некоторые другие. Не
|
|
||||||
является обязательным, но с ним удобнее.
|
|
||||||
|
|
||||||
layouts
|
|
||||||
Директория для шаблонов Jinja2.
|
|
||||||
|
|
||||||
assets
|
|
||||||
Директория для хранения статических файлов, будь то CSS, JS или изображения.
|
|
||||||
Всё что нужно для визуального оформления страниц. Внутренняя структура
|
|
||||||
каталога может быть произвольной.
|
|
||||||
|
|
||||||
content
|
|
||||||
Директория с исходниками статей в reStructuredText. Сюда можно также
|
|
||||||
положить любые файлы и директории.
|
|
||||||
|
|
||||||
build
|
|
||||||
В эту директорию копируются ассеты, файлы и сгенерированный HTML.
|
|
||||||
|
|
||||||
Статьи, шаблоны и ассеты могут быть оформлены абсолютно любым образом. Скрипту
|
|
||||||
безразлично что собирать. Пути и имена всех директорий можно переопределить в
|
|
||||||
settings.toml.
|
|
||||||
|
|
||||||
Исходники с небольшой инструкцией я положил сюда: https://git.nxhs.cloud/ge/blog
|
|
||||||
|
|
||||||
Написание постов
|
|
||||||
================
|
|
||||||
|
|
||||||
Тут всё предельно просто. Пишем файл и кладём в директорию `content`. В файле
|
|
||||||
должны быть указаны обязательные атрибуты ``:title:`` и ``:date:``.
|
|
||||||
|
|
||||||
Блог пока не умеет работать с вложенной структурой статей. Поэтому всё будет
|
|
||||||
свалено в кучу в корневую директорию сайта.
|
|
||||||
|
|
||||||
Все статьи добавляются в список постов и отображаются на главной странице.
|
|
||||||
|
|
||||||
Для того, чтобы сделать "отдельную" страницу, надо добавить атрибут
|
|
||||||
``:not_a_post:``.
|
|
||||||
|
|
||||||
================= ======= =========== ====================================
|
|
||||||
Атрибут Тип Умолчание Описание
|
|
||||||
================= ======= =========== ====================================
|
|
||||||
``:title:`` Строка Заголовок статьи
|
|
||||||
``:date:`` Дата Дата публикации, формат задаётся в
|
|
||||||
settings.toml
|
|
||||||
``:not_a_post:`` Флаг для одиночных страниц
|
|
||||||
================= ======= =========== ====================================
|
|
||||||
|
|
||||||
Темы оформления
|
|
||||||
===============
|
|
||||||
|
|
||||||
Никаких готовых тем. Пишем CSS вручную. Генератору сайтов всё равно что там
|
|
||||||
будет. От уровеня представления он никак не зависит. Так что можно писать любые
|
|
||||||
шаблоны и стили для них.
|
|
||||||
|
|
||||||
Отдельно можно задать тему для блоков кода. Список тем для Pygments с превью
|
|
||||||
есть на странице https://pygments.org/styles/
|
|
||||||
|
|
||||||
Чтобы поменять тему, например, на `default` надо выполнить команду:
|
|
||||||
|
|
||||||
.. code-block:: shell
|
|
||||||
|
|
||||||
make css default
|
|
||||||
# или
|
|
||||||
pygmentize -f html -S default -a .highlight > assets/css/pygments/default.css
|
|
||||||
|
|
||||||
Затем поменять значение ``theme`` в секции ``pygments`` settings.toml.
|
|
||||||
|
|
||||||
.. code-block:: toml
|
|
||||||
|
|
||||||
[pygments]
|
|
||||||
theme = 'default'
|
|
||||||
|
|
||||||
Шаблоны
|
|
||||||
========
|
|
||||||
|
|
||||||
Шаблоны можно писать какие угодно. Для этогой сайта я написал три файла.
|
|
||||||
Приведу их без лишних строк.
|
|
||||||
|
|
||||||
**base.j2**
|
|
||||||
|
|
||||||
.. code-block:: html+jinja
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en" dir="ltr">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
|
||||||
<link rel="icon" href="data:image/png;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=">
|
|
||||||
<link rel="stylesheet" href="assets/css/pygments/{{ pygments_theme }}.css">
|
|
||||||
<link rel="stylesheet" href="assets/css/custom.css">
|
|
||||||
<title>{{ page_title }} | {{ site_title }}</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<header>
|
|
||||||
<p>
|
|
||||||
{% if posts %}
|
|
||||||
{{ site_title }}
|
|
||||||
{% else %}
|
|
||||||
<a href="/">{{ site_title }}</a> / {{ page_title }}</p>
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
{% block content %}{% endblock %}
|
|
||||||
|
|
||||||
<footer>
|
|
||||||
<!-- Footer content -->
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
**post.j2**
|
|
||||||
|
|
||||||
.. code-block:: html+jinja
|
|
||||||
|
|
||||||
{% extends "base.j2" %}
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<article>
|
|
||||||
{{ post | safe }}
|
|
||||||
<article>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
**index.j2**
|
|
||||||
|
|
||||||
.. code-block:: html+jinja
|
|
||||||
|
|
||||||
{% extends "base.j2" %}
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<ul id="posts">
|
|
||||||
{% for post in posts %}
|
|
||||||
<li>
|
|
||||||
<a href="/{{ post['path'] }}">{{ post['title'] }}</a>
|
|
||||||
<span class="meta"> — {{ post['date'] }}</span>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
settings.toml
|
|
||||||
=============
|
|
||||||
|
|
||||||
Сначала я хотел использовать обычный INI, но мне нужно было получать из конфига
|
|
||||||
словарь. Немного подумал и выбрал TOML. Он отлично сериализируется в словарь,
|
|
||||||
визуально повторяет INI.
|
|
||||||
|
|
||||||
**settings.toml** разделён на несколько секций.
|
|
||||||
|
|
||||||
site
|
|
||||||
Данные касающиеся непосредственно сайта.
|
|
||||||
|
|
||||||
title
|
|
||||||
Название сайта
|
|
||||||
|
|
||||||
index_page_title
|
|
||||||
Заголовок главной страницы. Для всех остальных страниц заголовок
|
|
||||||
берётся из атрибута.
|
|
||||||
|
|
||||||
datatime_format
|
|
||||||
Формат даты для атрибута ``:date:``.
|
|
||||||
|
|
||||||
build
|
|
||||||
Параметры, используетмые при сборке.
|
|
||||||
|
|
||||||
build_dir
|
|
||||||
Директория, куда будет сохранён собранный сайт.
|
|
||||||
|
|
||||||
content_dir
|
|
||||||
Директория с исходниками статей.
|
|
||||||
|
|
||||||
templates_dir
|
|
||||||
Директория с шаблонами Jinja2.
|
|
||||||
|
|
||||||
assets_dir
|
|
||||||
Директория с ассетами.
|
|
||||||
|
|
||||||
pygments
|
|
||||||
Параметры подсветки синтаксиса в блоках кода.
|
|
||||||
|
|
||||||
theme
|
|
||||||
Стиль Pygments.
|
|
||||||
|
|
||||||
docutils
|
|
||||||
Конфигурация для docutils. Здесь можно указать любые параметры, которые
|
|
||||||
есть здесь: https://docutils.sourceforge.io/docs/user/config.html
|
|
||||||
|
|
||||||
Мне достаточно:
|
|
||||||
|
|
||||||
.. code-block:: toml
|
|
||||||
|
|
||||||
[docutils]
|
|
||||||
initial_header_level = 2
|
|
||||||
section_self_link = true
|
|
||||||
syntax_highlight = 'short'
|
|
||||||
|
|
||||||
Что ещё хочется сделать
|
|
||||||
=======================
|
|
||||||
|
|
||||||
В перспективе я планирую добавить следующие фичи.
|
|
||||||
|
|
||||||
- RSS
|
|
||||||
- OpenGraph
|
|
||||||
- Webmention
|
|
||||||
- Расширить возможности rST до уровня Sphinx
|
|
||||||
- Улучшить CSS
|
|
||||||
- Комментарии
|
|
||||||
- Кастомный лейаут для отдельных статей
|
|
||||||
- Поддержка вложенной структуры статей
|
|
||||||
|
|
||||||
.. * https://jinja.palletsprojects.com/en/3.0.x/templates/
|
|
||||||
* https://docutils.sourceforge.io/docs/user/config.html
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user