Layout 351
standardText Align Left4 ColumnsAccordionImageBenefits SectionServices Section

Code
relume-layout351.tsx
"use client";
import { useState } from "react";
import { motion } from "motion/react";
import { useMediaQuery } from "@/hooks/use-media-query";
import { Card } from "@/components/ui/card";
type ImageProps = {
src: string;
alt?: string;
};
type Feature = {
columnText: string;
verticalText: string;
horizontalText: string;
heading: string;
description: string;
image: ImageProps;
};
type FeatureWithState = Feature & {
isActive: boolean;
setIsActive: () => void;
};
type Props = {
tagline: string;
heading: string;
description: string;
features: Feature[];
};
export type Layout351Props = React.ComponentPropsWithoutRef<"section"> & Partial<Props>;
export const Layout351 = (props: Layout351Props) => {
const { tagline, heading, description, features } = {
...Layout351Defaults,
...props,
};
const [activeIndex, setActiveIndex] = useState<number | null>(0);
const handleSetIsActive = (index: number) => {
setActiveIndex((prevIndex) => {
if (prevIndex === index && features.filter((_, i) => i === prevIndex).length === 1) {
return prevIndex;
}
return prevIndex === index ? null : index;
});
};
return (
<section className="px-[5%] py-16 md:py-24 lg:py-28">
<div className="container">
<div className="mb-12 w-full max-w-lg md:mb-18 lg:mb-20">
<p className="mb-3 font-semibold md:mb-4">{tagline}</p>
<h1 className="mb-5 text-h2 font-bold md:mb-6">{heading}</h1>
<p className="text-medium">{description}</p>
</div>
<Card className="flex w-full flex-col overflow-hidden lg:h-[90vh] lg:flex-row">
{features.map((feature, index) => (
<FeatureCard
key={index}
isActive={activeIndex === index}
setIsActive={() => handleSetIsActive(index)}
{...feature}
/>
))}
</Card>
</div>
</section>
);
};
const FeatureCard = ({ isActive, setIsActive, ...feature }: FeatureWithState) => {
const isMobile = useMediaQuery("(max-width: 991px)");
return (
<motion.div
className="flex flex-col justify-start overflow-hidden border-b border-scheme-border last:border-b-0 lg:h-[90vh] lg:min-w-20 lg:flex-row lg:border-r lg:border-b-0 lg:last:border-r-0"
onClick={setIsActive}
initial={{ width: isMobile ? "100%" : isActive ? "100%" : "5rem" }}
animate={{
width: isMobile ? "100%" : isActive ? "100%" : "5rem",
}}
transition={{ duration: 0.3, ease: "easeInOut" }}
>
<div className="relative flex h-16 w-full min-w-full cursor-pointer items-center justify-center py-8 md:h-20 lg:h-[90vh] lg:w-20 lg:min-w-20 lg:flex-col lg:justify-between">
<h5 className="absolute left-6 text-h5 font-bold whitespace-nowrap md:left-10 lg:relative lg:left-0">
{feature.columnText}
</h5>
<h2 className="hidden text-h5 [writing-mode:vertical-rl] lg:block lg:rotate-180 lg:font-bold">
{feature.verticalText}
</h2>
<h5 className="text-h5 font-bold lg:hidden">{feature.horizontalText}</h5>
</div>
{isMobile ? (
<motion.div
className="w-full overflow-hidden lg:h-full lg:w-auto lg:min-w-[200vw] lg:overflow-auto"
initial={{ height: isActive ? "auto" : "0px" }}
animate={{
height: isActive ? "auto" : "0px",
}}
transition={{ duration: 0.3, ease: "easeInOut" }}
>
<div className="flex flex-col px-6 pt-4 pb-8 md:px-10 md:pt-12 md:pb-12 lg:w-[40rem] lg:px-12 lg:pt-16 lg:pb-16">
<h3 className="mb-5 text-h3 font-bold md:mb-6">{feature.heading}</h3>
<p className="text-medium">{feature.description}</p>
<div className="mt-8 h-80 md:mt-10 md:h-[25rem] lg:mt-12">
<img
src={feature.image.src}
alt={feature.image.alt}
className="size-full rounded-image object-cover"
/>
</div>
</div>
</motion.div>
) : (
<div className="w-full overflow-hidden lg:h-full lg:w-auto lg:min-w-[200vw] lg:overflow-auto">
<div className="flex h-full flex-col px-6 pt-4 pb-8 md:px-10 md:pt-12 md:pb-12 lg:w-[40rem] lg:px-12 lg:pt-16 lg:pb-16">
<h3 className="mb-5 text-h3 font-bold md:mb-6">{feature.heading}</h3>
<p className="text-medium">{feature.description}</p>
<div className="mt-8 h-80 md:mt-10 md:h-[25rem] lg:mt-12">
<img
src={feature.image.src}
alt={feature.image.alt}
className="size-full rounded-image object-cover"
/>
</div>
</div>
</div>
)}
</motion.div>
);
};
export const Layout351Defaults: Props = {
tagline: "Tagline",
heading: "Medium length section heading goes here",
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
features: [
{
columnText: "01",
verticalText: "Feature one",
horizontalText: "Feature one",
heading: "Short heading goes here",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat.",
image: {
src: "https://d22po4pjz3o32e.cloudfront.net/placeholder-image-landscape.svg",
alt: "Relume placeholder image 1",
},
},
{
columnText: "02",
verticalText: "Feature two",
horizontalText: "Feature two",
heading: "Short heading goes here",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat.",
image: {
src: "https://d22po4pjz3o32e.cloudfront.net/placeholder-image-landscape.svg",
alt: "Relume placeholder image 2",
},
},
{
columnText: "03",
verticalText: "Feature three",
horizontalText: "Feature three",
heading: "Short heading goes here",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat.",
image: {
src: "https://d22po4pjz3o32e.cloudfront.net/placeholder-image-landscape.svg",
alt: "Relume placeholder image 3",
},
},
{
columnText: "04",
verticalText: "Feature four",
horizontalText: "Feature four",
heading: "Short heading goes here",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat.",
image: {
src: "https://d22po4pjz3o32e.cloudfront.net/placeholder-image-landscape.svg",
alt: "Relume placeholder image 4",
},
},
],
};npm i @radix-ui/react-dialog @radix-ui/react-slot @radix-ui/react-tabs class-variance-authority@0.7.1 clsx@^2.1.1 motion@^12.15.0 relume-icons@1.3.0 tailwind-merge@^2.2.2


