DEV Community

Cover image for Building in Public: React Image Layout with Flexbox and Grid - ACT 5 : Creating and Styling an Image Gallery using Flexbox
Voke
Voke

Posted on

Building in Public: React Image Layout with Flexbox and Grid - ACT 5 : Creating and Styling an Image Gallery using Flexbox

EPISODE ONE: react-image-rendering
ACT 5:
ACT 5:PART ONE:

INTRO/RECAP:
{In the last ACT, we introduced the react-router. Set it up and got it working properly, explained the Routes and Route, also talked about the attributes in the Route, the path and element. And prior to the react-router, we sorted out the legacy JS API deprecation warning. We also worked on the Link/NavLink in the MainNavigation.tsx file}.

Link to ACT4 Here

Brace up fellas! Better grab yourselves some soda and popcorn to go with this ACT. You are ready? if so, then let's go.

ACT 5:PART TWO:
Creating the Imagedata File:

So now, we can navigate around components. If I click on the image-flex, I get taken to that route and the component appears. Same with me clicking on image-grid.
The next thing we want to do now is to create an imageData file. The imageData file is where we are going to store our images, it's gonna be serving as a mock database for us.
For us to do that, we go into the components folder, then proceed to the images folder, then create a new file imageData.tsx. After creating it, we will type out this code in the file:

import tlou from "../../assets/tlos1.jpeg";
import doom from "../../assets/doom 64 1.jpeg";
import messi from "../../assets/messi11960x0.jpg";
import cod from "../../assets/cod1.jpeg";
import gow from "../../assets/vgow3.jpeg";
import tlou2 from "../../assets/tlou3.jpeg"


export const Array = [

    {
        id:"1",
        image:tlou,
        name:"The last of us",
        description:"A naughty dog classsic"
    },
    {
        id:"2",
        image:doom,
        name:"Doom",
        description:"An evergreen title, still waxing strong."
    },
    {
        id:"3",
        image:messi,
        name: "Messi at barca",
        description:"One of the greatest to ever do it."
    },
    {
        id:'4',
        image:cod,
        name:"Call of duty",
        description:"A modern first person shooter game"
    },
    {
        id:"5",
        image:gow,
        name:"God of war 3",
        description:"Picks up where the part 2 left off. Kratos seeks his vengeance"
    },
    {
        id:"6",
        image: tlou2,
        name:"The last of us 2",
        description:"Another naughty dog classic."
    },
]
Enter fullscreen mode Exit fullscreen mode

Explanation of the imageData content:

O.k, let's go in once again like needles. The first 6 lines of code are importing images from a folder called assets. This means that we have a folder called assets which holds our images. And each image is then assigned a variable. The variables are for example: tlou,doom, messi etc. These images are used in the Array.

Going down, we define an Array of 6 objects. Each representing a game, well save for messi. And each object has these properties:
id: Which is a unique identifier for the object
image: The imported image we talked about earlier.
name: The name of the item.
description: A brief description of the item.

This Array will now be used to display a list of items in another component. To be more specific, it will be used to display items as a list in the imagesFlex and imagesGrid components. This code "export const Array" makes it possible.

ACT 5:PART THREE:
Displaying the Images with the Card Component:

So let's head to our imagesFlex.tsx component. We then import Array from where we stored it, by running this line of code:

import { Array } from "../imageData";
Enter fullscreen mode Exit fullscreen mode

And oh! before I forget, we have to do somethings. The first thing we gonna do is to create the imagesFlex.module.scss file. This will be useful in styling the imagesFlex.tsx file. Then the other thing we gonna do is create a Card component.

Card:
What is a card?
And Why Do We Need It?

A card is a component that is used to display content in an organized format. It is like a shell, a surrounding div. It helps to easily showcase information in a structured way. Card helps in making our content visually appealing thereby enhancing the user experience.

So to create the Card, we go into our components folder, then create a folder in it called ui. Inside that folder, we will create another folder called card. Now inside that card folder, we will create a file called Card.tsx. And another file called Card.module.scss. In the Card.tsx, I will set it up with this code:

import classes from "./Card.module.scss";
import React from "react";

