~M•29
Published on

Project 08 - A Responsive Tailwind Grid

Table of Contents

Problems we need to solve:

Create a new allCaseStudies layout in @/components/layout/PostGridLayout.tsx using the PostSimple layout as a guide. Grid is based on Tailwind CSS Grid System and is added into tailwind.config.js to extend the theme.

This continues what we started in Project 07 - Adding new PostGridSimple Layout. In this series, we will explore converting the default ListLayout to a GridLayout. Currently, we've used Tailwind CSS to convert an ListLayout into smaller, card-shaped posts.

The challenge: to convert these posts into a grid layout.


Establishing requirements for our methodology:

Getting Started

4. Can convert the PostGridLayout into an actual Grid?

According to the documentation, a simple change to a <div> className may be all we need to do.

<div>-code-changes
/** @/components/layout/PostGridLayout.jsx
 *
 * Function ---------------
 * Creates a new allCaseStudies layout in @/components/layout/PostGridLayout.tsx
 * using the LatestArticles.tsx layout as a guide.  Grid is  based on Tailwind CSS
 * Grid System and is added into tailwind.config.js to extend the theme.
 *
 * ------------------------
 *
 * Author| workflow
 * mrsdo@29signals.com | project-07-29s-202401111300-new-layout-postgridsimple
 */

// Import content

import Link from '@/components/shared/Link';
import { siteConfig } from '@/data/config/site.settings';
import NewsletterForm from '@shipixen/pliny/ui/NewsletterForm';
import { sortPosts, allCoreContent } from '@shipixen/pliny/utils/contentlayer';
import { allBlogs } from 'shipixen-contentlayer/generated';
import Image from 'next/image';
import Tag from '@/components/shared/Tag';

// Limit # of Posts
const MAX_DISPLAY = 6
// Component



export default function PostGridLayout({
                                         numberOfPosts = MAX_DISPLAY,
                                         showImage = true,
                                       }: {
  numberOfPosts?: number;
  showImage?: boolean;
}) {
  const sortedPosts = sortPosts(allBlogs);
  const posts = allCoreContent(sortedPosts);

  return (
    <>
     // was: <div className="flex flex-col gap-2 mt-6">
      <div className="flex flex-col mt-6">

        <div>
          <div className="relative rounded-xl overflow-auto ">

           // was: <div className="flex flex-col gap-3 ">
             <div className="grid gap-3 sm:grid-cols-1 md:grid-col-2 lg:grid-cols-3 xl:grid-cols-3">

              {!posts.length && 'No articles found.'}
              {posts.slice(0, MAX_DISPLAY).map((post) => {
                const { path, slug, date, title, summary, tags, images } = post;
                const imgSrc = images?.[0];

                return (
                    // was:  <div  key={slug} className="md:bg-white max-w-[544px] p-2 md:w-1/2 dark:md:bg-black rounded-md overflow-hidden relative md:shadow-sm md:hover:shadow-xl dark:md:hover:bg-slate-800 transition-all">

                    <div  key={slug} className="bg-white max-w-[1024px] p-2 lg:w-full dark:bg-black rounded overflow-hidden relative shadow-sm hover:shadow-xl dark:hover:bg-slate-800 transition-all">

                      <div
                        className={`${
                          imgSrc && 'h-full'
                        }  overflow-hidden rounded-md border-1 border-gray-200 border-opacity-60 dark:border-gray-700 bg-white`}
                      >
                        {imgSrc &&
                          (path ? (
                            <Link
                              href={`/${path}`}
                              aria-label={`Link to ${title}`}
                            >
                              <Image
                                alt={title}
                                src={imgSrc}
                                className="object-cover object-center md:h-36 lg:h-48"
                                width={544}
                                height={306}
                              />
                            </Link>
                          ) : (
                            <Image
                              alt={title}
                              src={imgSrc}
                              className="object-cover object-center md:h-36 lg:h-48"
                              width={544}
                              height={306}
                            />
                          ))}

                          <div className="p-6">
                            <h2 className="mb-3 text-2xl font-bold leading-8 tracking-tight">
                              {path ? (
                                <Link href={path}
                                      aria-label={`Link to ${title}`}

                                >
                                  {title}
                                </Link>
                              ) : (
                                title
                              )}
                            </h2>
                            <div className="flex flex-wrap relative mb-1">
                              {tags?.map((tag) => <Tag key={tag} text={tag} />)}
                            </div>
                            <p className="prose mb-3 max-w-none text-gray-500 dark:text-gray-400">
                              {summary}
                            </p>

                            {path && (
                              <Link
                                href={`/${path}`}
                                className="text-base font-medium leading-6 text-primary-500 hover:text-primary-600 dark:hover:text-primary-400"
                                aria-label={`Link to ${title}`}
                              >
                                Learn more &rarr;
                              </Link>
                            )}
                          </div>


                      </div>
                    </div>

              );
              })}
            </div>
          </div>
        </div>
      </div>

      {posts.length > MAX_DISPLAY && (
        <div className="mt-12 flex text-base font-medium leading-6">
          <Link
            href={siteConfig.allArticlesPath}
            className="text-primary-500 hover:text-primary-600 dark:hover:text-primary-400"
            aria-label="See all articles"
          >
            See all projects &rarr;
          </Link>
        </div>
      )}

      {siteConfig.newsletter?.provider && (
        <div className="flex items-center justify-center pt-4">
          <NewsletterForm />
        </div>
      )}

    </>
  );
}


This was exactly the solution! After generating the grid, we create a new PostGridLayout component with just JSX then imported the code into the Case Studies page as a component.

Tailwind Grid Generator Image
one

REF(s):

Internal Pages

Project 07 - New Layout PostGridLayout

External Site Reference & Functional Concepts

TailwindCSS : Grid Template Columns | https://tailwindcss.com/docs/grid-template-columns

TailwindCSS: Background Colors | https://tailwindcss.com/docs/background-colors