/hugo-theme-more-contentful

A revamped batteries-included version of the Hugo theme Contentful.

Primary LanguageHTML

hugo-theme-more-contentful

The project logo (for the kicks)

A batteries-included version of the Contentful Hugo theme. It features modern aesthetics and some optimizations making full use of Hugo's feature set while using as less dependencies as possible.

Tested primarily with Chromium-based and Firefox-based browsers.

Demo

But first, a quick screenshot of the theme.

The theme in desktop-sized windows.

An example of a Hugo project configured with this theme is available at ./exampleSite/ directory. It is automatically deployed with GitHub workflow and its output is available in https://foo-dogsquared.github.io/hugo-theme-more-contentful. It also provides an example how to deploy your Hugo site with GitHub Pages and how to use and configure this theme.

Feature list

Like the original theme, the best way to describe it is with a list. The following features highlights the differences from the original.

  • Batteries-included theme with a revamped appearance.

  • Clean(er) reader mode interface for a nice reading experience for your readers.

  • Uses SCSS instead of CSS for more concise formatting. [1]

  • More colors with a base-16-based color scheme. [1]

  • Create more custom color schemes easily with Base16 color schemes without touching any CSS! [1]

  • Link your social media platforms with icons from the entire set from Simple Icons featuring more than 2000 icons!

  • With most of the features retained from the original theme (except fancier).

This is mainly for personal blogs running a one-man show. [2]

Project goals

  • Create a batteries-included theme that is easy to extend and/or modify.

  • Focus on the ease of migration of content and data in case the user wants to switch themes.

  • Accessibility for people with disabilities (PWD).

  • Make the theme browsable with the following text browsers:

  • Low performance budget of 30KB or even less, must load under 1 second on a mobile 3G connection, and has a Lighthouse score of >90. [3]

  • Make the theme functional on <noscript> (preferably testing with LibreJS extension).

Non-goals

  • Include all of the modern things commonly found on today’s web sites (or even Hugo themes). It may not fit with the requirements that a complex project demands. Thus, it is encouraged that the author should modify according to their settings.

  • Make every possible option as a setting or a toggle switch.

Getting started

Prerequisites

As a prerequisite, you need the following programs installed.

  • Hugo v0.95.0 extended version and above.

  • The latest version of Go runtime installed (as of 2020-11-01, the latest version is v1.15).

  • Git since the project uses as the version control system.

The latter two are needed as this theme makes heavy use of Hugo modules.

Note
To verify you’ve the extended version installed, run hugo version and look for the extended keyword in the result (e.g., hugo version | grep "extended").

Installation

There are different ways to install a Hugo theme but I recommend using the Hugo modules especially now that this method is starting to get widespread.

Hugo modules

First, you need to initialize your Hugo project as a Hugo module. This can be done by running hugo mod init $HUGO_MODULE_PATH.

Then, you can import the Hugo module in your site config.

[[module.imports]]
  path = "github.com/foo-dogsquared/hugo-theme-more-contentful"

It is also recommended to specify the tag (e.g., hugo-theme-more-contentful@v1.2.3) or the commit (e.g., hugo-theme-more-contentful@abcdefg) to prevent stray updates for the theme. For more information, you can see how to specify Go modules since Hugo modules are built on top of it.

Next, get the dependency by running hugo mod get and to update the component, run hugo mod get -u. (You could also run the server [i.e., hugo server] to download the modules.)

If you want to fully modify the theme yourself, you can use hugo mod vendor.

The theme folder

Caution
It is recommended to use the Hugo module method instead.

You can install the theme by putting this project in themes/. Since this project is using a Git repo, you can simply git clone the project. You should also checkout into the version tag

git clone https://github.com/foo-dogsquared/hugo-theme-more-contentful themes/more-contentful

If you intend to vendor this for major modifications, you can store the project as a Git submodule (e.g., git submodule add $GIT_REPO) or a Git subtree (e.g., git subtree add --prefix ./themes/more-contentful $GIT_REPO --squash).

