Front Page Tags and More!
Do I even know what I'm doing? 😀
Get a List of Tags
- the tags are all in separate arrays in each post
- flatten them into one array
flattenTags()
- sort all tags using
sortTags()
- use reduce to create an object that has each distinct tag with the number of occurrences, from Stack Overflow
- Convert it to an array using
Object.entries()
- flatten them into one array
- add a grid container
- map everything into it See tagData Function below
Create Tags Template
It's going to look an awful lot like the post-list
template. Instead of showing all the posts, paginated, for a collection, it's going to show all of the posts, in a list, with a given tag.
Initial Version
I'm going to start by stealing all the code from post-list
and using a query that is almost the same. Shhhh!
1query SingleTagPostsQuery($id: [String]) {2 allMdx(3 sort: { fields: frontmatter___date, order: DESC }4 filter: { frontmatter: { tags: { in: $id } } }5 ) {6 edges {7 node {8 fields {9 collection10 }11 frontmatter {12 tags13 slug14 title15 date(formatString: "MMMM D, YYYY")16 updated(formatString: "MMMM D, YYYY")17 coverAlt18 coverImage {19 publicURL20 childImageSharp {21 gatsbyImageData(layout: FULL_WIDTH)22 }23 }24 }25 id26 excerpt27 }28 }29 }30}
I'm passing the posts into the Posts
component and it looks exactly the same as a collection list.
Next Version
I want it to be shorter. I want one post per row. I want cover photo, Title, Excerpt, Date, Updated under date if it is there, and finally, under everything, a list of tags. I guess in hindsight, it is the same content the posts display in the sections except for adding the tags.
Specifications
- Somewhere on the front page, there are the tags that are in use in the site.
- On desktop, they could perhaps be on the right-hand side as I've seen on other sites. (nope)
- They wouldn't work there on mobile and would instead be at the bottom, or perhaps in the menu.
- A Tags section after Most Recent Posts might work out well. (yes)
- Click on a tag and it takes you to a page for that tag
- That page displays all the posts with that tag
- To be different, the card could be smaller so more could fit on the page, or it could be more of a column thing.
- If column-like, or smaller, could contain all the tags on that page. Of course, that could also go on the main card too!
- Or it could be exactly like any other of my collections with 6 on a page and paging.
- At first thought, I like the idea of, small picture, title, date, and update, sorting by newest first.
- I'd really like to sort by
coalesce(update, date)
but I don't know how!
- I'd really like to sort by
tags
Query Development
Snippet for all collection/slug (file path) with tags array. This can be added in gatsby-node.js
in the createPages
function.
1tags: allMdx(filter: { fields: { collection: { ne: "collections" } } }) {2 edges {3 node {4 frontmatter {5 tags6 slug7 }8 fields {9 collection10 }11 }12 }13}
There will be a record for each post with the slug, an array of tags, and the collection it belongs in. Do not ask me why collection is there! Perhaps that is extra or left over from defining the filter on it.
TagList Component
First up, let's get a list of tags on the front page! I fiddled around with a grid and decided on some Tailwind styling to make it work well for large (5 columns), medium (4 columns), and small (2 columns) screens. The exciting part here is a bunch of JavaScript to create the tagData
. I wanted to look through all the posts for each discrete tag and count up how many posts it is involved with. I'll end up with something like gatsby (15)
when I'm done.
tagData Function
1function flattenTags(tags) {2 let listOfTags = [,]3 tags.forEach((f) => {4 if (f.node.frontmatter.tags)5 f.node.frontmatter.tags.forEach((t) => {6 listOfTags.push(t)7 })8 })9
10 return listOfTags11}12function sortTags(allTags) {13 return allTags.sort()14}15function tagData(tags) {16 const flatTags = sortTags(flattenTags(tags))17
18 const tagSummary = flatTags.reduce(function (acc, curr) {19 return acc[curr] ? ++acc[curr] : (acc[curr] = 1), acc20 }, {})21 return Object.entries(tagSummary)22}23
24module.exports = tagData
Take the array of all the tags, flatten them, add a count of how many times they are used, and sort them. If this were SQL, I'd probably think of group by tagName and Count(1) but it's not, so this is how I approached it. Hence, flatten, sort, summarize. Pop those in a link and I've got each tag with it's count as something that you can click on to get to a page of all posts that share that tag. Since I want to use this function in gatsby-node.js
it has to use CommonJS modules. As I hoped, it is easy to require
inside of React, instead of import
as I normally do so I could use this in both environments.
Single-tag Template
This template is more like the post-list
template even though it is for a single tag. It's multiple posts per tag though. So it copies a lot of what was going on with the post-list
template. I decided against a cover image. I figured I'd have to have either a cover image for each tag or a single all encompassing one. Neither excited me. I just feed the data to the Posts component like normal and I get my two column list of posts!
Add to Gatsby-node
In gatsby-node.js
, I added the new query defined above to the createPages graphQL. Then I could loop through that data to create all the pages for tags.
Change Posts to a List
Instead of a two column list for the tagged posts, I wanted it all in a single list. I had envisioned more of a table but as I worked with it, it looked fine mostly as-is. However, since it had a different look, I wanted to move away from Posts
and towards PostList
. Naming is hard! PostList
is practically the same as Posts
but with a different layout. Also, it will use PostListCard
instead of PostCard
. Not too exciting. PostListCard
looks about the same as PostCard
but it has a few stylistic changes. I could probably refactor this code to remove a bunch of duplication at some point.
Why yes, I am getting tired. Apparently I've decided against adding code examples at this point. I'm tired of looking at it all I suppose!
Add Tags to the PostListCards
Since everything is about tags now, I wanted to show all the tags in the file when listing them. Since I shot myself in the foot earlier by making the whole card
a link so you can click anywhere on it, if I put the tags in there, they won't be clickable. So, I separated them out into a little Container of their own. I don't have any posts with that many tags, so I haven't seen a need to make a change for mobile yet. I imagine there will be a tradeoff between multiple columns and scrollable area. As I've never done a scrollable area, I may try that method!
Padding for Tags
I used some guidance from a Scrimba course I did a while ago and used px-2 py-1
, treating the tag as a button. It looks good! I was worried I was going to have to figure out how to do it with a style I didn't have to get the .5em 1.25em
I was shooting for.
Add the Collection to the PostListCard
Oh, I almost forgot! When there is a list of posts for a tag, they could be a part of any of the three collections: Blog, Project, or Site. I wanted to indicate that somewhere. I had this idea of doing something at an angle. So far, I'm doing that, without any background so it looks rather plain, unless it is very small screen, then it just overlays the picture a bit.
An Accident That I Liked
When I added the TagLinks
component to the Post, it came with the background color and shadow that looked good on the list but not so much on the Post. I tried to override it with a className. I tried removing the offending classes from the TagLinks
component and adding them in with a className for the list. Turns out, I sort of like it better this way, so I left it alone. No background on the tags! This way the text-xs
looks just fine instead of text-sm
. I want it to be subtler.
And with All That Done!
- If you're reading a post, you can click on a tag and see all the other posts with that tag.
- If you want to just go straight to perusing tags, you can jump to the bottom of the site and pick one.
Attributions
I always liked "Be Curious", "Stay Curious", and the like so this picture hit me quickly as the one to use!
Photo by Gary Butterfield (@garybpt) on Unsplash