Skip to main content

Subsections of Customization

Partials

Usable Partials

You can call other partials from themes/hugo-relearn-themes/ besides those in themes/hugo-relearn-themes/layouts/partials/_relearn. However, using partials not mentioned as customizable below might make future updates more challenging.

Customizable Partials

The Relearn theme allows you to customize various parts of the theme by overriding partials. This makes the theme highly configurable.

A good rule to follow: The less code a partial contains, the easier it will be to update the theme in the future.

Here’s a list of partials you can safely override:

  • layouts/partials/content.html: The main content of a page. Override this to display additonal page metadata.

  • layouts/partials/content-header.html: The header above the title. By default, it shows tags, but you can change this.

  • layouts/partials/content-footer.html: The footer below the content. By default, it shows author info, modification dates, and categories. You can customize this.

  • layouts/partials/custom-header.html: For adding custom CSS. Remember to include the style HTML tag.

  • layouts/partials/custom-footer.html: For adding custom JavaScript. Remember to include the script HTML tag.

  • layouts/partials/favicon.html: The favicon. You should definitely customize this.

  • layouts/partials/heading.html: the page’s title headings

  • layouts/partials/heading-pre.html: Add content before the page’s title headings. Remember to consider the headingPre front matter.

  • layouts/partials/heading-post.html: Add content after the page’s title headings. Remember to consider the headingPost front matter.

  • layouts/partials/logo.html: The logo in the top left corner. You should customize this.

  • layouts/partials/menu-pre.html: Add content before menu items. Remember to consider the menuPre front matter.

  • layouts/partials/menu-post.html: Add content after menu items. Remember to consider the menuPost front matter.

  • layouts/partials/menu-footer.html: The footer of the left menu.

You can override other partials from themes/hugo-relearn-themes/, but be careful as this might make future updates more difficult.

Adding Scripts

A common question is how to add extra CSS styles or JavaScript to your site. This depends on what you need.

Adding JavaScript or Stylesheets to All Pages

Simple Solution

Previous documentation of Hugo recommended adding css/custom.css and/or js/custom.js to your static or assets directory. This is supported by the theme.

To gain more flexibility, see the next section below.

Flexible Solution

To add CSS stylesheets, JavaScript files or any other addition to the <head> of every page, you can include them in layouts/partials/custom-header.html or layouts/partials/custom-footer.html.

However, this can make your site larger than necessary if these files are only needed on a few pages. The next section explains how to add dependencies only when needed.

This way of customization will discard the mechanism for the simple solution above. You will have to add code for inclusion of css/custom.css and/or js/custom.js yourself if you still need this.

Custom Shortcodes with Dependencies

Some shortcodes need extra JavaScript and CSS files. The theme only loads these when the shortcode is used. You can use this for your own shortcodes too.

For example, to create a shortcode called myshortcode that needs the jquery library:

  1. Create the shortcode file layouts/shortcodes/myshortcode.html and add the folloging line somewhere:

    ​
    ...
    {{- .Page.Store.Set "hasMyShortcode" true }}
    ...
  2. Option Add this to your project configuration:

    hugo.
    params:
      relearn:
        dependencies:
          myshortcode:
            name: MyShortcode
    [params]
      [params.relearn]
        [params.relearn.dependencies]
          [params.relearn.dependencies.myshortcode]
            name = 'MyShortcode'
    {
       "params": {
          "relearn": {
             "dependencies": {
                "myshortcode": {
                   "name": "MyShortcode"
                }
             }
          }
       }
    }
  3. Create loader file layouts/partials/dependencies/myshortcode.html:

    ​
    {{- if eq .location "footer" }}
      <script src="https://www.unpkg.com/jquery/dist/jquery.js"></script>
    {{- end }}

Important notes:

  • Character casing is relevant!
  • The name in your project configuration must match the Store key used in the shortcode file, prefixed with a has.
  • The key of relearn.dependencies must match the loader file name.

See the math, mermaid, and openapi shortcodes for examples.

Note

For advanced customization, you can use the dependency loader in your own partials:

{{- partial "dependencies.html" (dict "page" . "location" "mylocation") }}

Give a unique name for the location parameter when you call it, so you can distinguish your loaders behavior depending on the location it was called from.

Link Effects

This page shows you, how to configure custom link effects on top of existing ones.

This setting can also be overridden by your front matter.

If you don’t configure anything in your project configuration, the link effects default to

Default Values

​
linkEffects:
  download: false
  target: false
[linkEffects]
  download = false
  target = false
{
   "linkEffects": {
      "download": false,
      "target": false
   }
}

Configuration

Option You can change these settings in your project configuration and add arbitrary custom effects as boolean values (like bg-white in the below snippet).

hugo.
params:
  linkEffects:
    bg-white: true
    target: _blank
[params]
  [params.linkEffects]
    bg-white = true
    target = '_blank'
{
   "params": {
      "linkEffects": {
         "bg-white": true,
         "target": "_blank"
      }
   }
}

