How to use Obsidian with Hugo Static Site Generator
Ignore unwanted files
All of my Obsidian notes are save in content
folder. That’s mean there are notes and files that I don’t want it to be part of the site included. I have to let Hugo know to ignore them. We can set that in hugo.yaml
file:
ignoreFiles:
- content/.obsidian/\.*
- content/10 Inbox/\.*
- content/20 Notes/\.*
- content/40 Projects/\.*
- content/50 Commonplace/\.*
- content/60 Resources/\.*
- content/70 Archive/\.*
Process markdown links
By default, the Obsidian’s internal links doesn’t work properly when processed with Hugo.
[[Wikilinks]] doesn’t have any relative path to notes in another folder. Make it difficult to phases the link, especially when there are notes with the same name in another folders. How would anyone know which note the link actually linked to, beside Obsidian?
It’s appeared that solution by ichmoimeyo is to change the settings in Obsidian as follow:
Under Files and Links
:
- Set
Default location for new notes
->Same folder as current file
. - Set
New Link format
->Relative path to file
. - Set
Use [[Wikilinks]]
->off
. - Set
Default location for new attachments
->In subfolder under current folder
. - Set
Subfolder name
->attachments
.
This will format link to be similar to standard the Markdown links. Make it easier to know which note in which folder the link actually linked to.
NoteEven if you disable the Wikilink format, you can still autocomplete links by typing two square brackets [[ . When you select one of the suggested files, Obsidian will generates a Markdown link.
Here is the inline partial template that converts Obsidian markdown links to links that works in Hugo:
Create obsidianMd.html
in layouts/partials/inline/
. Copy code from below and save it to the file:
{{- define "partials/inline/obsidianMd.html" -}}
{{- $content := .content -}}
{{- $pageRelLink := .pageRelLink -}}
{{- $regexLinks := `href="([^"]*)` -}}
{{- $links := $content | findRE $regexLinks -}}
{{- /* Run through all the links in content */ -}}
{{- range $links -}}
{{- $source := . -}}
{{- /* Extract only URL from source */ -}}
{{- $url := substr . 6 -}}
{{- /* Skip external link */ -}}
{{- if hasPrefix $url "https://" -}}
{{- continue -}}
{{- end -}}
{{- if hasPrefix $url "http://" -}}
{{- continue -}}
{{- end -}}
{{- /* Convert link to a fragment */ -}}
{{- if hasPrefix $url "#" -}}
{{- $baseName := path.BaseName $pageRelLink -}}
{{- $url = path.Join $baseName $url -}}
{{- end -}}
{{- /* Convert URL */ -}}
{{- $url = lower $url -}}
{{- $url = replace $url " - " " " -}}
{{- $url = replace $url " " "-" -}}
{{- $url = replace $url "%20" "-" -}}
{{- $url = replace $url ".md" "" -}}
{{- $url = replace $url "#" "/#" -}}
{{- if hasPrefix $url "../" -}}
{{- $url = replace $url "../" "../../" -}}
{{- else -}}
{{- $url = print "../" $url -}}
{{- end -}}
{{- $link := print `href="` $url -}}
{{- /* Replace link in content */ -}}
{{- $content = replace $content $source $link -}}
{{- end -}}
{{- /* Output content */ -}}
{{- $content | safeHTML -}}
{{- end -}}
Here is how to use it:
{{- partial "inline/obsidianMd" (dict "content" .Content "pageRelLink" .Page.RelPermalink) -}}
How to make external link open in a new tab
Create render-link.html
in layouts/_default/_markup/
. Copy code from below and save it to the file:
<a href="{{ .Destination | safeURL }}"{{ with .Title}} title="{{ . }}"{{ end }}{{ if or (strings.HasPrefix .Destination "http") (strings.HasPrefix .Destination "https") }} target="_blank"{{ end }} >{{ .Text | safeHTML }}</a>
How to add external link indicator
Use this code instead of the one above. This one will also open external link in a new tab.
<a {{ if or (strings.HasPrefix .Destination "http") (strings.HasPrefix .Destination "https") }}class="external-link"{{ end }} href="{{ .Destination | safeURL }}"{{ with .Title}} title="{{ . }}"{{ end }}{{ if or (strings.HasPrefix .Destination "http") (strings.HasPrefix .Destination "https") }} target="_blank"{{ end }} >{{ .Text | safeHTML }}</a>
Then, in your CSS file, add the following:
.external-link::after {
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="rgb(136, 136, 136)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-external-link"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" x2="21" y1="14" y2="3"/></svg>');
top: 1px;
padding-left: 2px;
position: relative;
}
This will add Lucide’s external link icon at the end of every external links.
Support Callouts
Obsidian has support for Callouts, and I want to implement that as I used it quite a lot on my notes.
Here is the code:
{{- $content := .content -}}
{{- $regexCallout := `<blockquote>\n<p>\[!(.+)\] ?(.+)?\n` -}}
{{- $callouts := $content | findRE $regexCallout -}}
{{- range $callouts -}}
{{- $callout := findRESubmatch $regexCallout . -}}
{{- $type := index $callout 0 1 -}}
{{- $title := index $callout 0 2 -}}
{{- if eq $title "" }}
{{- $content = replaceRE $regexCallout `<blockquote class="callout $1"><div class="title">%%$1%%</div><p></p>` $content 1 -}}
{{- $content = replaceRE $regexCallout `<blockquote class="callout $1"><div class="title">$2</div><p></p>` $content 1 -}}
{{- end -}}
{{- end -}}
{{- $content = replace $content "Note" "Note" -}}
{{- $content = replace $content "Quote" "Quote" -}}
Put it before the {{- /* Run through all the links in content */ -}}
block like the following:
{{- $content := .content -}}
{{- $pageRelLink := .pageRelLink -}}
{{- $regexCallout := `<blockquote>\n<p>\[!(.+)\] ?(.+)?\n` -}}
{{- $regexLinks := `href="([^"]*)` -}}
{{- $callouts := $content | findRE $regexCallout -}}
{{- $links := $content | findRE $regexLinks -}}
{{- /* Convert Callouts */ -}}
{{- range $callouts -}}
{{- $callout := findRESubmatch $regexCallout . -}}
{{- $type := index $callout 0 1 -}}
{{- $title := index $callout 0 2 -}}
{{- if eq $title "" }}
{{- $content = replaceRE $regexCallout `<blockquote class="callout $1"><div class="title">%%$1%%</div><p></p>` $content 1 -}}
{{- $content = replaceRE $regexCallout `<blockquote class="callout $1"><div class="title">$2</div><p></p>` $content 1 -}}
{{- end -}}
{{- end -}}
{{- $content = replace $content "Note" "Note" -}}
{{- $content = replace $content "Quote" "Quote" -}}
{{- /* Run through all the links in content */ -}}
{{- range $links -}}
How to test Hugo site on the other devices within LAN
Use the following command line:
hugo server --bind <your-ip-address> --baseURL http://<your-ip-address>
To test your Hugo site with draft contents as well, use this command line:
hugo server --bind -D <your-ip-address> --baseURL http://<your-ip-address>