org-static-blog
Генератор статического блога, который я сейчас использую для своего публичного цифрового сада.
- https://github.com/bastibe/org-static-blog/
- https://gitlab.com/_zngguvnf/org-static-blog-example - гитлабный пример
Плюсы вполне очевидны:
- простой;
- внутриемаксовый;
- учитывает настройки org-export и ox-html естественным образом - так как использует их.
Из минусов:
- неудобно смотреть сайт локально, малореально вешать в разных местах, почти всё завязано на указанное место публикации.
- очень хочет каталог для черновиков. Ну, сделала пустой, чо…
- не занимается картинками и всем таким. Ну, эт мы и через org-publish могем.
И конечно, жаль, что не умеет вычищать ссылки на то, чего на сайте нет. Вероятно, это плохо совместимо с простотой и скоростью.
Забавно, что ссылку на список всех постов оказалось удобно засунуть в org-static-blog-post-comments
. Для комментариев я всё равно ничего не использую, а если класть в org-static-blog-page-postamble
, то она во многих местах дублирует уже существующую. Тоже ничего страшного, но зачем, если можно обойтись без этого.
2024-07-04 Для того, чтоб публиковал только то, что я хочу, файлы, которые публикуются, имеют расширение org, остальные заметочные – txt. В org-static-blog внутри указано брать org. Раньше делала специальное расширение publ.org и меняла соответствующий кусок через el-patch, но чот подумала, что можно же не усложнять. :)
Мои настройки, доработки и наблюдения
- пробел после даты мешает сортировке по дате.
Исключить пост из rss-ленты
(setq org-static-blog-rss-excluded-tag "norss")
Временами почему-то жалуется на то, что нет запрошенного бэкенда для экспорта
Так и не поняла, в каких случаях, но нашла лекарство:
(org-export-define-derived-backend 'org-static-blog-post-bare 'html :translate-alist '((template . (lambda (contents info) contents))))
Выполнить вот этот фрагмент из тамошнего же кода. Скопировала к себе поближе, иногда применяю.
Вариант сортировки по дате создания
Сделала, попробовала и работает, но убрала, потому что решила, что пусть отображается по последней правке.
Если выполняется это, то посты в блоге отображают как дату и сортируются по created, а не по date, то есть, по времени типа-создания, а не изменения.
(defun my-org-static-blog-get-date (post-filename) "Extract the `#+created:` from POST-FILENAME as date-time." (let ((case-fold-search t)) (with-temp-buffer (insert-file-contents post-filename) (goto-char (point-min)) (if (search-forward-regexp "^\\#\\+created:[ ]*<\\([^]>]+\\)>$" nil t) (date-to-time (match-string 1)) (time-since 0))))) (advice-add 'org-static-blog-get-date :override #'my-org-static-blog-get-date)
Настройки, кроме путей, названий и ещё некоторых мелочей
(setq org-static-blog-enable-tags t) (setq org-static-blog-preview-link-p t) (setq org-static-blog-use-preview t) (setq org-export-with-toc t) (setq org-export-with-section-numbers nil) (setq org-static-blog-langcode "ru") (setq org-static-blog-preview-date-first-p nil) (setq org-static-blog-index-length 30)
Как определяем границы preview
(setq org-static-blog-preview-start "<div class=\"preview\"") (setq org-static-blog-preview-end "</div>")
Соответствующий див задаётся блоком #+begin_preview #+end_preview
Rss
(setq org-static-blog-rss-extra "<atom:link href=\"http://agnessa.pp.ru/rss.xml\" rel=\"self\" type=\"application/rss+xml\" />") (setq org-static-blog-rss-max-entries 10)
Даты в локали С, у rss замороченней заголовок.
(defun my-org-static-blog--write-rss (items &optional tag) "Generates an RSS file for the given TAG, or for all tags is TAG is nil." (let ((title (format "%s%s" org-static-blog-publish-title (if tag (concat " - " tag) ""))) (url (format "%s%s" org-static-blog-publish-url (if tag (concat "/tag-" (downcase tag) ".html") ""))) (items (sort items (lambda (x y) (time-less-p (car y) (car x)))))) (org-static-blog-with-find-file (org-static-blog--rss-filename tag) (concat "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" "<rss version=\"2.0\" xmlns:atom=\"http://www.w3.org/2005/Atom\">\n" "<channel>\n" "<title><![CDATA[" title "]]></title>\n" "<description><![CDATA[" title "]]></description>\n" "<link>" url "</link>\n" "<lastBuildDate>" (let ((system-time-locale "C")) ; force dates to render as per RSS spec (format-time-string "%a, %d %b %Y %H:%M:%S %z" (current-time))) "</lastBuildDate>\n" org-static-blog-rss-extra (apply 'concat (mapcar 'cdr (org-static-blog--prune-items items))) "</channel>\n" "</rss>\n")))) (advice-add 'org-static-blog--write-rss :override #'my-org-static-blog--write-rss)
Урленкодить ссылки, добавить guid, локаль C.
(defun my-org-static-blog-get-rss-item (post-filename) "Assemble RSS item from post-filename. The HTML content is taken from the rendered HTML post." (concat "<item>\n" " <title><![CDATA[" (org-static-blog-get-title post-filename) "]]></title>\n" " <description><![CDATA[" (org-static-blog-get-body post-filename t) ; exclude headline! "\n\n]]></description>\n" (let ((categories "")) (when (and (org-static-blog-get-tags post-filename) org-static-blog-enable-tags) (dolist (tag (org-static-blog-get-tags post-filename)) (setq categories (concat categories " <category><![CDATA[" tag "]]></category>\n")))) categories) " <link>" (url-encode-url (org-static-blog-get-post-url post-filename)) "</link>\n" " <guid>" (url-encode-url (org-static-blog-get-post-url post-filename)) "</guid>\n" " <pubDate>" (let ((system-time-locale "C")) ; force dates to render as per RSS spec (format-time-string "%a, %d %b %Y %H:%M:%S %z" (org-static-blog-get-date post-filename))) "</pubDate>\n" "</item>\n")) (advice-add 'org-static-blog-get-rss-item :override #'my-org-static-blog-get-rss-item)
Задаю всякий html, примерно
в head каждой страницы
Автор, стили, иконка. Потом, вероятно, надо будет сюда часть микроразметки по заветам indieweb.
(setq org-static-blog-page-header "<meta name=\"author\" content=\"Agnessa\"> <meta name=\"follow_it-verification-code\" content=\"code\"/> <link href= \"https://agnessa.pp.ru/static/style.css\" rel=\"stylesheet\" type=\"text/css\" /> <link rel=\"icon\" type=\"image/png\" sizes=\"150x150\" href=\"https://agnessa.pp.ru/static/bonsai-small.png\"> ")
follow.it - это сервис, через который можно подписаться на обновления.
Шапка страницы, оно же начало body каждой страницы
(setq org-static-blog-page-preamble "<div class=\"header\"> <p style=\"float:right\"><a href=\"https://agnessa.pp.ru\"><img src=\"https://agnessa.pp.ru/static/bonsai-small.png\" alt=\"Цифровой садик - приветственная\"/></a></p> <p><a href=\"https://agnessa.pp.ru\">Цифровой садик - приветственная</a> | <a href=\"https://agnessa.pp.ru/archive.html\">Полный список всего, что тут есть</a> | <a href=\"https://forms.yandex.ru/u/61057e8e2f1b2d9ca96ab333/\">Отправить сообщение через Яндекс.Форму</a> | <a href=\"https://agnessa.pp.ru/rss.xml\">RSS</a> | <a href=\"https://follow.it/m2wkzr?action=followPub\">Подписаться через follow.it</a></p> </div>")
Подвал каждой страницы
(setq org-static-blog-page-postamble "<hr/> <p>Если у вас есть мысли, комментарии, предложения или отклики по поводу этой страницы или этого цифрового сада в целом, <a href=\"https://forms.yandex.ru/u/61057e8e2f1b2d9ca96ab333/\">напишите мне сообщение через Яндекс.Форму</a>. Мне ооочень интересно!</p> ")
Под постами
(setq org-static-blog-post-comments "<div id=\"archive\"> <a href=\"https://agnessa.pp.ru/archive.html\">Все посты</a> </div>")
Начало приветственной страницы
(setq org-static-blog-index-front-matter "<h1>Привет!</h1>\n <div class=\"epigraph\"> <p>Я несу свою пургу,<br/> Потому что я — могу!<br/> — Я </p> <p>Нередко мы считаем свои заблуждения как раз находками, почему же ими не поделиться?..<br/> — Виктор Кротов</p> <p>Мнение автора может не совпадать с его точкой зрения.<br/> — Дисклеймер</p> <p>...надо всё-таки возделывать свой сад.<br/> — Вольтер «Кандид» </div> <p>Тут мой маленький <a href=\"https://agnessa.pp.ru/0-20210912/20210721053232-digital_garden.html\">цифровой садик</a>. Наполняю содержанием. Даже не столько создаю, сколько выбираю, что из существующего беспорядка мне ок показывать наружу. :) Делаю это медленно, по мере постоянного текущего разгребания базы.</p> <p><a href=\"https://agnessa.pp.ru/archive.html\">Полный список всего, что тут есть</a>, ссылка также внизу примерно на каждой странице. Там же возможность <a href=\"https://forms.yandex.ru/u/61057e8e2f1b2d9ca96ab333/\">написать мне в яндекс-форму</a>. Мне интересно, что вы думаете, и отклики сильно улучшают сад. Если хотите написать о конкретной странице — скопируйте ссылку на эту страницу в форму, пожалуйста. Форма не скажет мне сама, с какой страницы вы пришли.</p> <p>На существующих страничках есть сколько-то ссылок на страницы, которые я пока не решилась или не добралась выложить. К сожалению, пока не знаю ни как убрать, не убирая рабочие, ни как отмечать, что они ведут в никуда. Давайте думать, что это хорошо для читателя, потому что даёт возможность подглядеть в закрытую часть сада :)</p> <p>Страницы расположены в хронологическом порядке, раньше — глубже. Дата — последняя правка соответствующего файла. И блоговость тут — иллюзия. Это не окончательные тексты по каким-то поводам, которые не предполагают меняться, быв раз написаны, это «растения», они растут, увядают и меняются прочими способами.</p> <p>Некоторые «входные точки»:</p> <ul> <li><a href=\"https://agnessa.pp.ru/texts/20210721093953-рецензия.html\">Как писать рецензию</a></li> <li><a href=\"https://agnessa.pp.ru/0-20210912/20200712142832-тг_каналы.html\">Телеграм-каналы и чаты</a></li> <li><a href=\"https://agnessa.pp.ru/computer/emacs/20200820235900-emacs.html\">Еmacs</a></li> <li><a href=\"https://agnessa.pp.ru/mine/20210826225955-мое.html\">мои стихи и что там ещё</a></li> <li><a href=\"https://agnessa.pp.ru/selfrelations/20200912193056-%D0%BE%D0%B1%D0%BE_%D0%BC%D0%BD%D0%B5.html\">обо мне</a></li> <li><a href=\"https://agnessa.pp.ru/me/20210820030406-%D0%B2%D0%B8%D1%88%D0%BB%D0%B8%D1%81%D1%82.html\">вишлист</a></li> </ul>")
Публикация
(defun my-auto-org-static-blog-publish() "Отправляет на место." (interactive) (org-static-blog-publish) (shell-command-to-string "syncgarden") )
Требует скриптика syncgarden, который живёт отдельно в папочке, добавленной в PATH. Там куда перейти и команда для rsync.
Hy, и
(add-hook 'midnight-hook 'my-auto-org-static-blog-publish)
чтоб временами автосрабатывало. https://www.emacswiki.org/emacs/MidnightMode
Потому что чем меньше рутины требует человеческого внимания, тем лучше. :)