Hugo and AsciiDoc TestTrack
TestTrack User Manual
I love Hugo! But while attempting to master the hugely popular "Go-powered" static website generator, I found Markdown, Hugo’s "Go-to" prep language, vastly inferior to AsciiDoc, my preferred markup tool that I’ve used for many years to craft articles, books and website pages.
Fully using AsciiDoc (the markup language) and Asciidoctor (the compiler) to build Hugo websites soon became my ultimate goal, not to replace Markdown, but to coexist cooperatively in the same spaces. I scanned tutorials, articles and videos, but I found few definitive answers. In fact, at least one source claimed the task couldn’t be done!
So I set out to find solutions that would allow me to use Asciidoctor in Hugo’s world. How well have I succeeded? This website and document are themselves examples, written entirely with Hugo and Asciidoctor using methods fully detailed here. My web site, tomswan.com, is another. Continue reading and learn how to bring Hugo and Asciidoctor together!
Requirements
To complete this tutorial, you need to have the following software installed:
-
Asciidoctor (https://asciidoctor.org/)
-
Plain text editor (e.g. Sublime Text)
-
Command-line interface (e.g. Bash, Terminal, …)
-
Browser (e.g. FireFox, Chrome, …)
Read this companion document while watching the associated YouTube videos in which I perform and demonstrate every step. Clone or download the Open Source GitHub repository containing files and folders for the finished site. I’m a Linux user, so all commands in this document are for "NIX" systems.
First Steps
Follow the steps in this text to build from scratch your own Hugo and AsciiDoc TestTrack website, identified more simply from now on as adoctest.
Start by creating a blank Hugo site named adoctest. Go into a suitable folder and execute the following commands individually or as a script, ending if all goes well by firing up the Hugo server:
hugo new site adoctest
cd adoctest
hugo new theme min
cp -r themes/min/layouts/* layouts
rm -rf themes/min
echo -e '{{ define "main" }}
{{ .Content }}
{{ end }}'>layouts/index.html
echo -e 'Hello World!\n'>content/_index.md
hugo server
Browse to http://localhost:1313/. If "Hello World!" appears (see Figure 1), TestTrack is ready to acquire some AsciiDoc content! (Select image to view full size):
CODE SECRET ONE
Let the Hugo server continue to run in the background for the rest of this tutorial! (If you must restart it, however, it’s always okay to press Ctrl+C and then enter hugo server in the terminal window.)
|
Contrary to what you may have heard, you do not usually have to halt the Hugo server in order to issue terminal commands. Instead, simply open a second terminal window and again go into the adoctest folder just created:
cd ~/sites/adoctest
Unless otherwise stated, pathnames in this text are relative to folder adoctest. Go (cd) into the site folder before entering suggested commands. Print Working Directory (pwd) to find out where you are.
Creating and Storing AsciiDoc Files
Make a place for storing AsciiDoc text files by creating a subfolder named adoc in the site’s static folder:
mkdir static/adoc
Hugo copies all files and subfolders that it finds in folder "static" directly to the final build, so everything inside static/adoc will end up in the finished site in a root-level folder named /adoc.
Create your first AsciiDoc text file or copy the file from the repository. Name it simple.adoc and save in static/adoc. For some text to use, the following listing showcases a few standard Asciidoctor practices such as hypertext links, syntax highlighting (as applied to a small C++ program listing) and a "TIP" admonition icon. (The repository offers a somewhat longer file but the shorty version here will work just as well):
static/adoc/simple.adoc
:source-highlighter: highlight.js
:icons: font
:sectanchors:
== Hello Hugo and AsciiDoc Fans!
TIP: http://asciidoctor.org[Asciidoctor] Documentation
.Hello World in C++
[source, cpp]
....
#include <iostream>
int main()
{
std::cout << "Hello World!\n";
return 0;
}
....
AsciiDoc documents can optionally begin with a front matter section at the top of the file with identifiers dressed in colons. A blank line ends the section.
The first front-matter declaration in simple.adoc selects a popular syntax highlighter, highlight.js, for adorning code samples. Setting icons
to font
makes Font Awesome graphical icons available for admonitions such as warnings and notes. Finally, defining sectanchors
enables section anchors--relative document URLs represented by an icon that appears when a mouse cursor hovers above (right click for options) or when tapped with a stylus:
← Try It Here
Also create a "shadow" Markdown page named the same as the AsciiDoc file, but ending with .md. Issue this command:
hugo new adoc/simple.md
Hugo creates new Markdown files in the site’s content folder. Any subfolders in the path are also created as needed. Open content/adoc/simple.md (the file just created) for editing. Here’s the completed listing with a few changes made:
content/adoc/simple.md
---
title: "Simple Method"
date: 2022-09-21T15:26:16-04:00
draft: false
layout: simple
---
Like AsciiDoc files, Markdown files can start with a front matter section in a format known as "YAML" (i.e. Yet Another Markdown Language). The section is delimited by two lines of triple dashes.
In simple.md, set draft to false, which tells Hugo that the page is ready for publishing. Also, as shown, add a layout parameter set to simple, same as the name of the file, the purpose of which is to direct Hugo to look for an HTML layout template named simple.html in folder layouts/adoc.
Markdown files, as will be seen, typically have content added below the front matter section, but in this case the content section is left empty. |
Save file content/adoc/simple.md. Create the layouts adoc subfolder with the command:
mkdir layouts/adoc
Compile simple.adoc using option -D to direct output to layouts/adoc:
asciidoctor -D layouts/adoc static/adoc/simple.adoc
Browse to the following address:
And there in the browser (see Figure 2) is the finished, formatted AsciiDoc document, appearing as a page in our Hugo website! Hooray!
Meanwhile, the site is still being served by the Hugo server. As proof, use browser buttons to return to the "Hello World" home page and then back to the document. Add some new text to the source text in static/adoc/simple.adoc and recompile. Changes are instantly reflected in the browser. Pretty cool!
Although even this relatively simple method works well enough, one drawback is that copies of the identical CSS styling rules used by browsers to fashion the page are inefficiently embedded in every generated HTML file.
That’s easily fixed, but let’s first improve TestTrack’s home page with some navigation for browsing through our growing library of documents (numbering only one so far). There are also a couple of basic deficiencies that need attention before we dare move further forward.
Global Configurations
One of the first essential tasks in any new Hugo site is to configure a few main parameters. In the site’s folder, open config.toml in which site-global configurations are defined. Modify the text to that listed below:
config.toml
baseURL = 'http://localhost:1313/'
languageCode = 'en-us'
title = 'Hugo and AsciiDoc TestTrack'
[params]
author = 'Tom Swan'
description = 'Hugo and Asciidoctor tutorial'
That’s an example of yet another markup language, known as TOML, or "The Other Markup Language." There are no front-matter delimiters this time; just parameter/value associations with equal signs between. There are also arrays of values as with [params], one of many features that make TOML ideal for configuration files.
Of course, feel free to compose your own title and use your own name. The baseURL setting is not relevant when using hugo server but it can be set as shown or assigned a null string:
baseURL = ''
Fixing the Home Page
Open file content/_index.md for editing and replace "Hello World" with some YAML front matter as all Hugo Markdown files should have, making sure that draft is set to false. Below the front matter section, compose some text or use what’s suggested in the completed listing:
content/_index.md
---
title: "Code Secrets 1"
date: 2022-09-21T15:26:16-04:00
draft: false
---
Welcome to my Hugo and Asciidoctor demonstration.
Select a document to view:
The browser shows the new text as soon as the file is saved, but this is only part of the job in fixing up the home page. As demonstrated next, a bit of Go templating builds up the page further by dynamically updating a document list as new files are added.
Layout Templates
For rendering the home page (or any page) into HTML, Hugo needs a layout template. In fact, a simple template currently in use is the principle reason that anything at all appears in the browser. Open the responsible template file, layouts/index.html and replace its simple programming with the more complex layout instructions listed here:
layouts/index.html
{{ define "main" }}
<h2>{{ .Site.Title }}</h2>
<h4>by {{ .Site.Params.Author }}</h4>
{{ .Content }}
<ul>
{{ range .Site.RegularPages.ByTitle }}
<li>
<a href="{{- .RelPermalink -}}">{{- .Title -}}</a>
—
(<a href="/adoc/{{- .File.TranslationBaseName -}}.adoc">
View Source
</a>)
</li>
{{ end }}
</ul>
{{ end }}
A Hugo layout template typically holds a mix of HTML elements, such as headers and anchor references, plus Go expressions in double curly braces. After processing by the Hugo compiler, template expressions are ultimately replaced in the final HTML output with actual values taken from various sources such as config.toml and markdown (.md) files.
Template expressions frequently make use of built-in parameters such as RelPermalink (relative permalink), Title and Author (taken from config.toml). References to those and other parameters, which are usually capitalized, are preceded by a period.
A "range" statement in index.html iterates over the site’s "regular" pages (as opposed to indexing types of pages, such as the home page itself), creating on each loop two hyperlinks, one to the compiled document and the other to the page’s AsciiDoc source text.
Save the layout file and then return to http://localhost:1313/. Refresh the browser if necessary to view the new home page, which now sports a title, a welcoming message, and a menu listing the contents of our growing library (still having only a single document—see Figure 3). Very nice!
Select "View Source" to view any document’s AsciiDoc source text file. There’s still only one so far, but stay tuned, more are coming.
Summary: Add New Documents
In short, to add AsciiDoc documents to Hugo sites using the simple method takes four basic steps:
-
Hugo new a "shadow" Markdown page such as adoc/example.md
-
Edit example.md; set draft to false and layout to example (same as the file name)
-
Create the "real" AsciiDoc file, static/adoc/example.adoc
-
Compile the AsciiDoc document to layouts/adoc/example.html
Let’s do that for a new document, but first, and typically when designing a new type of page, an archetype provides a template that can save time by supplying default front matter and other elements such as boiler-plate text and instructions.
Copy Hugo’s default archetype, default.md in the archetypes folder, to a new file named archetypes/adoc.md:
cp archetypes/default.md archetypes/adoc.md
Open archetypes/adoc.md for editing. Most of the text can be left unchanged, but set draft to false and add a new front matter tuple for a parameter named layout as shown in the finished file:
archetypes/adoc.md
---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: false
layout: {{ .Name }}
---
Here is another use for Go templating, this time in a Markdown text file. First, the page title is assembled from the file .Name (less extension), capitalizing words and replacing dashes with blanks. The current date and time are next supplied followed by setting parameter draft to false so that the page is publshed (i.e. because it is not just a draft).
Lastly, the new layout parameter is assigned a Go template expression that resolves to the file name being created, which as a result directs Hugo to look for an HTML file of that name in layouts/adoc.
Many Hugo authorities recommend setting draft to false in the default archetypes/default.md file. That way, new pages are immediately published to the final build, ready or not. Maybe that’s not always the best plan, but for this tutorial it’s a good idea, so go ahead and make that change now: Open archetypes/default.md, change draft to false and save. |
With the new archetype in place, from now on, a "hugo new" command such as
hugo new adoc/newtest.md
creates content/adoc/newtest.md using a filled-in copy of the adoc.md archetype. Issue that command now and then open the generated content/adoc/newtest.md file for editing.
Notice that draft is already set to false and that layout is correctly initialized to newtest, same as the file name. Add some identifying text below the front matter (it can be anything):
content/adoc/newtest.md
---
title: "Newtest"
date: 2022-09-22T20:23:04-04:00
draft: false
layout: newtest
---
Hugo had a little lamb
Notice in the browser that simply creating newtest.md creates a new menu entry for Newtest on TestTrack’s home page. Nifty! But selecting its hyperlink isn’t so great—a dreaded 404 page not found error ruins the show (see Figure 4)!
That happens because we haven’t yet told Hugo what to do with new adoc Markdown pages. The layout template created earlier was strictly for the home page, not others. Also, a candidate AsciiDoc document at this point doesn’t even exist, but even if it did, it hasn’t yet been compiled.
Meanwhile, Hugo needs a default layout to use at least temporarily, but also for any future adoc "single" pages (as opposed to listing or index pages).
Open the supplied single.html file in layouts/_default for editing. The file, copied from the temporary Hugo theme created earlier by the "Hello World" script, is currently empty. Enter the four lines of text listed here:
layouts/_default/single.html
{{ define "main" }}
<h2>{{ .Site.Title }}</h2>
{{ .Content }}
{{ end }}
Using some more Go templating, a block named "main" first creates a level two head (<h2>) for the global site title followed by any content accessed through named parameters .Site.Title and .Content respectively. Though minimal, the layout template is all that Hugo needs to create a finished HTML page. Without it, Hugo has no idea what to do with files such as content/adoc/newtest.md!
Save single.html and again select Newtest from the home page menu. Now, instead of a 404 error, the Markdown file’s content appears in the browser (see Figure 5). How poetic!
But the page still doesn’t show any AsciiDoc content as we actually want, so create some in a file named newtest.adoc, stored as usual in static/adoc.
Following is a listing to use, starting with some random so-called lorem ipsum text. Two sidebars and an example table are followed by five "admonitions" that are frequently useful as attention grabbing sidebars. Feel free to enter the text listed here or type whatever you like:
static/adoc/newtest.adoc
:icons: font
:sectanchors:
== New Test Document
*_Crypto-nodal point BASE jump_* nodality sunglasses silent film apophenia katana euro-pop 8-bit sign denim narrative claymore mine. Shrine footage smart-Tokyo kanji pre-systema crypto-bridge stimulate.
.Tables
****
Tables are laid out using a proportional grid system. In the following table, columns one and two have 2 units each out of 5 total; column three takes one of 5 units.
****
[%header,cols="2,2,1"]
|===
|Label 1
|Label 2
|Label 3
|Cell col 1, row 1
|Cell col 2, row 1
|Cell col 3, row 1
|Cell col 1, row 2
|Cell col 2, row 2
|Cell col 3, row 2
|===
.Admonitions
****
Five admonitions draw attention to important information, cautions and warnings, and help to break up lengthy text for better readability.
****
NOTE: This is worth taking *_NOTE:_* of
IMPORTANT: Some advice is very *_IMPORTANT:_*
TIP: Always *_TIP:_* your bar tender well!
CAUTION: Do throw *_CAUTION:_* to the wind (sometimes)!
WARNING: Pay attention to all *_WARNING:_* signs!
Compile as before with the -D option, sending output to layouts/adoc:
asciidoctor -D layouts/adoc static/adoc/newtest.adoc
Once again, select Newtest and now the AsciiDoc document comes into view (see Figure 6). Select each document in turn, edit the adoc source files and recompile to see changes instantly appear in the browser.
CODE SECRET TWO
Asciidoctor sports loads of cool features. For example, along with a helper Ruby Gem, "Ascii Art" text diagrams are magically transformed into great looking PNG images. Just "draw" what you want right in the text using dashes and other common characters! (Search online for Ascii drawing sites too.) Here’s one of the images from the Diagrams sample document (see Figure 7):
Reference: http://ditaa.sourceforge.net/ |
Using Ascii Art and other advanced Asciidoctor features in Hugo requires paying close attention to where external files such as PNG images are stored and accessed. A related concern is how to use and share external stylesheets among multiple documents, both topics to be covered next.
Developing With Style
One problem with the simple method is that, as mentioned, every compiled HTML file gets a full copy of the extensive Asciidoctor CSS rule set. In sites with dozens or hundreds of files (or more), that much duplication can bloat a site’s HTML footprint and complicate updates.
Sharing style definitions stored in a common file, typically named asciidoctor.css, allows multiple pages to efficiently share style rules. That way, selecting new style settings such as text and background colors affects all sharing documents, which is often advantageous for designing and editing page layouts.
Cloning asciidoctor.css
Create a css directory in folder static/adoc:
mkdir static/adoc/css
Clone the standard stylesheet into the folder. There are several methods. One of the easiest is to run the following script:
echo "" > .temp.txt
asciidoctor -a linkcss .temp.txt
rm .temp.*
mv asciidoctor.css static/adoc/css
Specifying the linkcss command-line attribute (-a) tells Asciidoctor to clone the standard stylesheet file into the current directory. The last line moves the resulting file to static/adoc/css.
You can also find asciidoctor.css in its official repository.
Browse to here for further help with cloning asciidoctor.css. |
Linking to External Stylesheets
With the standard stylesheet now available in a separate file, the Asciidoctor linkcss option can be used to share styles among multiple documents. The next example Asciidoc file also demonstrates that and also how to create and display some great looking PNG images using Ascii Art.
Enter listing static/adoc/diagrams.adoc. As usual for large examples, copy the complete and much longer file from the repository, but in its absence, the abbreviated text shown here is completely functional.
static/adoc/diagrams.adoc
:sectanchors:
:linkcss:
:stylesdir: ../css
:imagesdir: img
:imagesoutdir: static/adoc/diagrams/img
== Hugo and Asciidoctor Diagrams!
.Color Codes
[ditaa, "figure-1"]
....
/-------------+-------------\
|cRED RED |cBLU BLU |
+-------------+-------------+
|cGRE GRE |cPNK PNK |
+-------------+-------------+
|cBLK BLK |cYEL YEL |
\-------------+-------------/
....
As always, enter a "hugo new" command to create a Markdown file, shadowing the real McCoy:
hugo new adoc/diagrams.md
TestTrack’s menu updates to show the new page. Open file content/adoc/diagrams.md for editing and make sure draft is false. (It probably already is and this step may be unnecessary, but checking doesn’t hurt.) Here’s the completed file (it needs no content):
content/adoc/diagrams.md
---
title: "Diagrams"
date: 2022-09-23T12:09:19-04:00
draft: false
layout: diagrams
---
Next, compile static/adoc/diagrams.adoc with the following command, sending output as usual to layouts/adoc:
asciidoctor -r asciidoctor-diagram -D layouts/adoc static/adoc/diagrams.adoc
Option -r "requires" the stated gem, which converts Ascii Art drawings into PNG images, saved in a folder named img as specified in the front matter imagesdir
option.
Because image files are generated directly in the site’s static subfolder via option imagesoutdir,
Hugo copies the PNG files to the site build with no further effort on the developer’s part. Just compile and publish!
If you receive compile-time errors, follow instructions in Diagrams to install the required Ruby gem. The generated images are already in the repository, however, and this extra step is not required in order to continue with the tutorial.
Extending the Standard Stylesheet
Sharing an external stylesheet is only half the game in designing good looking AsciiDoc Hugo pages. Equally important is gaining full control over document styles, including but not limited to the colors and sizes of fonts and the placement of elements on a page.
Such control makes it possible to create "Dark Themes" and other stylistic webpage layouts, as demonstrated by the next AsciiDoc document, "Using Custom Stylesheets" (see Figure 8).
The stylistic "themes" mentioned here are unrelated to Hugo Themes, an important subject that is beyond the scope of this tutorial! |
Create static/adoc/custom-styles.adoc, listed below with some more lorem ipsum random text—type anything you want, or grab a copy of the repository file, but be sure to enter the front matter as shown:
static/adoc/custom-styles.adoc
:icons: font
:sectanchors:
:linkcss:
:stylesdir: ../
:stylesheet: css/custom-styles.css
== Using Custom Stylesheets!
Hacker engine j-pop drugs fetishism convenience store youtube nodal point futurity.
Post-smart-grenade carbon physical rebar modem long-chain hydrocarbons artisanal disposable denim cardboard Tokyo sunglasses towards.
link:{stylesdir}{stylesheet}[View Stylesheet]
NOTE: Happiness is good health ...
=== Headers To Cheddars
Kanji cardboard voodoo god free-market soul-delay Kowloon semiotics decay singularity military-grade euro-pop industrial grade shrine jeans grenade drugs.
CAUTION: ... And a bad memory!
==== The End
Also, as always, create the required "shadow" Markdown file. Enter:
hugo new adoc/custom-styles.md
There isn’t anything to add to the generated Markdown file created by the hugo new command, but here it is in full for reference:
content/adoc/custom-styles.md
---
title: "Custom Styles"
date: 2022-10-02T16:00:21-04:00
draft: false
layout: custom-styles
---
Compiling the AsciiDoc document at this stage with the command:
asciidoctor -D layouts/adoc static/adoc/custom-styles.adoc
produces a warning that the specified stylesheet cannot be found:
asciidoctor: WARNING: ...stylesheet does not exist or cannot be read: ...css/custom-styles.css
The warning, which can be safely ignored, results from two front-matter settings in the source file repeated here for reference:
:stylesdir: ../
:stylesheet: css/custom-styles.css
Asciidoctor looks for the specified stylesheet, which doesn’t yet exist, hence the warning. The stylesdir setting on the first line effectively relocates the specified stylesheet to its deployed path.
In folder static/adoc/css, which contains stylesheet asciidoctor.css from the previous section, create and save the first part of a custom CSS stylesheet listing as shown next. You can get the completed file from the repository, but entering the file one section at a time while viewing the results in a browser will be more instructive.
Select Custom Styles from the developing site to view style changes as they are saved. Preview the result here. |
Here’s the first part:
static/adoc/css/custom-styles.css
@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700";
@import "asciidoctor.css";
Two @import statements represent the minimum required programming for using an external stylesheet according to official Asciidoctor recommendations. The first loads some fonts over a CDN. The second references the site’s local copy of the standard Asciidoctor stylesheet.
Create a "Dark Theme" by adding a new rule for elements identified by the article class. Append this declaration to custom-styles.css:
static/adoc/css/custom-styles.css (add)
.article {
color: white;
background-color: black;
}
Save the stylesheet to see effects.
If nothing happens, clear the cache and refresh the browser! |
That looks great, but make the headers more visible by also adding:
static/adoc/css/custom-styles.css (add)
h2, h3 {
color: gold;
text-shadow: 2px 2px #ff0000;
}
"The End" is barely visible, so fix that up too:
static/adoc/css/custom-styles.css (add)
h4 {
color: cyan;
text-align: center;
text-decoration: none;
}
Brighten the link colors as well:
static/adoc/css/custom-styles.css (add)
a:link, a:visited {
color: green;
}
a:hover {
color: lightgreen;
}
And finally, bring out the admonition text, which is currently hidden. I’m not sure whether using "first-line" this way is the best method for accessing the element text in admonitions, configured as finicky-to-style table cells, but it works!:
static/adoc/css/custom-styles.css (add)
table td.content::first-line {
color: white;
text-transform: uppercase;
text-shadow: 3px 3px red;
text-align: center;
}
As dramatically illustrated in the browser, simply by adjusting a few colors and styles, the styled document’s "Dark Theme" brings an entirely unique look to the page compared with all other documents in the library.
Building the Library
Following are all the commands needed to rebuild TestTrack’s document library up to this point. Execute them one by one, or add them to a script or "batch" file for running them all in succession.
asciidoctor -D layouts/adoc \
-r asciidoctor-diagram static/adoc/diagrams.adoc
asciidoctor -D layouts/adoc static/adoc/newtest.adoc
asciidoctor -D layouts/adoc static/adoc/simple.adoc
asciidoctor -D layouts/adoc static/adoc/custom-styles.adoc
cp -r layouts/css static/adoc/css
# rm -rf layouts/css # optional
The repository includes file Makefile for automatically and efficiently building TestTrack’s entire AsciiDoc document library. To use it, go into folder adoctest and enter make. Enter make clean to remove generated targets. Instructions in this tutorial continue to document the individual commands needed to build every example. Either way’s okay, but using make is easier and can save a lot of time.
CODE SECRET THREE
Making AsciiDoc documents more "site-aware" requires writing some new Go templates and also employing a few new strategies in using Asciidoctor to generate HTML for plugging into Hugo template assemblies.
The results, however, make the extra efforts more than worthwhile. By fully integrating Hugo and Asciidoctor, site pages and documents, both potentially written using AsciiDoc markup, can share elements such as stylesheets, nav bars and other resources as explained in this part.
The steps are a bit complicated, but no worries. Everything is fully documented coming up next.
Asciidoctor Goes Hugoistic!
TestTrack needs some TLC. For it to improve much beyond its current simplistic design, and to allow for full Asciidoctor integration, at a minimum the site needs:
-
About page plus other standard website pages
-
Footer showing Copyright information and date
-
Nav bar to be shared site-wide along with the Footer
Adding New Website Pages
Regular pages are always easy to create in Hugo. For example, create a new About page plus an AsciiDoc "shadow" document for a Manual by issuing these two commands:
hugo new about.md
hugo new adoc/manual.md
Each new page is automatically added to TestTrack’s document list, but since the first does not specify subfolder adoc, its Markdown file is created directly in the content directory. On the other hand, the second page’s Markdown file, manual.md, is created in subfolder content/adoc. Also, manual.md has a layout field added to its front matter that about.md lacks.
Open the two files for editing, make sure draft is set to false in each and add some place-holder text (type whatever you want) as shown in the following completed listings:
Type-Casting Pages
The site is coming along well, but one problem is that all pages are listed as AsciiDoc test documents, even those that aren’t. It’s a bug! Squish it by locating this line in file layouts/index.html:
layouts/index.html
{{ range .Site.RegularPages.ByTitle }}
Change the line to:
{{ range (where .Site.RegularPages "Type" "in" "adoc").ByTitle }}
Save the template to remove non "adoc" type documents from the index.
A "range" statement is very common in Hugo programming. Here, the statement ranges, or loops, over the site’s "regular" pages (as opposed to listing or indexing pages such as the Home page itself). Since Manual is identified as an AsciiDoc document, it still shows up in the list; but the new About page has gone missing! We’ll get it back when we add proper navigation to the site, as explained next.
It’s Full of Partials!
In Hugo, a partial is similar to what’s known as an "include file" in many other programming languages.
Hugo uses partials in various places mainly for importing short HTML snippets of Go templating code. TestTrack uses partials in that way too but also as a means for injecting Asciidoctor-generated HTML into Hugo’s inner works, as will be seen.
Partials are important to and are widely used in Hugo programming. It’s probably not wrong to state that every Hugo site is full of partials! |
Default Partials
TestTrack’s layouts/partials folder contains three files typically provided for in every Hugo site:
-
head.html — <head>, <meta>, <link> and <title> tags
-
header.html — <nav> and other <header> elements
-
footer.html — site footer within <footer> tags
All or some of those three files may initially be empty. Replace and fill them up with a mix of HTML and Go templating as listed next. Most of the following code is self explanatory, but brief comments follow each listing.
With Hugo server running, the browser automatically updates TestTrack’s display as soon as each file is saved, visually illustrating every effect. For best results, enter and save each file in the order presented. |
layouts/partials/header.html
{{/* Header Partial */}}
<header>
<nav class="navbar">
<div class="navbar-logo">
<a href="/">ADOC</a></div>
<div class="navbar-links"><ul>
<li><a href="/">Home</a></li>
<li><a href="/adoc/manual">Manual</a></li>
<li><a href="/about">About</a></li>
</ul></div>
</nav>
</header>
Upon saving header.html, a navigation menu appears at the top of the page. Now it’s possible to view the About page again. There’s also a handy way to get back Home.
The Header partial utilizes a classic HTML design, with an unordered list <ul> of <li> and anchor <a> tags within a <nav> section. Three class declarations provide for eventual styling, but currently, the "bar" appears as an unstyled bulleted list. |
layouts/partials/footer.html
{{/* Footer Partial */}}
<footer>
Copyright © {{now.Format "2006"}}
by {{ .Site.Params.author }}
</footer>
Obviously, this partial is for defining a site’s footer element. As soon as the file is saved, a Copyright notice appears below TestTrack’s document index.
The "now.Format" command may seem strange—maybe because it is! The string "2006" is just Hugo’s odd way of formatting date components such as year values "by example."
Copy and paste the following listing, which defines several head elements using Go templating for needed values such as the site title. Also defined are link tags for referencing site-wide style information:
layouts/partials/head.html
{{/* Head Partial */}}
<head>
<meta charset="utf-8">
<meta name="viewport" content=
"width=device-width, initial-scale=1">
<title>{{- .Title }} | {{ .Site.Title -}}</title>
<meta name="author" content=
"{{ .Site.Params.author }}">
<meta name="description" content=
"{{ .Site.Params.description }}">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" href="/adoc/css/asciidoctor.css">
<link rel="stylesheet" href="/css/style.css">
</head>
Saving the head.html partial produces a dramatic effect in the browser—instantly, all of Asciidoctor’s standard styles are enabled, even for the home page, which now looks entirely different (see Figure 9)!
As for the code, what may seem to be a complex beast is, on close inspection, revealed to be merely the standard set of <meta>, <title> and <link> tags commonly found in the <head> section of most modern, search-engine-friendly web sites.
Complicating the picture of understanding how it all works, however, are several Go templating expressions between double curly braces that may seem odd to those not used to reading them mixed in with HTML. As with layout templates, in the final HTML output, Hugo replaces template expressions with the author name, description, and other values.
Defining Site-Wide Styles
To define site-wide styles for TestTrack, first create subfolder static/css for storing stylesheet files. Enter the command:
mkdir static/css
Ignore any error given if the folder already exists. In the css folder, create a new file named style.css listed in full here:
static/css/style.css
body {
font-family: Arial;
height: 100vh;
width: 100vw;
color: black;
display: flex;
flex-direction: column;
}
h2, h3, h4, h5, h6 {
font-weight: bold;
}
footer {
text-align: center;
}
#content {
margin: 0 auto;
padding-left: 3em;
padding-right: 2em;
overflow-y: auto;
display: flex;
flex-direction: column;
}
.navbar {
display: flex;
position: relative;
flex-direction: row;
list-style-type: none;
margin: 0;
justify-content: space-between;
align-items: center;
overflow: auto;
background-color: maroon;
color: white;
}
.navbar-logo a {
color: white;
text-decoration: none;
font-size: 1.5rem;
padding-left: 1rem;
}
.navbar-links {
height: 100%;
}
.navbar-links ul {
display: flex;
margin: 0;
padding: 0;
}
.navbar-links li {
list-style: none;
}
.navbar-links li a {
display: block;
text-decoration: none;
color: white;
padding: .75rem;
}
.navbar-links li:hover {
background-color: #0f0f0f;
}
Save style.css, and with Hugo server running, the browser instantly shows the resulting page now with a maroon-colored nav bar at top and a footer below. In addition, the page contents are centered between some border space left and right (see Figure 10).
Similar dramatic effects were seen with the Custom Styles example. But the significant difference here is that site-wide style rules now apply to the entire website, not only to isolated AsciiDoc documents as before.
Sample documents presented so far do not automatically adapt to the new site-wide styles. They could be made to do so, but because this is a tutorial, documents presented up to now are intentionally left unaffected by TestTrack’s stylistic improvements. |
CODE SECRET ADOC
Hugo now has all the tools and raw materials it needs to construct search-engine-optimized, modern and responsive HTML website pages. The final step is to blend in some AsciiDoc content.
Doing that takes advantage of a compilation option (-s) that strips the head from Asciidoctor-generated HTML (containing elements now handled in Hugo partials), leaving the page’s body elements to be inserted into the final page assembly.
It’s the third and final, and also the most versatile, of the three methods presented in this tutorial for bringing Hugo and Asciidoctor together.
Proof of a Plugged-In Concept
As "Proof of Concept" select Newtest from the developing TestTrack’s menu. While viewing the page, open file content/adoc/newtest.md and in the front matter change layout’s value, which is now set to newtest, to single:
layout: single
Save the file and immediately the page’s AsciiDoc content is replaced by its "shadow" Markdown text! Change layout back to newtest (lowercase) and the AsciiDoc content reappears.
Also notable is that only the Markdown content is styled with a nav bar and footer. That’s easily changed, but as mentioned, early examples such as Newtest purposely do not conform to site-wide style rules. |
That the layout parameter selects the template for assembling the page provides the perfect trigger for injecting AsciiDoc content as a Hugo partial. To demonstrate, the next part does exactly that, compiling an AsciiDoc document into a Hugo partial for insertion into the final HTML output assembly.
Generating Asciidoctor Partials
To provide a place for storing Asciidoctor-generated HTML partials, create a new adoc folder inside layouts/partials:
mkdir layouts/partials/adoc
We also need a layout template for Asciidoctor generated content. Up until now that wasn’t necessary because documents presented so far were already full-blown HTML pages. Now that we are injecting partial Asciidoctor output into the Hugo template machinery, a layout template is needed to handle the new type of material.
Following is a suggested AsciiDoc layout template (there are many possible designs). Save it as layouts/_default/adoc.html:
layouts/_default/adoc.html
{{ define "main" }}
<h2>{{ .Site.Title }}</h2>
{{ .Content }}
{{ $fn := lower .Name }}
{{ $fn := print "adoc/" $fn ".html" }}
{{ $pn := print "layouts/partials/" $fn }}
{{ if fileExists $pn }}
{{- partial $fn . -}}
{{ end }}
{{ end }}
The first two statements in block main are optional, but they demonstrate that, in Hugo, content can come from a variety of sources. Here, the site’s title is obtained from config.toml after which any Markdown content follows. After that, the named partial is loaded if found. In that way, Asciidoctor-generated HTML is injected directly into the page.
Putting Theory Into Practice
Since TestTrack needs an About page, we may as well create one using AsciiDoc markup, illustrating that Asciidoctor can be used in writing any Hugo page, not only for separate documents.
Our developing TestTrack already has an About page "shadow" Markdown file, but here it is in full again for reference:
content/about.md
---
title: "About"
date: 2022-09-29T12:23:06-04:00
draft: false
---
Much to do about Nuttin'!
Create the "real" AsciiDoc file containing the About page text in the usual location, static/adoc/. Following are the first few lines for those who are copying and pasting, but as always, the preferred and much longer file is found in the repository:
static/adoc/about.adoc
:icons: font
:sectanchors:
:toc:
link:../about.adoc[View Source]
== About this Site
TestTrack is _your_ playground for trying out Hugo and Asciidoctor Code Secrets in real time. Follow instructions in the user Manual to build your own TestTrack _from scratch_--the same website that you are viewing right now!
== Resources
Even though Font Awesome admonition icons are now loaded by a Hugo partial, it is still necessary to define :icons: font
in the front matter section to make icon images visible.
The other two front-matter settings are, in this example, not strictly required but illustrate that Asciidoctor features such as Table of Contents generation and section anchors are still available when using this advanced method of integration. However, some options such as linkcss
are no longer meaningful since linking to an external stylesheet is now accomplished in a Hugo partial.
Compile about.adoc directing output to layouts/partials/adoc and using the -s option to strip the generated HTML, leaving a headless body for use as a partial:
asciidoctor -D layouts/partials/adoc -s static/adoc/about.adoc
No immediate effect is seen, but browse to TestTrack’s About page and then add layout: adoc
to the front matter in content/about.md:
content/about.md (add)
layout: adoc
Instantly, upon saving the "shadow" about.md file, AsciiDoc content appears in the browser! That happens because changing layout to adoc "pulls the trigger" injecting the generated HTML partial into the About page along with any other content that’s already there. The effect is immediate!
Change layout from adoc to single and save. Now the AsciiDoc content is hidden, but content from other sources remains, suggesting there are many possible ways to get information onto a page. Change layout back to adoc and save once more to return to normal viewing.
Complexity in a Nutshell
To summarize the preceding instructions start to finish, let’s walk through the three basic steps for creating new AsciiDoc documents to be injected into a site as Hugo partials.
For a test document, the next AsciiDoc file marks up and individually colors header levels 2 to 6. A companion Markdown file in the next section does the same. The finished page is then constructed using content from both sources.
All steps from the preceding part starting from CODE SECRET THREE must be completed (just once) before proceeding with the following three numbered steps. |
1: Create an AsciiDoc document, such as the following with inline-colored samples of header levels 2 through 6:
static/adoc/headers.adoc
- - -
[big]#_Above: *Markdown* syntax_#
[big]#_Below: *AsciiDoc* syntax_#
== [green]#Header level 2#
=== [blue]#Header level 3#
==== [red]#Header level 4#
===== [orange]#Header level 5#
====== [yellow]#Header level 6#
The first line (three spaced-out dashes) creates a divider "ruled" line in the finished page. There are no front matter settings to make. Note how, in AsciiDoc syntax, font sizes and colors are specified ahead of text encased in hatch characters.
Asciidoctor reserves header level 1 for docbook output. That’s no hindrance because the parent site title is often treated as a level 1 header, making level 2 headers probably the better choice anyway for article and page titles in the site. |
2: Create the always-needed Markdown "shadow" file with the command:
hugo new adoc/headers.md
Open the file for editing and add several lines of content below the front matter section as shown here:
content/adoc/headers.md
---
title: "Headers"
date: 2022-10-03T09:49:29-04:00
draft: false
layout: adoc
---
## <span style="color:blue">Header level 2</span>
### <span style="color:green">Header level 3</span>
#### <span style="color:yellow">Header level 4</span>
##### <span style="color:orange">Header level 5</span>
###### <span style="color:red">Header level 6</span>
Be sure to set layout to adoc as shown in the front matter! It might initially be set to headers or single.
For AsciiDoc content to appear on the page, layout must be set to adoc in the document’s "shadow" Markdown file. |
Here again are five header levels, colored uniquely inline, but this time using Markdown HTML <span> tags.
Unfortunately, however, viewing the finished page shows headers colored normally. What’s wrong? Using the browser’s View Source command to investigate reveals the cause. Replacing the expected inline <span> tags are numerous comments such as:
<!-- raw HTML omitted -->
That’s because, for security reasons, Hugo ordinarily disables raw HTML inside Markdown text. To enable it, open the site’s config.toml file and add the following declarations:
config.toml (add)
[markup]
[markup.goldmark]
[markup.goldmark.renderer]
unsafe = true
Header text levels in AsciiDoc may be preceded by equal signs or hatch characters. For example, "== Header" or "## Header". Markdown recognizes only hatch characters. |
There’s one more step to go.
3: Compile the AsciiDoc document, headers.adoc, to a Hugo partial, using the -D and -s options:
asciidoctor -D layouts/partials/adoc -s static/adoc/headers.adoc
Browse to the new Headers document and examine the page content (see Figure 11), assembled from two different source files using two different markup languages, proving that, while Markdown and Asciidoctor may be syntactically incompatible, they can work happily together on the same Hugo website page!
On occasion, it might be necessary to clear the browser cache and to execute a browser refresh in order for style and other changes to take effect. |
Sticky Headers and Footers
To unstick the footer so it doesn’t appear on every page (unless, of course, that’s how you want it!) open file baseof.html in folder layouts/_default/, listed here:
layouts/_default/baseof.html
<!DOCTYPE html>
<html>
{{- partial "head.html" . -}}
<body>
{{- partial "header.html" . -}}
<div id="content">
{{- block "main" . }}{{- end }}
{{- partial "footer.html" . -}}
</div>
</body>
</html>
As its name implies, baseof.html is way down at the base of Hugo’s template totem pole. It’s where all partials and blocks ultimately come together to form the final HTML page. You might find that, as supplied, baseof.html positions the footer partial below the closing </div> tag.
Modify the file as shown, moving the footer partial into the id="content" <div> section, "unsticking" it from the page.
Compiling the User Manual
To optionally add the User Manual (which you are now reading) to your TestTrack, copy source file manual.adoc from the repository to the target site’s static/adoc folder. Compile with the command:
asciidoctor -D layouts/partials/adoc -s static/adoc/manual.adoc
Open content/adoc/manual.md, change layout to adoc, and the full manual text should appear. (You may want to delete the place-holder text too!)
About Image Files
PNG image files for the manual’s figures are stored in folder static/adoc/manual/img. All images for the manual are in the repository.
For other documents, it will be necessary to provide a location for images and other data. For such purposes, create nested subfolders using commands such as the following (replace "manual" with the document name):
mkdir static/adoc/manual/
mkdir static/adoc/manual/img/
Copy PNG image files into the img folder and set imagesdir
as shown at the beginning of this document’s source text:
:imagesdir: /adoc/manual/img
Deploying the Finished Site
There is nothing special about deploying a Hugo site with AsciiDoc content. Simply enter hugo:
hugo
That lone, simple command completely updates the public directory, newly created if necessary, with all of the site’s HTML and data files and folders. After Hugo finishes, usually after only a brief second or so since Hugo is very fast, the finished site is ready for deployment directly from the public folder.
Remember to set the baseURL property in config.toml before compiling and deploying the site! |
Deleting AsciiDoc / Hugo Documents
I always find it comforting to know that, when trying out new software, if anything goes wrong I can "Delete a Disaster" and start over.
To encourage experimentation with TestTrack, this section explains the steps for deleting all files associated with any document or page created using the methods described in this manual.
In the instructions that follow, replace "example" with the name of the document to be deleted. |
-
Delete content/adoc/example.md
-
Delete layouts/adoc/example.html
-
Delete static/adoc/example.adoc
-
Delete subfolder static/adoc/example/
Some of the preceding files and folders may or may not exist when you go to delete them! |
-
Delete content/example.md or content/adoc/example.md
-
Delete layouts/partials/adoc/example.html
-
Delete static/adoc/example.adoc
-
Delete subfolder static/adoc/example/
As with the first two methods, some or all of the preceding files and folders may or may not exist when you go to delete them! |
Also delete target(s) and rule(s) from Makefile for all removed documents.
Final Words
TestTrack is an unfinished, evolving project—and that is probably the only thing about it that will never change! I welcome any and all contributions and suggestions for making it better.
To those who have read through this manual from start to finish, my heartfelt thanks. To all, thank you for trying out TestTrack! I value your comments and if you find an error, please let me know right away!
I learned a tremendous amount by meticulously "performing" this manual several times over. It’s my hope that if you do the same—maybe once, maybe twice—you will learn what you want to know about Asciidoctor and Hugo more easily and more enjoyably than by only reading a book or watching a couple of videos (even mine!).
'Cause nothin' beats hands-on learnin'!
Good luck!
Tom Swan