мені вдалося перестворити щоденник: тепер він генерується за допомогою hugo замість jekyll, і хоститься на codeberg pages замість у мене на сервері; обслуговування й налаштування значно спростилися. але оформлення страшне — потрібно модифікувати тему, щоби щоденник виглядав принаймні читабельно; в ідеалі — якомога подібніше до попередньої версії (на ілюстрації). я дуже погано знаю html і css, доведеться експериментувати.

так виглядав щоденник tivasyk@home до міграції на hugo

тема як субмодуль?

більшість підказок в тенетах радять додавати тему як субмодуль (git submodule); мені це не підходить. в попередньому дописі я забув згадати, що мені довелося позбутися субмодуля:

це не найправильніший спосіб, але він простий. тепер можна скільки завгодно модифікувати тему в окремій гілці й випробовувати зміни локально.

перший експеримент

трохи потицькав css та шаблони горища (header), підвалу (footer) й допису; приблизно зрозумів, яке оформлення хочу (третє зображення на ілюстрації), і як його зробити. зрозумів також, що якщо не всю тему, то принаймні css доведеться повністю перероблювати: не зроблене воно по-людському.

для простоти й швидкості локальні blog.hugo та blog.content змонтовано (mount --bind) до blog.test, hugo перебудовує все повністю за найменшої зміни:

hugo server --forceSyncStatic --disableFastRender --source blog.test

деякий час не міг зрозуміти, як зручно відкрити інструменти відладки в qutebrowserʼі під сторінкою: :devtools bottom.

оригінальна тема hugo-xmin, і перший результат моїх експериментів

побудова сторінки

далі все буде дуже примітивно і нудно, але я вже визнав, що погано знаю html та css; мені потрібні нотатки, щоби скласти в голові цей пазл.

tree ~/blog/blog.hugo/themes/hugo-xmin -I 'exampleSite|archetypes|*.Rproj|*.md|images'
themes/hugo-xmin
├── layouts
│   ├── 404.html
│   ├── _default
│   │   ├── list.html
│   │   ├── single.html
│   │   └── terms.html
│   └── partials
│       ├── foot_custom.html
│       ├── footer.html
│       ├── head_custom.html
│       └── header.html
├── static
│   └── css
│       ├── fonts.css
│       └── style.css
└── theme.toml

сторінка зі звичайним дописом в hugo-xmin складається з трьох частин:

поки що майже нічого не модифікую, але виправляю побудову, бо те, що є в hugo-xmin, не дозволяє мені зробити деякі покращення.

горище

після переструктурування того, що було в темі:

┌─body─────────────────────────────────────────────────────┐
│┌─header─────────────────────────────────────────────────┐│
││    ┌─nav.header───────────────────────────────────┐    ││
││    │ ┌─a.logo──────┐         ┌─ul.menu──────────┐ │    ││
││    │ │ .Site.Title │         │ .Site.Menus.menu │ │    ││
││    │ └─────────────┘         └──────────────────┘ │    ││
││    └──────────────────────────────────────────────┘    ││
│└────────────────────────────────────────────────────────┘│
┊                                                          ┊

фрагмент header.html:

<html>
...
    <body>
        <header>
            <nav class="header">
                <a class="logo" href={{ .Site.BaseURL }}>{{ .Site.Title }}</a>
                <ul class="menu">
                  {{ range .Site.Menus.main }}
                  <li><a href="{{ .URL | relURL }}" class="menu">{{ .Name }}</a></li>
                  {{ end }}
                </ul>
            </nav>
        </header>

основа

коробочки:

┊                                                          ┊
│┌─main───────────────────────────────────────────────────┐│
││    ┌─article──────────────────────────────────────┐    ││
││    │ ┌─div.article-meta─────────────────────────┐ │    ││
││    │ │ h1.title                                 │ │    ││ 
││    │ │ span.date | span.author                  │ │    ││
││    │ └──────────────────────────────────────────┘ │    ││
││    │ .Content                                     │    ││
││    └──────────────────────────────────────────────┘    ││
│└────────────────────────────────────────────────────────┘│
┊                                                          ┊

файл single.html:

{{ partial "header.html" . }}

        <main>
            <article>
                <div class="article-meta">
                    <h1 class="title">{{ .Title | markdownify }}</h1>
                    {{ if (gt .Params.date 0) }}<span class="date">{{ .Date.Format "2006-01-02, 15:04" }}</span>{{ end }}
                    {{ with .Params.author }}<span class="date"> | {{ . }}</span>{{ end }}
                </div>
                {{ .Content }}
            </article>
        </main>