After installation

Setting up shop for your new blog, there are some things this theme expects in order for things to just work.

  • Favicon are expected to be in $BASE_URL/favicon.png. This means you can simply plop the appropriate file in the static folder (i.e., static) of your project.

  • Markdown documents are the main supported markup format. Though Hugo do support other markup formats (e.g., Asciidoctor, org-mode), the layout and style is more expected for Markdown documents. Otherwise, you would have additional CSS styles to support those formats on your own.

  • There are things to configure most of which are mentioned in the Configuration section. Some things include Creating your own color scheme for your website to stand out and Authors to set the appropriate metadata for content authors.

Configuration

This theme, like the original, tries to use as little custom parameters as possible. In fact, you can get started with only the title key in the site config and you’ll be fine.

I’ll let the config do the talking. If you want to know more details about the additional Hugo modules, simply visit the path as a URL in your browser.

baseURL = "https://example.com"
title = "Contentful"
enableGitInfo = true
paginate = 20


[module]
  [[module.imports]]
    path = "github.com/foo-dogsquared/hugo-theme-more-contentful"
  [[module.imports]]
    path = "github.com/foo-dogsquared/hugo-web-feeds"


[author.john_doe]
     name = "John Doe"
     email = "johndoe@example.com"

[author.jane_doe]
    name = "Jane Doe"
    email = "jane_doe_1995@example.com"


[languages]
    [languages.en]
        # This key is used for more readable links to translated versions.
        languageName = "English"

    [languages.tl]
        languageName = "Tagalog"


[mediaTypes]
    [mediaTypes."application/atom+xml"]
        suffixes = ["atom"]

    [mediaTypes."application/rss+xml"]
        suffixes = ["rss"]


[outputFormats]
    [outputFormats.RSS]
        mediaType = "application/rss+xml"
        baseName = "index"

    [outputFormats.Atom]
        mediaType = "application/atom+xml"
        baseName = "index"


[outputs]
    home = ["HTML", "RSS", "ATOM", "JSON"]
    section = ["HTML", "RSS", "ATOM", "JSON"]


[menu]
    [[menu.main]]
        name = "About"
        url = "about/"

    [[menu.main]]
        name = "Categories"
        url = "categories/"

    [[menu.main]]
        name = "Tags"
        url = "tags/"


[params]
    # Enable table of content generation (only valid for Markdown and Asciidoctor files to be parsed by Hugo's built-in parsers).
    toc = true

    # Sections that should be included in the homepage.
    mainSections = [ "posts", "recipes", "projects" ]

As for the page variables, it uses no custom frontmatter variables. For more information, you can refer to the predefined variables that Hugo accepts.

Site configuration keys

Here are some of the assumptions made with certain keys from the site configuration:

  • copyright is a Markdown string to be rendered in the footer.

  • params.mainSections is a list of terms from the site sections for its pages to be listed in the homepage (e.g., a value of [ "posts" "projects" ] lists all of the pages under posts and projects).

  • params.toc contains a boolean value to indicate whether a table of content should be present.

Authors

Despite this theme is aimed for personal blogs, it has support for multiple authors. As hinted from the example configuration, the author site parameter (i.e., $.Site.Author) is a map of objects. The author object only requires a value for name key. You can also add more keys for more metadata.

An example of indicating authors in the site configuration
[author.john_doe]
    name = "John Doe"
    email = "john_doe@example.com"
    birthdate = "1996-01-12"

[author.jane_doe]
    name = "Jane Doe"

Indicating the author(s) is also the same with content pages.

For completeness and best practice, the author object should be structured with the following schema.

  • name (string), as already mentioned, is the name of the author.

  • url (string) that points to the homepage (or whatever link of their choosing) of the author.

  • email (string) for the author’s public email.

  • img (string) points to a URL of the profile image of the author. It can also point relative to the Hugo project root.

