Obsidian and Quartz for Static Website Generation

Brief

Create a static website from markdown using Obsidian as markdown editor and Quartz to generate the HTML site. This is an SSG written in NodeJS in the traditional sense. It reads the Obsidian Markdown and auto-generates the site. You use node on CLI to show a web preview inside a locally running webserver or you output the files to a directory.

Quartz is not a plugin for obsidian. Quartz is a stand alone project reportedly written to work with Obsidian Markdown files. It does require minor some setup.

SSGs are great at generating static HTML files until your needs do not match what the developers choices were. Then you have to know HTML, CSS, and also get into the low level details of how the SSG works to generate the website. For example, I wanted a logo on every page. I have to figure out which file to edit and how it all gets combined to find the right place, and know the HTML5 syntax that works with what else is already there and if needed how and where to change the CSS.

Quartz does a pretty good job overall. It has nice basic website with sane defaults. There is a little overhead required and learning for sure to make it work. Like you can add properties in front-matter (header) of your pages. Which means you need to set this up according to the rules.

The lack of navigation on Mobile is a real deal breaker for me, but it looks like that may be available at any time so give it a try before you let that stop you. I think plugins like WebPage Html Export Plugin for Obsidian gives an easier path to get started. But if you want a middle ground with more flexibility, Quartz might offer more customization capabilities. That is if you are willing to dive into the weeds of learning them. There may also be more specific needs you need met. If you want including things like say website analytics you may need to explore the customization options. Or you can pay for analytics from the hosting company.

Open the Quartz Docs Full sized on desktop to see the navigation.

My Journey

I am documenting my journey and providing some experience and tops in case you want to follow along. You do so at your own risk. This is not advice. I am showing you what I learned which may be incomplete. It may not correlate to your machine and may be dangerous if you are unaware. So be careful. Make your backups. Read documentation fully. Educate yourself.

I used to generate my site with HUGO but maybe I am denser than most as I found it incredibly hard to use. Anything beyond the starter website never worked and required extensive understanding of features that IMO were not well presented. It took me forever to figure out what front matter meant. I could never remember the commands. The themes were a mess and rarely worked There were version problems with themes and no real standards I could see. Maybe that is a benefit but it meant I couldn't even slightly easily modify a website without figuring out some giant complex theme. In the end I found it easier to write my own. I spent weeks trying to make my own theme and site. Then i'd forget how I did everything. I did not like the Golang templates. I was this fighting toml vs yaml going on. I never did get google website statistics to work. Then I felt like the community was not exactly welcoming. I really wanted to like Hugo. I gave it a try many times over a few years. For me it was just too much work. YMMV.

So this path is really about me starting over creating a new Static Website using these tools for a simpler path. I am going to reuse my existing hosting so there wont be much shown how that part works. I'll summarize though.

I will try to explain where I struggled but the path below is a summary in the interest of brevity. It may not be 100% accurate. I include like to Docs so I can continue learning later.

Troubleshooting

When things go wrong.

Needs and Wants

  • Use markdown to create pages. Simple and plain text.
  • Templating support (variable replacement/reusable components)
  • Easy to understand website creation. Some of these SSG require lots of learning.
  • Live preview via local webserver. Good for seeing change without publishing online.
  • Generate static site easily to a local folder. Many tutorials only show publishing on github.
  • I don't need crazy theme customization but it must be something easy to change
  • Some sort of menu and navigation system. I prefer it to auto-generate easily.
  • Tags or categories for my various topics. Photography, lutherie, automation...
  • Images. This goes with photography and blogging. Should be easy. Would be nice to have a decent looking gallery plugin.

Comparison

Consider searching comparisons for Quartz vs hugo vs Jekyll vs Eleventy....
For example I do not think we have theme options here. There is a cssclasses property option that may help here but this is self styling and not a coherent theme. I also have not tested it. There is the ability to custom hack the layout and code. But things are pretty basic.

Video Tutorial - Not Mine

https://www.youtube.com/watch?v=6s6DT1yN4dw
Overview video. Great video. Nicole amkes some choices that are not what I would do. She uses the ENTIRE quartz directory as the vault not just the content folder. I don't really need or want all that in the vault. Worth the watch.

Steps I Took

Upgrading NodeJS and NPM

at least Node v18.14 and npm v9.3.1

My distro has old versions of node and NPM below the recommendations
Installing node and npm
which led me to nvm which handled the install for me.
First I uninstalled