{{ partial "footer.html" . }}

підвал

коробочки:

┊                                                          ┊
│┌─footer─────────────────────────────────────────────────┐│
││    ┌─div.footer───────────────────────────────────┐    ││
││    │ .Site.Params.footer                          │    ││
││    └──────────────────────────────────────────────┘    ││
│└────────────────────────────────────────────────────────┘│
└─body─────────────────────────────────────────────────────┘

файл footer.html:

        <footer>
            <div class="footer">
                {{ partial "foot_custom.html" . }}
                {{ with .Site.Params.footer }}
                    {{ replace . "{Year}" now.Year | markdownify}}
                {{ end }}
            </div>
        </footer>
    </body>
</html>

геометрія і позиціонування

не знаю, наскільки страшно виглядала би сторінка, складена лише з цих «коробочок», але ще без стилювання геометрії та позиціонування в style.css, — бо я вже там потицькав трохи. по-перше, параметризація (за похардкоджені кольори й розміри відривав би рученята):

:root {
    /* основні розміри */
    --main_width: 800px;        /* ширина основної колонки */
    --main_padding: 1em;        /* внутрінші відступи праворуч, ліворуч в оновній колонці */
    --main_spacing: 3em;        /* інтервал між основною частиною і горищем, підвалом */
    --meta_spacing: 2em;        /* відступ у статті між заголовком і текстом */
    --head_size: 4em;           /* висота горища */
    --foot_size: 3em;           /* висота підвалу */
    --decoration_size: 3px;     /* товщина різних декорацій, акцентованих елементів */
    --text_padding: 1em;        /* внутрішні відступи для різних текстових полів */

позиціонування:

body {
    margin: 0;
    padding: 0;
}

/* горище */
header {
    width: 100%;
    height: var(--head_size);
    margin: 0;
    padding: 0;
    position: sticky;
    top: 0;
    z-index: 999;
}

nav.header {
    max-width: var(--main_width);
    margin: 0 auto;
    height: 100%;
    padding: 0 var(--main_padding);
    display: flex;
    justify-content: space-between;
    align-items: center;
}

a.logo { 
    display: inline-block;
}

.menu ul { display: inline-block; }

.menu li { display: inline-block; }

...

/* підвал */
footer {
    width: 100%;
    height: var(--foot_size);
    background-color: var(--color_plates);
}

div.footer {
    max-width: var(--main_width);
    height: 100%;
    display: flex;
    margin: auto;
    padding-left: var(--main_padding);
    padding-right: var(--main_padding);
    align-items: center;
}

/* основна частина */
main {
    width: 100%;
    margin: 0;
    padding: var(--main_spacing) 0;
}

article {
    max-width: var(--main_width);
    margin: auto;
    padding-left: var(--main_padding);
    padding-right: var(--main_padding);
}

.article-meta {
    margin-bottom: var(--meta_spacing);
}

.article-meta h1 { 
    margin: 0;
}

оформлення

шрифти

раніше пробував завантажувати веб-шрифти… але навіщо? не все, що має сенс в поліграфії, чи для великих комерційних проєктів, так само потрібно в малому вебі. цього разу все буде якомога простіше (файл fonts.css):

body {
    font-family: sans-serif;
}
main {
    font-family: serif;
}
.meta, table, h1, h2, h3, h4 {
    font-family: sans-serif;
}
code {
    font-family: monospace;
}

стилі css

залишилося «застилювати» оформлення, і базова сторінка з дописом готова. звісно, доведеться модифікувати й інші шаблони — переліки дописів тощо. враховуючи кількість змін відносно hugo-xmin, можна вже й тему якось інакше.

:root {
    /* основні розміри */
    --main_width: 800px;        /* ширина основної колонки */
    --main_padding: 1em;        /* внутрінші відступи праворуч, ліворуч в оновній колонці */
    --main_spacing: 3em;        /* інтервал між основною частиною і горищем, підвалом */
    --meta_spacing: 2em;        /* відступ у статті між заголовком і текстом */
    --header_size: 4em;         /* висота горища */
    --footer_size: 3em;         /* висота підвалу */
    --decoration_size: 3px;     /* товщина різних декорацій, акцентованих елементів */
    --text_padding: 1em;        /* внутрішні відступи для різних текстових полів */
    /* колірна палітра */
    --color_background: white;  /* колір тла */
    --color_text: black;        /* основний колір, найконтрастніший відтінок: текст. тонкі лінії */
    --color_plates: gainsboro;  /* світлий відтінок основного: плашки */
    --color_shaded: dimgrey;    /* темний відтінок основного: неосновний текст, додаткові елементи */
    --color_accent: orange;     /* додатковий колірний акцент */
}

body {
    /* геометрія */
    margin: 0;
    padding: 0;
    /* оформлення */
    background: var(--color_background);
}

/* горище */
header {
    /* геометрія */
    width: 100%;
    height: var(--header_size);
    margin: 0;
    padding: 0;
    position: sticky;
    top: 0;
    z-index: 999;
    /* оформлення */
    background-color: var(--color_plates);
    border-bottom: var(--decoration_size) solid var(--color_accent);
}

nav.header {
    /* геометрія */
    max-width: var(--main_width);
    margin: 0 auto;
    height: 100%;
    padding: 0 var(--main_padding);
    display: flex;
    justify-content: space-between;
    align-items: center;
    /* оформлення */
}

a.logo { 
    /* геометрія */
    display: inline-block;
    /* оформлення */
    font-weight: bold;
    font-size: 1.1em;
    color: var(--color_text);
    text-decoration: none;
}

.menu ul { display: inline-block; }

.menu li { display: inline-block; }

.menu a {
    color: var(--color_text);
    padding: 0 0.3em; 
}
.menu a:link { text-decoration: none; }
.menu a:hover { text-decoration: underline; }
.menu a:active { text-decoration: underline; color: var(--color_accent); }
.menu a:visited { text-decoration: none }

/* підвал */
footer {
    /* геометрія */
    width: 100%;
    height: var(--footer_size);
    background-color: var(--color_plates);
    /* оформлення */
    border-top: 1px solid var(--color_shaded);
}

div.footer {
    /* геометрія */
    max-width: var(--main_width);
    height: 100%;
    display: flex;
    margin: auto;
    padding-left: var(--main_padding);
    padding-right: var(--main_padding);
    align-items: center;
}

footer a { color: var(--color_text); }
footer a:link { text-decoration: none; }
footer a:hover { text-decoration: underline; }
footer a:active { text-decoration: underline; color: var(--color_accent); }
footer a:visited { text-decoration: none }

/* основна частина */
main {
    /* геометрія */
    width: 100%;
    margin: 0;
    padding: var(--main_spacing) 0;
}

article {
    /* геометрія */
    max-width: var(--main_width);
    margin: auto;
    padding-left: var(--main_padding);
    padding-right: var(--main_padding);
    /* оформлення */
    line-height: 1.5;
}

.article-meta {
    /* геометрія */
    margin-bottom: var(--meta_spacing);
    /* оформлення */
    text-decoration: none;
}

.article-meta h1 { 
    /* геометрія */
    margin: 0;
    /* оформлення */
    font-size: 2em; 
    text-align: left;
}

span.meta {
    /* оформлення */
    color: var(--color_shaded);
}

article a { color: var(--color_text); }
article a:link { color: var(--color_text); }
article a:hover { text-decoration: underline; }
article a:active { text-decoration: underline; color: var(--color_accent); }
article a:visited { text-decoration: none }

hr {
  border-style: solid;
  color: var(--color_shaded);
}

article h1, h2, h3, h4, h5 {
    text-align: left;
}

article p {
    hyphens: auto; 
    text-align: justify;
}

article li {
    text-align: left;
    margin-right: var(--text_padding);
}

/* code */
pre {
  /* геометрія */
  border-left: var(--decoration_size) solid var(--color_accent);
  border-top: 1px solid var(--color_plates);
  box-shadow: var(--decoration_size) var(--decoration_size) var(--decoration_size) var(--color_plates);
  padding: var(--text_padding);
  overflow-x: auto;
  /* оформлення */
  line-height: 1.1;
}

/* цитати */
blockquote {
  background: var(--color_plates);
  border-left: var(--decoration_size) solid var(--color_accent);
  padding: var(--text_padding);
}

/* таблиці */
table {
  margin: auto;
  border-top: 1px solid var(--color_plates);
  border-bottom: 1px solid var(--color_plates);
}

table thead th { border-bottom: 1px solid var(--color_plates); }
th, td { padding: var(--decoration_size); }
thead, tfoot, tr:nth-child(even) { background: var(--color_plates); }

/* misc elements */
img, iframe, video { max-width: 100%; }

структура сайту

не зовсім про оформлення: під час міграції я втратив організацію сторінок (обкладинка, архів, пошук тощо); зараз навігація сайтом… гхм, примітивна: hugo-xmin просто вивалює на обкладинку повний перелік усіх сторінок сайту (це 2 тисячі з гаком посилань). треба щось робити, і це буде наступний етап. чіткого плану немає, щось таке в голові:

використана документація та підказки