Quantcast
Channel: Active questions tagged flexbox - Stack Overflow
Viewing all articles
Browse latest Browse all 1675

How can I create a grid that meets custom specifications?

$
0
0

I have an ad system with two categories: TOP and BASIC. Ads are loaded from the backend in random order, returning a paginated object where TOP ads come first and BASIC ads come after. I want to display them in a grid, using either CSS Grid or Flexbox (or any better alternative someone may suggest—I’d really appreciate it).

I need the following layout conditions within the same grid or flexbox container:

TOP ads:

  • Mobile: 2 per row
  • Tablet: 3 per row
  • Desktop: 4 per row
  • Big screen: 5 per row

BASIC ads:

  • Mobile: 2 per row
  • Tablet: 3 per row
  • Desktop: 4 per row
  • Big screen: 5 per row

This is what I’ve implemented so far, but the rows don’t align properly some end up larger than others, and vice versa.

//styles.tsexport const AdsGrid = styled.div`    display: flex;    flex-wrap: wrap;    gap: 16px;    padding: 1rem;    width: 100%;`;export const GridItem = styled.div<{ isTop?: boolean }>`    transition: transform 0.3s ease;&:hover {        transform: scale(1.02);    }    // Mobile (default)    flex: ${({ isTop }) => (isTop ? "31.33%" : "15%")};    @media (min-width: ${({ theme }) => theme.breakpoints.md}) {        width: ${({ isTop }) => (isTop ? "33.33%" : "25%")}; // tablet    }    @media (min-width: ${({ theme }) => theme.breakpoints.lg}) {        width: ${({ isTop }) => (isTop ? "25%" : "20%")}; // desktop    }    @media (min-width: ${({ theme }) => theme.breakpoints.xxl}) {        width: ${({ isTop }) => (isTop ? "31.33%" : "15%")}; // big screen    }`;

and the component:

import { useModelProfileContext } from "@/context/ModelProfileContext";import InfiniteScroll from "react-infinite-scroll-component";import { AdCardSkeleton, ListSkeleton } from "@/components";import { AdsContainerStyles, AdsGrid } from "@/components/home/ads/styles";import { AdCard } from "@/components/home";const gridConfig = {    gutter: 16,    xs: 3,    sm: 2,    md: 3,    lg: 4,    xl: 4,    xxl: 6,};export default function AdsWrapper() {    const { data, hasMore, loadMore, isLoading } = useModelProfileContext();    if (isLoading && data.length === 0) {        return (<ListSkeleton count={12} gridConfig={gridConfig}><AdCardSkeleton /></ListSkeleton>        );    }    return (<AdsContainerStyles><InfiniteScroll                next={loadMore}                hasMore={hasMore}                loader={<ListSkeleton count={6} gridConfig={gridConfig}><AdCardSkeleton /></ListSkeleton>                }                dataLength={data.length}                className="overflow-hidden"><AdsGrid>                    {data.map((model) => (<AdCard key={model.id} model={model} />                    ))}</AdsGrid></InfiniteScroll></AdsContainerStyles>    );}

and AdCard.tsx

"use client";import {    GridItem,    IsTopAdTagStyles,    NewProfileTagStyles,} from "@/components/home/ads/styles";import { Badge, Flex, Typography } from "antd";import Link from "next/link";import { CustomCard, Text } from "@/components/antd";import { AdCover } from "@/components/home";import { RiVerifiedBadgeFill } from "react-icons/ri";import { formatSentences, sectionColor } from "@/utils/helper";import { TfiLocationPin } from "react-icons/tfi";import { Model } from "@/types/models";export default function AdCard({ model }: { model: Model }) {    const sectionHex = model?.section && sectionColor(model.section);    const isNew = model?.isNew || false;    const isTop = model?.isTop || false;    return (<GridItem key={model.id} isTop={isTop} className="intro-x"><Badge.Ribbon                text={model?.package?.name}                placement="start"                style={{ zIndex: 1000 }}            /><Link href={`/profile/${model.slug}`}><CustomCard                    cover={<AdCover file={model?.ad?.cover?.thumbnail} />}                    styles={{                        body: {                            minHeight: 126,                            padding: 10,                            backgroundColor: sectionHex,                        },                        cover: {                            overflow: "hidden",                        },                    }}>                    {isNew && (<NewProfileTagStyles>Novedad</NewProfileTagStyles>                    )}                    {isTop && <IsTopAdTagStyles>Novedad</IsTopAdTagStyles>}<Flex justify="space-between" vertical><Flex justify="center" align="center" gap={5}><RiVerifiedBadgeFill /><Text size="md" className="bold uppercase" ellipsis>                                {model.alias}</Text></Flex><Typography.Paragraph                            style={{                                textAlign: "center",                            }}                            ellipsis={{                                rows: 2,                                suffix: ".",                            }}>                            {formatSentences(model?.ad?.content || "")}</Typography.Paragraph><Flex justify="center" align="start" gap={5}><TfiLocationPin style={{ fontSize: 14 }} /><Text size="xs" className="uppercase bold" ellipsis>                                {model?.location?.cityName}</Text></Flex></Flex></CustomCard></Link></GridItem>    );}```[Image][1]  [1]: https://i.sstatic.net/Kn6Rs3JG.png

Viewing all articles
Browse latest Browse all 1675

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>