node -v
npm -v
# Uninstalled NODE via package manager GUI I had instaleld earlier
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
nvm -v
npm install -g npm@latest
# new window
node -v 
npm -v

Discussion

I chose a location that does not get everything backed up. The entire dir is 231M and the content dir is only ~500k.
It does not seem to matter what I named the directory.
I copied my .obsidian config folder with my settings into the /content/.obsidian and that seemed to work. This is where my vault will be.

Setup

cd ~/Projects
npm i
npm quarts create
# answers
# - empty quartz
# - treat links as shortest path
git clone https://github.com/jackyzha0/quartz.git
# call it what you want. hereafter known as $qroot 
mv quartz witchdoctor.com_quartz
cd witchdoctor.com_quartz
# we can set qroot so we can use it later: e.g. cp $qroot/files content/folder
# mnemoniq q=quartz, root is the base directory
export qroot=$PWD
# aka export qroot=~/Projects/witchdoctor.com_quartz/

and $qroot are the same thing hereafter.

In obsidian, I opened "Open Folder as Vault": /content

Author Content

authoring-conten says to create "index" page
content/index
Pasted image 20240313184918.png
very simple. Gave it a title, add date property.

Note: Somehow I missed the npx quartz create. The result missing this "Properties" part of the UI (and likely more). Doing it again blew away my content. Do a backup. Also note that we cloned this repo and that repo was in source control. So it is covered by that repo source control. I will have to figure out how to deal with this multilayering. I don;t want a pull of qaurtz to blow away my content. Hmm can we actually use the source control for this? Maybe I could create a branch then whenever it changes I could remerge the branch and resolve conflicts as desi

Build the Website Locally

# cd $qroot
# show a live view
npx quartz build --serve
# show a live view and output to $qroot/public folder
npx quartz build --serve --output

NOTE: If you get a module not found error try running npm i.

Creating more content

Here I ran into a snag. I am not sure why creating new pages does not come with the front matter. I guess I need to create a template.
Templates

Created a template

  • created a new folder called _templates
  • added folder in Settings → Core plugins → Templates → Template folder location
  • created a new file: _templates/quartz_default.md
  • added front matter to the file via text editor so I could copy from index.md.
---
title: Witchdoctor.com - Page Title
tags: 
date: 2024-03-13
---

You may also choose to add draft: to the front matter if you like to work on pages but not publish them. I probably should have done this now. To add draft. I found the templatein Obsidian, clicked "+ add property", and typed in "draft" and "true".

Created a new Folder and Pages

  • Created a folder: Technology
  • Added "new note" inside folder: "index" aka index.md
  • Clicked: Insert template and selected quartz_default # this is on the left menu
  • Customized the title property: Witchdoctor.com - Technology
  • Added a second page in folder: "automation" aka automation.md
  • Clicked: Insert template and selected quartz_default # this is on the left menu
  • Customized the title property: Witchdoctor.com - Automation
  • npx quartz build --serve # Since I had killed it
  • Crtl-Click in terminal to launch website

Pasted image 20240313205009.png

What we see and assume:
- _templates folder shows in Explorer. We don't really want this to. I wonder if I can figure out the default templates location if it would auto-ignore this.
- What is going on with the "page Title" in the explorer. The Explorer menu seemed to have the wrong names and sections until I started clicking around. This maybe an artifact of my "playing". Maybe I need to clear the cache sometimes. This would happen on Hugo too.
- The only Site Navigation seems to be the explorer on the left. Not the prettiest but it is functional I suppose.
- Including the site name in the title is a bit long.
- Technology Folder shows up as a collapse able list.
- The index inside of Technology shows up when you click on a subpage then click on the breadcrumbs to click on the technology folder link.
- We can click on Quartz 4.0 to get back to the home page.

To hide the templates we need to figure out how to setup ignorePatterns on Private Pages

Some changes
- Removed the sitename from the titiles
- add a new page inside Technology called Test and leave draft as true to test the added draft feature
- Ctrl-C to kill and arrow up to rerun the server.

Pasted image 20240313211802.png
What we see and assume:
- The test note does not appear and hence the draft: true was honored
- Oddly the _templates folder no longer exists in Explorer. I posted the info above on where to start in case this comes back.

Changing the TItle

I don't want the main page bold item above the navigation menu to say "Quartz 4.0" (on the left hand side when Full Screen)> Lets see if we can make that to be the website name and logo. Since this page gets added to all pages it is quick way to unify the look of the site.

