cssreactjsflexboxcss-positionabsolute

Center DIV containing elements with display absolute


I'm trying to replicate the following design in react: enter image description here

Here's what I've currently got: enter image description here

Here's the code for it:

import React, {  useState } from "react";
import "./DisplayCards.css";

type DisplayCardsProps = {
  images: string[];
  group: number;
};

const DisplayCards: React.FC<DisplayCardsProps> = ({ images, group }) => {
  const [currentGroup, setCurrentGroup] = useState(0);
  const startIndex = currentGroup * group;

  const firstGroup = images.slice(0, startIndex);
  const secondGroup = images.slice(startIndex, startIndex + group);
  const thirdGroup = images.slice(startIndex + group);

  return (
    <div>
      <div className="main-cards">
        {secondGroup.map((name, index) => {
          return (
            <img
              key={index}
              src={name}
              style={{
                position: "absolute",
              }}
            />
          );
        })}
      </div>

      <div>
        <button
          onClick={() =>
            setCurrentGroup((prevGroup) =>
              thirdGroup.length !== 0 ? prevGroup + 1 : prevGroup
            )
          }
        >
          Shift Group Forward
        </button>
        <button
          onClick={() =>
            setCurrentGroup((prevGroup) =>
              firstGroup.length !== 0 ? prevGroup - 1 : prevGroup
            )
          }
        >
          Shift Group Backward
        </button>
      </div>
      <div style={{ padding: "200px" }}></div>

      <div className="grid-container">
        <div className="first-group">
          {firstGroup.map((name, index) => {
            return (
              <img
                key={index}
                src={name}
                width={157}
                height={219}
                style={{
                  position: "absolute",
                  left: `${10 * index}px`,
                }}
              />
            );
          })}
        </div>

        <div className="third-group">
          {thirdGroup.map((name, index) => {
            return (
              <img
                key={index}
                src={name}
                width={157}
                height={219}
                style={{
                  position: "absolute",
                  left: `${10 * index}px`,
                  marginLeft: "500px",
                }}
              />
            );
          })}
        </div>
      </div>
    </div>
  );
};

export default DisplayCards;

And the CSS:

.main-cards {
  display: flex;
  justify-content: center;
}

.grid-container {
  display: flex;
  justify-content: space;
}

I can't figure out how to center the cards on the bottom. Also, the cards on top are three images on top of each other. I tried spreading them out with:

        {secondGroup.map((name, index) => {
          return (
            <img
              key={index}
              src={name}
              width={157}
              height={219}
              style={{
                position: "absolute",
                left: `${30 * index}px`,
              }}
            />
          );
        })}

Which kind of worked, but it wasn't centered perfectly. It was off by like 50px or something. How can I center all the cards and display them like shown in the design I'm trying to replicate?

Last question, when I'm moving the cards forward (i.e., clicking the Shift Group Forward button), how can I make the left stack of cards grow backward like in this video?


Solution

  • I finally got everything working. I don't know what I really changed (mostly because I did a lot of changes), but here's the final code:

    import React, { useState } from "react";
    import { FaArrowLeft, FaArrowRight } from "react-icons/fa";
    import { BiChevronsLeft, BiChevronsRight } from "react-icons/bi";
    
    import Button from "../Button";
    
    import "./DisplayCards.css";
    
    type DisplayCardsProps = {
      images: string[];
      group: number;
      data: any;
    };
    
    const DisplayCards: React.FC<DisplayCardsProps> = ({ images, group, data }) => {
      const [currentGroup, setCurrentGroup] = useState(0);
      const startIndex = currentGroup * group;
    
      const firstGroup = images.slice(0, startIndex);
      const secondGroup = images.slice(startIndex, startIndex + group);
      const thirdGroup = images.slice(startIndex + group);
    
      let margin: string;
      if (data["cardSpacing"] == "regular") margin = "-125px";
      else margin = "-175px";
    
      return (
        <div>
          <div className="first-section">
            <div className="button">
              <Button
                icon={<FaArrowLeft />}
                className="arrow"
                onClick={() =>
                  setCurrentGroup((prevGroup) =>
                    firstGroup.length !== 0 ? prevGroup - 1 : prevGroup
                  )
                }
              />
            </div>
    
            <div className="main-cards">
              {secondGroup.map((name, index) => {
                return (
                  <img
                    key={index}
                    src={name}
                    style={{
                      marginLeft: index == 0 ? "0px" : margin,
                    }}
                  />
                );
              })}
            </div>
    
            <div className="button">
              <Button
                icon={<FaArrowRight />}
                className="arrow"
                onClick={() =>
                  setCurrentGroup((prevGroup) =>
                    thirdGroup.length !== 0 ? prevGroup + 1 : prevGroup
                  )
                }
              />
            </div>
          </div>
    
          <div className="second-section">
            <div className="first-cards" style={{
              marginLeft: firstGroup.length !== 0 ? "0px" : "110px",
            }}>
              {firstGroup.map((name, index) => {
                return (
                  <img
                    key={index}
                    src={name}
                    width={157}
                    height={219}
                    style={{
                      marginLeft: index == 0 ? "0px" : "-145px",
                    }}
                  />
                );
              })}
            </div>
    
            {thirdGroup.length !== 0 && (
              <div className="third-cards">
                {thirdGroup.map((name, index) => {
                  return (
                    <img
                      key={index}
                      src={name}
                      width={157}
                      height={219}
                      style={{
                        marginLeft: index == 0 ? "0px" : "-145px",
                      }}
                    />
                  );
                })}
              </div>
            )}
          </div>
    
          <div className="third-section"></div>
        </div>
      );
    };
    
    export default DisplayCards;
    

    And here's the CSS:

    .first-section {
      display: flex;
      justify-content: space-around;
      align-items: center;
      margin-bottom: 20px;
    }
    
    .second-section {
      display: flex;
      justify-content: center;
    }
    
    .third-cards {
      margin-left: -110px;
    }
    
    .arrow {
      padding: 0.78571429em 1.5em 0.78571429em;
      padding-right: 10px;
      border-radius: 0.28571429rem;
      background-color: var(--button-ok-background-color);
      color: var(--button-ok-text-color);
    }
    

    Here's how it looks: final showcase