mirror of
https://github.com/XRPLF/xrpl-dev-portal.git
synced 2026-07-31 02:50:16 +00:00
Add CardsIconGrid and CardsTextGrid Section Patterns (#3505)
* CardsIconGrid and CardsTextGrid + showcase pages * cleaning up code * more code clean up * using the spacing tokens for values
This commit is contained in:
committed by
Calvin Jhunjhuwala
parent
c8bed8b698
commit
fe1aa0ecb1
87
shared/patterns/CardsIconGrid/CardsIconGrid.scss
Normal file
87
shared/patterns/CardsIconGrid/CardsIconGrid.scss
Normal file
@@ -0,0 +1,87 @@
|
||||
// BDS CardsIconGrid Pattern Styles
|
||||
// Brand Design System - Section with heading, description, and grid of CardTextIconCard
|
||||
//
|
||||
// Naming Convention: BEM with 'bds' namespace
|
||||
// .bds-cards-icon-grid - Base section container
|
||||
// .bds-cards-icon-grid__header - Header section (heading + description)
|
||||
// .bds-cards-icon-grid__list - Grid list (ul as PageGrid.Row)
|
||||
|
||||
// =============================================================================
|
||||
// Design Tokens (uses BDS spacing from _spacing.scss)
|
||||
// =============================================================================
|
||||
|
||||
$bds-cards-icon-grid-padding-base: $bds-space-2xl;
|
||||
$bds-cards-icon-grid-padding-md: $bds-space-3xl;
|
||||
$bds-cards-icon-grid-padding-lg: $bds-space-4xl;
|
||||
|
||||
$bds-cards-icon-grid-header-gap-base: $bds-gap-header-sm;
|
||||
$bds-cards-icon-grid-header-gap-md: $bds-gap-header-md;
|
||||
$bds-cards-icon-grid-header-gap-lg: $bds-gap-header-lg;
|
||||
|
||||
$bds-cards-icon-grid-header-margin-base: $bds-gap-section-sm;
|
||||
$bds-cards-icon-grid-header-margin-md: $bds-gap-section-md;
|
||||
$bds-cards-icon-grid-header-margin-lg: $bds-gap-section-lg;
|
||||
|
||||
// =============================================================================
|
||||
// Section Container
|
||||
// =============================================================================
|
||||
|
||||
.bds-cards-icon-grid {
|
||||
padding-top: $bds-cards-icon-grid-padding-base;
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
padding-top: $bds-cards-icon-grid-padding-md;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(lg) {
|
||||
padding-top: $bds-cards-icon-grid-padding-lg;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding-left: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
@include bds-theme-mode(dark) {
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Header Section
|
||||
// =============================================================================
|
||||
|
||||
.bds-cards-icon-grid__header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $bds-cards-icon-grid-header-gap-base;
|
||||
margin-bottom: $bds-cards-icon-grid-header-margin-base;
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
gap: $bds-cards-icon-grid-header-gap-md;
|
||||
margin-bottom: $bds-cards-icon-grid-header-margin-md;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(lg) {
|
||||
gap: $bds-cards-icon-grid-header-gap-lg;
|
||||
margin-bottom: $bds-cards-icon-grid-header-margin-lg;
|
||||
}
|
||||
|
||||
h2, p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// List Grid - Aspect Ratios
|
||||
// =============================================================================
|
||||
|
||||
.bds-cards-icon-grid__list > li {
|
||||
aspect-ratio: 3 / 2;
|
||||
@include media-breakpoint-up(md) {
|
||||
aspect-ratio: 4 / 3;
|
||||
}
|
||||
@include media-breakpoint-up(lg) {
|
||||
aspect-ratio: 4 / 3;
|
||||
}
|
||||
}
|
||||
66
shared/patterns/CardsIconGrid/CardsIconGrid.tsx
Normal file
66
shared/patterns/CardsIconGrid/CardsIconGrid.tsx
Normal file
@@ -0,0 +1,66 @@
|
||||
import React from 'react';
|
||||
import clsx from 'clsx';
|
||||
import { PageGrid, PageGridRow, PageGridCol } from 'shared/components/PageGrid/page-grid';
|
||||
import { CardTextIconCard, CardTextIconCardProps } from 'shared/components/CardTextIcon';
|
||||
|
||||
export interface CardsIconGridProps {
|
||||
/** Section heading (required) */
|
||||
heading: string;
|
||||
/** Optional description text */
|
||||
description?: string;
|
||||
/** Array of card data to display */
|
||||
cards: CardTextIconCardProps[];
|
||||
/** Additional CSS classes */
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* CardsIconGrid Component
|
||||
*
|
||||
* A section pattern with a header (heading + description) and a grid of
|
||||
* CardTextIconCard components. Uses PageGrid.Row as="ul" with cards as
|
||||
* PageGrid.Col as="li". Aspect ratios: sm 3:2, md/lg 4:3.
|
||||
*
|
||||
* @example
|
||||
* <CardsIconGrid
|
||||
* heading="Explore Tools"
|
||||
* description="Choose a tool to get started"
|
||||
* cards={[
|
||||
* { icon: "/icons/docs.svg", heading: "Documentation", description: "..." },
|
||||
* ]}
|
||||
* />
|
||||
*/
|
||||
export const CardsIconGrid: React.FC<CardsIconGridProps> = ({
|
||||
heading,
|
||||
description,
|
||||
cards,
|
||||
className,
|
||||
}) => {
|
||||
return (
|
||||
<PageGrid className={clsx('bds-cards-icon-grid', className)}>
|
||||
<PageGridRow>
|
||||
<PageGridCol className="bds-cards-icon-grid__header" span={{ base: 12, md: 6, lg: 8 }}>
|
||||
<h2 className="h-md">{heading}</h2>
|
||||
{description && <p className="body-l">{description}</p>}
|
||||
</PageGridCol>
|
||||
</PageGridRow>
|
||||
|
||||
<PageGridRow as="ul" className="bds-cards-icon-grid__list list-none pl-0">
|
||||
{cards.map((card, index) => (
|
||||
<CardTextIconCard
|
||||
key={card.heading || index}
|
||||
icon={card.icon}
|
||||
iconAlt={card.iconAlt}
|
||||
heading={card.heading}
|
||||
description={card.description}
|
||||
height={card.height}
|
||||
width={card.width}
|
||||
gridColSpan={{ base: 4, md: 4, lg: 4 }}
|
||||
/>
|
||||
))}
|
||||
</PageGridRow>
|
||||
</PageGrid>
|
||||
);
|
||||
};
|
||||
|
||||
export default CardsIconGrid;
|
||||
53
shared/patterns/CardsIconGrid/README.md
Normal file
53
shared/patterns/CardsIconGrid/README.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# CardsIconGrid Pattern
|
||||
|
||||
A section pattern with a header (heading + description) and a grid of CardTextIconCard components.
|
||||
|
||||
## Overview
|
||||
|
||||
CardsIconGrid mirrors the LinkTextDirectory header structure and renders cards in a responsive grid using PageGrid.Row as="ul" and CardTextIconCard with gridColSpan. Each card is a PageGrid.Col as="li"—no div wrapper.
|
||||
|
||||
## Features
|
||||
|
||||
- Header with heading and optional description
|
||||
- Responsive grid: 3 cards/row at all breakpoints (base, md, lg)
|
||||
- Aspect ratios: sm 3:2, md/lg 4:3
|
||||
- Light/dark mode support
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx
|
||||
import { CardsIconGrid } from 'shared/patterns/CardsIconGrid';
|
||||
|
||||
<CardsIconGrid
|
||||
heading="Explore Tools"
|
||||
description="Choose a tool to get started"
|
||||
cards={[
|
||||
{
|
||||
icon: "/icons/docs.svg",
|
||||
iconAlt: "Documentation",
|
||||
heading: "Documentation",
|
||||
description: "Access everything you need.",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
```
|
||||
|
||||
## Props
|
||||
|
||||
| Prop | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `heading` | `string` | Section heading |
|
||||
| `description` | `string` | Optional description |
|
||||
| `cards` | `CardTextIconCardData[]` | Array of card configs |
|
||||
| `className` | `string` | Additional CSS classes |
|
||||
|
||||
## Grid Column Spans
|
||||
|
||||
- base: 4, md: 4, lg: 4 (3 cards per row)
|
||||
|
||||
## Files
|
||||
|
||||
- `CardsIconGrid.tsx` - React component
|
||||
- `CardsIconGrid.scss` - Styles
|
||||
- `index.ts` - Barrel exports
|
||||
- `README.md` - This file
|
||||
4
shared/patterns/CardsIconGrid/index.ts
Normal file
4
shared/patterns/CardsIconGrid/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export {
|
||||
CardsIconGrid,
|
||||
type CardsIconGridProps,
|
||||
} from './CardsIconGrid';
|
||||
87
shared/patterns/CardsTextGrid/CardsTextGrid.scss
Normal file
87
shared/patterns/CardsTextGrid/CardsTextGrid.scss
Normal file
@@ -0,0 +1,87 @@
|
||||
// BDS CardsTextGrid Pattern Styles
|
||||
// Brand Design System - Section with heading, description, and grid of CardTextIconCard
|
||||
//
|
||||
// Naming Convention: BEM with 'bds' namespace
|
||||
// .bds-cards-text-grid - Base section container
|
||||
// .bds-cards-text-grid__header - Header section (heading + description)
|
||||
// .bds-cards-text-grid__list - Grid list (ul as PageGrid.Row)
|
||||
|
||||
// =============================================================================
|
||||
// Design Tokens (uses BDS spacing from _spacing.scss)
|
||||
// =============================================================================
|
||||
|
||||
$bds-cards-text-grid-padding-base: $bds-space-2xl;
|
||||
$bds-cards-text-grid-padding-md: $bds-space-3xl;
|
||||
$bds-cards-text-grid-padding-lg: $bds-space-4xl;
|
||||
|
||||
$bds-cards-text-grid-header-gap-base: $bds-gap-header-sm;
|
||||
$bds-cards-text-grid-header-gap-md: $bds-gap-header-md;
|
||||
$bds-cards-text-grid-header-gap-lg: $bds-gap-header-lg;
|
||||
|
||||
$bds-cards-text-grid-header-margin-base: $bds-gap-section-sm;
|
||||
$bds-cards-text-grid-header-margin-md: $bds-gap-section-md;
|
||||
$bds-cards-text-grid-header-margin-lg: $bds-gap-section-lg;
|
||||
|
||||
// =============================================================================
|
||||
// Section Container
|
||||
// =============================================================================
|
||||
|
||||
.bds-cards-text-grid {
|
||||
padding-top: $bds-cards-text-grid-padding-base;
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
padding-top: $bds-cards-text-grid-padding-md;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(lg) {
|
||||
padding-top: $bds-cards-text-grid-padding-lg;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding-left: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
@include bds-theme-mode(dark) {
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// Header Section
|
||||
// =============================================================================
|
||||
|
||||
.bds-cards-text-grid__header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $bds-cards-text-grid-header-gap-base;
|
||||
margin-bottom: $bds-cards-text-grid-header-margin-base;
|
||||
|
||||
@include media-breakpoint-up(md) {
|
||||
gap: $bds-cards-text-grid-header-gap-md;
|
||||
margin-bottom: $bds-cards-text-grid-header-margin-md;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(lg) {
|
||||
gap: $bds-cards-text-grid-header-gap-lg;
|
||||
margin-bottom: $bds-cards-text-grid-header-margin-lg;
|
||||
}
|
||||
|
||||
h2, p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// List Grid - Aspect Ratios
|
||||
// =============================================================================
|
||||
|
||||
.bds-cards-text-grid__list > li {
|
||||
aspect-ratio: 16 / 9;
|
||||
@include media-breakpoint-up(md) {
|
||||
aspect-ratio: 3 / 2;
|
||||
}
|
||||
@include media-breakpoint-up(lg) {
|
||||
aspect-ratio: 3 / 1;
|
||||
}
|
||||
}
|
||||
62
shared/patterns/CardsTextGrid/CardsTextGrid.tsx
Normal file
62
shared/patterns/CardsTextGrid/CardsTextGrid.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import React from 'react';
|
||||
import clsx from 'clsx';
|
||||
import { PageGrid, PageGridRow, PageGridCol } from 'shared/components/PageGrid/page-grid';
|
||||
import { CardTextIconCard, CardTextIconCardProps } from 'shared/components/CardTextIcon';
|
||||
|
||||
export interface CardsTextGridProps {
|
||||
/** Section heading (required) */
|
||||
heading: string;
|
||||
/** Optional description text */
|
||||
description?: string;
|
||||
/** Array of card data to display */
|
||||
cards: CardTextIconCardProps[];
|
||||
/** Additional CSS classes */
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* CardsTextGrid Component
|
||||
*
|
||||
* A section pattern with a header (heading + description) and a grid of
|
||||
* CardTextIconCard components. Uses PageGrid.Row as="ul" with cards as
|
||||
* PageGrid.Col as="li". Aspect ratios: sm 16:9, md 3:2, lg 3:1.
|
||||
*
|
||||
* @example
|
||||
* <CardsTextGrid
|
||||
* heading="Explore Tools"
|
||||
* description="Choose a tool to get started"
|
||||
* cards={[
|
||||
* { icon: "/icons/docs.svg", heading: "Documentation", description: "..." },
|
||||
* ]}
|
||||
* />
|
||||
*/
|
||||
export const CardsTextGrid: React.FC<CardsTextGridProps> = ({
|
||||
heading,
|
||||
description,
|
||||
cards,
|
||||
className,
|
||||
}) => {
|
||||
return (
|
||||
<PageGrid className={clsx('bds-cards-text-grid', className)}>
|
||||
<PageGridRow>
|
||||
<PageGridCol className="bds-cards-text-grid__header" span={{ base: 12, md: 6, lg: 8 }}>
|
||||
<h2 className="h-md">{heading}</h2>
|
||||
{description && <p className="body-l">{description}</p>}
|
||||
</PageGridCol>
|
||||
</PageGridRow>
|
||||
|
||||
<PageGridRow as="ul" className="bds-cards-text-grid__list list-none pl-0">
|
||||
{cards.map((card, index) => (
|
||||
<CardTextIconCard
|
||||
key={card.heading || index}
|
||||
heading={card.heading}
|
||||
description={card.description}
|
||||
gridColSpan={{ base: 4, md: 4, lg: 6 }}
|
||||
/>
|
||||
))}
|
||||
</PageGridRow>
|
||||
</PageGrid>
|
||||
);
|
||||
};
|
||||
|
||||
export default CardsTextGrid;
|
||||
53
shared/patterns/CardsTextGrid/README.md
Normal file
53
shared/patterns/CardsTextGrid/README.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# CardsTextGrid Pattern
|
||||
|
||||
A section pattern with a header (heading + description) and a grid of CardTextIconCard components.
|
||||
|
||||
## Overview
|
||||
|
||||
CardsTextGrid mirrors the LinkTextDirectory header structure and renders cards in a responsive grid using PageGrid.Row as="ul" and CardTextIconCard with gridColSpan. Each card is a PageGrid.Col as="li"—no div wrapper.
|
||||
|
||||
## Features
|
||||
|
||||
- Header with heading and optional description
|
||||
- Responsive grid: 3 cards/row at base+md, 2 cards/row at lg
|
||||
- Aspect ratios: sm 16:9, md 3:2, lg 3:1
|
||||
- Light/dark mode support
|
||||
|
||||
## Usage
|
||||
|
||||
```tsx
|
||||
import { CardsTextGrid } from 'shared/patterns/CardsTextGrid';
|
||||
|
||||
<CardsTextGrid
|
||||
heading="Explore Tools"
|
||||
description="Choose a tool to get started"
|
||||
cards={[
|
||||
{
|
||||
icon: "/icons/docs.svg",
|
||||
iconAlt: "Documentation",
|
||||
heading: "Documentation",
|
||||
description: "Access everything you need.",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
```
|
||||
|
||||
## Props
|
||||
|
||||
| Prop | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `heading` | `string` | Section heading |
|
||||
| `description` | `string` | Optional description |
|
||||
| `cards` | `CardTextIconCardData[]` | Array of card configs |
|
||||
| `className` | `string` | Additional CSS classes |
|
||||
|
||||
## Grid Column Spans
|
||||
|
||||
- base: 4, md: 4, lg: 6 (3 cards/row at base+md, 2 at lg)
|
||||
|
||||
## Files
|
||||
|
||||
- `CardsTextGrid.tsx` - React component
|
||||
- `CardsTextGrid.scss` - Styles
|
||||
- `index.ts` - Barrel exports
|
||||
- `README.md` - This file
|
||||
4
shared/patterns/CardsTextGrid/index.ts
Normal file
4
shared/patterns/CardsTextGrid/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export {
|
||||
CardsTextGrid,
|
||||
type CardsTextGridProps,
|
||||
} from './CardsTextGrid';
|
||||
Reference in New Issue
Block a user