Most Recent Posts
Previously on koamar.com...
The site's front page had a lovely Hero control but beyond that, it was just a blurb about what's happened so far on the site. Perhaps this stuff it was fun, silly, useful, but it didn't belong here! I want the front page to have a way to get to most recent posts, as one of a few ideas for the front page.
Requirements
The post-list.js
template displays all the posts for section of the site: project, blog, or site dev. That looks like a good first stab at what the front page component should be like. In a perfect world, I'd get a lot of the code that can be reused and put it into its own component.
- ✅ Display the six most recent posts from any section (based on update then created)
- Currently, the default is two per row of grid, for the front page and that seems fine.
- ❌ Could have
content/collections/front-page
for text that appears- In that way,
front-page
could be a collection equivalent to the others - At least for the moment, I'm not going to do this.
- In that way,
- ❌ Could display which section the post is in on the front page
- Not going to do this right now either!
- No need for pagination since there is always a fixed number of cards.
Update Steps
- Extract
Posts
to its own component so it can be reused inindex.js
- Add 6 most recent posts to query in
gatsby-node.js
so I can access them on the front page, this requires stealing frompost-list.js
(don't worry, I realized I didn't need to do this) - Delete or move the intro text about updates - moving them to the Site Development page
- Update
Posts
component so it works for bothpost-list.js
andindex.js
Extract Posts
post-list.js
, displays a list of six posts, which is exactly what I want on the front page. I decide to extract that to its own component, Posts
, and use it for the front page. It did not work as-is. I ended up duplicating some code, for now. The six most recent posts can cross all the collections while the current code expects everything to be in one collection.
1import * as React from 'react'2import tw, { styled } from 'twin.macro'3import { PostCard } from '../components'4
5const PostContainer = styled.div(tw`grid gap-y-0 lg:grid-cols-2 lg:gap-x-4 lg:pb-4`)6
7export const Posts = ({ posts, collection }) => (8 <PostContainer>9 {posts.map((post) => (10 <PostCard post={post} collection={collection} key={post.node.id} />11 ))}12 </PostContainer>13)
1// ...2 <Content>3 <h1>{site.frontmatter.title}</h1>4 {currentPage === 1 && <MDXRenderer>{site.body}</MDXRenderer>}5 <Posts posts={posts} collection={collection} />6 </Content>7// ...
I feel this will eventually work for the front page, but it has to send the collection a different way.
Add query to gatsby-node.js for front page
You don't need to create pages in Gatsby to use GraphQL if you already have a page!
- I have an
index.js
file that I want to populate with GraphQL - I don't need to do anything other than add a query to this file
- I have an
A GraphQL query returns a
data
object!- I haven't had much experience getting data from APIs so the magic of
data
was not known to me. In the GraphQL query editor, you can even see thedata
object being returned. Ah well... - So, data just magically appears when you have a GraphQL query in a component.
- I'm not sure I get it yet, but that's one of the magical things about JavaScript I suppose, and, I don't know all of the JavaScript magic at the moment.
- I mean, seriously, it's just a function on the page. Nothing is running it. Perhaps it is Gatsby magic?
- I haven't had much experience getting data from APIs so the magic of
I want to have a slightly different query for most recent tasks.
- It's a fixed number so
limit
will always be 6 - It can cross all collections so I don't want to sort or filter by collection
I want to access the current GraphQL query that drives everything, in gatsby-node.js
but I'll need two queries. I try adding another query and get an error. This leads me to finding out if I want two allMdx
queries, I'm going to have to alias them. So I figure that all out. It's rather easy, only needing to put the alias in front of that part of the query.
1query CreatePagesQuery {2 front: allMdx(3 sort: { fields: [frontmatter___date], order: [DESC] }4 filter: { frontmatter: { name: { eq: null }, draft: { eq: false } } }5 limit: 66 )7 ...8
9 pages: allMdx(10 sort: { fields: [fields___collection, frontmatter___date], order: [ASC, DESC] }11 )12
13 ...
Then change everywhere it says data.allMdx
to data.pages
and everything is working just fine. [Yep, just peachy!]
Now, I want to access data
on the index.js
page but I don't see how. After cursing the magic for a bit, giving up, and trying again, I remembered I had queried things outside of gatsby-node.js
before. Sure enough, I just had to include the new query in the index.js
page and I could access the GraphQL data just fine!
1export const query = graphql`2 query recentPosts {3 allMdx(4 sort: { fields: [frontmatter___date], order: [DESC] }5 filter: { frontmatter: { name: { eq: null }, draft: { eq: false } } }6 limit: 67 ) {8 edges {9 node {10 frontmatter {11 slug12 title13 date(formatString: "MMMM D, YYYY")14 updated(formatString: "MMMM D, YYYY")15 excerpt16 coverAlt17 coverImage {18 publicURL19 childImageSharp {20 gatsbyImageData(layout: FULL_WIDTH)21 }22 }23 }24 id25 excerpt26 fields {27 collection28 }29 }30 }31 }32 }33`
It's not magic, I just lack a bit of understanding of JavaScript and/or Gatsby.
Move intro text on updates to Site Dev page
I didn't copy and paste! I rewrote them in Markdown just so I could feel them. I didn't change much so it wasn't one of those editing epiphanies we all enjoy (right?). Perhaps I enjoy typing, perhaps I like thinking about something again. I tend to not copy and paste stuff.1
Update Posts component
Posts is passed posts
and collection
. If I want to reuse it, it will need to get collection
a different way. In the case of the post-list template, it is always going to be the same collection, hence I could pass that separately. On the front page, it's not necessarily so. I'll include the collection as part of the posts result and it will work in both situations. I already had to make this change for the front page to work.
1import * as React from 'react'2import tw, { styled } from 'twin.macro'3import { PostCard } from '../components'4
5const PostContainer = styled.div(tw`grid gap-y-0 lg:grid-cols-2 lg:gap-x-4 lg:pb-4`)6
7export const Posts = ({ posts }) => (8 <PostContainer>9 {posts.map((post) => (10 <PostCard post={post} collection={post.node.fields.collection} key={post.node.id} />11 ))}12 </PostContainer>13)
In the GraphQL for both index.js
and post-list.js
I added collection to the result site.
1) {2 edges {3 node {4 frontmatter {5 slug6 title7 date(formatString: "MMMM D, YYYY")8 updated(formatString: "MMMM D, YYYY")9 excerpt10 coverAlt11 coverImage {12 publicURL13 childImageSharp {14 gatsbyImageData(layout: FULL_WIDTH)15 }16 }17 }18 id19 excerpt20 fields {21 collection22 }23 }24 }
Git is awesome
Most of my use of git
is straight-forward, no issues, happy path, usage. Create a branch, work on it, commit, push it when done. I had committed a change to gatsby-node.js
at one point, that I did not want anymore. At that point, I had made changes to other files. I reverted my prior commit and it only affected gatsby-node.js
and not the other files I was working on. I didn't have to stash or anything (though i did back them up just in case). Learning is fun!
Attributions
Photo by Jason Leung (@handle) on Unsplash
- Sometimes you see something on unsplash that may not have anything to do with what you are searching for, but it feels right. There were some I spotted searching for a cover on this article that were like that. This search on
new post
got me some confetti. - I spotted
alt
text on the picture I'm using for the first time. I thought I should use that as well instead of making up my own.
- You've copy and pasted so much on this article!↩