const Card:React.FC<{children:React.ReactNode,className:string}> = (props) => {
    return ( 
        <div className={`${classes.card} ${props.className}`}>
            {props.children}
        </div>
     );
}

export default Card;
Enter fullscreen mode Exit fullscreen mode

This is similar to the Explanation I gave when we created our first component.

classes is imported from Scss file named Card.module.scss. This will contain the styles for our Card.

Then React is imported, so React features can work with our component. This will be helpful in using React.FC.

Then we define Card as a functional component. The component accepts 2 props:
children (React.ReactNode): This is a special prop that represents any nested content placed inside .... Then the second prop is:
className(string): This allows us to pass Css class in here. This will make it possible for us to style each card differently.

The Card component also returns a div. This div has 2 classes.

The first is classes.card: This will serve as the default styling for all of our Cards.

Then the second is props.className: Here any additional class is passed here.

Also, inside the div, props.children is placed, rendering any nested elements or components inside the card.

Then we got the:

export default Card;
Enter fullscreen mode Exit fullscreen mode

The component is exported as Card, so it can be reused anywhere in the app.

ACT 5:PART FOUR:
Rendering the Image Data in ImagesFlex.tsx:

So we now know what a Card is. And we have been able to set it up. Now let's go back to our imagesFlex.tsx file. In there I am going to type out the following code:

import classes from "./ImagesFlex.module.scss";
import Card from "../../ui/card/Card";
import { Array } from "../imageData";

const ImagesFlex = () => {
  return (
    <div className={classes["main-container"]}>
      <div className={classes.heading}>
        <h2>Images Flex</h2>
      </div>
      <div className={classes["main-content"]}>
        {Array.map((item) => {
          return (
            <Card key={item.id} className={classes.card}>
              <div className={classes["main-image"]}>
                <img src={item.image} alt={item.name} />
              </div>
              <div className={classes.content}>
                <h5>{item.name}</h5>
                <div className={classes.desc}>
                  <p>{item.description}</p>
                </div>
              </div>
            </Card>
          );
        })}
      </div>
    </div>
  );
};

export default ImagesFlex;
Enter fullscreen mode Exit fullscreen mode

EXPLANATION:

The first line, classes is importing style from ImagesFlex.module.scss. By now you should know that, that is where the styles of this component are going to be.

In the second line, we are bringing in Card, we are importing it so we can work with it here. Remember that Card is a reusable component that will help us achieve consistent styling.

And lastly, we are importing Array. Remember that Array is holding an array of 6 objects which we defined in the imageData.tsx file earlier on. It has several properties like id, image, name, and description. So we are bringing all of them here. And this is only possible because we exported them from their original files when we made them as components.

Let's continue, By now you should know, we defined the component and it's called ImagesFlex. That's what the const ImagesFlex = ()=>{} block of code means. It's also a function. Remember when I told you earlier on that a component in React is a function?

And here it returns a container div with a class of main-container. This class is going to be used to style the overall container, the parent container.

Inside the parent container, there's another div and that div is meant for the heading. It even got a heading className which would be used to style it.

Then there's a second div, this second div has a class of main-content. And we are using it to hold all our data in which we would be getting from Array. And these data or items will sit pretty in our Card.

Watchout fellas, There is a Javascript method in serious action here. It's called the map method. This is a very very important javascript method when using React. To be honest with you, the first time I encountered it, I was lost, totally lost. lol! It's a javascript array method that creates a new array by applying a function to each item in the array. And I must stress again, it is D^mn useful in react.

So, we are looping over each item in the Array with this code:

{Array.map((item) => {
//content goes here folks!!!
})
}
Enter fullscreen mode Exit fullscreen mode

For each item, it will render a Card component with the following:

key: item.id; This makes sure that each card is unique and that there's no clash. The key serves as a unique identifier. The ids in our Array are unique; 1,2,3 etc. So the first Card would be 1, second would be 2, etc.
className: classes.card; This is used to add styling to our card.

Then there are 3 divs that are housed in the Card. 3 of them are meant for different purposes.

The first div: This is meant for our image. The src is item.image . That means the image it's gonna render is going to be gotten from our Array. And mind you, the item is representing what we have in our array. It's representing id, it's representing name, and also, it's representing image. So in here, an img element displays the image from our Array, with alt text from item.name.

