SNP
SNP

Reputation: 11

GatsbyJS / GraphQL simple blog

I'm building a simple blog with GatsbyJS using Contentful. I have a blogpage with the list of all posts with titles and dates. I want to add, just for the last post, the first lines of the article and the image used in the article.

...

import React from 'react'
import Layout from '../components/layout'
import { Link, graphql, useStaticQuery } from 'gatsby'
import { documentToReactComponents } from "@contentful/rich-text-react-renderer"

import blogStyles from './blog.module.scss'
import Head from '../components/head'

import TransitionLink from "gatsby-plugin-transition-link"
import AniLink from "gatsby-plugin-transition-link/AniLink"

const BlogPage = () => {
    const data = useStaticQuery(graphql`
    query{
         allContentfulBlogPost (sort: { fields: publishedDate, order: DESC}){
             edges{
                 node{
                     title
                     slug
                     publishedDate(formatString:"MMMM Do, YYYY")
                 }
             }
         }

    }
`)

    return (
        <Layout>
            <Head title = "Post" />
            <h1>Post</h1>

            <ol data-sal="slide-up" data-sal-delay="300" data-sal-easing="ease" 
            className={blogStyles.posts}>
                {data.allContentfulBlogPost.edges.map((edge) => {
                    return (
                    <li className={blogStyles.post}>
                        <Link to={`/blog/${edge.node.slug}`}>
                            <h2>{edge.node.title}</h2>
                            <p>{edge.node.publishedDate }</p>
                        </Link>
                    </li>
                )
                })}
            </ol>
        </Layout>
    )
}

export default BlogPage

Upvotes: 1

Views: 94

Answers (1)

ksav
ksav

Reputation: 20821

Note: I've assumed you mean latest post, instead of last post.


You could use Aliases to split your query into two parts.

latestArticle has a limit: 1 and queries for the extra fields needed for the first lines of the article and the image used in the article (as well as title, slugExt, publishDate).

allOtherArticles has a skip: 1 and just queries for title, slugExt, publishDate.

const BlogPage = () => {
  const { latestArticle, allOtherArticles } = useStaticQuery(graphql`
    query MyQuery {
      latestArticle: allContentfulBlogPost(sort: {order: DESC, fields: publishDate}, limit: 1) {
        nodes {
          title
          slug
          publishDate
          excerpt {
            excerpt
          }
          thumbnailImage {
            imageFile {
              id
              fluid {
                ...GatsbyContentfulFluid
              }
            }
          }
        }
      }
      allOtherArticles: allContentfulBlogPost(sort: {order: DESC, fields: publishDate}, skip: 1) {
        nodes {
          title
          slug
          publishDate
        }
      }
    }
  `)

  const latest = latestArticle.edges[0].node

  return (
    <Layout>
      <ol data-sal="slide-up" data-sal-delay="300" data-sal-easing="ease" className={blogStyles.posts}>
        <li className="latest-post">
          <Link to={`/blog/${latest.slug}`}>
            <h2>{latest.title}</h2>
            <p>{latest.excerpt.excerpt}</p>
            <Img fluid={latest.thumbnailImage.imageFile.fluid} />
          </Link>
        </li>
        {allOtherArticles.edges.map((edge) => {
          return (
            <li className={blogStyles.post}>
              <Link to={`/blog/${edge.node.slug}`}>
                <h2>{edge.node.title}</h2>
                <p>{edge.node.publishedDate }</p>
              </Link>
            </li>
          )
        })}
      </ol>
    </Layout>
  )
}

export default BlogPage

The other option is to just query for all the fields you need. When you map over the data you can check the index and conditionally render the thumbnail and the excerpt (as well as the other stuff).

{data.allContentfulBlogPost.edges.map((edge, index) => {
  const firstArticle = index === 0

  return (
    <li className={ blogStyles.post }>
      <Link to={ `/blog/${edge.node.slug }`}>
        { firstArticle && (<Img fluid={edge.node.thumbnailImage.imageFile.fluid } />)}
        <h2>{ edge.node.title }</h2>
        { firstArticle && (<p>{ edge.node.title }</p>)}
        <p>{ edge.node.publishedDate }</p>
      </Link>
    </li>
  )
})}

Upvotes: 1

Related Questions