This would result in

​
linkEffects:
  bg-white: true
  download: false
  target: _blank
[linkEffects]
  bg-white = true
  download = false
  target = '_blank'
{
   "linkEffects": {
      "bg-white": true,
      "download": false,
      "target": "_blank"
   }
}

Example

With this configuration in effect, the following URL

​
[Magic in new window](images/magic.gif)

would result in

​
<a href="/images/magic.gif?target=_blank" target="_blank" class="bg-white">Magic in new window</a>

Styling Effects

If the resulting effect value is true a class with the effect’s name will be added.

Styles for default effects are contained in the theme. Add styles for your custom effects to layouts/partials/content-header.html.

For the above custom effect you could add the following style:

​
<style>
a.bg-white {
  background-color: white;
}
</style>

Image Effects

This page shows you, how to configure custom image effects on top of existing ones.

This setting can also be overridden by your front matter.

If you don’t configure anything in your project configuration, the image effects default to

Default Values

​
imageEffects:
  border: false
  dataurl: false
  inlinecontent: false
  lazy: true
  lightbox: true
  rounded: true
  shadow: false
[imageEffects]
  border = false
  dataurl = false
  inlinecontent = false
  lazy = true
  lightbox = true
  rounded = true
  shadow = false
{
   "imageEffects": {
      "border": false,
      "dataurl": false,
      "inlinecontent": false,
      "lazy": true,
      "lightbox": true,
      "rounded": true,
      "shadow": false
   }
}

Configuration

Option You can change these settings in your project configuration and add arbitrary custom effects as boolean values (like bg-white in the below snippet).

hugo.
params:
  imageEffects:
    bg-white: true
    border: true
    lazy: false
[params]
  [params.imageEffects]
    bg-white = true
    border = true
    lazy = false
{
   "params": {
      "imageEffects": {
         "bg-white": true,
         "border": true,
         "lazy": false
      }
   }
}

This would result in

​
imageEffects:
  bg-white: true
  border: true
  dataurl: false
  inlinecontent: false
  lazy: false
  lightbox: true
  rounded: true
  shadow: false
[imageEffects]
  bg-white = true
  border = true
  dataurl = false
  inlinecontent = false
  lazy = false
  lightbox = true
  rounded = true
  shadow = false
{
   "imageEffects": {
      "bg-white": true,
      "border": true,
      "dataurl": false,
      "inlinecontent": false,
      "lazy": false,
      "lightbox": true,
      "rounded": true,
      "shadow": false
   }
}

Example

With this configuration in effect, the following URL

