I’m currently writing on a post about a cool new tool I recently found GitGraph.js. In the article, I wanted to show some examples of what you can do with it and how it' renders. But of course, this did not work out-of-box with Hugo. While investigating how to do Git graphs I found that MermaidJS had some primitive support for GitGraph.js
.
It’s is not a complicated task to include support for GitGraph.js
using Hugo shortcodes, there is however some caveats to it. Below I have written a guide to include support for GitGraph.js
and MermaidJS
in your Hugo site
Base Setup
While I’m writing this article, I’m using this configuration.
Hugo v0.78.2/extended
.
Theme simple-blog by 10mohi6 (with personal customizations)
$ > hugo version
Hugo Static Site Generator v0.78.2/extended darwin/amd64 BuildDate: unknown
File Structure and Purpose
For me, it’s essential not to touch the original theme’s files, so I overwrite them in my file structure.
Relative Path in the Repo | File Description |
---|---|
config/_default/config.toml | Hugo Static Site Generator global configuration file See Hugo-CI |
archetypes/default.md | Default Configuration used to create a new Post |
data/git-example.yaml | Git Graph Commit Information Data file |
layouts/partials/script.html | Partial template that enables additional imports for JavaScript and CSS |
layouts/shortcodes/mermaid.html | Short Code to use for MermaidJS |
layouts/shortcodes/gitgraph.html | Short Code to use for GitGraph.js Inclusion |
Short Code for MermaidJS
Basic Configguration
Include Custem 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]
mermaidJS = '<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: layouts/partials/script.html
We selectively check if the post asks for MermaidJS to be included or not and include the JS required, only when that parameter is set to true. This is done 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.mermaidJS | safeHTML }}
{{- end }}
Include it in the site
At the bottom of the themes/simple-blog/layouts/_default/single.html
or you can do as I did and copy it to layouts/_default/single.html
and add the following line to the file you wish to use.
...
{{ partial "scripts.html" . }}
Create the shortcode files
layouts/shortcodes/mermaid.html
should look as follow
<!-- file: layouts/shortcodes/mermaid.html -->
<div class="mermaid">
{{.Inner}}
</div>
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
---
Consuming MermaidJS Short Codes
Now we can create a new Post using the Hugo command-line option.
$> hugo new content/posts/example.md
content/posts/example.md created
---
title: "Example"
date: 2020-07-03T17:14:38+05:30
draft: true
mermaidJS:
enable: true
---
# Mermaid example
{ {< mermaid >}} <-- notice the space between the two {{ it should not be there!
sequenceDiagram
A->B: Normal line
B-->C: Dashed line
C->>D: Open arrow
D-->>A: Dashed open arrow
{ {</ mermaid >}} <-- notice the space between the two {{ it should not be there!
and you’ll get
Mermaid example
Futher 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 primitive support for the GitGraph.js
that can be used to render a commit-graph of your git logs. However, it is very primitive and not extendable yet as it is still in the experimental phase. But there is an excellent alternative in the form of GitGraph.js
.
Including this one took a bit more effort than including the mermaidJS
. Since the integration wasn’t that simple, and I wanted it to be backed by a data file instead of hard-coding the commit-graph’s contents in the markdown
document of the Blog.
Basic configuration
Include Custom JavaScript and CSS Files
Same as we did while performing mermaidJS
integration, we will include a configuration file record to have javascript and CSS files that will bring in the GitGraph.js
support.
[params]
gitgraph = '<script src="https://cdn.jsdelivr.net/npm/@gitgraph/js" crossorigin="anonymous"></script>'
Conditionally Enable GitGraph on posts
<!--
file: layouts/partials/script.html
We selectively check if the post asks for MermaidJS to be included or not and include the JS required only when that parameter is set to true. This is done 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.gitGraph. | safeHTML }}
{{- end }}
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. 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" }}
<div id="graph" class="svg-container"></div>
{{ $arg := .Get 0 }}
{{ $dataFile := index .Site.Data $arg }}
<script>
window.onload = (event) => {
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, {
author: "Jes Struck <mail@jesstruck.dk>",
template: template,
orientation: "vertical",
layout: "responsive",
svgClasses: ["svc-content"],
});
window.gitGraph = gitGraph;
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
- More work
- Introduce responsive layout
- "Add media query support."
- "Add parameterized template override."
Consuming GitGraph shortcode
---
title: "Example"
date: 2020-07-03T17:14:38+05:30
draft: true
gitGraph:
enable: true
---
{ {< gitgraph "git-example" >}} <-- Skip the space between the two {{
Which will render a GitGraph.js
like the one below.
GitGraph example
Tagged: #Hugo #javascript #GitGraphJS #MermaidJS