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.css
and 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! 🍻