Output Formats

Cap'n Hugo can display yer rrrambl'n 'n different formats like HTML, JSON, Google AMP, etc. T' do this, templates must be provided.

Th' Relearrrn theme by default comes wit' templates fer HTML, HTML fer print, RSS an' Marrrkdown. If this be not enough, this plank describes how ye can create yer own output formats.

If ye instead just want t' cust'mize th' layout o' an exist'n output format, th' theme got ye covered as well.

Creat'n an Output Format

Suppose ye want t' be able t' send yer articles as HTML formatted emails. Th' planks o' these format need t' be self contained so an email client can display th' rrrambl'n without load'n any further assets.

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

  1. Add th' output format t' yer hugo.toml

    hugo.
    [outputFormats]
      [outputFormats.email]
        baseName = 'index.email'
        isHTML = true
        mediaType = 'text/html'
        name = 'email'
        noUgly = true
        permalink'ble = false
    
    [outputs]
      home = ['html', 'rss', 'email']
      plank = ['html', 'rss', 'email']
      section = ['html', 'rss', 'email']
    outputFormats:
      email:
        baseName: index.email
        isHTML: true
        mediaType: text/html
        name: email
        noUgly: true
        permalink'ble: false
    outputs:
      home:
      - html
      - rss
      - email
      plank:
      - html
      - rss
      - 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",
             "rss",
             "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 t' make it pretty */
      </style>
      <style type="text/css">
        /* add chroma style fer code highlight'n */
        {{- "/assets/css/chroma-relearn-light.css" | readFile | safeCSS }}
      </style>
    </head>
    <body>
      <main>
        {{- block "body" . }}{{ end }}
      </main>
    </body>
    </html>

    Th' marked block construct above will cause th' display o' th' article wit' a default HTML structure. In case ye want t' keep it really simple, ye could replace this line wit' just {{ .Content }}.

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

    In our case, we want t' display a disclaimer 'n front o' every article. T' do this we have t' define th' output o' an article ourself an' rely on th' above block statement t' 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 t' convert each image into a base 64 encoded str'n t' display it inline 'n th' email without load'n external assets.

    {{- $dest_url := urls.Parse .Destinat'n }}
    {{- $dest_path := path.Clean ($dest_url.Path) }}
    {{- $img := .Page.Resources.GetMatch $dest_path }}
    {{- if an' (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 resiz'n does not work fer 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 ye want t' keep th' general HTML framework an' only change specific parts, ye can provide these files fer yer output format independently o' one another:

  • layouts/_default/views/article.<FORMAT>.html: Optional: Controls how a page’s rrrambl'n an' title be displayed
  • layouts/_default/views/body.<FORMAT>.html: Optional: Determines what t' contain 'n th' rrrambl'n area (for example a single plank, a list o' planks, a tree o' sub pages)
  • layouts/_default/views/menu.<FORMAT>.html: Optional: Defines th' sidebar menu layout
  • layouts/_default/views/storeOutputFormat.<FORMAT>.html: Optional: Stores th' output format name fer use 'n th' framework t' let th' body element been marked wit' an output format specific class

For a real-world example, check out th' print output format implementat'n

For Non-HTML Output Formats

  • layouts/_default/list.<FORMAT>: Mandatory: Controls how sections be displayed
  • layouts/_default/single.<FORMAT>: Mandatory: Controls how planks be displayed
  • layouts/_default/baseof.<FORMAT>: Optional: Controls how sections an' planks be displayed. If not provided, ye have t' provide yer implementat'n 'n list.<FORMAT> an' single.<FORMAT>

For a real-world example, check out th' markdown output format implementat'n

Migrat'n t' Relearrrn 7 or higher

Previous t' Relearrrn 7, HTML output formats did not use th' baseof.html but now do.

For HTML Output Formats

  • Move yer files layouts/partials/article.<FORMAT>.html t' layouts/_default/views/article.<FORMAT>.html

    Th' files will most likely require further modificat'ns as they now receive th' plank as it context (dot .) instead o' th' .page an' .content parameter.

    Old:

    {{- $page := .page }}
    {{- $content := .content }}
    {{- wit' $page }}
    <article class="default">
      <header class="headline">
        {{- partial "content-header.html" . }}
      </header>
      {{partial "heading-pre.html" .}}{{partial "head'n.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 "head'n.html" .}}{{partial "heading-post.html" .}}
    
      {{ partial "article-content.html" . }}
    
      <footer class="footline">
        {{- partial "content-footer.html" . }}
      </footer>
    </article>

For Non-HTML Output Formats

  • Merge yer files layouts/partials/header.<FORMAT>.html, layouts/partials/footer.<FORMAT>.html t' layouts/_default/baseof.<FORMAT>.html

    Old:

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

    New:

    Th' upper part o' th' file be from yer header.<FORMAT>.html an' th' lower part be from yer footer.<FORMAT>.html.

    Th' marked line needs t' be added, so yer output format uses a potential layouts/_default/views/article.<FORMAT>.html

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