mirror of
https://github.com/foo-dogsquared/hugo-theme-contentful.git
synced 2025-01-31 10:58:07 +00:00
e2dbaf5d25
Still the same demo to be deployed, just on a different location than a separate branch this time.
209 lines
8.9 KiB
Plaintext
209 lines
8.9 KiB
Plaintext
---
|
|
title: "Extending Contentful"
|
|
date: 2020-05-12T17:25:55+08:00
|
|
|
|
categories:
|
|
- "guide"
|
|
tags:
|
|
- "theme"
|
|
- "extending"
|
|
---
|
|
|
|
= Extending Contentful
|
|
2020-05-12
|
|
|
|
Extending a Hugo theme is nothing new and a https://gohugo.io/content-management/sections/[few] http://hugocodex.org/add-ons/[places] provide a place for the most common extensions.
|
|
In this post, I'll be listing a few personal recipes I've always used for extending a Hugo theme.
|
|
Though this only applies specifically to Contentful and may need some tweaking when applying it other themes.
|
|
|
|
|
|
|
|
|
|
== Customizing your `<head>`
|
|
|
|
Let's start with the most basic and perhaps most useful customization: modifying the `<head`>.
|
|
This is useful for adding your own CSS and JavaScript files, changing certain metadata, or adding icons.
|
|
|
|
First, copy the `head` partial from the theme (`theme/contentful/layouts/partials/head.html`) to your own (`layouts/partials/head.html`).
|
|
We're simply taking advantage of https://gohugo.io/templates/lookup-order/[Hugo's lookup order] where we've override the `head` partial with our own copy.
|
|
|
|
Then, feel free to add your own (or others') scripts and stylesheets, https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML[icons and other metadata], or whatever suitable things.
|
|
|
|
In my case, I often use certain JavaScript libraries like https://www.mathjax.org/[MathJax] for mathematical typesetting, https://prismjs.com/[Prism] for syntax highlighting, and https://github.com/francoischalifour/medium-zoom/[medium-zoom] for interactive image zooms.
|
|
|
|
Here's the modified code.
|
|
(The example code is snipped for brevity.)
|
|
|
|
```go
|
|
<!--snip-->
|
|
|
|
{{- /* MathJax */ -}}
|
|
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
|
|
<script id="MathJax-script" defer src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
|
|
|
|
{{- /* Prism.js */ -}}
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/themes/prism-tomorrow.min.css" type="text/css">
|
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/components/prism-core.min.js"></script>
|
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/plugins/autoloader/prism-autoloader.min.js">
|
|
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.20.0/plugins/keep-markup/prism-keep-markup.min.js">
|
|
|
|
{{- /* medium-zoom */ -}}
|
|
<script defer src="https://cdn.jsdelivr.net/npm/medium-zoom@1.0.5/dist/medium-zoom.min.js"></script>
|
|
<script>window.addEventListener('load', () => mediumZoom('article img', { 'background': 'rgba(0, 0, 0, 0.75)' }))</script>
|
|
```
|
|
|
|
Since most of the JavaScript libraries used here are not really a requirement (except for MathJax for mathematical typesetting), I've set them to be loaded at the end of the page loading with https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script[`defer` attribute].
|
|
If you have an inline script, you can simply wrap it in an event listener for page loading (`window.addEventListener("load", your_function_goes_here)`).
|
|
|
|
If you want document-specific libraries, you have to pass some raw HTML through the parser of the document.
|
|
For Goldmark, the default Markdown parser starting https://gohugo.io/news/0.60.0-relnotes/[Hugo v0.60.0], blocks raw HTML by default and you can disable it by setting `markup.goldmark.renderer.unsafe` to `true`.
|
|
|
|
For Blackfriday, it parses even the raw HTML just fine.
|
|
Though, you have to set it as the default Markdown parser.
|
|
|
|
For https://asciidoctor.org/[Asciidoctor], you can use https://asciidoctor.org/docs/user-manual/#passthroughs[passthroughs] to get raw HTML through.
|
|
|
|
|
|
|
|
|
|
== Twitter cards
|
|
|
|
This will add https://developer.twitter.com/en/docs/tweets/optimize-with-cards/guides/getting-started[Twitter cards] for your webpages.
|
|
(Be sure to copy the `head` partial first in your own layout folder.)
|
|
|
|
Thankfully, Hugo already has https://gohugo.io/templates/internal/#twitter-cards[an internal template for Twitter cards].
|
|
Simply add `{{- template "_internal/twitter_cards.html" . -}}` somewhere in your own copy.
|
|
(For reference, https://github.com/gohugoio/hugo/blob/25a6b33693992e8c6d9c35bc1e781ce3e2bca4be/tpl/tplimpl/embedded/templates/twitter_cards.html[here's the source code for the internal template].)
|
|
|
|
You could also roll your own Twitter cards but I recommend to modify the internal template instead fitting your specific needs.
|
|
(Copy the internal template from the given link, create it as a partial in `layouts/partials/twitter_cards.html`, modify it, and insert the template with `{{- partial "twitter_cards.html" -}}`.)
|
|
|
|
|
|
|
|
|
|
== Open Graph protocol
|
|
|
|
Next up, we're implementing https://opengraphprotocol.org/[Open Graph protocol] for our webpages.
|
|
Commonly used for making suitable format when sharing the content on certain sites like Facebook.
|
|
(Be sure to copy the `head` partial first in your own layout folder.)
|
|
|
|
Similar to Twitter cards, Hugo has https://gohugo.io/templates/internal/#open-graph[an internal template for this].
|
|
Simply add `{{- template "_internal/opengraph.html" . -}}` somewhere in your own copy.
|
|
(For reference, https://github.com/gohugoio/hugo/blob/25a6b33693992e8c6d9c35bc1e781ce3e2bca4be/tpl/tplimpl/embedded/templates/opengraph.html[here's the source code for the internal template].)
|
|
|
|
If you want more control and customized version of the output, I recommend to copy the internal template and create a partial (e.g., `layouts/partials/opengraph.html`) and modify it.
|
|
|
|
|
|
|
|
|
|
== An archive page
|
|
|
|
This will add an archive page similar to archive pages https://davidtranscend.com/archives/[like] https://lukesmith.xyz/blogindex.html[these].
|
|
|
|
```go
|
|
{{- define "main" -}}
|
|
|
|
<h1>{{ .Title }}</h1>
|
|
|
|
{{ .Content }}
|
|
|
|
<hr>
|
|
|
|
{{- /* Creating a section that lists out regular pages by year */ -}}
|
|
{{ range $.Site.RegularPages.GroupByPublishDate "2006" }}
|
|
{{- /* Skip regular pages with an invalid creation date string. */ -}}
|
|
{{- /* This is convenient if we want to exclude certain posts to be listed by giving no value to `date` in the frontmatter. */ -}}
|
|
{{- /* We will also exclude hidden pages. */ -}}
|
|
{{ if ne .Key "0001" }}
|
|
<section data-year="{{ .Key }}">
|
|
<h2 id="{{ .Key }}">{{ .Key }}</h2>
|
|
<ul>
|
|
{{- range where .Pages "Params.hidden" "!=" true -}}
|
|
<li>
|
|
<date>{{ .Date.Format "2006-01-02" }}</date> -
|
|
<a aria-label="{{ .Title }}" href="{{ .Permalink }}">{{ .Title }}</a>
|
|
</li>
|
|
{{- end -}}
|
|
</ul>
|
|
</section>
|
|
{{- end }}
|
|
{{ end }}
|
|
|
|
{{- end -}}
|
|
```
|
|
|
|
We will simply add this as a layout in our customized theme.
|
|
Let's call it `archives` so we have to add a file in `layouts/_default/archives.html` then set a page of our project with the `layout` key in the frontmatter.
|
|
|
|
We want the archives page to be accessed at `$.Site.BaseURL/archives` so we'll simply create `archives.adoc` (https://gohugo.io/content-management/formats/#list-of-content-formats[any valid content files with certain file extensions can do], I'm using https://asciidoctor.org/[Asciidoctor]) with the following example content.
|
|
|
|
```asciidoctor
|
|
---
|
|
title: "Archives"
|
|
layout: "archive"
|
|
---
|
|
|
|
= Archives
|
|
|
|
This is the archives of the century.
|
|
```
|
|
|
|
|
|
|
|
|
|
== Configurable social media links
|
|
|
|
Most themes offer quick social media links with site configuration.
|
|
However, it is only limited to popular media sites such as Facebook, Twitter, Instagram, GitHub, etc.
|
|
|
|
To get around this, we'll make use of https://gohugo.io/templates/data-templates/[data templates].
|
|
Let's create a quick game plan how does it work.
|
|
|
|
The data is a top-level dictionary/object with each key contains an object with the following fields.
|
|
|
|
* `url` is the... contact link itself and it is required to have it.
|
|
|
|
* `name` is the text to appear in the output.
|
|
Also required to have.
|
|
|
|
* `weight` is an integer similar to how Hugo sorts the pages with the lower weight having high precedence;
|
|
if this key is absent, it will be interpreted as 0.
|
|
|
|
And here's the data example in TOML which is placed in `data/contact.toml`.
|
|
|
|
```toml
|
|
[github]
|
|
name = "GitHub"
|
|
url = "https://github.com/foo-dogsquared"
|
|
|
|
[gitlab]
|
|
name = "Gitlab"
|
|
url = "https://gitlab.com/foo-dogsquared"
|
|
|
|
[keybase]
|
|
name = "Keybase"
|
|
url = "https://keybase.io/foo_dogsquared"
|
|
weight = -1
|
|
|
|
[twitter]
|
|
name = "Twitter"
|
|
url = "https://twitter.com/foo_dogsquared"
|
|
```
|
|
|
|
I want my Keybase profile to appear first than anything else for whatever reason so the `weight` key is set to -1.
|
|
|
|
With this data, we can then create a template out of it.
|
|
I've put the following template in a partial named `contacts` (i.e., `layouts/partials/contacts`).
|
|
|
|
```go
|
|
<address>
|
|
{{- range (sort $.Site.Data.contact "weight" "asc") -}}
|
|
| <a rel="me" href="{{ .url }}">{{- .name -}}</a> |
|
|
{{- end -}}
|
|
</address>
|
|
```
|
|
|
|
A suggestion (and an exercise) for extending this is to create image links.
|
|
Maybe add another key named `image` that accepts either URL.
|
|
The `name` would now be the image alternative text.
|