The second div: This div is for displaying the item's name in a h5 tag and displaying the discription in a p tag.

ACT 5:PART FIVE:
Previewing ImagesFlex.tsx without Styles:

Now let me show you something, keep in mind that as of now our imagesFlex.module.scss is blank. So without styling, this is how our imagesFlex component would look:

no-styles-added

So, it's a must we add some Css or should I say Scss.

ACT 5:PART SIX:
Styling the ImagesFlex.tsx File:

Lets get to work people. Men! I am Loving this...

So I will go into the ImagesFlex.module.scss file and type out this code:

.main-container{
    width: 100%;
    padding: 1rem;

    .heading{
        display: flex;
        justify-content: center;
        align-items: center;
        flex-direction: column;
        padding: 1rem;
    }

    .main-content{
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 1rem;
        flex-wrap: wrap;
        padding: 1rem;

        .card{
            width: 30%;

            .main-image{
                width: 100%;
                height: 10rem;
                overflow: hidden;

                img{
                    width: 100%;
                    height: 100%;
                    object-fit: contain;
                }
            }

            .content{
                h5{
                    padding: 0.25rem;
                    font-size: large;
                    font-weight: bold;
                }
                padding: 0.5rem;
                text-align: center;
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Explanation:

Let's break it down. If you look closely, there's really not much that is new here. But let me just run right through it.

for main-container:
width: 100%;: The main-container takes up the full width of the parent element. And remember that the parent element was set in the Layout main tag. That's where the props.children reside.

padding: 1rem;: Adds space inside the container, creating a small margin on all sides

for heading:
display:flex: This turns .heading into a flex container

justify-content and align-items:center: Centers the content horizontally and vertically within the .heading area

flex-direction:column: It arranges the elements vertically

padding:1rem: Adds padding around the .heading area

for card:
width: 30%: Each card takes up 30% of the container's width

for main-image:
width:100% and height:10rem: Sets the image container size
overflow:hidden: This crops any part of the image that overflows

for main-image img:
width:100% and height:100%: This allows the image to take the size of its container
object-fit:contain: This code ensures the whole image is visible and scaled to fit
And so on...

Before we see what it looks like, I would want make some changes to the ImagesFlex.tsx file.

Catch you in PART SEVEN

Wheeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeew! I know this ACT is really long, But hang on abit. We are nearly there.

ACT 5:PART SEVEN:
Shortening Text in the ImagesFlex.tsx file:

Before we checkout our page, there is something I want to correct in the ImagesFlex.tsx. So let's go there. The description that is being rendered, we gat to shorten it. Let's make the length uniformed. Not that one might have 14 characters and another 100 characters. Let's make them all the same length. You feel me?

So I will head over to the file and write this code:

const shortenText = (text:string,n:number)=>{   
      if(text.length > n){
        const shortenedText = text.substring(0,n).concat("...");
        return shortenedText
      };
      return text
  }
Enter fullscreen mode Exit fullscreen mode

Then in the jsx which we are returning, I will change this:

 <div className={classes.desc}>
    <p>{item.description}</p>
  </div>
Enter fullscreen mode Exit fullscreen mode

To this:

 <div className={classes.desc}>
    <p>{shortenText(item.description,10)}</p>
  </div>
Enter fullscreen mode Exit fullscreen mode

What this does is that, if the description length is more than 10 letters, cut it at that number(10) and concat/append (...) to the rest.

If we do that and save,
We will have this bad boy, no Pdidy:

image-ok

Wheeeeeeeew!!! Now you can see, it's looking all good now. If you followed up till this point, big ups! thanks! you are incredible.

So that's how you display an image and content using flex in react
Let's move on to ACT 6, where we will display images using grid

Outro:

About the writer: Voke Bernard is a passionate {obsessive} and ambitious M.E.R.N developer. Building of Reactjs && Expressjs applications is all he does. He is currently open to work, Feel free to reach out.

Call to Action: If you enjoyed this act, stay tuned. ACT6 follows shortly . Stay tuned.

Top comments (0)