Configuration
[!tip] Use a TypeScript editor like VSCode for editing safety.
Essentially "content" and basic behavior goes here.

const config: QuartzConfig = {
  configuration: {
    pageTitle: "ðŸŠī Quartz 4.0",
    enableSPA: true,
    enablePopovers: true,
    analytics: {
      provider: "plausible",
    },
    locale: "en-US",
    baseUrl: "witchdoctor.com",
    ignorePatterns: ["private", "templates", ".obsidian"],
    defaultDateType: "created",
	    ...

I can see:

  • pageTitle is what I want to change
  • pageTitle what is up with that logo in a string field?
  • baseURL is important
  • ignorePatterns will allow me to ignore '_templates'
  • ignorePatterns It looks like I could also put things in a folder called "private" to work on them instead of using drafts maybe
  • ignorePatterns I see no distinction between folders and files. Are these substrings?

[!tip] Make a Backup.
I have not enabled source control yet. I should backup this file before making edits.

What is up with that icon?

Honestly this annoys me. I should cut them a break because I don't know why this was. But this sure seems silly not to have a separate build in way to add a default logo.

After doing some searching it looks like this is a Unicode Emoji called Potted Plant. I do not want or need an emoji here so I am just going to delete and not even try to figure out how to change it to something else. But it would be changing that unnicode char I would guess.

I did some searching and found an alternate emoji to use Zombie . I tried pasting the code and also the shortcode but those did not work. Copy and paste of the Emoji field (the icon itself) did.

Now that I have changed this, I worry a git pull to update quartz will blow away my config. So how do we use git to separte conflicts of interest liek this file? I need a copy inside my repo to restore if needed. I guess I could make a copy inside a "private" folder.

I guess I am gonna have to edit the Layouts and perhaps even create my own component to add a logo.

const config: QuartzConfig = {
  configuration: {
    pageTitle: "🧟 Witchdoctor.com",
    enableSPA: true,
    enablePopovers: true,
    analytics: {
      provider: "plausible",
    },
    locale: "en-US",
    baseUrl: "quartz.jzhao.xyz",
    ignorePatterns: ["_private", "_templates", ".obsidian"],

My final changes were to pageTitle and ignorePatterns to add the underscores
Then I created a folder called content/_private to make a copy of the config since I plan to version control that. It's a bit hacky but it works as long as I remember to do it. I probably won't change this file often. I ended up removing the emoji from here later.

Layouts

Layouts
Has more details about customizing the templates. The default layouts are in $qroot/quartz.layout.ts. The individual files are stored in $qroot/quartz/components.

  • opening quartz.layout.ts
  • we can see the "footer" contains the links if I wanted to change those. Might be nice to make that a list/hash to be passed in. I'll just leave those to help others find the project.
  • we see "left" is defined inside both defaultContentPageLayout and defaultListPageLayout and it seems to have Component.PageTitle(). i'll start there.
  • $qroot/quartz/components/pageTItle.tsx
  return (
    <h1 class={classNames(displayClass, "page-title")}>
      <a href={baseDir}>{title}</a>
    </h1>
  )

Need to add in am HTML based img tag. but how do we specify URLs from Obsidian or filesystem paths? Final resutls...

return (
 <h1 class={classNames(displayClass, "page-title")}>
   <img src="../_attachments/menu-top.gif" alt="Witchdoctor Logo"></img>
   <a href={baseDir}>{title}</a>
 </h1>
)

Can put the img tag above or below the href if desired. I cant decide. Having the words at the top is a quick way to click to go "home". But the logo looks better on top.

Made backups to my local intended repo:

  • cd $qroot
  • 1cp quartz.*.ts content/_private/1

Then I went into the content/index and removed the logo since it is now in the sidebar.

Source control

This is setting up a git repo on my local machine only.

cd $qroot/content
git init

Publishing a website

There are a TON of ways to do this. But it essenitally boils down to

  • generating the website and outputting it to a folder
  • publishing that to a remote location online.
    Which might just be a folder in ahosting provider. It also might be a source control repo that gets automatically pulled when changes occur.

Generating the Output to a Folder

build and output the website.
npx quartz build --output .
Output will be placed into $qroot/public

Publishing to a remote site

Option 1: Easier - Copying the files to online hosting

The easier way is likely to just copy the files from the folder $qroot/public to publish on your website in the root. So for example using ftp to your hosting provider, and copy all the files to the very base level of your site. You would likely want to completely overwrite all the files. You may want to delete the existing files first to remove stragglers but you run the risk of losing other files. For example if you have .htaccess files or robots.txt or some other file not contained in what you are pushing, you would delete those. There is also a short time where your website would not be accessible. I wont cover advanced techniques here.

Option 2: Set up source control online and a pipeline to publish

I.e. github, gitlab, bitbucket.
This involves two steps.

  • Publish our repo into the online provider.
  • Set up a trigger/pipeline. This notices the source control changes and publishes to the provider. This may be an all in one solution like githuib and github pages. Or it may be gitlab for source control and render.com for the website.

There are tons of tutorials out there covering these. I won't get into this here it is already long enough.

My Old Setup

This is from memory and may not be 100% correct. Since it has been difficult to update the site I have not made any updates in well over a year.

The mostly free hosting setup for my domain:

  • Zoho has a free email tier for domains which is limited to a few email accounts
  • My domain and hosting was at GoDaddy but thier initial rates expired and I was tired of paying for a low use site hosting
  • I found Render.com so I could host my domain for free with a CDN.
  • Render required a source cotrol repo IIRC.
  • I set up GitLab for online source control, so I could get a private repo for free.
  • I could not get the pipelines to work and decided Manual Deploy is fine as little as I do it.
  • I left the "domain" at Godaddy but got rid of the "hosting". I had already paid for many years of domain registration and did not want to deal with moving
  • I used the GoDaddy domain tools to manage the DNS record
  • In DNS management I pointed the MX records to Zoho per the Zoho docs
  • In DNS management I pointed the web/www records to Render per the Render docs

So as you can see this is a bit more advanced. I don't need to get into these steps it is quite involved and left up to you if you are following along. Mine is already setup. The only cost of the above is for the domain itself. I am sure there is a free service out there but at some level I want some authenticity and domains are trust based. Using free services is often seen as less trust by reputation engines.

How I fixed my old setup to use the new output

Get a copy of the old repo and purge the old
  • cloned my gitlab repo to a local folder cd <somelocation>; git clone ....
  • export GITLAB_LOCAL=~/My/Local/Gitlab/RepoName
  • cd into $GITLAB_LOCAL
  • removed all files. # I shouldnt need to do this in the future
copy the --output files from public and upload to remote repo
  • export QUARTZ_LOCAL=$qroot/public/
  • cp -a $QUARTZ_LOCAL/* $GITLAB_LOCAL/
  • git add --all
  • git commit -m "rework entire site using obsidian and quartz"
  • git push -u origin main
rework Render to use the new Pre-generated content.
  • Render.com > Dashboard > (Static Site Name) > Settings
    Since I am essentially deploying already generated site and I am putting it at the root of the repo. I changed to the following:
    - Root directory:
    - build command:
    - publish directory: ./
    - Auto-Deploy: No
Deploy (rebuild) the Actual Website
  • Deploy: Render.com > Dashboard > (Static Site Name) > Manual Deploy > Deploy Latest Commit

Mobile Navigation

Once the live view page comes up, In Firefox I can view mobile with Ctrl-Shift-M.
There does not seem to be any navigation. Frankly, id rather lose the live graph and have navigation.

Editing Layouts

Layouts
Layouts live in quartz.layout.ts.
There are definitions for for defaultContentPageLayout and defaultListPageLayout. The one with list in it is used when its a folder, The one with Page in it is used when its a note.

The sections of the site.I.e. "left" or "right" are a list. We can tell because of the brackts []. Inside those lists we put components we want to display in order we want them to display. The MobileOnly and DesktopOnly are used to define what gets displays only when its mobile or desktop. There we see that Explorer is only displayed when desktop.

After looking around quite a bit at the issues and jumping on the discord, it seems that the the Explorer component is not currently support on mobile and it looks like a hamburger menu in the works. As of 2024-03-14.

I think I will continue to work on content for now and see if that gets resolved anytime soon and I can avoid learning how to program and make my own components.

Backups

So I never did add my content and code changes to my backups. . I only need to add $qroot/content to back up all my unique content.

Thoughts

Now that I have finished this what do I think? Well I actually kind of like this. There are definitely some growing pains and what seems like silly choices to me. For example, the config doesn't even include a standard way to include a logo. I mean every site has that right? Also on Mobile there is no navigation in the default view. No hamburger and the "Explorer" used in the desktop view is removed. So I still have to figure that out. Seems kind of silly to have a blog with a ton of pages that you can only see the main page. Also the graph view is kind of silly on mobile. You can't really hover over the graph on mobile to see the page names anyway so what good is a giant graph of points?

I think that customization is where static site generators all become difficult. It is where I really struggled with Hugo. It seems to be the same here. The first point for change is the config. If the creators of the SSG implement an option that I can simply change a variable all is easy. For example setting the site name and site URL is simple. However, if I am hosting it in a sub-folder or its a custom domain, did they do it the way I need? In my case I wanted to add my logo to the site. Something I would say most sites use. I do not see any place in the config to add a logo. To add a logo I had to "go into the code". Thankfully I know a touch of how HTML and coding work and was able to look at the docs and the code and add a simple line into the code. But this begins us down a journey.

What happens when we update the project to the new version? This is someone else's code project we have changed and we do a "pull" of the code it blows away our changes by overwriting the file with a new version. We need to learn new tools and development methodologies that are designed to handle these scenarios, or we need to implement our own cp file to another directory and restore after a pull hacks. Yes of course, I hear you all saying, that is why we have git, and forks, and.... The point here is that the second we diverge from the "built in methods" we are forcing someone to know the complex world that is development. We are no longer living in the simplicity of markdown and SSG. And when the developers have yet to add features that nearly all websites use as standard?

Lets also discuss styling. I added the Explorer component to mobile and it looked horrible. I need to figure out how to turn the horizontal mess into a vertical single component per line. We often see people saying something like "just go edit the margins in the style...". The styling is also part of the original project I cloned. With all the risks and management issue of losing work. Side note: Hugo has this neat structure where you override in a different file and the original file can update as needed without worry. But this adds even more overhead to the learning process. Back to styling, I am not even sure where to change the styling. The page layout is not HTML but code and these weird quartz classes I do not understan. I don't see styling for the "LEFT" page section under styles. I don;t think I want to change the component styling because that will change it for both mobile and desktop I think. I am not familiar with what HTML containers are being used, where that code is, or how HTML layout controls even work. So there is a lot of learning and figuring out to do and it is even more complicated than if I had just learned HTML and CSS. It is also learning NodeJS and Quartz and figuring out how to "do it right". Lack of themes also makes this force us to get into this if we want to change the look and feel.

So there is this huge disconnect to me with SSG's. I come to them to get away from the complexity. The promise of using simple markdown, devolves pretty quickly into doing MORE work up front to learn the inner workings of some open source project to do "development" to work around deficiencies. This is not the simplicity I was promised. Yes it is largely up-front work then we get to enjoy the benefits right? Not exactly, the project gets updated and all your changes no longer work with the new code and you have to re-learn it all to re-implement.

Themes! This is where HUGO really lost me. Themes suck IMO. I would go through the list and find something close (but never quite right) and try to use it. Many don't even support the base features properly and I found they never did what I wanted. And I'm not all that picky. I actually like most of the default choices Quartz make. Though, silly me I want to put a logo on my site and have navigation on mobile without having to spend time learning to change the code or how themes work (Hugo). In Hugo, I spent MANY WEEKS on themes and gave up and wrote my own and forget later how it worked and it broke with project upgrades and got frustrated with it all. It would be really nice if there was some themes which are somehow guaranteed to work with some set of core features. They might be project maintained or they might be someone stamped as "verified to work". For example, I expect to be able to setup Quartz and create pages based on some well documented rules and know that some defined set of core features will work without getting into code or themes myself. For example, if I create pages and setup config as documented I can expect these approved themes will generate a functional, well formatted site on both Desktop and mobile. It will... contain a title with optional logo, navigation (1+ of Component type of navigation), optional tags, optional back-links, optional tag-cloud. Index and List type pages are both handles and work with navigation.

The point here are that IMO an SSG is really only as good as the base core features and styling easy path work for your needs; unless you are willing to be a developer.

I think Quartz is way simpler than Hugo but it still "feels" new and limited. Which I kind of like. Though, it is version 4 so maybe that is a misjudgment. I like it so far, but how will future changes make my life easier instead of making me have to constantly rework things? I'll stick with it for now and see how it goes.

Desired Features

I'd love to see logos built in to the config. Some basic standard/approved themes guaranteed to work with standard components without having to learn programming just to style and reorder a page. A hamburger or some sort of navigation on mobile by default. Comment components. Some sort of primer for dummies on the code might help me.

Thanks for the work on the project. I like it so far.