Originally written on 2023-09-04

Publish: Theming

In the 1st part of this series, we looked into getting Publish set up using Mint. If you haven't read that part already, I recommend reading it before continuing here.

This part will describe what a theme is and how to create a custom theme for your website.

We're going to assume that you're deploying the website to https://hellopublish.com.

Let's me start by explaining the function of a few folder.

Content

This folder contains all of your website sections.

By default, you can see that Publish created an index.md file, which represents the root of your website. It created a posts folder, which contains the root of your https://hellopublish.com/posts route. It also created a file named first-post.md which would be accessible by going to https://hellopublish.com/posts/first-post/

Output

This folder contains the final product. The generated website.

Unless you have specific reasons to commit these files to your repo, don't. It will bloat your repo of unnecessary content and since it's the final product, you really will never modify its content.

In fact, remember when I said "Make sure to include the .gitignore file that was created."? We're going to ignore this entire folder.

Open up .gitignore in VS Code and add the Output folder on the last line:

Commit this file. This will ensure that all future git commits will not contain files from this folder.

Resources

This folder contains all the resources, assets, fonts, stylesheets, etc... for your website.

I recommend creating this structure to get you started:

We're going to be putting our stylesheet under styles.

You can organize images any way you want. I personally chose to group images by post, under a posts folder.

Sources

This folder is part of a normal Swift Package. It contains a folder for each target declared in your Package.swift manifest file.

This is where you'll be doing all of the Swift work.

Anatomy of main.swift

Take a look at your main.swift file:

Your website is declared as a simple struct.

To configure your website, you simply change the values. Most of them are pretty self explanatory, however, I would like to focus on 2 parts.

SectionID

You can add as many cases as you want here. These are the sections that will appear in your website's navigation. For this website (https://srz/io), there are 2 sections: posts and about.

ItemMetadata

This one isn't as obvious at first glance.

Font matter is described by Jekyll and Hugo

Creating A Custom Theme

Publish ships with a theme named Foundation.

Take a look at your main.swift file, once again:

Specifically, the last line:

This is where you get to specify which theme your website should use. First, we need to create it.

By now, you should have run the website at least once and all the dependencies should be downloaded, if not, simply run mint run publish generate and it should download all the dependencies for you.

We'll start by copying the foundation theme to our project, and then we'll make a few modifications.

From the root of your project, look for the foundation them file, it should be in:

.build/checkouts/publish/Sources/Publish/API/Theme+Foundation.swift

Save a copy of this file right next to your main.swift file. I saved it as Theme+Hello.swift.

Here's what you should see:

Oof! There's a lot in here! Don't worry, it's pretty straight forward, We'll break it down in the next section. For now, pay attention to this part only:

This contains a simple declaration of the theme name, and where to find it's CSS file. Let's change it:

First, we need to import Publish since we made a copy outside of the library.

Second, we are renaming the FoundationHTMLFactory to HelloHTMLFactory. Naming is important, let's be consistent.

Lastly, notice the resource path to the CSS file. To make this all work, we need to copy the Foundation theme's CSS. You can modify this later, or even start with an empty CSS file if you're interested. For now, copy the file located in.build/checkouts/publish/Resources/FoundationTheme/styles.cssand paste it into your resources folder:Resources/ThemeHello/styles.css.

Ok, great! All of we have to do now is to change the theme used by our main.swift file:

🎉 You're now using your own custom theme. Granted, it's not looking any different from the Foundation theme, but you now get to modify the CSS to your heart's content.

Understanding Custom Themes

Ok, let's take a deeper dive into the theme factory. Publish is built using result builders. For this reason, you might start recognizing some similarities between Publish and SwiftUI.

There are 6 methods to understand for a Publish theme:

Let's start with the first one:

This function is called when the framework is generating your index.html page. You can modify this content with whatever you want. Each method is given a PublishingContext object from which you can pull a ton of information. The context contains your website object (name, favicon, description, url, etc...), the sections, the tags, the pages, and more. All you need to construct your site.

Here, you can see that a SiteHeader is used, followed by a Wrapper, which contains an ItemList. This list contains all your posts sorted by their date, in descending order.

Moving on to the next one:

This function is called when the framework is generating the page for a given section. In this case, we only have a single section, the posts (see above, the anatomy of main.swift). If you decide to include more sections, you can define different HTML for each section by using the section ID provided as parameter.

Moving on to the next one:

If you recall the folder structure, you add each section, as a folder, under the Content folder. Each section can contain their own index.md and any other items named as you please. This function is called for every item you have in your section.

In this case, we add the SiteHeader and inside the Wrapper, we include the body of each post's markdown file's body, followed by the list of tags for the post. We'll explore the anatomy of a markdown file a bit later.

Moving on to the next one:

Going back to the folder structure, you can add any other markdown files at the root of the Content folder. This method will be call for each one of those files. They are nice to have for pages that aren't part of a section, and aren't an item, such as posts.

Moving on to the next one:

This one is pretty self explanatory. This function is called for every item that contains tags. You are given a reference to the page which allows you to access more information, such as audio, video, images and more.

And finally, the last one:

This function generates a page for when a tag is clicked by the user. What should the user see when they click on the tag "swift"? Presumably, a list of all the posts that are tagged with "swift". This is where you define the HTML for this use case.

Conclusion

As you can see, Publish is a lot less intimidating than it first appears. Understanding how the theming works is really key to understanding how your website is generated.

In the 3rd part of this series, we'll look into posts and how you can add custom metadata.

Don't forget to tell someone you love them.
Cheers! 🍻

Tagged with: