f6a0673082
CI Pipeline / test (20) (pull_request) Failing after 1m17s
CI Pipeline / test (18) (pull_request) Failing after 1m28s
CI Pipeline / e2e (chromium) (pull_request) Failing after 1m33s
CI Pipeline / e2e (firefox) (pull_request) Failing after 1m27s
CI Pipeline / e2e (webkit) (pull_request) Failing after 1m34s
CI Pipeline / visual-regression (pull_request) Failing after 2m9s
CI Pipeline / storybook (pull_request) Failing after 1m5s
CI Pipeline / performance (pull_request) Failing after 1m42s
CI Pipeline / lint (pull_request) Failing after 49s
CI Pipeline / build (pull_request) Failing after 1m29s
94 lines
2.9 KiB
TypeScript
94 lines
2.9 KiB
TypeScript
"use client";
|
|
|
|
import React, { memo, useMemo } from "react";
|
|
import NumberedCard from "./NumberedCard";
|
|
import SectionHeader from "./SectionHeader";
|
|
import Button from "./Button";
|
|
|
|
interface Card {
|
|
text: string;
|
|
iconShape?: string;
|
|
iconColor?: string;
|
|
}
|
|
|
|
interface NumberedCardsProps {
|
|
title: string;
|
|
subtitle: string;
|
|
cards: Card[];
|
|
}
|
|
|
|
const NumberedCards = memo<NumberedCardsProps>(({ title, subtitle, cards }) => {
|
|
// Memoize schema data to prevent unnecessary re-computations
|
|
const schemaData = useMemo(
|
|
() => ({
|
|
"@context": "https://schema.org",
|
|
"@type": "HowTo",
|
|
name: title,
|
|
description: subtitle,
|
|
step: cards.map((card, index) => ({
|
|
"@type": "HowToStep",
|
|
position: index + 1,
|
|
name: card.text,
|
|
text: card.text,
|
|
})),
|
|
}),
|
|
[title, subtitle, cards]
|
|
);
|
|
|
|
return (
|
|
<>
|
|
<script
|
|
type="application/ld+json"
|
|
dangerouslySetInnerHTML={{ __html: JSON.stringify(schemaData) }}
|
|
/>
|
|
<section className="bg-transparent py-[var(--spacing-scale-032)] px-[var(--spacing-scale-020)] sm:py-[var(--spacing-scale-048)] sm:px-[var(--spacing-scale-032)] lg:py-[var(--spacing-scale-064)] lg:px-[var(--spacing-scale-064)] xl:py-[var(--spacing-scale-076)] xl:px-[var(--spacing-scale-064)]">
|
|
<div className="max-w-[var(--spacing-measures-max-width-lg)] mx-auto">
|
|
<div className="grid grid-cols-1 gap-y-[var(--spacing-scale-032)] lg:gap-y-[var(--spacing-scale-056)]">
|
|
{/* Section Header */}
|
|
<div>
|
|
<SectionHeader
|
|
title={title}
|
|
subtitle={subtitle}
|
|
titleLg="How CommunityRule helps"
|
|
/>
|
|
</div>
|
|
|
|
{/* Cards Container */}
|
|
<div className="grid grid-cols-1 gap-y-[var(--spacing-scale-024)] lg:grid-cols-3 lg:gap-[var(--spacing-scale-024)]">
|
|
{cards.map((card, index) => (
|
|
<NumberedCard
|
|
key={index}
|
|
number={index + 1}
|
|
text={card.text}
|
|
iconShape={card.iconShape}
|
|
iconColor={card.iconColor}
|
|
/>
|
|
))}
|
|
</div>
|
|
|
|
{/* Call to Action Button */}
|
|
<div className="text-center sm:text-left lg:text-center">
|
|
{/* Default button for xsm and sm breakpoints */}
|
|
<div className="block lg:hidden">
|
|
<Button variant="default" size="large">
|
|
Create CommunityRule
|
|
</Button>
|
|
</div>
|
|
{/* Outlined button for lg and xlg breakpoints */}
|
|
<div className="hidden lg:block">
|
|
<Button variant="outlined" size="large">
|
|
See how it works
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</>
|
|
);
|
|
});
|
|
|
|
NumberedCards.displayName = "NumberedCards";
|
|
|
|
export default NumberedCards;
|