​
![Minion](https://octodex.github.com/images/minion.png)

would result in

​
<img src="https://octodex.github.com/images/minion.png" loading="lazy" alt="Minion" class="bg-white border lightbox rounded">

Styling Effects

If the resulting effect value is true a class with the effect’s name will be added.

Styles for default effects are contained in the theme. Add styles for your custom effects to layouts/partials/content-header.html.

For the above custom effect you could add the following style:

​
<style>
img.bg-white {
  background-color: white;
}
</style>

Topbar

The theme comes with a reasonably configured topbar. You can learn how to configure the defaults in this section.

topbar on mobile devices topbar on mobile devices

Nevertheless, your requirements may differ from this configuration. Luckily, the theme has you covered as the topbar, its elements, and the functionality behind these elements are fully configurable by you.

Tip

All mentioned file names below can be clicked and show you the implementation for a better understanding.

Areas

The default configuration comes with predefined areas that may contain an arbitrary set of elements.

topbar with default areas marked topbar with default areas marked

  • start: shown between menu and breadcrumb
  • middle: shown between the start and the end area, taking the remaining space; contains the breadcrumb
  • end: shown on the opposite breadcrumb side in comparison to the start area
  • more: shown when pressing the more button in the topbar

While you cannot add additional areas in the topbar, you are free to write additional area buttons that behave like the more button, each providing a further user-defined area with its own option.

Elements

Everything displayed in an area is an element. Most elements are buttons, but an element can display anything else.

The theme ships with the following predefined elements (from left to right in the screenshot). Each is identified by its type:

Not all elements are displayed at every given time. This is configurable (see below if interested).

Defining Topbar Elements

Option Front Matter The elements are defined for each area of the topbar:

  • topbarstart: the start area
  • topbarmiddle: the middle area
  • topbarend: the end area
  • topbarmore: the more area

As these options are arrays, you can define as many elements as you like in each area. The elements are displayed in the given order. Each element is identified by its type and may be given further parameters, depending on the element.

If you don’t set these options in your project configuration, the theme defaults to the following configuration. The more area is empty by default; some elements are moved there depending on the screen width.

​
params:
  topbarend:
  - type: editbutton
  - type: sourcebutton
  - type: markdownbutton
  - type: printbutton
  - type: prevbutton
  - type: nextbutton
  - type: morebutton
  topbarmiddle:
  - type: breadcrumbs
  topbarmore: []
  topbarstart:
  - type: sidebarbutton
  - type: tocbutton
[params]
  topbarmore = []

  [[params.topbarend]]
    type = 'editbutton'

  [[params.topbarend]]
    type = 'sourcebutton'

  [[params.topbarend]]
    type = 'markdownbutton'

  [[params.topbarend]]
    type = 'printbutton'

  [[params.topbarend]]
    type = 'prevbutton'

  [[params.topbarend]]
    type = 'nextbutton'

  [[params.topbarend]]
    type = 'morebutton'

  [[params.topbarmiddle]]
    type = 'breadcrumbs'

  [[params.topbarstart]]
    type = 'sidebarbutton'

  [[params.topbarstart]]
    type = 'tocbutton'
{
   "params": {
      "topbarend": [
         {
            "type": "editbutton"
         },
         {
            "type": "sourcebutton"
         },
         {
            "type": "markdownbutton"
         },
         {
            "type": "printbutton"
         },
         {
            "type": "prevbutton"
         },
         {
            "type": "nextbutton"
         },
         {
            "type": "morebutton"
         }
      ],
      "topbarmiddle": [
         {
            "type": "breadcrumbs"
         }
      ],
      "topbarmore": [],
      "topbarstart": [
         {
            "type": "sidebarbutton"
         },
         {
            "type": "tocbutton"
         }
      ]
   }
}
Note

If you want to reconfigure an area, you have to copy over every element from the default configuration you want to keep, as reconfiguration will reset all elements of that area.

Example

The following example

  • removes all elements but the more button from the end area
  • displays the more button even if its overlay is empty by setting its onempty parameter to disable
  • puts the print button into the more area on all screen widths
​
params:
  topbarend:
  - onempty: disable
    type: morebutton
  topbarmore:
  - type: printbutton
[params]
  [[params.topbarend]]
    onempty = 'disable'
    type = 'morebutton'

  [[params.topbarmore]]
    type = 'printbutton'
{
   "params": {
      "topbarend": [
         {
            "onempty": "disable",
            "type": "morebutton"
         }
      ],
      "topbarmore": [
         {
            "type": "printbutton"
         }
      ]
   }
}

Redefining Topbar Elements for Certain Pages

Suppose you are building a site that contains a topmost log section.

When the user is on one of the log pages, the topbar should not offer to edit the page, and the print button should be tucked away in the more area. All other pages should keep the default elements.

Directory structure:

  • content
    • log
      • first-day.md
      • second-day.md
      • third-day.md
      • _index.md
    • _index.md

Option Front Matter Using Hugo’s cascade feature, we can redefine the elements once in log/_index.md setting topbarend and topbarmore so they will be used in all children pages.

Setting the topbarend Front Matter will overwrite all default elements of the end area. If you want to display the arrow navigation and the more button as well like in this example, you have to declare them with the Front Matter as given in the default options. The start area is not redefined and keeps its elements.

log/_index.md
---
cascade:
- params:
    topbarend:
    - type: prevbutton
    - type: nextbutton
    - type: morebutton
    topbarmore:
    - type: printbutton
title: Captain's Log
---
+++
title = "Captain's Log"

[[cascade]]
  [cascade.params]
    [[cascade.params.topbarend]]
      type = 'prevbutton'

    [[cascade.params.topbarend]]
      type = 'nextbutton'

    [[cascade.params.topbarend]]
      type = 'morebutton'

    [[cascade.params.topbarmore]]
      type = 'printbutton'
+++
{
   "cascade": [
      {
         "params": {
            "topbarend": [
               {
                  "type": "prevbutton"
               },
               {
                  "type": "nextbutton"
               },
               {
                  "type": "morebutton"
               }
            ],
            "topbarmore": [
               {
                  "type": "printbutton"
               }
            ]
         }
      }
   ],
   "title": "Captain's Log"
}

Defining Own Elements

Besides the predefined elements, you can write your own. Store its template in layouts/partials/topbar/element/<TYPE>.html of your site and add it with { type = '<TYPE>' } to one of the topbar areas.

Your template receives every parameter of its configuration, and additionally the displayed page as page.

The topbar manages what the button function writes: it shows, hides and moves it depending on the screen width. So use this function to display your element, even if it is not a plain button, putting what you want to show into the content of the button.

​
{{- with .page }}
  {{- partial "topbar/func/button.html" (dict
    "page" .
    "class" "topbar-button-home"
    "href" (partial "permalink.gotmpl" (dict "to" site.Home))
    "icon" "home"
    "hint" "Home"
  )}}
{{- end }}

Defining Own Areas

The more area is nothing special: the more button opens it by calling the area-button function with the area name more, and the option topbarmore fills it.

You can add further areas the same way. Write your own element calling the area-button function with an area name <AREA>. Its area is filled by the option topbar<AREA>, which is configured like the options of the predefined areas and can be set in the front matter as well.

​
{{- partial "topbar/func/area-button.html" (dict
  "page" .page
  "area" "tools"
  "icon" "wrench"
  "hint" (T "Tools-action")
  "onempty" "hide"
)}}
​
params:
  topbarend:
  - type: toolsbutton
  topbartools:
  - type: printbutton
[params]
  [[params.topbarend]]
    type = 'toolsbutton'

  [[params.topbartools]]
    type = 'printbutton'
{
   "params": {
      "topbarend": [
         {
            "type": "toolsbutton"
         }
      ],
      "topbartools": [
         {
            "type": "printbutton"
         }
      ]
   }
}

As your template is free to call Hugo’s T function, the tooltip is taken from your translation files.

i18n/en.
Tools-action:
  other: Tools
[Tools-action]
  other = 'Tools'
{
   "Tools-action": {
      "other": "Tools"
   }
}

Other elements can be moved into your area depending on the screen width with the area-tools action.

Button Types

The theme distinguishes between two types of buttons:

  • button: a clickable button that either browses to another site, triggers a user-defined script or opens an overlay containing user-defined content
  • area-button: the template for the more button, to define your own area overlay buttons

Element Parameters

Screen Widths and Actions

Depending on the screen width, you can configure how a button should behave. This applies to every element written by the button or area-button function, but not to other elements like the breadcrumbs, which always stay in their area. Screen width is divided into three classes:

  • s: (controlled by the onwidths parameter) small (mobile) layout where the menu sidebar is hidden
  • m: (controlled by the onwidthm parameter) medium desktop layout with visible sidebar while the content area width still resizes
  • l: (controlled by the onwidthl parameter) large desktop layout with visible sidebar once the content area reached its maximum width

For each width class, you can configure one of the following actions:

  • show: the button is displayed in its given area
  • hide: the button is removed
  • area-XXX: the button is moved from its given area into the area XXX; for example, this is used to move buttons to the more area overlay in the mobile layout

Hiding and Disabling Stuff

While hiding an element depending on the screen size can be configured with the above-described hide action, you may want to hide the element on certain other conditions as well.

For example, the print button in its default configuration should only be displayed if print support was configured. This is done in your element template by checking the conditions first before displaying the element (see layouts/partials/topbar/element/printbutton.html).

Another preferred condition for hiding a button is if the displayed overlay is empty. This is the case for the toc (see layouts/partials/topbar/element/tocbutton.html) as well as the more button and controlled by the parameter onempty.

This parameter can have one of the following values:

  • disable: the button is displayed in a disabled state if the overlay is empty
  • hide: the button is removed if the overlay is empty

If you want to disable a button containing no overlay, this can be achieved by an empty href parameter. An example can be seen in the prev button (see layouts/partials/topbar/element/prevbutton.html) where the URL for the previous site may be empty.

Reference

Predefined Elements

The predefined button elements by the theme (all predefined elements besides the breadcrumbs, tocbutton and morebutton). The breadcrumbs element has no parameters besides its type.

The <varying> parameter values are different for each element and configured for standard behavior as seen on this page.

Name Default Notes
type <empty> Mandatory type of the element.
onwidths <varying> The action that should be executed if the site is displayed in the given width:

- show: The element is displayed in its given area
- hide: The element is removed.
- area-XXX: The element is moved from its given area into the area XXX.
onwidthm <varying> See above.
onwidthl <varying> See above.

Predefined Overlay Elements

The predefined elements by the theme that open an overlay (the tocbutton and morebutton).

The <varying> parameter values are different for each element and configured for standard behavior as seen on this page.

Name Default Notes
type <empty> Mandatory type of the element.
onempty hide Defines what to do with the button if the content overlay is empty:

- disable: The button is displayed in a disabled state.
- hide: The button is removed.
onwidths <varying> The action that should be executed if the site is displayed in the given width:

- show: The element is displayed in its given area
- hide: The element is removed.
- area-XXX: The element is moved from its given area into the area XXX.
onwidthm <varying> See above.
onwidthl <varying> See above.

Button

Contains the basic button functionality and is used as a base implementation for all predefined button elements (layouts/partials/topbar/func/button.html).

Call this from your own element templates if you want to implement a button without an overlay like the print button (layouts/partials/topbar/element/printbutton.html) or with an overlay containing arbitrary content like the toc button (layouts/partials/topbar/element/tocbutton.html).

For displaying an area in the button’s overlay, see Area-Button.

Parameters

Name Default Notes
page <empty> Mandatory reference to the page.
class <empty> Mandatory unique class name for this button. Displaying two buttons with the same value for class is undefined.
href <empty> Either the destination URL for the button or JavaScript code to be executed on click.

- If starting with javascript: all following text will be executed in your browser
- Every other string will be interpreted as URL
- If empty and no action is set, the button will be displayed in a disabled state regardless of its content
action <empty> Name of the action to execute on click, handled by a script instead of inline JavaScript, so it works with a strict Content Security Policy. If set, href is not needed.

- toggle-flyout: shows or hides the content overlay
- toggle-nav: shows or hides the sidebar menu
- any other name: execute your own code, see the button shortcode
istoggle false If true, the button announces to assistive technology that it shows and hides something. Set it if your action is toggle-flyout or toggle-nav. For your own action, see the button shortcode.
icon <empty> Font Awesome icon name.
onempty disable Defines what to do with the button if the content parameter was set but ends up empty:

- disable: The button is displayed in a disabled state.
- hide: The button is removed.
onwidths show The action that should be executed if the site is displayed in the given width:

- show: The button is displayed in its given area
- hide: The button is removed.
- area-XXX: The button is moved from its given area into the area XXX.
onwidthm show See above.
onwidthl show See above.
hint <empty> Arbitrary text displayed in the tooltip.
title <empty> Arbitrary text for the button.
content <empty> Arbitrary HTML to put into the content overlay. This parameter may be empty. In this case, no overlay will be generated.

Area-Button

Contains the basic functionality to display area overlay buttons (layouts/partials/topbar/func/area-button.html).

Call this from your own element templates if you want to implement a button with an area overlay like the more button (layouts/partials/topbar/element/morebutton.html), see Defining Own Areas.

Parameters

Name Default Notes
page <empty> Mandatory reference to the page.
area <empty> Mandatory unique area name for this area. Displaying two areas with the same value for area is undefined. The area is filled by the option topbar<AREA>.
icon <empty> Font Awesome icon name.
onempty disable Defines what to do with the button if the content overlay is empty:

- disable: The button is displayed in a disabled state.
- hide: The button is removed.
onwidths show The action that should be executed if the site is displayed in the given width:

- show: The button is displayed in its given area
- hide: The button is removed.
- area-XXX: The button is moved from its given area into the area XXX.
onwidthm show See above.
onwidthl show See above.
hint <empty> Arbitrary text displayed in the tooltip.
title <empty> Arbitrary text for the button.

Migration for Relearn 9

Previously, the content of an area was defined by a template in layouts/partials/topbar/area that you had to override in your site to change it, calling button templates from layouts/partials/topbar/button. Now the areas are configured by options, the same way as the sidebar menus, listing elements stored in layouts/partials/topbar/element.

Your templates are still honored. If the theme finds an area template, it defines the area and takes precedence over the options. The theme’s button templates can still be called from it. In both cases your build will give you a deprecation warning naming the file. Start to migrate early, as this will be removed with the next major update of the theme.

Predefined Areas

If you have overridden start.html, end.html or more.html in layouts/partials/topbar/area, turn each call of a button template into an entry of the option named after the area and delete the file.

Legacy Template New Option
layouts/partials/topbar/area/start.html topbarstart
layouts/partials/topbar/area/end.html topbarend
layouts/partials/topbar/area/more.html topbarmore

The button template becomes the type of the entry according to the following table. Every parameter besides page is carried over unchanged.

Legacy Template New Type
topbar/button/sidebar.html sidebarbutton
topbar/button/toc.html tocbutton
topbar/button/edit.html editbutton
topbar/button/source.html sourcebutton
topbar/button/markdown.html markdownbutton
topbar/button/print.html printbutton
topbar/button/prev.html prevbutton
topbar/button/next.html nextbutton
topbar/button/more.html morebutton

For example, this template

​
{{ partial "topbar/button/print.html" (dict
  "page" .
)}}
{{ partial "topbar/button/more.html" (dict
  "page" .
  "onempty" "disable"
)}}

becomes

​
params:
  topbarend:
  - type: printbutton
  - onempty: disable
    type: morebutton
[params]
  [[params.topbarend]]
    type = 'printbutton'

  [[params.topbarend]]
    onempty = 'disable'
    type = 'morebutton'
{
   "params": {
      "topbarend": [
         {
            "type": "printbutton"
         },
         {
            "onempty": "disable",
            "type": "morebutton"
         }
      ]
   }
}

If your template showed different buttons depending on the page, set the option in the front matter of these pages instead.

Own Buttons

Move your button templates from layouts/partials/topbar/button to layouts/partials/topbar/element. Once the area template calling them is deleted, list them in the option by their file name. The templates themselves don’t need to be changed.

An element now receives all parameters of its entry and the displayed page as page, where your button previously received what your area template passed to it.

Overridden Buttons

If you have overridden one of the theme’s button templates in layouts/partials/topbar/button, your version is only used by your own area templates. The configured elements don’t know of it.

Move it to layouts/partials/topbar/element, renaming it according to the table above.

Own Areas

If you have written your own button calling topbar/func/area-button.html together with a template layouts/partials/topbar/area/<AREA>.html for its content, move your button to layouts/partials/topbar/element like your other buttons and replace the area template by the option of its area.

For example, these templates

​
{{ partial "topbar/func/area-button.html" (dict
  "page" .page
  "area" "tools"
  "icon" "wrench"
)}}
​
{{ partial "topbar/button/print.html" (dict
  "page" .
)}}

become the unchanged button template moved to layouts/partials/topbar/element/toolsbutton.html and

​
params:
  topbarend:
  - type: toolsbutton
  topbartools:
  - type: printbutton
[params]
  [[params.topbarend]]
    type = 'toolsbutton'

  [[params.topbartools]]
    type = 'printbutton'
{
   "params": {
      "topbarend": [
         {
            "type": "toolsbutton"
         }
      ],
      "topbartools": [
         {
            "type": "printbutton"
         }
      ]
   }
}

Page Designs

Page designs are used to provide different layouts for a given output format. If you instead want to provide a new output format, the theme got you covered as well.

A page is displayed by exactly one page design for each output format, is represented by Hugo’s reserved type front matter and uses Hugo’s content view mechanism.

A page design usually consists of

Warning

Don’t use Hugo’s reserved type option in your modifications for other functionality!

Using a Page Design

Regardless of shipped or custom page designs, you are using them in the same way. Either by manually setting the type front matter to the value of the page design or by using an archetype during creation of a new page.

If no type is set in your front matter or the page design doesn’t exist for a given output format, the page is treated as if type was set to default.

The Relearn theme ships with the page designs home, chapter, and default for the HTML output format.

The shipped print and markdown output formats only display using the default page design.

Creating a Page Design

Suppose you are writing a documentation site for some software. Each time a new release is created, you are adding a new releasenotes page to your site. Those pages should contain a common disclaimer at the top. You neither want to copy the text into each new file nor want you to use a shortcode but create a page design called releasenotes.

  1. Choose a name (here, releasenotes)

  2. Create a content view file at layouts/releasenotes/article.html

    ​
    <article class="releasenotes">
      <header class="headline">
        {{partial "content-header.html" .}}
      </header>
      {{partial "heading-pre.html" .}}{{partial "heading.html" .}}{{partial "heading-post.html" .}}
      <p class="disclaimer">
        This software release comes without any warranty!
      </p>
      {{partial "article-content.html" .}}
      <footer class="footline">
        {{partial "content-footer.html" .}}
      </footer>
    </article>

    The marked lines are your customizations, the rest of the file was copied over from the default implementation of layouts/_default/article.html

    In this file, you can customize the page structure as needed. For HTML based output formats, typically you’ll want to:

    • Set a class at the article element for custom CSS styles
    • Call {{ partial "article-content.html" . }} to show your page content
  3. Optional: create an archetype file at archetypes/releasenotes.md

    ​
    ---
    title: '{{ replace .Name "-" " " | title }}'
    type: releasenotes
    ---
    
    This is a new releasenote.
  4. Optional: add CSS in the file layouts/partials/custom-header.html

    ​
    <style>
    .releasenotes .disclaimer {
      background-color: pink;
      font-size: 72rem;
    }
    </style>

Partials

For any Output Format

These files are common for all output formats.

  • layouts/<DESIGN>/baseof.<FORMAT>: Optional: The top most file you could provide to completely redefine the whole design. No further partials will be called if you don’ call them yourself

For HTML Output Formats

If you want to keep the general HTML framework and only change specific parts, you can provide these files for the page desingn for the HTML output format independently of one another.

  • layouts/<DESIGN>/article.html: Optional: Controls how one page’s content and title are displayed
  • layouts/<DESIGN>/body.html: Optional: Determines what to contain in the content area (for example a single page, a list of pages, a tree of sub pages)
  • layouts/<DESIGN>/menu.html: Optional: Defines the sidebar menu layout

For a real-world example, check out the changelog page design implementation

Migration from Relearn 7

Hugo 0.146 or newer required some changes to the themes file structure.

  • Move your files from layouts/<DESIGN>/views up one level to layouts/<DESIGN>

Migration from Relearn 6

Previous to Relearn 7, page designs were defined by a proprietary solution unique to the theme. Depending on your modifications you may have to change some or all of the following to migrate to Relearn 7’s page designs.

  • In all your *.md files, replace the archetype front matter with type; the value stays the same; don’t forget your archetype files if you have some

  • Move your files layouts/partials/archetypes/<DESIGN>/article.html to layouts/<DESIGN>/article.html

    The files will most likely require further modifications as they now receive the page as it context (dot .) instead of the .page and .content parameter.

    Old:

    ​
    {{- $page := .page }}
    {{- $content := .content }}
    {{- with $page }}
    <article class="default">
      <header class="headline">
        {{- partial "content-header.html" . }}
      </header>
      {{partial "heading-pre.html" .}}{{partial "heading.html" .}}{{partial "heading-post.html" .}}
    
      {{ $content | safeHTML }}
    
      <footer class="footline">
        {{- partial "content-footer.html" . }}
      </footer>
    </article>
    {{- end }}

    New:

    ​
    <article class="default">
      <header class="headline">
        {{- partial "content-header.html" . }}
      </header>
      {{partial "heading-pre.html" .}}{{partial "heading.html" .}}{{partial "heading-post.html" .}}
    
      {{ partial "article-content.html" . }}
    
      <footer class="footline">
        {{- partial "content-footer.html" . }}
      </footer>
    </article>

Output Formats

Hugo can display your content in different formats like HTML, JSON, Google AMP, etc. To do this, templates must be provided.

The Relearn theme by default comes with templates for HTML, HTML for print, RSS and Markdown. If this is not enough, this page describes how you can create your own output formats.

If you instead just want to customize the layout of an existing output format, the theme got you covered as well.

Creating an Output Format

Suppose you want to be able to send your articles as HTML formatted emails. The pages of these format need to be self contained so an email client can display the content without loading any further assets.

Therefore we add a new output format called email that outputs HTML and assembles a completely custom HTML document structure.

  1. Add the output format to your project configuration

    hugo.
    outputFormats:
      email:
        baseName: index.email
        isHTML: true
        mediaType: text/html
        name: email
        noUgly: true
        permalinkable: false
    outputs:
      home:
      - html
      - rss
      - email
      page:
      - html
      - email
      section:
      - html
      - rss
      - email
    [outputFormats]
      [outputFormats.email]
        baseName = 'index.email'
        isHTML = true
        mediaType = 'text/html'
        name = 'email'
        noUgly = true
        permalinkable = false
    
    [outputs]
      home = ['html', 'rss', 'email']
      page = ['html', 'email']
      section = ['html', 'rss', 'email']
    {
       "outputFormats": {
          "email": {
             "baseName": "index.email",
             "isHTML": true,
             "mediaType": "text/html",
             "name": "email",
             "noUgly": true,
             "permalinkable": false
          }
       },
       "outputs": {
          "home": [
             "html",
             "rss",
             "email"
          ],
          "page": [
             "html",
             "email"
          ],
          "section": [
             "html",
             "rss",
             "email"
          ]
       }
    }
  2. Create a file layouts/_default/baseof.email.html

    ​
    <!DOCTYPE html>
    <html>
    <head>
      <title>{{ .Title }}</title>
      <style type="text/css">
        /* add some styles here to make it pretty */
      </style>
      <style type="text/css">
        /* add chroma style for code highlighting */
        {{- "/assets/css/chroma-relearn-light.css" | readFile | safeCSS }}
      </style>
    </head>
    <body>
      <main>
        {{- block "body" . }}{{ end }}
      </main>
    </body>
    </html>

    The marked block construct above will cause the display of the article with a default HTML structure. In case you want to keep it really simple, you could replace this line with just {{ .Content }}.

  3. Optional: create a file layouts/_default/article.email.html

    In our case, we want to display a disclaimer in front of every article. To do this we have to define the output of an article ourself and rely on the above block statement to call our template.

    ​
    <article class="email">
      <blockquote>
        View this article on <a href="http://example.com{{ .RelPermalink }}">our website</a>
      </blockquote>
      {{ partial "article-content.html" . }}
    </article>
  4. Optional: create a file layouts/_default/_markup_/render-image.email.html

    In our case, we want to convert each image into a base 64 encoded string to display it inline in the email without loading external assets.

    ​
    {{- $dest_url := urls.Parse .Destination }}
    {{- $dest_path := path.Clean ($dest_url.Path) }}
    {{- $img := .Page.Resources.GetMatch $dest_path }}
    {{- if and (not $img) .Page.File }}
      {{- $path := path.Join .Page.File.Dir $dest_path }}
      {{- $img = resources.Get $path }}
    {{- end }}
    {{- if $img }}
      {{- if (gt (len $img.Content) 1000000000) }}
        {{/* currently resizing does not work for animated gifs :-( */}}
        {{- $img = $img.Resize "600x webp q75" }}
      {{- end }}
      <img src="data:{{ $img.MediaType }};base64,{{ $img.Content | base64Encode }}">
    {{- end }}

Partials

For HTML Output Formats

If you want to keep the general HTML framework and only change specific parts, you can provide these as blocks:

  • layouts/_default/list.<FORMAT>.html: Optional: Controls how sections are displayed
  • layouts/_default/single.<FORMAT>.html: Optional: Controls how a pages are displayed
  • layouts/_default/taxonomy.<FORMAT>.html: Optional: Controls how taxonomy pages are displayed
  • layouts/_default/term.<FORMAT>.html: Optional: Controls how term pages are displayed

For a real-world example, check out the print output format implementation

For Non-HTML Output Formats

  • layouts/_default/list.<FORMAT>.<EXTENSION>: Mandatory: Controls how sections are displayed
  • layouts/_default/single.<FORMAT>.<EXTENSION>: Mandatory: Controls how pages are displayed
  • layouts/_default/baseof.<FORMAT>.<EXTENSION>: Optional: Controls how sections and pages are displayed. If not provided, you have to provide your implementation in list.<FORMAT>.<EXTENSION> and single.<FORMAT>.<EXTENSION>

For a real-world example, check out the markdown output format implementation

Migration from Relearn 7

Hugo 0.146 or newer required the theme to make changes that may affect you if you are using own output formats. You may have to adjust your templates in layouts/_default according to Hugo’s migration instructions.

For HTML Output Formats

  • You need to define a block storeOutputFormat for your HTML based output format templates and add {{- .Store.Set \"relearnOutputFormat\" \"<your-output-format-name>\" }} to it.

For Non-HTML Output Formats

  • Move your files layouts/<DESIGN>/views up one level to layouts/<DESIGN>

Migration from Relearn 6

Previous to Relearn 7, HTML output formats did not use the baseof.html but now do.

For HTML Output Formats

  • Move your files layouts/partials/article.<FORMAT>.html to layouts/_default/article.<FORMAT>.html

    The files will most likely require further modifications as they now receive the page as it context (dot .) instead of the .page and .content parameter.

    Old:

    ​
    {{- $page := .page }}
    {{- $content := .content }}
    {{- with $page }}
    <article class="default">
      <header class="headline">
        {{- partial "content-header.html" . }}
      </header>
      {{partial "heading-pre.html" .}}{{partial "heading.html" .}}{{partial "heading-post.html" .}}
    
      {{ $content | safeHTML }}
    
      <footer class="footline">
        {{- partial "content-footer.html" . }}
      </footer>
    </article>
    {{- end }}

    New:

    ​
    <article class="default">
      <header class="headline">
        {{- partial "content-header.html" . }}
      </header>
      {{partial "heading-pre.html" .}}{{partial "heading.html" .}}{{partial "heading-post.html" .}}
    
      {{ partial "article-content.html" . }}
    
      <footer class="footline">
        {{- partial "content-footer.html" . }}
      </footer>
    </article>

For Non-HTML Output Formats

  • Merge your files layouts/partials/header.<FORMAT>.html, layouts/partials/footer.<FORMAT>.html to layouts/_default/baseof.<FORMAT>.html

    Old:

    ​
    <!DOCTYPE html>
    <html>
    <head>
      <title>{{ .Title }}</title>
      <style type="text/css">
        /* add some styles here to make it pretty */
      </style>
      <style type="text/css">
        /* add chroma style for code highlighting */
        {{- "/assets/css/chroma-relearn-light.css" | readFile | safeCSS }}
      </style>
    </head>
    <body>
      <main>
    ​
      </main>
    </body>
    </html>

    New:

    The upper part of the file is from your header.<FORMAT>.html and the lower part is from your footer.<FORMAT>.html.

    The marked line needs to be added, so your output format uses a potential layouts/_default/article.<FORMAT>.html

    ​
    <!DOCTYPE html>
    <html>
    <head>
      <title>{{ .Title }}</title>
      <style type="text/css">
        /* add some styles here to make it pretty */
      </style>
      <style type="text/css">
        /* add chroma style for code highlighting */
        {{- "/assets/css/chroma-relearn-light.css" | readFile | safeCSS }}
      </style>
    </head>
    <body>
      <main>
        {{- block "body" . }}{{ end }}
      </main>
    </body>
    </html>

Taxonomies

This page explains how to show custom taxonomies on your pages.

For more details, check the official docs on setting up custom taxonomies and using them in your content.

Default Behavior

The Relearn theme automatically shows Hugo’s default taxonomies tags and categories out of the box.

  • Tags appear at the top of the page in alphabetical order in form of baggage tags.
  • Categories appear at the bottom of the page in alphabetical order as a list prefixed with an icon.

Each item links to a page showing all articles with that term.

Setting Up Custom Taxonomies

To add custom taxonomies, update your project configuration. You also have to add the default taxonomies if you want to use them.

hugo.
taxonomies:
  category: categories
  mycustomtag: mycustomtags
  tag: tags
[taxonomies]
  category = 'categories'
  mycustomtag = 'mycustomtags'
  tag = 'tags'
{
   "taxonomies": {
      "category": "categories",
      "mycustomtag": "mycustomtags",
      "tag": "tags"
   }
}

Showing Custom Taxonomies

To display your custom taxonomy terms, add this to your page (usually in layouts/partials/content-footer.html):

{{ partial "term-list.html" (dict
  "page" .
  "taxonomy" "mycustomtags"
  "icon" "layer-group"
) }}

Parameters

Name Default Notes
page <empty> Mandatory reference to the page.
taxonomy <empty> The plural name of the taxonomy to display as used in your front matter.
class <empty> Additional CSS classes set on the outermost generated HTML element.

If set to tags you will get the visuals for displaying the tags taxonomy, otherwise it will be a simple list of links as for the categories taxonomy.
style primary The style scheme used if class is tags.

- by severity: caution, important, info, note, tip, warning
- by brand color: primary, secondary, accent
- by color: blue, cyan, green, grey, magenta, orange, red, yellow
- by special color: default, transparent, code, link, action, inline
color see notes The CSS color value to be used if class is tags. If not set, the chosen color depends on the style. Any given value will overwrite the default.

- for severity styles: a nice matching color for the severity
- for all other styles: the corresponding color
icon <empty> An optional Font Awesome icon name set to the left of the list.