Мои изменения в теме Hugo Stack

Что я поменял в настройках этого сайта

Коротко

Сначала пройдёмся списком по изменениям. Коротко и по делу. А потом будет проще дать развёрнутый ответ по некоторым моментам.

  • Закинул аватарку в каталог img.
  • Скачал новые иконки для ссылок под аватаркой.
  • Изменил стили виджетов. Изначально текст был под логотипом, теперь в ряд.
  • Изменил стандартную тему с auto на dark. Поберегите свои глаза.
  • Удалил лишние языки из каталога i18n. Для русского и английского языков сделал перевод всего и вся. Адаптировал код под полную поддержку нескольких языков на будущее. Теги, категории, даты, название и содержание статей, всё теперь может отображаться на двух языках.
  • Добавил облако тегов во вкладку архивы. На случай, если будет много тегов, то их можно будет посмотреть там. На главной странице их все не уместить.
  • Изменил поиск по сайту. Теперь он будет искать на любом языке, независимо от выбранного пользователем. Я считаю это более удобным вариантом. При поиске на родном языке найдёшь что надо. А если говоришь на двух языках, то не придётся дёргать переключатель для нахождения нужной статьи.
  • У всех постов всегда задаю язык в имени файла. У меня не существует index.md, я использую index.ru.md. В будущем пригодится.
  • Сделал автоматическое указание даты редактирования поста в конце страницы.

Все изменения можно найти в моём форке этой темы. Единстненное, что я там выключил, это автоматическое указание даты редактирования поста через гит в этом файле. Если кому-то нужен этот функционал, то можно просто раскомментировать строку.

Отложено на потом

  • Система комментариев под постами
  • Переключатель языка. Я настроил блог под работу с несколькими языками, но сам переключатель временно выключен

Подробнее о некоторых изменениях

Тут будет очень много блоков с кодом, которые изображены в формате diff, тоесть красным цветом с минусом в начале показаны удалённые строки, а зелёные строки с плюсом в начале показывают новые, добавленные строки кода. Из минусов такого формата - читателю не получится удобно скопировать несколько строк, придётся удалять плюсы в начале каждой строки и полностью удалять строки с минусами. Но я решил использовать именно этот формат, чтоб визуально показать различия.

Заголовки виджетов

Изначально у виджетов была иконка сверху, а текст под ними с новой строки. Это не красиво. Я захотел в ряд.

В файле themes/hugo-theme-stack/assets/scss/general.scss я удалил эти три строки (выделено красным):

1
2
3
4
5
6
7
8
9
.section-title {
    text-transform: uppercase;
-   margin-top: 0;
-   margin-bottom: 10px;
-   display: block;
    font-size: 
    font-weight: 
    color: var(--body-text-color); 
}

В файле themes/hugo-theme-stack/assets/scss/partials/article.scss я вынес стили для .article-category, чтоб они были отдельно:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
                 }
             }
         }
+    }
+}

-        @for $i from 1 through length($defaultTagBackgrounds) {
-            &:nth-child(#{length($defaultTagBackgrounds)}n + #{$i}) {
-                .article-category a {
-                    background: nth($defaultTagBackgrounds, $i);
-                    color: nth($defaultTagColors, $i);
-                }
-            }
-        }

