Not so long ago, this very blog was being hosted on DigitalOcean using Ghost. However, it did not take me long to realize that for the kind of content I have in mind for the blog, a hosting on DigitalOcean with Ghost as a backend isn’t the best option. It was not cost effective and not easy to manage data backups without extra cost.
So, I moved my entire content (which had one post at that time) to Hugo and it has been an incredible experience to get it up and running. Netlify has been a saving grace with their amazing hosting and GitHub integration. All I had to worry about was making sure that I keep my domain name active and configure it the right way.
Base Setup
This entire post is written with the following configuration in mind.
- Hugo
v0.73.0/extended
- Theme Pure by xiaoheiAh (with personal customizations)
▲ ~/Documents/personal-blog.harshanarayana.dev hugo version 45s ⇡ staging :: 36m :: ⬡
Hugo Static Site Generator v0.73.0/extended darwin/amd64 BuildDate: unknown
File Structure and Purpose
Relative Path in the Repo | File Description |
---|---|
config.toml | Hugo Static Site Generator global configuration file |
archetypes/default.md | Default Configuration used to create a new Post |
data/git-example.yaml | Git Graph Commit Information Data file |
themes/pure/assets/js/application.js | Customized version of the base JavaScript setup for the Blog theme |
themes/pure/layouts/partials/script.html | Partial template that enables additional imports for JavaScript and CSS |
themes/pure/layouts/shortcodes/mermaid.html | Short Code to use for MermaidJS |
themes/pure/layouts/shortcodes/gitgraph.html | Short Code to use for GitGraph.Js Inclusion |
Short Code for MermaidJS
Basic Configurations
Include Custom JavaScript and CSS Files
Let us make a few changes in the config.toml
to include a few items that indicate all the required js
and css
files to be included into
the static site to get the mermaidJS
diagrams working.
# config.toml
[params.publicCDN.mermaidJS]
javascript = '<script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/8.5.2/mermaid.min.js" integrity="sha256-y9inIfeUjJK2oCN6/ER6D/iC661lxlvgYGHt6WnZ/xk=" crossorigin="anonymous"></script>'
Conditionally Enable MermaidJS on posts
Now, we need to include the Javascript configured above in the config.toml
so that it can be included while generating the static site if required.
<!--
file: themes/pure/layouts/partials/script.html
We selectively check if the post asks for MermaidJS to be included or not and include the JS reqired for it only
when that parameter is set to true. This is done in order to ensure that we don't include unwanted js and slow
down the page load time.
-->
{{- if and ( .Params.mermaidJS.enable ) (or .IsPage .IsHome) -}}
{{ .Site.Params.publicCDN.mermaidJS.javascript | safeHTML }}
{{- end }}
Create a shortcode file
<!-- file: themes/pure/layouts/shortcodes/mermaid.html -->
<div class="mermaid">
{{.Inner}}
</div>
Activate MermaidJS templates
Initialize the mermaidjs
instance if the window
has a property of mermaid
. Which happens only if the inclusion was performed in the step above.
// themes/pure/assets/js/application.js
if (window.mermaid) {
var config = {
theme: "null",
logLevel: "fatal",
securityLevel: "strict",
startOnLoad: true,
arrowMarkerAbsolute: false,
flowchart: {
htmlLabels: true,
curve: "linear",
},
sequence: {
diagramMarginX: 50,
diagramMarginY: 10,
actorMargin: 50,
width: 150,
height: 65,
boxMargin: 10,
boxTextMargin: 5,
noteMargin: 10,
messageMargin: 35,
messageAlign: "center",
mirrorActors: true,
bottomMarginAdj: 1,
useMaxWidth: true,
rightAngles: false,
showSequenceNumbers: false,
},
gantt: {
titleTopMargin: 25,
barHeight: 20,
barGap: 4,
topPadding: 50,
leftPadding: 75,
gridLineStartPadding: 35,
fontSize: 11,
fontFamily: '"Open-Sans", "sans-serif"',
numberSectionStyles: 4,
axisFormat: "%Y-%m-%d",
},
};
window.mermaid.initialize(config);
}
Setup Default options for ShortCode configuration
Configure the archetypes/default.md
file to include the default values for shortCode configuration
---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
mermaidJS:
enable: false
---
Consuiming MermaidJS Short Codes
Now we can create a new Post using the hugo
command line option.
▲ ~/Documents/personal-blog.harshanarayana.dev hugo new content/posts/example.md ⇡ staging :: 10m :: ⬢
content/posts/example.md created
---
title: "Example"
date: 2020-07-03T17:14:38+05:30
draft: true
mermaidJS:
enable: true
---
{{< mermaid >}}
sequenceDiagram
A->B: Normal line
B-->C: Dashed line
C->>D: Open arrow
D-->>A: Dashed open arrow
{{</ mermaid >}}
This will render into a sequence diagram shown below.
Further Reading
- MermaidJS Documentation to explore the possible options and usage examples
Short Code for GitGraph.js
While exploring the possibilities of mermaidjs
I noticed they have a primitive support for the gitGraph
that can be used to render a commit graph of your git logs.
However, it is very primitive and not really extendable yet as it is still in experimental phase. But there is a great alternative in the form of GitGraph.js
Including this one took a bit more effort that including the mermaidjs
since the integration wasn’t really that simple and I wanted it to be backed by a data file instead of
hard-coding the contents of the commit graph in the markdown
document of the Blog.
Basic Configurations
Include Custom JavaScript and CSS Files
Same as we did while performing mermaidjs
integration, we will go ahead and include a configuration file record to include javascript
and css
files that will bring in the
gitgraph.js
support.
[params.publicCDN.gitGraph]
javascript = '<script src="https://cdn.jsdelivr.net/npm/@gitgraph/js" crossorigin="anonymous"></script>'
Conditionally Enable GitGraph on posts
<!--
file: themes/pure/layouts/partials/script.html
We selectively check if the post asks for MermaidJS to be included or not and include the JS reqired for it only
when that parameter is set to true. This is done in order to ensure that we don't include unwanted js and slow
down the page load time.
-->
{{- if and ( .Params.gitGraph.enable ) (or .IsPage .IsHome) -}}
{{ .Site.Params.publicCDN.gitGraph.javascript | safeHTML }}
{{- end }}
Activate GitGraph instance
if (window.GitgraphJS) {
const graphContainer = document.getElementById("graph");
var template = {
colors: ["#6963FF", "#47E8D4", "#6BDB52", "#E84BA5", "#FFA657"],
arrow: { size: 5, color: null, offset: -1.5 },
branch: {
color: "#e0ebeb",
lineWidth: 3,
mergeStyle: "straight",
spacing: 30,
label: {
display: true,
bgColor: "white",
font: "normal 10pt 'Fira Mono', monospace",
borderRadius: 5,
},
},
commit: {
spacing: 50,
hasTooltipInCompactMode: true,
dot: {
size: 5,
strokeWidth: 1,
strokeColor: "#e0ebeb",
font: "normal 10pt 'Fira Mono', monospace",
},
message: {
display: true,
displayAuthor: false,
displayHash: true,
color: "black",
font: "normal 10pt 'Fira Mono', monospace",
},
},
tag: {},
};
var gitGraph = window.GitgraphJS.createGitgraph(graphContainer, {
template: template,
author: "Harsha Narayana <harsha2k4@gmail.com>",
orientation: "vertical",
layout: "responsive",
svgClasses: ["svc-content"],
});
window.gitGraph = gitGraph;
Setup Default options for ShortCode configuration
Configure the archetypes/default.md
file to include the default values for shortCode configuration
---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
gitGraph:
enable: false
---
Setup data Rendering using Data Files and ShortCode
Hugo has an incredible concept called data templates that lets you use toml
yaml
or json
file as a source of data and use them in your shortcode templates as you see fit. In order to activate this all you need to do is create the following.
Create a file data/example.toml
and you are done. Now you can access the data from the file using example
arg and combine it with a magic sauce {{ $dataFile := index .Site.Data "example" }}
// file: themes/pure/layouts/shortcodes/gitgraph.html
<div id="graph" class="svg-container"></div>
{{ $arg := .Get 0 }}
{{ $dataFile := index .Site.Data $arg }}
<script>
window.onload = (event) => {
var g = window.gitGraph;
function createNewGitBranch(data){
/**
* Check if there is a property for the window object that matches the
* name of the branch in question. If it is present, that means a branch
* has already been created and there is nothing else that needs to be done.
*
* However, if the is no property matching the branch name is present then
* this is a new branch and needs to be created.
*
* You are free to customize the way these properties are managed at the
* window lever for better optimization.
*/
var parentBranch = data.meta.parent;
var branchName = data.meta.name
if ( window.hasOwnProperty(branchName) ) {
return branchName;
}
if ( parentBranch === "" ) {
var branch = g.branch(branchName);
} else {
var branch = window[parentBranch].branch(branchName);
}
window[branchName] = branch;
return branchName
}
/**
* Conditionally add comments and other branch level components so that the
* graph is built and rendered on the UI.
*/
{{ range $branch := $dataFile.gitGraph }}
var branchName = createNewGitBranch({{ .branch }});
{{ range $commit := .branch.commit }}
window[branchName].commit({{ . }});
{{ end }}
{{ if index .branch "merge" }}
var baseBranch = {{ .branch.merge.base }};
var mergeCommit = {{ .branch.merge.commit }};
window[baseBranch].merge(window[branchName], mergeCommit);
{{ end }}
{{ if index .branch "tag" }}
var branchToTag = {{ .branch.tag.branch }};
var tagVersion = {{ .branch.tag.version }};
window[branchToTag].tag(tagVersion);
{{ end }}
{{ end }}
}
</script>
Create an Example Data File
# data/git-example.yaml
gitGraph:
- branch:
meta:
parent: ""
name: master
commit:
- Initial commit
- branch:
meta:
name: develop
parent: master
commit:
- Cut new Dev Branch
- branch:
meta:
name: feature/f1
parent: develop
commit:
- "feat: introduce form layout"
- branch:
meta:
name: feature/f2
parent: develop
commit:
- "feat: introduce responsive layout"
- "enh: add media query support"
- "enh: add parameterized template override"
merge:
base: develop
commit: "feat: branch responsive layout into main dev"
Consuming GitGraph shortcode
---
title: "Example"
date: 2020-07-03T17:14:38+05:30
draft: true
gitGraph:
enable: true
---
{{< gitgraph "git-example" >}}
Which will render a gitgraph
as the one below.
Further Reading
- GitGraph.js Documentation has a few great examples and documentation to indicate the usage.
To Do
- If you carefully look at the current shortcode implementation, it can support only one graph per page due to how the branches are managed. This needs to be customized
to add an additional property in the data file to take the name of the graph and store all properties inside that named property on
window
object.