Creating your own color scheme

Creating your own color scheme has been simplified with the use of data templates. Furthermore, with asset bundling, CSS variables, and SCSS, it is ensured that all of the schemes will be kept in one resulting stylesheet.

Note
In case you want to modify the stylesheet, the website has been styled according to the Base16 styling guidelines with some liberties applied. Not all Base16 color schemes follow the guideline strictly so it may result in a bad-looking color palette of the website.

To create a color scheme, simply place a Base16 color scheme data file in data/more-contentful/themes/. For example, take the default Base16 dark scheme which is also the default scheme for this theme.

scheme: "Default Dark"
author: "Chris Kempson (http://chriskempson.com)"
base00: "181818"
base01: "282828"
base02: "383838"
base03: "585858"
base04: "b8b8b8"
base05: "d8d8d8"
base06: "e8e8e8"
base07: "f8f8f8"
base08: "ab4642"
base09: "dc9656"
base0A: "f7ca88"
base0B: "a1b56c"
base0C: "86c1b9"
base0D: "7cafc2"
base0E: "ba8baf"
base0F: "a16946"

The schemes are then pressed against a template (i.e., ./assets/templates/theme.scss) then added to the resulting stylesheet.

[data-theme="Default Dark"]:root {
  --base00: #181818;
  --base01: #282828;
  --base02: #383838;
  --base03: #585858;
  --base04: #b8b8b8;
  --base05: #d8d8d8;
  --base06: #e8e8e8;
  --base07: #f8f8f8;
  --base08: #ab4642;
  --base09: #dc9656;
  --base0A: #f7ca88;
  --base0B: #a1b56c;
  --base0C: #86c1b9;
  --base0D: #7cafc2;
  --base0E: #ba8baf;
  --base0F: #a16946; }

By default, this theme enforces setting system themes with a light and a dark theme. You can set the custom themes for both system light and dark theme for your website by naming them _light.{json,toml,yaml} and _dark.{json,toml,yaml}, respectively. This theme has kept some usecases in mind:

  • If either theme is missing, the theme will generate one for you with the assumption that the user-given color scheme is set correctly (e.g., _dark is a dark theme and the theme will generate a light theme). The color generation for the counterpart theme is not yet great (or even acceptable) so it is recommended to handcraft both of the system themes.

  • If neither system themes are given, the Hugo theme will use the fallback system themes which can be found at ./data/more-contentful/themes. The fallback themes are named _{dark,light}_fallback.yaml. It is discouraged to change or override them.

For practical purposes, you should build your own color palette. The theme is styled closer to color schemes that can have a suitable palette with 3 colors such as Nord, default-dark, Dracula, and Solarized. I recommend creating a color scheme closer to their practices. Nord has a comprehensive documentation on the colors and palettes which can be a good starting point. If you’re feeling a bit lazy, you can easily create one with a brand color palette generator or a Base16-compatible color generator like the one found in terminal.sexy.

Social icons

Unlike most themes which features limited amount of social media icons, this theme offers the full icon set from Simple Icons offering more than 1400 icons [4] made possible with Hugo modules. (Bonus feature of not installing with Node but you do have the Go runtime and Git installed, right?)

To do so, you need to create a file at data/more-contentful/contacts.{json,toml,yaml}. The data needs to be a top-level object with specific keys.

  • useImage (boolean) is an optional key indicating to display the social links as an image. If disabled, which is the default value, it will display the text.

  • links (array of objects) is the main attraction with a list of your links. It is an array of objects with each object can contain the following keys.

    • id (string) is a required key used as an identifier for the link. Despite the name, it is also used as the file name of the icon in the Simple Icons set. To search for the icon, search for the icon file name from the source.

    • url (string) is a required key referring to the URL of your platform.

    • name (string) is an optional key and contains the text to be displayed when you don’t want to show the icons. It is also used as the aria-label value if present.

    • weight (integer) accepts an integer dictating the order of the links. It is optional and has a default value of 0. The icon object with the smallest weight will be the first to appear in the list (then the second smallest and so forth). If a link object has the same weight, it will be ordered alphabetically by its id.

Consider the example that I have a list of social media accounts and want my Keybase account to be listed first. Thus, the related object will have a weight of -1.

useImage = false

[[links]]
id = "twitter"
url = "https://twitter.com/foo_dogsquared"
name = "Twitter"

[[links]]
id = "github"
url = "https://github.com/foo-dogsquared/"
name = "GitHub"

[[links]]
id = "gitlab"
url = "https://gitlab.com/foo-dogsquared/"
name = "GitLab"

[[links]]
id = "keybase"
url = "https://keybase.io/foo_dogsquared"
name = "Keybase"
weight = -1
social icons config output
Figure 1. The resulting social media footer with the given configuration.

If the social platform icon is not included in the icon set, it will not have any fallback. Thus, it is recommended to display the text (i.e., useImage = false) instead.

Extending the theme

There are mainly two situations when you customize the theme.

  • You want to customize a part of theme while making use the official version.

  • You want to branch off and fully customize the theme according to your vision.

If you belong in the former, you could override the theme by copying the file from the theme to the equivalent location from your project root. For a concrete example, if you want to customize the footer, copy ./layouts/partials/footer.html of this theme (e.g., ./themes/more-contentful/layouts/partials/footer.html) to ./layouts/partials/footer.html and modify it there.

If you want to customize the style, simply create a SCSS file at assets/scss/extend.scss and make your style there. One of the main things you should keep in mind is the Base16 color palette available in the stylesheet if you want a consistent look. They are available as CSS custom properties from base00 to base0F. They could be useful if you want to add your own styling or to integrate with other libraries such as D3, Mermaid, and Prism.

The downside when customizing it partially, updating the theme can be problematic. Thus, it is recommended to check out the project if its updated. Fortunately, this could be automated with the use of the GitHub API and a JSON parser such as jq which makes it possible to update it in the shell. The following shell one-liner gets the latest version of the theme.

curl --silent --location https://api.github.com/repos/foo-dogsquared/hugo-theme-more-contentful/commits | jq '.[0].sha' --raw-output | xargs --replace='{}' hugo mod get -u "github.com/foo-dogsquared/hugo-theme-more-contentful@{}" && hugo mod tidy
Tip
You can then put the one-liner in a script or in a Makefile to make it easier.

Otherwise, if you want to fully customize the theme, you can vendor this project into yours. Also, see the Development guidelines for more information.

  • The recommended way is to fork the project, make your customizations there, and use it.

  • If you use Hugo modules, you can run hugo mod vendor and it will pull the files in _vendor/.

  • If you don’t want to create another repo for the customized version of the theme intended only for one Hugo site, make the project as a a Git subtree preferably in themes/more-contentful/.

Theme conventions and guidelines

If you’re planning on extending the theme, warts and all, it can be frustrating to start by diving into the source code head-first. Here’s a list of guidelines and conventions that the theme uses. It isn’t exhaustive but it is a start.

Like most guidelines, they are not followed to the absolute and not set in stone. You can also see the Development guidelines for more details.

  • For editing the CSS files…​

    • It uses BEM-style class names.

    • Each of the theme will generate a custom property of --base00, --base01, --base02 up to --base0F. This should be treated as a palette, nothing more.

    • To set a color with a role, put it under a custom property and use that instead (e.g., if --base05 will be used mainly for text color, then create a custom property named --text-color to be used for any text-related styles that changes its color). This will make maintaining the theme easier. You can see a sample of this from ./assets/scss/main.scss defined at :root.

    • Place all CSS global variables at ./assets/scss/main.scss.

  • For setting assets in the theme, SVG icons are preferred. It should be optimized or sanitized to be able to easily set the color along with the text. In this case, the theme has a preferred use for Heroicons which has the added bonus of consistency.

  • If an element should hold stateful data, make full use of data-* attributes.

  • Don’t place <script> snippets at the end of the <body> mindlessly.

Development guidelines

This theme should provide an intuitive and smooth developer experience (DX) for more potential to new contributions and easier time customizing this theme.

In order to provide that, there should be an established guidelines for development. The following exhaustive list sets the following:

  • Install an EditorConfig plugin for your text editor. If it’s not possible, follow the the EditorConfig config.

  • For theme-specific data templates, the data should be pulled from ./data/more-contentful/ directory. This is to make data migration easier for the user in case they want to switch themes.

  • If the partial is small enough (<60 lines), you should include them in ./layouts/partials/components.html as an inline partial.

    • Speaking of which, if you saw a partial use (e.g., partial "components/post-meta.html" .) and does not have a physical file, it is most likely defined there.

  • Documentations are written in Asciidoctor.

  • Any changes should be documented in the changelog. This is to make future references easier for the user and developers.

  • If you want to improve the accessibility of this theme, please install the popular text browsers (e.g., Browsh, Links, Lynx) and test it by navigating using them.

  • Before committing, be sure to run hugo mod tidy to clean up the Hugo module declaration.

Frequently asked questions (FAQ)

  1. Add scheme inheritance?

    It will not be considered since it will open a lot of unpredictable problems (or at least I think it is) and it is easy to create errors with them. For now, being explicit with the schemes is better despite more cumbersome.

  2. How are my content hidden?

    Your content may either be draft (i.e., draft is set to true ), future (i.e., the date is set in the future compared to the build time), or expired (i.e., when the expirydate is passed). It may also be hidden from the build options (i.e., _build.render is set to false). Please check if the appropriate keys are set (or unset).

  3. How to extend with custom styling?

    Simply create assets/scss/extend.scss and you’re on your merry way. This will be appended with the main stylesheet so it will still be in one file. In fact, with the capabilities of Sass, it is enough for you to fully extend and/or modify the styling with its features — imports, mixins, greater string interpolations, etc.

  4. How to hide a post from being listed?

    You can make use of the build options with _build.list have a value of never. Though, this is only available in Hugo v0.65.0 and above.

  5. How to minimize the total site weight as much as possible?

    If you’re including your links, do not use images and go with the text instead. Make use of PostCSS to minimize the CSS further with PurgeCSS.

  6. How to modify the homepage?

    Copy ./layouts/_default/list.html to layouts/index.html and modify it to your heart’s content.

  7. Support for Asciidoctor?

    Hugo now has support for other formats though this theme is not styled with Asciidoctor or any other formats in mind. There is no style associated with Asciidoctor output (as it has multiple HTML-based backend) so you’ll have to style it yourself. For starters, you can take a look at my modified stylesheet that styles some of the Asciidoctor components (with the default backend).

  8. Syntax highlighting without the highlight shortcode?

    You can make use of existing highlighting libraries such as highlight.js. I recommend Prism for its small core size and solely because of its autoloader plugin. Just link it in your page and it will automatically download the script for the detected languages. Pretty convenient. If you choose Prism, I also have a Prism stylesheet for the theme. It is not included in the final output so you’ll have to override ./layouts/partials/head.html with your own modifications.

  9. Table of contents for Asciidoctor?

    You can enable it with markup.asciidocExt.attributes.toc set to true in the site config. Then enable it with params.toc (e.g., params.toc = true) also in the site config to globally apply to all posts. You can also enable it in your content with the toc frontmatter.

TODO

  • Improve the color scheme generation for the counterpart system theme.

  • Improve the taxonomies page layout.

Acknowledgments


1. It needs Hugo extended version.
2. Still, this theme is designed with multiple authors in mind.
3. It only considered with the default configuration and without non-textual resources such as images and videos.
4. Practically one or two hundred icons since not a lot of them are social platforms.