By Erik Larson | August 22, 2020
Follow @statropy Sponsor Watch Star Fork Use this template Issue Download
GitHub provides a javascript library to add GitHub-related buttons to your website.
This website is generated using Hugo, a static site generator written in Go. A site is generated using a theme, which specifies the layout and look of the site. It also allows customization using .toml
configuration files. Content (like this blog entry) is created using markdown. Hugo then generates the HTML and CSS for the site using the theme and content.
One way to provide features for a hugo site is with shortcodes. Shortcodes allow the content creator to add simple tags in a markdown file to create specific content. Hugo uses the shortcode and parameters to create html using snippets. The GitHub buttons can be used by adding a javascript source and a single anchor tag. Let’s create a shortcode to allow adding these buttons in hugo.
GitHub Button API
This is the html snippet for the follow
button at the top of the page
<a
class="github-button"
href="https://github.com/statropy"
aria-label="Follow @statropy on GitHub"
>
Follow @statropy
</a>
Create an anchor tag with class="github-button"
. The href
links to the GitHub user page. The aria-label
provides a description of the button.
Follow Button
To create a shortcode snippet for a follow button, create an html file and place it in the /layouts/shortcodes
folder of either the hugo project or theme. The name of the html file is the name of the shortcode. github_follow_button.html
<a
class="github-button"
href="https://github.com/{{.Get 0}}"
aria-label="Follow @{{.Get 0}} on GitHub"
>
Follow @{{.Get 0}}
</a>
Hugo uses {{
and }}
to insert text into static files. The .Get
hugo function is used to access the parameters provided with the shortcode. We are only going to use a single parameter, the GitHub username, so {{.Get 0}}
will be replaced with the username provided in the markdown.
The javascript library also needs to be included in the <head>
of the page. To only load a script when a specific shortcode is used, add this to the head.html
snippet
{{ if .HasShortcode "github_follow_button" }}
<script async defer src="https://buttons.github.io/buttons.js"></script>
{{ end }}
This calls the hugo function .HasShortCode
, which will only insert the inner text into the file if the shortcode is on that page. Now we can add the shortcode to a markdown file.
{{< github_follow_button "statropy" >}}
And now we have a button!
Follow @statropyStar Button
The Star button will allow a user to Star a given repo, so let’s add a shortcode for that also, github_star_button.html
<a
class="github-button"
href="https://github.com/{{.Get 0}}/{{.Get 1}}"
aria-label="Star {{.Get 0}}/{{.Get 1}} on GitHub"
data-show-count="{.Get 2}"
>
Star {{.Get 0}}/{{.Get 1}}
</a>
For the Star button, there is an option to display the star count along with the button. Now there are 3 parameters, user
, repo
and count
.
{{< github_star_button "statropy" "github-button-hugo-shortcode" "true" >}}
Because it is a different shortcode, the script tag in head.html
needs to be inserted for this one too
{{if or (.HasShortcode "github_follow_button") (.HasShortcode "github_star_button")}}
<script async defer src="https://buttons.github.io/buttons.js"></script>
{{ end }}
A Better Shortcode
We have 2 working buttons now, but there are some problems creeping in. There are 6 more buttons to add, which means 6 more shortcodes. The head.html
snippet will have to be updated for each one, leading to a pretty big if
statement. There are more parameters that can be added, such as color scheme and large button flags, but keeping track of them just by order is getting difficult. The code to implement those options is the same for each button, which leads to a lot of copy-and-paste. We should be able to combine these buttons into a single shortcode.
The github_button Shortcode
The new shortcode will be named github_button
. The first change to make is switching from positional parameters
(0, 1, 2, etc) to named parameters
. The first parameter to define is button
, which will be the type of button to display. The possible values for button
will be
follow
sponsor
watch
star
fork
template
issue
download
For now only the follow
and star
types will be implemented, since we know how to do those already. Once those are working, the other types cand be added.
The next parameter is user
, which is the GitHub username. The button
and user
parameters are used in every github_button
.
The remaining parameters are repo
, which is the GitHub repository name and count
, which will add the appropriate number to the button.
Edit the head.html
snippet so that it only checks for the new shortcode.
{{ if .HasShortcode "github_button" }}
<script async defer src="https://buttons.github.io/buttons.js"></script>
{{ end }}
Create a new shortcode file named github_button.html
.
1{{ $button := .Get "button"}}
2{{ $data_icon := "mark-github" }}
3{{ $aria_label := "" }}
4{{ $button_text := "" }}
5{{ $href := "" }}
6
7{{if eq $button "follow"}}
8 {{ $href = printf "%s" (.Get "user")}}
9 {{ $aria_label = printf "Follow @%s on GitHub" (.Get "user") }}
10 {{ $button_text = printf "Follow @%s" (.Get "user") }}
11{{else if eq $button "star"}}
12 {{ $href = printf "%s/%s/" (.Get "user") (.Get "repo")}}
13 {{ $data_icon = "star" }}
14 {{ $aria_label = printf "Star %s/%s on GitHub" (.Get "user") (.Get "repo")}}
15 {{ $button_text = "Star" }}
16{{end}}
17
18<a
19 class="github-button"
20 href="https://github.com/{{$href}}"
21 data-icon="octicon-{{$data_icon}}"
22 aria-label="{{$aria_label}}"
23 {{ with .Get "count"}} data-show-count="{{.}}"{{ end }}
24>
25{{$button_text}}
26</a>
Lines 1-5 define the variables to be used. The $button
variable is the button type, which is set by using the .Get
function, this time with the parameter name instead of the position number. mark-github
is the default icon, so $data_icon
is set to that. The other variables will be set based on the button type.
To build the strings from variables and parameters, the printf
function is used. Notice that the variable declaration syntax $var := "value"
is different from assigning to an existing variable $var = "new value"
. Lines 7-16 make the string assignments for each button type.
For the anchor tag, the class
is always the same. The href
always begins with https://github.com/
, so the $href
variable only contains the rest of the URL. The data-icon
and aria-label
are set also.
The data-show-count
uses some new syntax. The with
function is useful for checking if the parameter exists. If the shortcode tag in the markdown includes the count
parameter, then the text inside the block (until {{ end }}
) is inserted, and the value of .Get "count"
is accessed using {{.}}
. If the count
parameter isn’t used, then the block is skipped. This makes adding optional parameters pretty simple and compact.
Finally the $button_text
is inserted, the tag is closed, and we have our new shortcode.
Edit the markdown file to use the new shortcode.
{{< github_button button="follow" user="statropy" >}}
{{< github_button button="star" user="statropy" repo="github-button-hugo-shortcode" count="true" >}}
Adding more options
Now that new parameters only need to be added in one place, adding color scheme
and size
options should be easy.
1{{ $button := .Get "button"}}
2{{ $data_icon := "mark-github" }}
3{{ $aria_label := "" }}
4{{ $button_text := "" }}
5{{ $href := "" }}
6
7{{if eq $button "follow"}}
8 {{ $href = printf "%s" (.Get "user")}}
9 {{ $aria_label = printf "Follow @%s on GitHub" (.Get "user") }}
10 {{ $button_text = printf "Follow @%s" (.Get "user") }}
11{{else if eq $button "star"}}
12 {{ $href = printf "%s/%s/" (.Get "user") (.Get "repo")}}
13 {{ $data_icon = "star" }}
14 {{ $aria_label = printf "Star %s/%s on GitHub" (.Get "user") (.Get "repo")}}
15 {{ $button_text = "Star" }}
16{{end}}
17
18<a
19 class="github-button"
20 href="https://github.com/{{$href}}"
21 data-icon="octicon-{{$data_icon}}"
22 aria-label="{{$aria_label}}"
23 {{ with .Get "count"}} data-show-count="{{.}}"{{ end }}
24 {{if eq "true" (.Get "dark")}}data-color-scheme="dark"{{ end }}
25 {{if eq "true" (.Get "large")}}data-size="large"{{ end }}
26>
27{{$button_text}}
28</a>
For the color-scheme, light
is the default. To use the dark
color scheme, a new optional parameter dark
is added. For the shortcode user, this is a true
/false
flag, with false
being the default. Specifying dark="true"
will add data-color-scheme="dark"
to the anchor tag. To do this, the eq function compares the value of dark
to true
. Any other value, or no value specified, will omit data-color-scheme
.
The large
parameter works the same way. data-size="large"
is only added if the large
parameter is set to true
{{< github_button button="follow" user="statropy" large="true" >}}
{{< github_button button="star" user="statropy" repo="github-button-hugo-shortcode" count="true" dark="true" >}}
Finishing github_button
1{{ $button := .Get "button"}}
2{{ $data_icon := "mark-github" }}
3{{ $aria_label := "" }}
4{{ $button_text := "" }}
5{{ $href := "" }}
6
7{{if eq $button "follow"}}
8 {{ $href = printf "%s" (.Get "user")}}
9 {{ $aria_label = printf "Follow @%s on GitHub" (.Get "user") }}
10 {{ $button_text = printf "Follow @%s" (.Get "user") }}
11{{else if eq $button "sponsor"}}
12 {{ $href = printf "sponsors/%s/" (.Get "user")}}
13 {{ $data_icon = "heart" }}
14 {{ $aria_label = printf "Sponsor @%s on GitHub" (.Get "user") }}
15 {{ $button_text = "Sponsor" }}
16{{else if eq $button "watch"}}
17 {{ $href = printf "%s/%s/subscription" (.Get "user") (.Get "repo")}}
18 {{ $data_icon = "eye" }}
19 {{ $aria_label = printf "Watch %s/%s on GitHub" (.Get "user") (.Get "repo")}}
20 {{ $button_text = "Watch" }}
21{{else if eq $button "star"}}
22 {{ $href = printf "%s/%s/" (.Get "user") (.Get "repo")}}
23 {{ $data_icon = "star" }}
24 {{ $aria_label = printf "Star %s/%s on GitHub" (.Get "user") (.Get "repo")}}
25 {{ $button_text = "Star" }}
26{{else if eq $button "fork"}}
27 {{ $href = printf "%s/%s/fork" (.Get "user") (.Get "repo")}}
28 {{ $data_icon = "repo-forked" }}
29 {{ $aria_label = printf "Fork %s/%s on GitHub" (.Get "user") (.Get "repo")}}
30 {{ $button_text = "Fork" }}
31{{else if eq $button "template"}}
32 {{ $href = printf "%s/%s/generate" (.Get "user") (.Get "repo")}}
33 {{ $data_icon = "repo-template" }}
34 {{ $aria_label = printf "Use this template %s/%s on GitHub" (.Get "user") (.Get "repo")}}
35 {{ $button_text = "Use this template" }}
36{{else if eq $button "issue"}}
37 {{ $href = printf "%s/%s/issues" (.Get "user") (.Get "repo")}}
38 {{ $data_icon = "issue-opened" }}
39 {{ $aria_label = printf "Issue %s/%s on GitHub" (.Get "user") (.Get "repo")}}
40 {{ $button_text = "Issue" }}
41{{else if eq $button "download"}}
42 {{ $branch := default "master" (.Get "branch")}}
43 {{ $href = printf "%s/%s/archive/%s.zip" (.Get "user") (.Get "repo") $branch}}
44 {{ $data_icon = "download" }}
45 {{ $aria_label = printf "Download %s/%s on GitHub" (.Get "user") (.Get "repo")}}
46 {{ $button_text = "Download" }}
47{{end}}
48
49<a
50 class="github-button"
51 href="https://github.com/{{$href}}"
52 data-icon="octicon-{{$data_icon}}"
53 aria-label="{{$aria_label}}"
54 {{ with .Get "count"}} data-show-count="{{.}}"{{ end }}
55 {{if eq "true" (.Get "dark")}}data-color-scheme="dark"{{ end }}
56 {{if eq "true" (.Get "large")}}data-size="large"{{ end }}
57>
58{{$button_text}}
59</a>
Adding the 6 remaining buttons only requires setting the existing variables for each new button type. The anchor tag doesn’t change! There is one new optional parameter, branch
, that is only used with the download
button. Specifying branch
in the shortcode will choose that branch for the zip file to download. If not specified, the default master
branch is used.
The shortcodes used to generate the buttons at the top of the page.
{{< github_button button="follow" user="statropy" >}}
{{< github_button button="sponsor" user="statropy" >}}
{{< github_button button="watch" user="statropy" repo="github-button-hugo-shortcode" count="true" >}}
{{< github_button button="star" user="statropy" repo="github-button-hugo-shortcode" count="true" >}}
{{< github_button button="fork" user="statropy" repo="github-button-hugo-shortcode" count="true" >}}
{{< github_button button="template" user="statropy" repo="github-button-hugo-shortcode" >}}
{{< github_button button="issue" user="statropy" repo="github-button-hugo-shortcode" count="true" >}}
{{< github_button button="download" user="statropy" repo="github-button-hugo-shortcode" >}}
More Customization
Software is never finished, only abandoned. Not ready to abandon this just yet, this shortcode can have more customizations.
View button type
github-button-hugo-shortcodeAdd a new button type that, by default, displays the repo
name and links to the repo
. All that’s needed is another else if
block.
{{else if eq $button "view"}}
{{ $href = printf "%s/%s" (.Get "user") (.Get "repo")}}
{{ $data_icon = "mark-github" }}
{{ $aria_label = printf "View %s/%s on GitHub" (.Get "user") (.Get "repo")}}
{{ $button_text = .Get "repo" }}
{{end}}
There are some more parameters that can be exposed for customization.
What?icon
parameter
Change the icon from the default, if specified.
{{ with .Get "icon" }}
{{ $data_icon = . }}
{{ end }}
text
parameter
Change the button text from the default, if specified.
{{ with .Get "text" }}
{{ $button_text = . }}
{{ end }}
aria_label
parameter
Change the aria-label from the default, if specified.
{{ with .Get "aria_label" }}
{{ $aria_label = . }}
{{ end }}
Conclusion
Adding a shortcode to hugo, as we’ve shown, is actually pretty easy. If you like this shortcode, then give it a Star ! Have an idea for improving this shortcode? Then Fork it and submit a pull-request. Just want to use the shortcode in your own hugo project? Then Download it. If you find a bug, please submit an Issue .
If interested in other things I’m working on?
Follow @statropy