Building My (This) Website
Initial Thoughts
When making a website we all have a few options:
- Use a site builder/generator that does the hosting for us (think Weebly, Wix, etc)
- Use some template out there for a static site and just kind of edit it
- Do it totally from scratch
- Use a CMS that is hosted live with our site to do edits when we want
- Do a little bit of a couple things from above to fit our style
We get to choose which we want to do based on what we want to accomplish :)
I chose to do a bit of CMS + from scratch using GatsbyJS and Strapi (and then hosting it on Netlify).
I also registered the domain on Google Domains but you can easily register one on something like bluehost if you don't want to give Google more money (and it'll probably cost the same).
Why 'From Scratch'
I haven't made a website to publish to the interwebs personally before. I know the details about what I need to do and I've done work on a few sites professionally here and there. However, I've never setup a website by myself and for myself.
My goal for this project was to accomplish a few things:
- Create my website
- Create a space for me to write about things I wanted to
- Actually publish said site on the internet
- Feel the warm fuzzies of finishing a project
Whether or not the site sticks around in it's original form doesn't matter, I'm mostly in it for the learning and experience.
Where To Start
For me, I started by using some tutorials
This tutorial is a good intro to creating a Gatsby site and was made by them as well.
Meanwhile this tutorial was what I based my site off of. It uses Strapi as a "headless CMS" that Gatsby will utilize to generate the static site.
Headless CMS(???) + Why A Static Site
If you don't know what headless CMS means, that's alright. It's not really relevant we know it to follow along with that tutorial but I'll explain it briefly anyway. First we should know what a traditional CMS does.
A traditional CMS typically renders the information on the page to be displayed for you. Nothing fancy to it, you have some interface that you make your content in, you can usually preview what it wil look like, and then you publish it and things do what they should.
A Headless CMS however is one that we pull data from when creating our site (with Gatsby in this case). It provides the content for a site (or app, or whatever else you want) via an API of some sort. In essence, it separates the data for your site from how it is being viewed. This can have advantages such as allowing you to build different ways to serve the same content without having to have all the logic in one encompassing location.
At this point some people would say "What the heck! Why would we want that?!"
To which I say something like "Well, it depends on what we are trying to achieve."
Then there's some weird discussion thing that happens and you figure out what you want, I figure out what I want, and we all go home happy.
Personally, I wanted to make a static site because I'm not hosting anything important that needs rendered by a server. I also have a feeling I may toy with different frameworks until I find something that sticks. Since I might be changing how I handle data, it makes it easier for me to be able to cleanly separate the content from how it gets displayed.
Changing It Up
Looking at this site we can tell there's some differences. A decent amount of that is quick CSS changes. I'm no expert in this domain so I won't try to walk you through any of it.
If you liked the card look of the original Gatsby + Strapi tutorial, I say stick with that. It's simple and it works fine, I just wanted some small tweaks.
The biggest CSS change was that I took some time, went through the grids for cards and such, and made various elements take up a little less spacing so they would fit better (in my opinion).
Below are some details on what I changed/modified in terms of functionality to make my site look/behave as it does.
(I also assume you've gone through the tutorial so I try not to repeat anything mentioned from there)
Things To Keep In Mind
- I have changed Articles to Posts for my site but will reference to them as Articles nonetheless below
- I don't use Authors as I presently don't see anyone else posting on my site in the future 🤷♂️
- An Article for my site can have multiple Categories instead of a single one
About Page Single Type
I created an "About Page" that was a one-off. I didn't want it to be an Article with it's own Category as that seemed kind of weird to shoe-horn a one time page into that collection.
It essentially has all the same fields as an article, but as a "Single Type" in Strapi.
This required me to make another template page, add it to the gatsby-node.js
via createPage, and voila! About page done.
(Also had to create a GraphQL query for the page but that's pretty straightforward using the GraphiQL in-browser IDE provided by Gatsby)
Reusable Nav Components
In addition to the About Page, I created another Single Type for "Social Nav Components". I'll call it Nav Type for brevity's sake.
This Nav Type holds only one "Component" and it allows that component to be repeated. I don't think the original tutorial goes over Components in Strapi so I'll cover it real quick.
A Component is something that we plan to reuse. We might reuse it for a Single Type (the Nav in this case) or we might reuse it across a number of pages (perhaps later we decide all pages can have a nav on the sidebar where we can search for articles).
In my case the Component I created would hold the information necessary for me to display some Social Icons wherever I wanted in the nav (whether it be the header, footer, or somewhere else). My Component's fields consisted of an Icon, Text to identify what the icon was/represented, and a Link to where the icon should take someone. My Nav Type uses said component and I pull that information from Strapi using GraphQL when building my site.
This wasn't strictly necessary to do, but it was something simple that had me figure out how to do my own GraphQL queries a bit.
Slugs
While using Strapi generated page id's is a blast (not), I personally prefer slugs. A slug is a unique identifier for a page that can be used to reference it. For my purposes it's the title of any given page (in almost all cases).
Strapi supports this by adding a slug field to any given type that we create. From there we can link it to any field for the given type and it will be auto generated when creating new instances of it (we can also change it to whatever we prefer).
In this case of this page the part of the url in the address bar that is building-my-website
is the slug! (I removed 'this' when the slug was generated for me)
I did have to go back and make sure to save the auto-generated slugs if I had already created an Article/Category and created the field later, so watch out for that.
After creating slugs, comb through the code and make sure to add that to various GraphQL queries so it will be accessible for Gatsby in addition to making sure all Link
elements will reference the proper pages using the slugs.
Definitely double check gatsby-node.js
for when any page is being created. If we don't change the paths there to use the slug, the references from other pages won't work.
Categories
The big change that diverge my site from the tutorial however is how Categories are handled.
Before we go any further, a gentle reminder that an Article can have multiple categories.
Originally we would create Categories and they would be listed in the Navigation. While this was convenient, it doesn't scale well if we plan on having more than maybe 4 or 5 Categories tops.
I took Categories and made them their own page entirely. This meant adding anothing template page in src/templates
named categories.js
in addition to having the original Category pages.
By doing this it makes it so we have a better separation between our data and view. I added a page to the gatsby-node.js
file and then started working on the Categories page itself.
Things Get Complicated
Previously the index page was kind of an "All Categories" page as it listed every article there. We don't want a repeat of that page, but we do want something that has most of the same data.
This is where things start to get a bit complicated.
See, while we might like to copy/paste our GraphQL query over from the index and start playing with things, Gatsby is NOT a fan of that. If we are querying the same data in the same manner, Gatsby is going to complain. I don't blame 'em because why the heck query the same data twice? We can change the name of the query and get away with it, but we should probably make some considerations about how we're making this query and handling the data. We have to know a bit about how we want the data before we can fix that however.
My plan for this 'Categories' page was to create something that would list the Title of each Category we have, and then the associated Articles under it. This meant a straightforward format but one that didn't make sense with the previous query where we got every Article and listed them. What we need is something that returns all the Categories, all the Articles with their associated Categories, and then we could use those associations to build the Categories page by looping through the list of Categories and placing the Articles that also have that same Category under them.
This does mean that some Articles will appear twice, but I don't really mind that. It would also be nice if there were some additional sorting options within each Category, but that wasn't something I felt necessary for getting this website initially set up. (Pagination would be cool too but at some point we have to draw the line)
If you're curious how the described Categories page works, here's the portion of the categories.js
file that renders the page to only contain the relevant Articles for a given Category (with some inline comments to more clearly define where the 'action' happens).
<Layout>
{categories.map(category => // Loop through the categories one by one and create a section for each
{
return (
<div className="uk-section">
<div className="uk-container uk-container-small">
<Link to={`/category/${category.node.slug}`}>
<h1 className="ui header">{category.node.name}</h1>
</Link>
<hr />
<PostsComponent posts={posts.map(post => ( // Loop through each post
post.node.categories.some(postCategory => ( // Find out if there is a value in the Post's categories that satisfies the below condition
category.node.name === postCategory.name) // Check if a Category for the post matches the current Section Category
) ? post : null // If we find a match, return this as a valid post for the list being collected, otherwise return null
)).filter(post => post !== null)} /> // Remove all null values from the list to be returned
</div>
</div>
)
})
}
</Layout>
I'll admit I'm not an expert in React so this may be a bit sloppy... But it gets the job done!
Other Small Additions
I added a few other things to pages such as:
- Tags at the top of Articles that let us access the Category Pages they belong to
- Dates of when an Article was published/updated
- Optional showing of a Card's image on the actual Article Page
- Labels on the Cards themselves that Link to a given Category Page
- Sorting of Articles by the most recently published (done by GraphQL when querying)
- Probably something else I've forgotten
Wrapping Up
With all the above out of the way, we end up landing where this site started off.
With everything above implemented, my plan was to add a few more small additions including:
- Hover effects on cards that displayed some of the text from the Article
- Limiting the max characters allowed to be display in the grid of cards on any given page
- More sorting options on Category Pages
- Better support for images (Strapi passes them with improper URL's that aren't handled by Gatsby)
- Also adding some images for reference to this post to break up the monotony of text 😅
If you read to the end of this post, I appreciate it and hope you learned some things, enjoyed it, or... well got something out of it in some way!