Help:Blog
Create a Blog Post.
Location
Directory | Description |
---|---|
./content/<Language>/blog/ | The base directory of the blog |
Create a New Blog Page
To create a new page, use the command npm run create -- 'blog/<year>/<pageName>.md'
.
After that you can edit your newly created page, which is located in content/en/blog/<year>/<pageName>.md
.
Example
Create a new page foo
:
$ npm run create -- 'blog/2024/foo.md'
>[email protected] create
> exec-bin node_modules/.bin/hugo/hugo new "blog/2024/foo.md"
Content "/home/username/path_to_repository/repository_root_directory/content/en/blog/2024/foo.md" created
Front Matter
Every Markdown file contains a header section, called front matter, in the YAML format to configure parts of the page or website. A blog page needs the following variables in the front matter.Variable | Type | Description |
---|---|---|
title | str | The title of the page or ressource |
description | str | The page description, normally for SEO |
lead | str | The page description shown after the title or in cards |
date | datetime | The datetime the page was created |
lastmod | datetime | The datetime the page was modified. Should be the same as date when the creating a new page |
draft | bool | flase shows the page, true hides the page,
as it does not exist |
weight | int | The weight, or priority of the page for page sorting |
images | list of
str | Images, which will be converted and moved to the static directory. Remember to add every image you used here |
math | bool | This page contains LaTeX math. This option preloads the font and includes the KaTeX script in the script footer. |
contributors | list of
str | A list of contributors |
floating_image | A image, which should be placed floating next to the content | |
floating_image_width | The width of the image in percent of the pages width | |
floating_image_position | The position of the image, which can be either left or right | |
floating_image_caption | The caption the image should have | |
header_image | A image, which will be placed between the header and the lead with a 100% width |
The Datetime Type
The date and time according to ISO 8601 . The following table shows the extended format specified in ISO 8601 we use for our website to specify, when e.g. a page was created or edited. It has three parts:
- the date
- the time, including it's designator
T
- the timezone offset
Value | Optional | Description |
---|---|---|
2021 | No | Year |
07 | No | Month |
08 | No | Day of the month |
T | No | T is a designator, which indicates the start of the time representation |
12 | No | Hour |
34 | No | Minute |
56 | No | Second |
+ or - | Yes | + for a positive or - a negative timezone
offset |
01 | Yes | Timezone offset in hours |
02 | Yes | Timezone offset in minutes |
Formatting Examples
The following example uses the values from the table to show the format. It does not use the actual UTC. If you are not using the timezone offset, you must calculate UTC yourself.
- Example with timezone offset:
2021-07-08T12:34:56+01:02
- Example without timezone offset:
2021-07-08T12:34:56
Header Example
Remember, the front matter is aYAML
structure embedded into the
Markdown file. The ---
delimiters signal Hugo that this is a front
matter in the YAML
format. Here is a generated example, how the
front matter might look like:
---
title: "MyTitle"
description: "A description of the page content"
lead: "A lead to the page content"
date: 2021-10-08T14:48:42+01:00
lastmod: 2021-10-08T14:48:42+01:00
draft: false
weight: 50
images: ["avatar.svg" "foo.svg" "bar.svg"]
math: true
contributors: ["UserA" "UserB" "UserC"]
floating_image: "foo.svg"
floating_image_width: 50
floating_image_position: "right"
floating_image_caption: "A optional caption line"
header_image: "foo.svg"# This is an example for a comment in YAML
---
Notice, the weight
in blog posts is always 50
.
Code
Below you find the implementation of the layout.
HTML
Single Page Layout
Defined in layouts/blog/single.html
.
{{/*<!--
Blog Layout
===========
Contributors: Michael Sasser
Maintainer: Michael Sasser
License: MIT
Version: 1
Type: Single
LAYOUT: /layouts/blog/single.html
DOCS: /content/<language>/wiki/Help:Layout_Blog.md
STYLE: /assets/scss/layouts/_docs.scss
Description
-----------
The single layout page for the blog.
Changelog
=========
Version 1
---------
Initial release
-->*/}}
{{ define "main" }}
<div class="container">
<div class="section pt-5 pb-0">
<a href="/blog/">← Back to blog</a>
<div class="row g-5 justify-content-center">
<div class="col-md-12 col-lg-9 col-xl-9">
<article class="blog-post">
<div class="blog-header">
{{ if isset .Params "header_image" }}
<div class="text-center">
<figure>
<img
data-sizes="auto"
class="img-fluid
{{ if eq .Site.Params.options.lazySizes true -}}
lazyload blur-up
{{ end }}"
src="{{ .Params.header_image }}"
/>
</figure>
</div>
{{ end }}
<h1 class="blog-post-title">
{{ .Title }}{{ if eq .Draft true }}
<span class="badge bg-danger">Draft</span>
{{ end }}
</h1>
<p class="blog-post-meta">
{{ partial "main/blog-meta.html" . }}
</p>
</div>
<p class="lead">{{ .Params.lead | safeHTML }}</p>
<div class="clearfix">
{{ if isset .Params "floating_image" }}
{{ $width := 50 }}
{{ $position := "right" }}
{{ $margin := "left" }}
{{ $margin_bot := "0" }}
<!-- width -->
{{ if isset .Params "floating_image_width" }}
{{ $width = .Params.floating_image_width }}
{{ end }}
<!-- bot margin -->
{{ if isset .Params "floating_image_margin_below" }}
{{ if eq .Params.floating_image_margin_below "true" }}
{{ $margin_bot = "32" }}
{{ end }}
{{ end }}
<!-- position -->
{{ if isset .Params "floating_image_position" }}
{{ if ne .Params.floating_image_position "right" }}
{{ $margin = "right" }}
{{ if ne .Params.floating_image_position "left" }}
{{ errorf "Failed to set the floating image position to: %s. The image position must be \"left\" or \"right\"." .Params.floating_image_position }}
{{ end }}
{{ end }}
{{ $position = .Params.floating_image_position }}
{{ end }}
<figure
style="max-width: {{ $width }}%;
float:{{ $position }};
margin-{{ $margin }}: 30px;
margin-bottom: {{ $margin_bot }}px;
margin-top: 0;
"
>
<img
data-sizes="auto"
class="img-fluid
{{ if eq .Site.Params.options.lazySizes true -}}
lazyload blur-up
{{ end }}"
src="{{ .Params.floating_image }}"
/>
{{ if isset .Params "floating_image_caption" }}
<figcaption class="figure-caption">
<center>
<em>{{ .Params.floating_image_caption | safeHTML }}</em>
</center>
</figcaption>
{{ end }}
</figure>
{{ end }}
<p>{{ .Content }}</p>
</div>
<div class="blog-data-section">
<!-- Last time edited -->
{{ if ne .Page.Date .Page.Lastmod }}
<p class="blog-post-updated text-muted ">
This blog post was updated on
{{ .Page.Lastmod.Format "January 2, 2006" -}}
</p>
{{ end }}
<table class="blog-data-table">
<tr>
<!-- Categories table head-->
{{ if isset .Params "categories" }}
<th>
<h5><i class="fa fa-folder-open"></i> Categories</h5>
</th>
{{ end }}
<!-- Tags table head-->
{{ if isset .Params "tags" }}
<th>
<h5><i class="fa fa-tag"></i> Tags</h5>
</th>
{{ end }}
</tr>
<tr>
<!-- Categories-->
<td>
{{ with .Params.categories }}
{{ range $index, $category := . -}}
{{ if gt $index 0 -}}
{{ if eq $index (sub (len $.Params.categories ) 1) }}
<span> and </span>
{{ else -}}
<span>, </span>
{{ end -}}
{{ end -}}<a
class="stretched-link position-relative"
href="{{ "/categories/" | relURL }}{{ . | urlize }}/"
>{{ . | title }}</a
>
{{- end }}
{{ end }}
</td>
<!-- Tags -->
<td>
{{ with .Params.tags }}
{{ range $index, $category := . -}}
{{ if gt $index 0 -}}
{{ if eq $index (sub (len $.Params.tags ) 1) }}
<span> and </span>
{{ else -}}
<span>, </span>
{{ end -}}
{{ end -}}<a
class="stretched-link position-relative"
href="{{ "/categories/" | relURL }}{{ . | urlize }}/"
>{{ . | title }}</a
>
{{- end }}
{{ end }}
</td>
</tr>
</table>
</div>
</article>
{{ partial "main/blog-navigation.html" . }}
</div>
{{ partial "main/blog-sidebar.html" . }}
</div>
</div>
</div>
{{ end }}
List Page Layout
Defined in layouts/blog/list.html
.
{{/*<!--
Blog Layout
===========
Contributors: Michael Sasser
Maintainer: Michael Sasser
License: MIT
Version: 1
Type: List
LAYOUT: /layouts/blog/list.html
DOCS: /content/<language>/wiki/Help:Layout_Blog.md
STYLE: /assets/scss/layouts/_docs.scss
Description
-----------
The list layout page for the blog.
Changelog
=========
Version 1
---------
Initial release
-->*/}}
{{ define "main" }}
<!-- Get the last element from the current URL -->
{{ $lastUrlElement := index (last 1 (split (delimit (split .Permalink "/") "," "") ",")) 0 }}
<!-- Page is blog or blogpage for a specific year -->
{{ $is_blog := false }}
{{ if (eq $lastUrlElement "blog") }}
{{ $is_blog = true }}
{{ end }}
<!-- Check if path for pagination should be /blog/ or /blog/<year>/ -->
{{ $current := "" }}
{{ if eq $is_blog true }}
{{ $current = (where .Site.RegularPages "Section" "blog") }}
{{ else }}
{{ $current = .Data.Pages }}
{{ end }}
<div class="container">
<section class="section pt-5 pb-0">
{{ if eq $is_blog false }}
<a href="/blog/">← Back to blog</a>
{{ end }}
<div class="row">
<div class="col-12 col-xl-9 col-4xl-10">
{{ if eq $is_blog false }}
<h1 class="pb-4 mb-4 fst-italic">
Archive —
{{ $lastUrlElement }}
</h1>
{{ end }}
<div class="container">
<div class="row g-5">
<!-- Setup paginate from "current" -->
{{ $paginator := .Paginate $current -}}
{{ range $paginator.Pages -}}
<div class="col-12 col-4xl-6 ">
{{ partial "main/blog-post-list-layout.html" . -}}
</div>
{{ end -}}
</div>
</div>
<!-- Pagination -->
<div class="pagination justify-content-center">
{{ $.Scratch.Set "paginator" true }}
{{ template "_internal/pagination.html" . }}
</div>
</div>
{{ partial "main/blog-sidebar.html" . }}
</div>
</section>
</div>
{{ end }}
SCSS
Defined in assets/scss/layouts/_blog.scss
.
/*
Blog Layout
===========
Contributors: Michael Sasser
Maintainer: Michael Sasser
License: MIT
Version: 1
Type: List, Single
LAYOUT: /layout/blog/*
DOCS: /content/<language>/wiki/Help:Layout_Blog.md
STYLE: /assets/scss/layout/_blog.scss
Reporting Issues Shortcode
==========================
LAYOUT: /layouts/shortcodes/reporting_issues.html
STYLE: /assets/scss/components/_shortcode_identifier.scss
DOCS: /content/<language>/wiki/Help:Shortcode_Reporting_Issues.md
*/
/* Needs cleaning */
.blog-meta {
display: flex;
align-items: flex-start;
justify-content: space-between;
.image {
border-radius: 50%;
display: block;
}
.name {
font-weight: 400;
line-height: 26px;
// TODO
font-size: 16px;
}
.data {
font-weight: 400;
// TODO
font-size: 14px;
}
.link {
color: gray;
}
img {
border-radius: 50%;
color: gray;
}
}
.blog-author {
float: left;
font-size: 14px;
letter-spacing: 0.05em;
}
.blog-date {
text-align: right;
font-size: 14px;
letter-spacing: 0.05em;
}
.blog-continue-reading {
text-align: right;
a {
text-transform: capitalize;
font-size: 14px;
letter-spacing: 0.05em;
}
}
.blog-widget {
padding: $spacer * 1.5; /* p-4 */
}
.blog-widget-btn {
a {
text-transform: capitalize;
font-size: 14px;
}
}
.blog-navigation a {
font-size: $font-size-base * 0.9;
}
.blog-tags {
list-style: none;
padding-left: 0;
margin-bottom: 0;
li {
display: inline-block;
a {
display: inline-block;
border: solid 1px $gray-300;
border-radius: 0;
margin: 5px 5px 5px 0;
padding: 5px;
font-size: 14px;
letter-spacing: 0.05em;
text-transform: capitalize;
}
}
}
.blog-post-updated {
margin-top: 2em;
text-align: right;
font-size: 14px;
}
.blog-data-section {
border-top: 1px solid;
margin-top: 2em;
margin-bottom: 2em;
}
.blog-data-table {
table-layout: fixed;
width: 100%;
margin-top: 2em;
margin-bottom: 45px;
h5 {
margin-top: 0;
margin-bottom: 0;
}
th,
tr,
td {
border: none;
}
}
.blog-navigation {
margin-top: 2rem;
margin-bottom: 0;
padding-top: 2rem;
}
@include media-breakpoint-up(lg) {
.blog-navigation {
margin-bottom: -1rem;
}
.blog-navigation a {
font-size: $font-size-base;
}
}
.blog-navigation table {
margin-top: 20px;
margin-bottom: 20px;
th,
tr,
td {
border: none;
}
td {
padding-top: 0;
padding-bottom: 0;
}
.right {
text-align: right;
}
.left {
text-align: left;
}
.glyph {
vertical-align: middle;
text-align: center;
font-size: $font-size-base * 1.25;
}
.next-prev {
font-size: $font-size-base;
}
.title {
font-weight: bold;
}
}
@include color-mode(dark) {
.blog-tags {
li {
a {
border: solid 1px $gray-800;
}
}
}
.blog-data-section {
border-top: 1px solid #343a40;
}
}
Archetype
Defined in archetypes/blog.md
.
---
title: "{{ replace .Name "-" " " | title }}"
description: ""
lead: ""
date: {{ .Date }}
lastmod: {{ .Date }}
draft: true
weight: 50
contributors: []
categories: []
tags: []
images: ["{{ .Name | urlize }}.jpg"]
header_image: ""
floating_image: ""
floating_image_width: 40
floating_image_position: "right"
floating_image_caption: ""
---
Categories | Contributors |
---|---|
Help, Contribute and Layout | Michael Sasser |