+@for $i from 1 through length($defaultTagBackgrounds) {
+    .article-category:nth-child(#{length($defaultTagBackgrounds)}n + #{$i}) a {
+        background: #0177b8;
+        color: nth($defaultTagColors, $i);
+    }

В файле themes/hugo-theme-stack/assets/scss/partials/widgets.scss я изменил позиционирование иконки:

1
2
3
4
5
6
7
    .widget-icon {
+       display: flex;
+       align-items: center; /* Центрирование по вертикали */
+       gap: 10px; /* Расстояние между SVG и текстом */
        svg {
            width: 32px;
            height: 32px;  

Если я правильно помню, все эти три изменения созданы для того, чтоб виджет навигации внутри поста и виджеты категорий и тегов на главной странице отображались как надо. Но изменения стилей для этого не достаточно. Надо так же изменить html разметку в следующих файлах.

Я изменил файлы archives.html, categories.html, tag-cloud.html, toc.html в каталоге themes/hugo-theme-stack/layouts/partials/widget/ по следующему принципу:

1
2
3
4
5
6
    <section class="widget archives">
        <div class="widget-icon">
            {{ partial "helper/icon" "infinity" }}
+           <h2 class="widget-title section-title">{{ T "widget.archives.title" }}</h2>
        </div>
-       <h2 class="widget-title section-title">{{ T "widget.archives.title" }}</h2>

Не буду дублировать код каждого файла. Суть ясна. Заголовок h2 я перенёс из секции в див с классом widget-icon.


Работа с несколькими языками

Хотя эта тема изначально настроена на работу с несколькими языками и с возможностью их переключать, видя лишь посты на нужном языке, мне пришлось кое что доделать. Я хотел, чтоб поиск по сайту работал по всем постам, независимо от выбранного языка. А ещё я хотел, чтоб теги и дата тоже имели перевод. Чтоб я во всех постах писал теги и дату по одному шаблону, а у юзера оно отображалось на выбранном языке. Начнём по порядку.

Поиск по сайту на любом языке

Изменил файл themes/hugo-theme-stack/layouts/page/search.json

1
2
3
4
5
-{{- $pages := where .Site.RegularPages "Type" "in" .Site.Params.mainSections -}}
-{{- $notHidden := where .Site.RegularPages "Params.hidden" "!=" true -}}
+{{- $pages := where .Site.AllPages "Type" "in" .Site.Params.mainSections -}}
+{{- $notHidden := where .Site.AllPages "Params.hidden" "!=" true -}}
 {{- $filtered := ($pages | intersect $notHidden) -}}

Отображение даты на языке пользователя

Чтоб дата отображалась на нужном языке, а не только на английском, надо изменить форматирование даты в .html шаблоне. Изначально там использовался стандартный метод языка Go .Date.Format. Но его надо заменить на один из двух вариантов самого Hugo:

  • {{ time.Format "desired-format" "your-date" }}
  • {{ dateFormat "desired-format" "your-date" }}

Для этого я изменил файлы в themes/hugo-theme-stack/layouts/partials/article/components/

1
2
3
4
5
6
# footer.html
- {{ T "article.lastUpdatedOn" }} {{ .Lastmod.Format ( or .Site.Params.dateFormat.lastUpdated "Jan 02, 2006 15:04 MST" ) }} 
+ {{ T "article.lastUpdatedOn" }} {{ time.Format "02 January 2006 15:04" .Lastmod }}
# details.html
- {{- .Date.Format (or .Site.Params.dateFormat.published "Jan 02, 2006") -}}
+ {{- time.Format "2 January 2006" .Date -}} 

Перевод тегов и категорий

Для перевода категорий ничего делать не надо. Так как они имеют свои каталоги с index.md файлами, то достаточно делать то, что требуется для перевода статей. Я задал каталогу категории имя на английском и во всех постах задаю категорию на английском. Но внутри каталога категории у меня два файла - index.ru.md и index.en.md, где я и дал название на двух языках.

С категориями есть только один нюанс - это страница с архивами. Там заголовок у виджета с категориями всегда на английском языке. Исправить можно в файле themes/hugo-theme-stack/layouts/_default/archives.html. Чтоб потом не возвращаться к этому файлу, я сразу покажу как добавить туда облако тегов с уже встроенным переводом тегов:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@@ -4,7 +4,7 @@
        {{- $taxonomy := $.Site.GetPage "taxonomyTerm" "categories" -}}
        {{- $terms := $taxonomy.Pages -}}
        {{ if $terms }}
-       <h2 class="section-title">{{ $taxonomy.Title }}</h2>
+       <h2 class="section-title">{{ T "widget.categoriesCloud.title" }}</h2>
        <div class="subsection-list">
            <div class="article-list--tile">
                {{ range $terms }}
@@ -15,6 +15,19 @@
        {{ end }}
    </header>

+   <section class="widget tagCloud">
+       <h2 class="section-title">{{ T "widget.tagCloud.title" }}</h2>
+       <div class="tagCloud-tags">
+           {{ range first 1000 $.Site.Taxonomies.tags.ByCount }}
+               {{ $tagID := printf "tags.%s" (.Page.Title | urlize | lower) }}
+               {{ $translation := i18n $tagID }}
+               <a href="{{ .Page.RelPermalink }}" class="font_size_{{ .Count }}">
+                   {{ $translation }}
+               </a>
+           {{ end }}
+       </div>
+   </section> 

Помимо этого, для перевода тегов надо изменить сам виджет themes/hugo-theme-stack/layouts/partials/widget/tag-cloud.html:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
    <div class="tagCloud-tags">
        {{ range first $limit $context.Site.Taxonomies.tags.ByCount }}
+           {{ $tagID := printf "tags.%s" (.Page.Title | urlize | lower) }}
+           {{ $translation := i18n $tagID }}
            <a href="{{ .Page.RelPermalink }}" class="font_size_{{ .Count }}">
-               {{ .Page.Title }}
+               {{ $translation }}
            </a>
        {{ end }}
    </div>

И шаблон тегов под постом в файле themes/hugo-theme-stack/layouts/partials/article/components/tags.html:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{{ if .Params.Tags }}
    <section class="article-tags">
        {{ range (.GetTerms "tags") }}
-           <a href="{{ .RelPermalink }}">{{ .LinkTitle }}</a>        
+           {{ $tagID := printf "tags.%s" (.LinkTitle | urlize | lower) }}
+           {{ $translation := i18n $tagID }}
+           <a href="{{ .RelPermalink }}">{{ $translation }}</a>
        {{ end }}
    </section>
{{ end }}

В теории это всё. Теперь все теги везде будут отображаться как пустое место без текста :D и чтоб это исправить, надо создать имена для тегов на разных языках. Для этого надо изменить файлы в каталоге themes/hugo-theme-stack/i18n. Я оттуда удалил все лишние языки, чтоб не мешали. Сейчас нам нужны лишь en.yaml и ru.yaml. Если планируется писать лишь на одном языке, но хочется на будущее сделать так, чтоб была поддержка всех языков, то на время можно заполнить лишь файл одного языка. Ниже я приведу пример того, что можно дописать в конец файла ru.yaml. Для любого другого языка логика такая же.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
tags:
    # Рандомные теги
    ai: ИИ
    keyboard: Клавиатуры
    health: Здоровье
    thoughts: Мысли
    books: Книги
    vr: VR
    rage: Бомбит
    memes: Мемы
    productivity: Продуктивность
    security: Безопасность
    travel: Путешествия
    social: Коммуникация
    # Технологии
    web: Веб
    hugo: Hugo
    # Linux
    linux: Linux
    gentoo-linux: Gentoo Linux
    void-linux: Void Linux
    arch-linux: Arch Linux
    alpine-linux: Alpine Linux
    ubuntu-linux: Ubuntu Linux
    nixos: NixOS

Получается шаблон название-тега: перевод, где название-тега это то, что надо будет писать в .md файле в поле тегов, а перевод это то, что будут видеть посетители сайта. Главное не допустить в будущем пересечения тегов, что одно слово будет использоваться для разных смыслов. По этой причине я в примере написал разные дистрибутивы линукса через дистрибутив-linux. Просто на всякий случай я бы делал так, вдруг это слово в будущем будет использоваться для чего-то другого. Ну и для удобства я стараюсь делить теги на категории и писать их в комментарии через #.

Чтоб, в случае чего, не запутаться в тегах и помнить какой смысл я в них вложил, я веду заметку в обсидиане, где у меня есть таблица по типу такой:

i18n English Russian Описание
ai AI ИИ Если обсуждается ИИ
linux Linux Linux Если обсуждается линукс в целом. Если конкретный дистр, то можно ставить оба тега
keyboard Keyboard Клавиатуры Сто процентов буду обсуждать клавы, так что да

В i18n я указываю название тега, которое пишу при создании поста. В языковые столбцы пишу то, как это должно отображаться у пользователя, в описании… описание. В моём примере описание не особо имеет смысл, но у меня в таблице есть теги, которые требуют пояснений. Чтоб не спойлерить, я лучше приведу пример такой же таблицы, но для категорий, там понятней зачем я пишу описание:

English Russian Описание
Software Программы Описание разных программ. Для разработки софта отдельная категория. Если софт для создания софта, например нвим, то можно ставить и эту категорию и разработку
Development Разработка Разработка чего-либо. Например, гайды по программированию или создание раздельной клавиатуры. Тоесть речь не только про софт, но и про ирл разработку
Hardware Техника Ирл девайсы. Если речь о прошивке, то сюда писать. Если речь о, например, софтине для смены ргб подсветки у клавы, то в Программы писать
OS ОС Операционные системы. Линух, не линух и тд. Дотсы мб сюда же. А описание конкретного софта из дотсов в софт. Или обе категории ставить. Или сначала писать посты по софту в Программы, а потом общий по дотсам в эту категорию, ссылаясь на посты по софту
Paper Статья Что-то огромное, тонну текста. Изначально хотел использовать для больших постов, которые не имют своей категории. Но мб буду так же использовать в качестве второй категории, если текста и правда много
IRL ИРЛ Что-то из реальной жизни. Мб про ЗОЖ и эргономику сюда писать
Other Остальное Если небольшой пост и под него нет отдельной категории

Тут уже больше смысла в описании. Без такого описания тегов я первое время использовал обсидиан для ведения заметок и это было мягко говоря не удобно. Сидишь думаешь “а какой тег мне выбрать в этот раз, если подходит и туда и сюда?”. Теперь думать не надо. В случае появления вопросов, на них есть ответы в заметке. Кстати, серия статей по созданию этого блога и загрузке его на сервер находится в категории Программы, а не Разработка, потому что мы тут ничего не изобретаем, а просто учимся пользоваться готовой программой Hugo. Многие настройки можно вообще не делать, поставить хуго и сразу начать писать посты через markdown. Так что, в данном случае, я считаю это просто продвинутым пользованием, а не разработкой.

ВАЖНО:

  • Категории можно называть именем каталога категории. На регистр плевать, можно и мелкой и большой буквой писать.
  • Теги надо писать так, как они названы в i18n, включая регистр. Поэтому я всё называю с маленькой буквы

И ещё, чуть не забыл, в файле ru.yaml я сделал некоторые изменения в переводе:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
@@ -2,7 +2,7 @@ toggleMenu:
    other: Показать/скрыть меню

darkMode:
-   other: Тёмный режим
+   other: Тёмная тема

list:
    page:
@@ -47,6 +47,9 @@ widget:
    tagCloud:
        title:
            other: Теги
+   categoriesCloud:
+       title:
+           other: Категории

search:
    title:  

Расположение категорий

Изначально категории поста отображались над его названием. Это выглядит интересно, если каждому посту указывать картинку-превью. Для меня поиск подходящего изображения тот ещё геморрой, поэтому я решил так не делать. Категории были перенесены в самый низ превью поста на главной странице. Это делается в файле themes/hugo-theme-stack/layouts/partials/article/components/details.html:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@@ -1,13 +1,4 @@
<div class="article-details">
-   {{ if .Params.categories }}
-   <header class="article-category">
-       {{ range (.GetTerms "categories") }}
-           <a href="{{ .RelPermalink }}" {{ with .Params.style }}style="background-color: {{ .background }}; color: {{ .
-               {{ .LinkTitle }}
-           </a>
-       {{ end }}
-   </header>
-   {{ end }}

    <div class="article-title-wrapper">
        <h2 class="article-title">
@@ -58,4 +49,14 @@
            </div>
        </footer>
    {{ end }}

+   {{ if .Params.categories }}
+   <header class="article-category">
+       {{ range (.GetTerms "categories") }}
+           <a href="{{ .RelPermalink }}" {{ with .Params.style }}style="background-color: {{ .background }}; color: {{ .
+               {{ .LinkTitle }}
+           </a>
+       {{ end }}
+   </header>
+   {{ end }}
</div>     

Изменения в основном конфиге

В hugo.yaml поменять пришлось не мало:

  • В начале конфига я указал свой домен, тему, ник и по 10 постов на страницу.
  • Потом поменял язык и удалил все старые языки.
  • Удалил настройку services: disqus, потому что не планирую пользоваться системой комментариев от них.
  • Указал иконку сайта, которую до этого закинул в static/favicon.ico.
  • Изменил дату создания сайта в футере на 2024 год.
  • Удалил стандартную настройку формата даты и времени dateFormat:.
  • Удалил sidebar: emoji, не понимаю зачем нужен смайлик в углу аватарки, мешает.
  • Изменил текст под аватаркой.
  • Временно выключил комментарии, но заранее указал, что движок будет remark42. Возможно я поменяю свой выбор, но сейчас мне это кажется самым простым и удобным вариантом. Минималистичное selfhost решение. Для меня главное не пользоваться услугами сторонних провайдеров.
  • В виджетах переместил архивы в самый низ, а облаку тегов увеличил лимит до 20.
  • В social добавил нужные мне ссылки, заранее скачав иконки для них из пака иконок этого сайта.

Вот код только с теми строками, которые я изменял. Прошлые значения, неизменённые и удалённые строки тут показаны не будут.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
baseurl: https://buliway.ru
languageCode: ru-RU
theme: hugo-theme-stack
paginate: 10
title: Buliway
copyright: Buliway

DefaultContentLanguage: ru

languages:
    ru:
        languageName: Russian
        weight: 1
        timeZone: Europe/Moscow
        params:
            description: Блог о программировании, Linux, эргономике и ЗОЖ # Это описание сайта, а не языка
            sidebar:
                subtitle: Люблю программирование, Linux, эргономику и ЗОЖ.
    en:
        languageName: English
        weight: 2
        params:
            description: Blog about programming, Linux, ergonomics and healthy lifestyle
            sidebar:
                subtitle: I love programming, Linux, ergonomics and healthy lifestyle.

permalinks:
    favicon: favicon.ico

    footer:
        since: 2024

    sidebar:
        # emoji: 🍥
        # subtitle: Люблю программирование, Linux, эргономику и ЗОЖ.

    comments:
        enabled: false
        provider: remark42

    widgets:
        homepage:
            - type: search
            - type: categories
              params:
                  limit: 10
            - type: tag-cloud
              params:
                  limit: 20
            - type: archives
              params:
                  limit: 5
        page:
            - type: toc

    social:
        - identifier: github
          name: GitHub
          url: https://github.com/Buliway/
          params:
              icon: brand-github

        - identifier: discord
          name: Discord
          url: https://discord.gg/MwKdpYujYh
          params:
              icon: brand-discord

        - identifier: telegram
          name: Telegram
          url: https://t.me/+q6STihSO6XQ4Mzhi
          params:
              icon: brand-telegram

        - identifier: email
          name: Email
          url: mailto:admin@buliway.ru
          params:
              icon: mail

Автоматически писать дату редактирования поста

Для этого надо инициализировать гит в основном каталоге проекта (мне пришлось удалить .git из каталога с темой) и в настройках hugo.yaml добавить такую настройку:

1
enableGitInfo: true

После этого всё должно работать. Теперь всё, что остаётся делать, это создавать коммиты в гите после каждого редактирования поста. Я в любом случае собирался это делать и загружать в свой приватный репозиторий, чтоб хранить всю историю изменений каждого из постов. При желании можно чуть донастроить. В одном гайде нашёл такой вариант:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
frontmatter:
	date:
	- date
	- publishDate
	- lastmod
	lastmod:
	- lastmod
	- :git
	- date
	- publishDate

Это тоже делается в hugo.yaml вместе с enableGitInfo: true. Тут мы настраиваем приоритеты. Допустим мы включили отображение lastmod по последней дате гита, но хотим иногда указывать эту дату руками в начале поста. Из коробки такое сделать не получится, потому что из коробки :git идёт первым в списке. В настройке выше мы это меняем, делая :git вторым, а ручное указание lastmod первым, что позволяет ставить руками дату редактирования поста, игнорируя дату коммита в гите.

P.S. Почему-то дата редактирования отображается не всегда. Например этот файл я создал 4 июля. Дату создания указал 5 июля (пробовал менять на 1 июля или даже июня, не помогло). Гит коммит сделал сейчас, 6 июля в 2 часа ночи. В самый первый пост, который про синтаксис написания статей, дата редактирования добавилась. Но в этот пост ничего не добавилось и я не знаю почему так…

Создано при помощи Hugo
Тема Stack, дизайн Jimmy