Files
xrpl-dev-portal/shared/sections/LinkSmallGrid/LinkSmallGrid.tsx
Calvin 32e89c1299 Component Library Refactor & New Components (#3510)
* adding showcase page

* adding CardStatsList

* clean up, tighter code

* code review and code clean up

* update import, clean up env for error message

* tweak some css code

* less css, rebuilt

* re-adding bem, modifier for bds variants
2026-02-23 15:00:18 -08:00

122 lines
3.8 KiB
TypeScript

import React, { useMemo } from 'react';
import clsx from 'clsx';
import { PageGrid, PageGridRow, PageGridCol } from 'shared/components/PageGrid/page-grid';
import { SectionHeader } from 'shared/patterns/SectionHeader';
import { TileLink, TileLinkProps } from 'shared/patterns/TileLinks';
import { calculateTileOffset } from 'shared/utils/helpers';
export interface LinkItem extends Omit<TileLinkProps, 'variant'> {}
export interface LinkSmallGridProps {
/** Color variant - determines tile background color */
variant?: 'gray' | 'lilac';
/** Heading text (required) */
heading: string;
/** Optional description text */
description?: string;
/** Array of link items to display in the grid */
links: LinkItem[];
/** Additional CSS classes */
className?: string;
}
/**
* LinkSmallGrid Component
*
* A responsive grid section pattern for displaying navigational links using TileLink components.
* Features a heading, optional description, and a grid of clickable tiles with 2 color variants
* and full light/dark mode support.
*
* Grid Layout (12-column grid system):
* - Base (< 576px): 1 tile per row (each tile spans 4 of 4 columns = full width)
* - MD (576px - 991px): 2 tiles per row (each tile spans 4 of 8 columns = 50% width)
* - LG (≥ 992px): 4 tiles per row (each tile spans 3 of 12 columns = 25% width)
*
* Right-Alignment Logic (applied when < 10 total tiles):
* The first tile of each row gets an offset to right-align the grid at LG breakpoint only:
* - LG: 1 tile = offset 9, 2 tiles = offset 6, 3 tiles = offset 3, 4 tiles = offset 0
* - 10+ tiles: no offset (left-aligned grid)
* - MD and Base: no offset applied
*
* Each tile uses the TileLink component which features:
* - Window shade hover animation
* - Arrow icon with animation
* - Responsive sizing (64px height at all breakpoints)
* - Support for both links (href) and buttons (onClick)
* - Gray and Lilac color variants
*
* @example
* // Basic usage with gray variant
* <LinkSmallGrid
* variant="gray"
* heading="Quick Links"
* description="Navigate to key sections"
* links={[
* { label: "Documentation", href: "/docs" },
* { label: "Tutorials", href: "/tutorials" }
* ]}
* />
*
* @example
* // Lilac variant with click handlers
* <LinkSmallGrid
* variant="lilac"
* heading="Get Started"
* links={[
* { label: "Quick Start", onClick: () => navigate('/start') },
* { label: "Examples", href: "/examples" }
* ]}
* />
*/
export const LinkSmallGrid: React.FC<LinkSmallGridProps> = ({
variant = 'gray',
heading,
description,
links,
className,
}) => {
// Build class names using BEM with bds namespace
const classNames = clsx(
'bds-link-small-grid',
`bds-link-small-grid--${variant}`,
className
);
// Memoize offset calculations - only recalculate when links array changes
const linkOffsets = useMemo(() => {
const total = links.length;
return links.map((_, index) => calculateTileOffset(index, total));
}, [links]);
return (
<section className={classNames}>
<PageGrid>
<SectionHeader heading={heading} description={description} span={{ base: 4, md: 6, lg: 8 }} />
<PageGridRow>
{links.map((link, index) => {
const offset = linkOffsets[index];
const hasOffset = offset.lg > 0;
// Use href or label as key, fallback to index
const key = link.href || link.label || index;
return (
<PageGridCol
key={key}
span={{ base: 4, md: 4, lg: 3 }}
offset={hasOffset ? { lg: offset.lg } : undefined}
>
<TileLink
variant={variant}
{...link}
/>
</PageGridCol>
);
})}
</PageGridRow>
</PageGrid>
</section>
);
};
export default LinkSmallGrid;