Compare commits

..

5 Commits

Author SHA1 Message Date
akcodez
3873ae0085 design QA and changes with Design team 2026-01-15 11:23:24 -08:00
akcodez
f62c99b387 fix tablet 2026-01-14 14:07:59 -08:00
akcodez
7383bf8044 add back bundle 2026-01-14 14:05:49 -08:00
akcodez
e12b1bf8dc complete pattern and showcase 2026-01-14 14:04:58 -08:00
akcodez
0b52e5f747 Add FeatureTwoColumn pattern and button enhancements
- Introduced the FeatureTwoColumn pattern for showcasing features in a two-column layout, supporting multiple color themes and responsive design.
- Implemented button behavior based on the number of links, with configurations for 1 to 5 links.
- Added `forceColor` prop to Button component to maintain button color across light and dark themes, particularly useful for colored backgrounds.
- Updated styles and documentation for both the FeatureTwoColumn pattern and Button component to reflect new features and usage guidelines.
2026-01-14 14:04:17 -08:00
17 changed files with 2331 additions and 728 deletions

View File

@@ -1,175 +0,0 @@
import { PageGrid, PageGridRow, PageGridCol } from "shared/components/PageGrid/page-grid";
import { CardsFeatured } from "shared/patterns/CardsFeatured";
import { Divider } from "shared/components/Divider";
export const frontmatter = {
seo: {
title: 'CardsFeatured Pattern Showcase',
description: "A comprehensive showcase of the CardsFeatured pattern component demonstrating light and dark mode variations in the XRPL.org Design System.",
}
};
// Sample image URL for demonstration
const SAMPLE_IMAGE = "/img/cards/card-image-showcase.png";
// Sample cards data - 6 cards for full showcase
const sampleCards = [
{
image: SAMPLE_IMAGE,
imageAlt: "Documentation illustration",
title: "Documentation",
subtitle: "Access everything you need to get started working with the XRPL.",
buttonLabel: "Get Started",
href: "#docs",
},
{
image: SAMPLE_IMAGE,
imageAlt: "Tutorials illustration",
title: "Tutorials",
subtitle: "Step-by-step guides to help you build on the XRP Ledger.",
buttonLabel: "View Tutorials",
href: "#tutorials",
},
{
image: SAMPLE_IMAGE,
imageAlt: "API Reference illustration",
title: "API Reference",
subtitle: "Comprehensive API documentation for all XRPL methods.",
buttonLabel: "Explore API",
href: "#api",
},
{
image: SAMPLE_IMAGE,
imageAlt: "Use Cases illustration",
title: "Use Cases",
subtitle: "Explore real-world applications built on the XRP Ledger.",
buttonLabel: "View Use Cases",
href: "#use-cases",
},
{
image: SAMPLE_IMAGE,
imageAlt: "Community illustration",
title: "Community",
subtitle: "Join the global community of XRPL developers and enthusiasts.",
buttonLabel: "Join Community",
href: "#community",
},
{
image: SAMPLE_IMAGE,
imageAlt: "Resources illustration",
title: "Resources",
subtitle: "Tools, libraries, and resources to accelerate your development.",
buttonLabel: "Browse Resources",
href: "#resources",
},
];
export default function CardsFeaturedShowcase() {
return (
<div className="landing">
<div className="overflow-hidden">
{/* Hero Section */}
<section className="py-26 text-center">
<div className="col-lg-8 mx-auto">
<h6 className="eyebrow mb-3">Pattern Showcase</h6>
<h1 className="mb-4">CardsFeatured Pattern</h1>
<p className="longform">
A section pattern that displays a heading, description, and a responsive grid
of CardImage components. Follows the "Logo Rectangle Grid" design from Figma.
</p>
</div>
</section>
{/* Design Specifications */}
<PageGrid className="py-26">
<PageGridRow>
<PageGridCol span={12}>
<h2 className="h4 mb-6">Design Specifications</h2>
<div className="d-flex flex-row gap-6 mb-6" style={{ flexWrap: 'wrap' }}>
<div style={{ flex: '1 1 250px' }}>
<h6 className="mb-3">Typography</h6>
<ul className="mb-0">
<li><strong>Heading:</strong> heading-md (Tobias Light)</li>
<li><strong>Description:</strong> body-l (Booton Light)</li>
</ul>
</div>
<div style={{ flex: '1 1 250px' }}>
<h6 className="mb-3">Header Gap</h6>
<ul className="mb-0">
<li><strong>Desktop:</strong> 16px</li>
<li><strong>Tablet:</strong> 8px</li>
<li><strong>Mobile:</strong> 8px</li>
</ul>
</div>
<div style={{ flex: '1 1 250px' }}>
<h6 className="mb-3">Cards Column Gap</h6>
<ul className="mb-0">
<li><strong>Desktop:</strong> 8px</li>
<li><strong>Tablet:</strong> 8px</li>
<li><strong>Mobile:</strong> 48px</li>
</ul>
</div>
<div style={{ flex: '1 1 250px' }}>
<h6 className="mb-3">Cards Row Gap (Vertical)</h6>
<ul className="mb-0">
<li><strong>Desktop:</strong> 56px</li>
<li><strong>Tablet:</strong> 52px</li>
<li><strong>Mobile:</strong> 48px</li>
</ul>
</div>
<div style={{ flex: '1 1 250px' }}>
<h6 className="mb-3">Section Padding (Vertical)</h6>
<ul className="mb-0">
<li><strong>Desktop:</strong> 80px</li>
<li><strong>Tablet:</strong> 64px</li>
<li><strong>Mobile:</strong> 48px</li>
</ul>
</div>
<div style={{ flex: '1 1 250px' }}>
<h6 className="mb-3">Grid</h6>
<ul className="mb-0">
<li><strong>Mobile:</strong> 1 column</li>
<li><strong>Tablet:</strong> 2 columns</li>
<li><strong>Desktop:</strong> 3 columns</li>
</ul>
</div>
<div style={{ flex: '1 1 250px' }}>
<h6 className="mb-3">Colors</h6>
<ul className="mb-0">
<li><strong>Light:</strong> $black (#141414)</li>
<li><strong>Dark:</strong> $white (#FFFFFF)</li>
</ul>
</div>
</div>
</PageGridCol>
</PageGridRow>
</PageGrid>
<Divider />
{/* 6 Cards Example - Full Showcase */}
<section>
<CardsFeatured
heading="Trusted by Leaders in Real-World Asset Tokenization"
description="Powering institutions and builders who are bringing real world assets on chain at global scale."
cards={sampleCards}
/>
</section>
<Divider />
{/* 3 Cards Example */}
<section>
<CardsFeatured
heading="Developer Resources"
description="Everything you need to start building on the XRP Ledger."
cards={sampleCards.slice(0, 3)}
/>
</section>
<Divider />
</div>
</div>
);
}

View File

@@ -0,0 +1,427 @@
import { PageGrid, PageGridRow, PageGridCol } from 'shared/components/PageGrid/page-grid';
import { FeatureTwoColumn } from 'shared/patterns/FeatureTwoColumn';
export const frontmatter = {
seo: {
title: 'FeatureTwoColumn Pattern Showcase',
description: 'Interactive showcase of the FeatureTwoColumn pattern with all color variants, arrangements, and button configurations.',
},
};
export default function FeatureTwoColumnShowcase() {
// Placeholder image
const placeholderImage = '/img/demo-bg.png';
return (
<div className="landing">
<div className="overflow-hidden">
{/* Hero Section */}
<section className="my-5 text-center">
<div className="col-lg-8 mx-auto">
<h6 className="eyebrow mb-3">Pattern Showcase</h6>
<h1 className="mb-4">FeatureTwoColumn Pattern</h1>
<p className="longform">
A feature section pattern that pairs editorial content with a media element
in a two-column layout. Supports four color themes, left/right arrangements,
and automatic button configuration based on link count.
</p>
</div>
</section>
{/* Button Behavior Section */}
<PageGrid className="my-5">
<PageGridRow>
<PageGridCol span={12}>
<h2 className="h4 mb-6">Button Behavior</h2>
<p className="mb-4">
The component automatically adjusts button rendering based on the number of links provided:
</p>
<ul className="mb-6">
<li><strong>1 link:</strong> Secondary button</li>
<li><strong>2 links:</strong> Primary + Tertiary buttons</li>
<li><strong>3-5 links:</strong> Primary + Tertiary (row), Secondary, then remaining Tertiary links</li>
</ul>
</PageGridCol>
</PageGridRow>
</PageGrid>
{/* 1 Link - Secondary Button */}
<div className="mb-5">
<PageGrid>
<PageGridRow>
<PageGridCol span={12}>
<div className="mb-3">
<strong>1 Link</strong> - Secondary Button
<br />
<small className="text-muted">Single action rendered as a secondary (outline) button.</small>
</div>
</PageGridCol>
</PageGridRow>
</PageGrid>
<FeatureTwoColumn
color="lilac"
arrange="left"
title="Institutions"
description="Banks, asset managers, PSPs, and fintechs use XRPL to build financial products and DeFi solutions efficiently and with more flexibility."
links={[
{ label: "Secondary Link", href: "#link1" }
]}
media={{ src: placeholderImage, alt: "Feature illustration" }}
/>
</div>
{/* 2 Links - Primary + Tertiary */}
<div className="mb-5">
<PageGrid>
<PageGridRow>
<PageGridCol span={12}>
<div className="mb-3">
<strong>2 Links</strong> - Primary + Tertiary Buttons
<br />
<small className="text-muted">Primary action with a secondary tertiary link.</small>
</div>
</PageGridCol>
</PageGridRow>
</PageGrid>
<FeatureTwoColumn
color="neutral"
arrange="left"
title="Institutions"
description="Banks, asset managers, PSPs, and fintechs use XRPL to build financial products and DeFi solutions efficiently and with more flexibility."
links={[
{ label: "Primary Link", href: "#link1" },
{ label: "Tertiary Link", href: "#link2" }
]}
media={{ src: placeholderImage, alt: "Feature illustration" }}
/>
</div>
{/* 5 Links - Multiple Tertiary */}
<div className="mb-5">
<PageGrid>
<PageGridRow>
<PageGridCol span={12}>
<div className="mb-3">
<strong>5 Links</strong> - Multiple Links Configuration
<br />
<small className="text-muted">Primary + Tertiary in first row, Secondary below, remaining as Tertiary list.</small>
</div>
</PageGridCol>
</PageGridRow>
</PageGrid>
<FeatureTwoColumn
color="neutral"
arrange="left"
title="Institutions"
description="Banks, asset managers, PSPs, and fintechs use XRPL to build financial products and DeFi solutions efficiently and with more flexibility."
links={[
{ label: "Primary Link", href: "#link1" },
{ label: "Tertiary Link", href: "#link2" },
{ label: "Secondary Link", href: "#link3" },
{ label: "Tertiary Link", href: "#link4" },
{ label: "Tertiary Link", href: "#link5" }
]}
media={{ src: placeholderImage, alt: "Feature illustration" }}
/>
</div>
{/* Color Variants Section */}
<PageGrid className="my-5">
<PageGridRow>
<PageGridCol span={12}>
<h2 className="h4 mb-6">Color Variants</h2>
<p className="mb-6">
Four color themes available: neutral, lilac, yellow, and green.
Each adapts automatically for light and dark modes.
</p>
</PageGridCol>
</PageGridRow>
</PageGrid>
{/* Neutral Variant */}
<div className="mb-5">
<PageGrid>
<PageGridRow>
<PageGridCol span={12}>
<div className="mb-3">
<strong>Neutral</strong> - <code>color="neutral"</code>
<br />
<small className="text-muted">
Light: <code>$gray-100</code> (#F0F3F7) | Dark: <code>$gray-200</code> (#E6EAF0)
<br />
From <code>styles/_colors.scss</code>
</small>
</div>
</PageGridCol>
</PageGridRow>
</PageGrid>
<FeatureTwoColumn
color="neutral"
arrange="left"
title="Institutions"
description="Banks, asset managers, PSPs, and fintechs use XRPL to build financial products and DeFi solutions efficiently and with more flexibility."
links={[
{ label: "Get Started", href: "#start" },
{ label: "Learn More", href: "#learn" }
]}
media={{ src: placeholderImage, alt: "Neutral theme" }}
/>
</div>
{/* Lilac Variant */}
<div className="mb-5">
<PageGrid>
<PageGridRow>
<PageGridCol span={12}>
<div className="mb-3">
<strong>Lilac</strong> - <code>color="lilac"</code>
<br />
<small className="text-muted">
Light: <code>$lilac-200</code> (#D9CAFF) | Dark: <code>$lilac-200</code> (#D9CAFF)
<br />
From <code>styles/_colors.scss</code>
</small>
</div>
</PageGridCol>
</PageGridRow>
</PageGrid>
<FeatureTwoColumn
color="lilac"
arrange="left"
title="Institutions"
description="Banks, asset managers, PSPs, and fintechs use XRPL to build financial products and DeFi solutions efficiently and with more flexibility."
links={[
{ label: "Get Started", href: "#start" },
{ label: "Learn More", href: "#learn" }
]}
media={{ src: placeholderImage, alt: "Lilac theme" }}
/>
</div>
{/* Yellow Variant */}
<div className="mb-5">
<PageGrid>
<PageGridRow>
<PageGridCol span={12}>
<div className="mb-3">
<strong>Yellow</strong> - <code>color="yellow"</code>
<br />
<small className="text-muted">
Light: <code>$yellow-100</code> (#F3F1EB) | Dark: <code>$yellow-100</code> (#F3F1EB)
<br />
From <code>styles/_colors.scss</code>
</small>
</div>
</PageGridCol>
</PageGridRow>
</PageGrid>
<FeatureTwoColumn
color="yellow"
arrange="left"
title="Institutions"
description="Banks, asset managers, PSPs, and fintechs use XRPL to build financial products and DeFi solutions efficiently and with more flexibility."
links={[
{ label: "Get Started", href: "#start" },
{ label: "Learn More", href: "#learn" }
]}
media={{ src: placeholderImage, alt: "Yellow theme" }}
/>
</div>
{/* Green Variant */}
<div className="mb-5">
<PageGrid>
<PageGridRow>
<PageGridCol span={12}>
<div className="mb-3">
<strong>Green</strong> - <code>color="green"</code>
<br />
<small className="text-muted">
Light: <code>$green-300</code> (#21E46B) | Dark: <code>$green-300</code> (#21E46B)
<br />
From <code>styles/_colors.scss</code>
</small>
</div>
</PageGridCol>
</PageGridRow>
</PageGrid>
<FeatureTwoColumn
color="green"
arrange="left"
title="Institutions"
description="Banks, asset managers, PSPs, and fintechs use XRPL to build financial products and DeFi solutions efficiently and with more flexibility."
links={[
{ label: "Get Started", href: "#start" },
{ label: "Learn More", href: "#learn" }
]}
media={{ src: placeholderImage, alt: "Green theme" }}
/>
</div>
{/* Arrangement Section */}
<PageGrid className="my-5">
<PageGridRow>
<PageGridCol span={12}>
<h2 className="h4 mb-6">Arrangement Variants</h2>
<p className="mb-6">
Control content position with the <code>arrange</code> prop.
Use alternating arrangements for visual variety on pages with multiple sections.
</p>
<div className="mb-4 p-3" style={{ backgroundColor: '#f0f3f7', borderRadius: '8px' }}>
<strong>📱 Responsive Behavior:</strong>
<ul className="mb-0 mt-2">
<li><code>arrange="left"</code>: Content above media on mobile/tablet, content left on desktop</li>
<li><code>arrange="right"</code>: Media above content on mobile/tablet, content right on desktop</li>
</ul>
</div>
</PageGridCol>
</PageGridRow>
</PageGrid>
{/* Arrange Left */}
<div className="mb-5">
<PageGrid>
<PageGridRow>
<PageGridCol span={12}>
<div className="mb-3">
<strong>Arrange Left (Default)</strong> - <code>arrange="left"</code>
<br />
<small className="text-muted">
Desktop: Content left, media right | Mobile/Tablet: Content above media
</small>
</div>
</PageGridCol>
</PageGridRow>
</PageGrid>
<FeatureTwoColumn
color="lilac"
arrange="left"
title="Content Left"
description="This content appears on the left side of the layout on desktop, and above the media on mobile/tablet. This is the default arrangement."
links={[
{ label: "Primary Action", href: "#primary" },
{ label: "Secondary Action", href: "#secondary" }
]}
media={{ src: placeholderImage, alt: "Left arrangement" }}
/>
</div>
{/* Arrange Right */}
<div className="mb-5">
<PageGrid>
<PageGridRow>
<PageGridCol span={12}>
<div className="mb-3">
<strong>Arrange Right</strong> - <code>arrange="right"</code>
<br />
<small className="text-muted">
Desktop: Content right, media left | Mobile/Tablet: Media above content
</small>
</div>
</PageGridCol>
</PageGridRow>
</PageGrid>
<FeatureTwoColumn
color="yellow"
arrange="right"
title="Content Right"
description="This content appears on the right side on desktop, and below the media on mobile/tablet. The media-first approach works well for visual hierarchy."
links={[
{ label: "Primary Action", href: "#primary" },
{ label: "Secondary Action", href: "#secondary" }
]}
media={{ src: placeholderImage, alt: "Right arrangement" }}
/>
</div>
{/* Alternating Pattern Example */}
<PageGrid className="my-5">
<PageGridRow>
<PageGridCol span={12}>
<h2 className="h4 mb-6">Alternating Pattern</h2>
<p className="mb-6">
Use alternating arrangements and colors to create visual rhythm on feature-heavy pages.
</p>
</PageGridCol>
</PageGridRow>
</PageGrid>
<FeatureTwoColumn
color="neutral"
arrange="left"
title="First Feature"
description="Banks, asset managers, PSPs, and fintechs use XRPL to build financial products."
links={[{ label: "Learn More", href: "#learn" }]}
media={{ src: placeholderImage, alt: "First feature" }}
/>
<FeatureTwoColumn
color="lilac"
arrange="right"
title="Second Feature"
description="Build powerful applications on XRPL with comprehensive documentation and tools."
links={[
{ label: "Get Started", href: "#start" },
{ label: "Documentation", href: "#docs" }
]}
media={{ src: placeholderImage, alt: "Second feature" }}
/>
<FeatureTwoColumn
color="yellow"
arrange="left"
title="Third Feature"
description="Scale your business with blockchain technology and enterprise-grade solutions."
links={[
{ label: "Contact Sales", href: "#contact" },
{ label: "View Plans", href: "#plans" }
]}
media={{ src: placeholderImage, alt: "Third feature" }}
/>
<FeatureTwoColumn
color="green"
arrange="right"
title="Fourth Feature"
description="Join thousands of developers building the future of finance on XRPL."
links={[
{ label: "Start Building", href: "#build" },
{ label: "Tutorials", href: "#tutorials" },
{ label: "API Reference", href: "#api" }
]}
media={{ src: placeholderImage, alt: "Fourth feature" }}
/>
{/* Design References */}
<PageGrid className="my-5">
<PageGridRow>
<PageGridCol span={12}>
<h2 className="h4 mb-6">Design References</h2>
<div className="d-flex flex-column gap-3">
<div>
<strong>Figma Design:</strong>{' '}
<a href="https://www.figma.com/design/3tmqxMrEvOVvpYhgOCxv2D/Pattern-Feature---Two-Column?node-id=20017-3501&m=dev" target="_blank" rel="noopener noreferrer">
Pattern - Feature - Two Column (Figma)
</a>
</div>
<div>
<strong>Component Location:</strong>{' '}
<code>shared/patterns/FeatureTwoColumn/</code>
</div>
<div>
<strong>Color Tokens:</strong>{' '}
<code>styles/_colors.scss</code>
</div>
<div>
<strong>Typography:</strong>{' '}
<code>styles/_font.scss</code>
</div>
</div>
</PageGridCol>
</PageGridRow>
</PageGrid>
</div>
</div>
);
}

View File

@@ -23,6 +23,12 @@ interface ButtonProps {
variant?: 'primary' | 'secondary' | 'tertiary';
/** Color theme - green (default) or black */
color?: 'green' | 'black';
/**
* Force the color to remain constant regardless of theme mode.
* When true, the button color will not change between light/dark modes.
* Use this for buttons on colored backgrounds where black should stay black.
*/
forceColor?: boolean;
/** Button content/label */
children: React.ReactNode;
/** Click handler */
@@ -48,6 +54,7 @@ interface ButtonProps {
- `variant`: `'primary'`
- `color`: `'green'`
- `forceColor`: `false`
- `disabled`: `false`
- `type`: `'button'`
- `className`: `''`
@@ -132,6 +139,37 @@ The black theme provides an alternative color scheme:
</Button>
```
### Force Color (Theme-Independent)
By default, black buttons automatically switch to green in dark mode for better visibility. However, when placing buttons on colored backgrounds (e.g., lilac, yellow, green), you may want black buttons to remain black regardless of theme mode.
Use the `forceColor` prop to prevent automatic color switching:
**Usage:**
```tsx
{/* Black button that stays black in both light and dark modes */}
<Button variant="primary" color="black" forceColor onClick={handleClick}>
Always Black
</Button>
{/* Useful for colored backgrounds like in FeatureTwoColumn pattern */}
<FeatureTwoColumn color="lilac">
<Button variant="primary" color="black" forceColor href="/get-started">
Get Started
</Button>
<Button variant="tertiary" color="black" forceColor href="/learn-more">
Learn More
</Button>
</FeatureTwoColumn>
```
**When to use `forceColor`:**
- Buttons on colored backgrounds (lilac, yellow, green variants)
- When you need consistent button colors regardless of user's theme preference
- Pattern components like `FeatureTwoColumn` where black text is required for readability
**Note:** The `forceColor` prop only affects the color behavior; all other button functionality (hover animations, focus states, etc.) remains the same.
## Link Buttons
The Button component can render as an anchor element for navigation by passing the `href` prop. When `href` is provided, the button is wrapped in a Redocly `Link` component for proper routing support within the application.

View File

@@ -1109,6 +1109,315 @@ html.dark {
}
}
// =============================================================================
// Force Color Modifier
// =============================================================================
// When .bds-btn--force-color is applied, the button color remains constant
// regardless of theme mode. This is used for buttons on colored backgrounds
// where black should stay black even in dark mode.
//
// Usage: <Button color="black" forceColor />
// =============================================================================
.bds-btn--force-color {
// Black buttons with force-color should maintain black styling in dark mode
&.bds-btn--black {
// Primary black - force black background
&.bds-btn--primary {
color: $bds-btn-primary-black-text !important;
background-color: $bds-btn-primary-black-bg !important;
&::before {
background-color: $bds-btn-primary-black-bg-hover !important;
}
.bds-btn__icon,
.bds-btn__icon-line,
.bds-btn__icon-chevron {
color: $bds-btn-primary-black-text !important;
stroke: $bds-btn-primary-black-text !important;
}
&:hover:not(:disabled):not(.bds-btn--disabled),
&:focus-visible:not(:disabled):not(.bds-btn--disabled),
&:active:not(:disabled):not(.bds-btn--disabled) {
color: $bds-btn-primary-black-text !important;
.bds-btn__icon,
.bds-btn__icon-line,
.bds-btn__icon-chevron {
color: $bds-btn-primary-black-text !important;
stroke: $bds-btn-primary-black-text !important;
}
}
&:focus-visible:not(:disabled):not(.bds-btn--disabled) {
outline-color: $bds-btn-neutral-black !important;
}
}
// Secondary black - force black text/border
&.bds-btn--secondary {
color: $bds-btn-secondary-black-text !important;
border-color: $bds-btn-secondary-black-border !important;
&::before {
background-color: $bds-btn-secondary-black-bg-hover !important;
}
.bds-btn__icon,
.bds-btn__icon-line,
.bds-btn__icon-chevron {
color: $bds-btn-secondary-black-text !important;
stroke: $bds-btn-secondary-black-text !important;
}
&:hover:not(:disabled):not(.bds-btn--disabled),
&:focus-visible:not(:disabled):not(.bds-btn--disabled),
&:active:not(:disabled):not(.bds-btn--disabled) {
color: $bds-btn-secondary-black-text !important;
border-color: $bds-btn-secondary-black-border !important;
.bds-btn__icon,
.bds-btn__icon-line,
.bds-btn__icon-chevron {
color: $bds-btn-secondary-black-text !important;
stroke: $bds-btn-secondary-black-text !important;
}
}
&:focus-visible:not(:disabled):not(.bds-btn--disabled) {
outline-color: $bds-btn-neutral-black !important;
}
}
// Tertiary black - force black text
&.bds-btn--tertiary {
color: $bds-btn-tertiary-black-text !important;
.bds-btn__icon,
.bds-btn__icon-line,
.bds-btn__icon-chevron {
color: $bds-btn-tertiary-black-text !important;
stroke: $bds-btn-tertiary-black-text !important;
}
&:hover:not(:disabled):not(.bds-btn--disabled),
&:focus-visible:not(:disabled):not(.bds-btn--disabled),
&:active:not(:disabled):not(.bds-btn--disabled) {
color: $bds-btn-tertiary-black-text !important;
.bds-btn__icon,
.bds-btn__icon-line,
.bds-btn__icon-chevron {
color: $bds-btn-tertiary-black-text !important;
stroke: $bds-btn-tertiary-black-text !important;
}
}
&:focus-visible:not(:disabled):not(.bds-btn--disabled) {
outline-color: $bds-btn-tertiary-black-focus-outline !important;
}
}
}
}
// =============================================================================
// Force Color Modifier - Dark Mode Overrides
// =============================================================================
// These overrides must have higher specificity than the dark mode color swaps
// to ensure black buttons stay black on colored backgrounds in dark mode.
// =============================================================================
html.dark {
// Primary black with force-color - override dark mode green swap
.bds-btn.bds-btn.bds-btn--primary.bds-btn--primary.bds-btn--black.bds-btn--force-color {
color: $bds-btn-primary-black-text !important;
background-color: $bds-btn-primary-black-bg !important;
&::before {
background-color: $bds-btn-primary-black-bg-hover !important;
}
.bds-btn__icon,
.bds-btn__icon-line,
.bds-btn__icon-chevron {
color: $bds-btn-primary-black-text !important;
stroke: $bds-btn-primary-black-text !important;
}
&:hover:not(:disabled):not(.bds-btn--disabled),
&:focus-visible:not(:disabled):not(.bds-btn--disabled),
&:active:not(:disabled):not(.bds-btn--disabled) {
color: $bds-btn-primary-black-text !important;
.bds-btn__icon,
.bds-btn__icon-line,
.bds-btn__icon-chevron {
color: $bds-btn-primary-black-text !important;
stroke: $bds-btn-primary-black-text !important;
}
}
&:focus-visible:not(:disabled):not(.bds-btn--disabled) {
outline-color: $white !important; // White outline for visibility on dark backgrounds
}
}
// Secondary black with force-color - override dark mode green swap
.bds-btn.bds-btn.bds-btn--secondary.bds-btn--secondary.bds-btn--black.bds-btn--force-color {
color: $bds-btn-secondary-black-text !important;
border-color: $bds-btn-secondary-black-border !important;
background-color: transparent !important;
&::before {
background-color: $bds-btn-secondary-black-bg-hover !important;
}
.bds-btn__icon,
.bds-btn__icon-line,
.bds-btn__icon-chevron {
color: $bds-btn-secondary-black-text !important;
stroke: $bds-btn-secondary-black-text !important;
}
&:hover:not(:disabled):not(.bds-btn--disabled),
&:focus-visible:not(:disabled):not(.bds-btn--disabled),
&:active:not(:disabled):not(.bds-btn--disabled) {
color: $bds-btn-secondary-black-text !important;
border-color: $bds-btn-secondary-black-border !important;
.bds-btn__icon,
.bds-btn__icon-line,
.bds-btn__icon-chevron {
color: $bds-btn-secondary-black-text !important;
stroke: $bds-btn-secondary-black-text !important;
}
}
&:focus-visible:not(:disabled):not(.bds-btn--disabled) {
outline-color: $white !important; // White outline for visibility on dark backgrounds
}
}
// Tertiary black with force-color - override dark mode green swap
.bds-btn.bds-btn.bds-btn--tertiary.bds-btn--tertiary.bds-btn--black.bds-btn--force-color {
color: $bds-btn-tertiary-black-text !important;
background-color: transparent !important;
.bds-btn__icon,
.bds-btn__icon-line,
.bds-btn__icon-chevron {
color: $bds-btn-tertiary-black-text !important;
stroke: $bds-btn-tertiary-black-text !important;
}
&:hover:not(:disabled):not(.bds-btn--disabled),
&:focus-visible:not(:disabled):not(.bds-btn--disabled),
&:active:not(:disabled):not(.bds-btn--disabled) {
color: $bds-btn-tertiary-black-text !important;
.bds-btn__icon,
.bds-btn__icon-line,
.bds-btn__icon-chevron {
color: $bds-btn-tertiary-black-text !important;
stroke: $bds-btn-tertiary-black-text !important;
}
}
&:focus-visible:not(:disabled):not(.bds-btn--disabled) {
outline-color: $white !important; // White outline for visibility on dark backgrounds
}
}
// Anchor link buttons with force-color - dark mode overrides
a.bds-btn.bds-btn--force-color {
&.bds-btn--primary.bds-btn--black {
color: $bds-btn-primary-black-text !important;
background-color: $bds-btn-primary-black-bg !important;
.bds-btn__icon,
.bds-btn__icon-line,
.bds-btn__icon-chevron {
color: $bds-btn-primary-black-text !important;
stroke: $bds-btn-primary-black-text !important;
}
&:hover,
&:focus,
&:focus-visible,
&:active,
&:visited {
color: $bds-btn-primary-black-text !important;
background-color: $bds-btn-primary-black-bg !important;
.bds-btn__icon,
.bds-btn__icon-line,
.bds-btn__icon-chevron {
color: $bds-btn-primary-black-text !important;
stroke: $bds-btn-primary-black-text !important;
}
}
}
&.bds-btn--secondary.bds-btn--black {
color: $bds-btn-secondary-black-text !important;
border-color: $bds-btn-secondary-black-border !important;
background-color: transparent !important;
.bds-btn__icon,
.bds-btn__icon-line,
.bds-btn__icon-chevron {
color: $bds-btn-secondary-black-text !important;
stroke: $bds-btn-secondary-black-text !important;
}
&:hover,
&:focus,
&:focus-visible,
&:active,
&:visited {
color: $bds-btn-secondary-black-text !important;
border-color: $bds-btn-secondary-black-border !important;
.bds-btn__icon,
.bds-btn__icon-line,
.bds-btn__icon-chevron {
color: $bds-btn-secondary-black-text !important;
stroke: $bds-btn-secondary-black-text !important;
}
}
}
&.bds-btn--tertiary.bds-btn--black {
color: $bds-btn-tertiary-black-text !important;
background-color: transparent !important;
.bds-btn__icon,
.bds-btn__icon-line,
.bds-btn__icon-chevron {
color: $bds-btn-tertiary-black-text !important;
stroke: $bds-btn-tertiary-black-text !important;
}
&:hover,
&:focus,
&:focus-visible,
&:active,
&:visited {
color: $bds-btn-tertiary-black-text !important;
.bds-btn__icon,
.bds-btn__icon-line,
.bds-btn__icon-chevron {
color: $bds-btn-tertiary-black-text !important;
stroke: $bds-btn-tertiary-black-text !important;
}
}
}
}
}
// =============================================================================
// Tertiary Variant
// =============================================================================

View File

@@ -7,6 +7,12 @@ export interface ButtonProps {
variant?: 'primary' | 'secondary' | 'tertiary';
/** Color theme - green (default) or black */
color?: 'green' | 'black';
/**
* Force the color to remain constant regardless of theme mode.
* When true, the button color will not change between light/dark modes.
* Use this for buttons on colored backgrounds where black should stay black.
*/
forceColor?: boolean;
/** Button content/label */
children: React.ReactNode;
/** Click handler */
@@ -99,6 +105,7 @@ const getTextFromChildren = (children: React.ReactNode): string => {
export const Button: React.FC<ButtonProps> = ({
variant = 'primary',
color = 'green',
forceColor = false,
children,
onClick,
disabled = false,
@@ -123,6 +130,7 @@ export const Button: React.FC<ButtonProps> = ({
{
'bds-btn--disabled': disabled,
'bds-btn--no-icon': !shouldShowIcon,
'bds-btn--force-color': forceColor,
},
className
);

View File

@@ -32,20 +32,20 @@ $bds-card-image-height-sm: 536px;
$bds-card-image-image-height-sm: 268px;
// Spacing - LG (Large) variant (default, ≥992px)
$bds-card-image-gap-lg: 24px; // Gap between image and content
$bds-card-image-gap-lg: 24px; // Gap between image and title
$bds-card-image-title-gap-lg: 12px; // Gap between title and subtitle
$bds-card-image-content-padding: 8px; // Horizontal padding for content (same for all)
$bds-card-image-button-margin-lg: 32px; // Margin above button
$bds-card-image-button-margin-lg: 30px; // Margin above button
// Spacing - MD (Medium) variant (576px - 991px)
$bds-card-image-gap-md: 16px; // Gap between image and content
$bds-card-image-gap-md: 20px; // Gap between image and title
$bds-card-image-title-gap-md: 8px; // Gap between title and subtitle
$bds-card-image-button-margin-md: 24px; // Margin above button
$bds-card-image-button-margin-md: 34px; // Margin above button
// Spacing - SM (Small) variant (<576px)
$bds-card-image-gap-sm: 16px; // Gap between image and content
$bds-card-image-title-gap-sm: 8px; // Gap between title and subtitle
$bds-card-image-button-margin-sm: 24px; // Margin above button
$bds-card-image-gap-sm: 16px; // Gap between image and title
$bds-card-image-title-gap-sm: 4px; // Gap between title and subtitle
$bds-card-image-button-margin-sm: 35px; // Margin above button
// Colors
$bds-card-image-bg: $white;
@@ -66,7 +66,9 @@ $bds-card-image-transition-timing: cubic-bezier(0.98, 0.12, 0.12, 0.98);
flex-direction: column;
gap: $bds-card-image-gap-lg; // Gap between image container and content
width: 100%; // Fill available width (4-column span on LG+)
height: $bds-card-image-height-lg;
background-color: $bds-card-image-bg;
overflow: hidden;
cursor: pointer;
// When inside a grid column, fill the column width
@@ -122,21 +124,8 @@ $bds-card-image-transition-timing: cubic-bezier(0.98, 0.12, 0.12, 0.98);
// Full Bleed Modifier
// =============================================================================
// When fullBleed is true, image fills entire container with object-fit: cover
// and uses aspect-ratio for responsive sizing
.bds-card-image--full-bleed {
// Override fixed heights - use auto height with aspect ratio
height: auto;
width: 100%; // Ensure card fills parent container
.bds-card-image__image-container {
// Use aspect-ratio instead of fixed height for responsive scaling
width: 100%;
height: auto;
// 1:1 aspect ratio for all breakpoints (from Figma designs)
aspect-ratio: 1 / 1;
}
.bds-card-image__image {
width: 100%;
height: 100%;
@@ -198,15 +187,7 @@ $bds-card-image-transition-timing: cubic-bezier(0.98, 0.12, 0.12, 0.98);
.bds-card-image__content .bds-btn {
align-self: flex-start;
flex-shrink: 0; // Don't shrink button
margin-top: $bds-card-image-button-margin-sm; // Mobile: 24px
@include media-breakpoint-up(md) {
margin-top: $bds-card-image-button-margin-md; // Tablet: 24px
}
@include media-breakpoint-up(lg) {
margin-top: $bds-card-image-button-margin-lg; // Desktop: 32px
}
// Button positioned at bottom via justify-content: space-between on parent
}
// =============================================================================
@@ -248,6 +229,7 @@ $bds-card-image-transition-timing: cubic-bezier(0.98, 0.12, 0.12, 0.98);
@include media-breakpoint-down(lg) {
.bds-card-image {
height: $bds-card-image-height-md;
gap: $bds-card-image-gap-md; // Gap between image container and content for MD
}
@@ -270,6 +252,7 @@ $bds-card-image-transition-timing: cubic-bezier(0.98, 0.12, 0.12, 0.98);
@include media-breakpoint-down(sm) {
.bds-card-image {
height: $bds-card-image-height-sm;
gap: $bds-card-image-gap-sm; // Gap between image container and content for SM
}

View File

@@ -140,7 +140,7 @@ export const CardImage: React.FC<CardImageProps> = ({
{/* Content area: title, subtitle, and button */}
<div className="bds-card-image__content">
<div className="bds-card-image__text">
<h3 className="bds-card-image__title sh-md-l">{title}</h3>
<h3 className="bds-card-image__title sh-md-r">{title}</h3>
<p className="bds-card-image__subtitle body-l">{subtitle}</p>
</div>

View File

@@ -1,104 +0,0 @@
# CardsFeatured Pattern
A section pattern that displays a heading, description, and a responsive grid of `CardImage` components. Follows the "Logo Rectangle Grid" design from Figma.
## Features
- Responsive grid layout (1 column mobile, 2 tablet, 3 desktop)
- Heading with `h-md` typography (Tobias Light)
- Description with `body-l` typography (Booton Light)
- Proper spacing using `PageGrid` for container and alignment
- Full dark mode support
## Usage
```tsx
import { CardsFeatured } from 'shared/patterns/CardsFeatured';
<CardsFeatured
heading="Trusted by Leaders in Real-World Asset Tokenization"
description="Powering institutions and builders who are bringing real world assets on chain at global scale."
cards={[
{
image: "/img/docs.png",
imageAlt: "Documentation",
title: "Documentation",
subtitle: "Access everything you need to get started working with the XRPL.",
buttonLabel: "Get Started",
href: "/docs"
},
{
image: "/img/tutorials.png",
imageAlt: "Tutorials",
title: "Tutorials",
subtitle: "Step-by-step guides to help you build on the XRP Ledger.",
buttonLabel: "View Tutorials",
href: "/tutorials"
},
// ... more cards
]}
/>
```
## Props
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `heading` | `React.ReactNode` | Yes | Section heading text |
| `description` | `React.ReactNode` | Yes | Section description text |
| `cards` | `CardsFeaturedCardConfig[]` | Yes | Array of card configurations (uses `CardImageProps`) |
| `className` | `string` | No | Additional CSS class names |
### CardsFeaturedCardConfig
Each card in the `cards` array accepts all props from `CardImageProps`:
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `image` | `string` | Yes | Image URL |
| `imageAlt` | `string` | Yes | Image alt text |
| `title` | `string` | Yes | Card title |
| `subtitle` | `string` | No | Card subtitle/description |
| `buttonLabel` | `string` | No | Button text |
| `href` | `string` | No | Link URL |
## Responsive Behavior
| Breakpoint | Grid Columns | Vertical Padding |
|------------|--------------|------------------|
| Mobile (< 768px) | 1 column | 48px |
| Tablet (768px - 1199px) | 2 columns | 64px |
| Desktop (≥ 1200px) | 3 columns | 80px |
## Design Tokens
### Colors
| Mode | Element | Color |
|------|---------|-------|
| Light | Heading | `$black` (#141414) |
| Light | Description | `$black` (#141414) |
| Dark | Heading | `$white` (#FFFFFF) |
| Dark | Description | `$white` (#FFFFFF) |
### Spacing
- Header gap (heading to description): 8px mobile/tablet, 16px desktop
- Section gap (header to cards): 24px mobile, 32px tablet, 40px desktop
- Cards gap: 48px mobile (vertical), 8px tablet/desktop
## CSS Classes
| Class | Description |
|-------|-------------|
| `.bds-cards-featured` | Base section container |
| `.bds-cards-featured__header` | Header wrapper for heading and description |
| `.bds-cards-featured__heading` | Section heading (uses `.h-md`) |
| `.bds-cards-featured__description` | Section description (uses `.body-l`) |
| `.bds-cards-featured__cards` | Cards grid container |
| `.bds-cards-featured__card-wrapper` | Individual card wrapper |
## Showcase
View the pattern showcase at: `/about/cards-featured-showcase`

View File

@@ -1,178 +0,0 @@
// BDS CardsFeatured Pattern Styles
// Brand Design System - Section with heading, description, and grid of CardImage components
//
// Naming Convention: BEM with 'bds' namespace
// .bds-cards-featured - Base section container
// .bds-cards-featured__header - Header wrapper for heading and description
// .bds-cards-featured__heading - Section heading (uses .h-md)
// .bds-cards-featured__description - Section description (uses .body-l)
// .bds-cards-featured__cards - Cards grid container
// .bds-cards-featured__card-wrapper - Individual card wrapper
//
// Design tokens from Figma:
// Light Mode:
// - Heading: Neutral Black (#141414) → $black
// - Description: Neutral Black (#141414) → $black
//
// Dark Mode:
// - Heading: Neutral White (#FFFFFF) → $white
// - Description: Neutral White (#FFFFFF) → $white
//
// - Header content max-width: 808px (approximately 8 columns at desktop)
// - Gap between heading and description: 16px
// - Gap between cards: 8px (matches $bds-grid-gutter)
// =============================================================================
// Design Tokens (from Figma)
// =============================================================================
$bds-grid-gutter: 8px;
// Spacing - Header gap (between heading and description)
$bds-cards-featured-header-gap-sm: 8px; // Mobile: 8px
$bds-cards-featured-header-gap-md: 8px; // Tablet: 8px
$bds-cards-featured-header-gap-lg: 16px; // Desktop: 16px
// Spacing - Section gap (between header and cards)
$bds-cards-featured-section-gap-sm: 24px; // Mobile
$bds-cards-featured-section-gap-md: 32px; // Tablet
$bds-cards-featured-section-gap-lg: 40px; // Desktop
// Spacing - Cards gap
$bds-cards-featured-cards-gap-sm: 48px; // Mobile: 48px vertical
$bds-cards-featured-cards-gap-md: 8px; // Tablet: 8px
$bds-cards-featured-cards-gap-lg: 8px; // Desktop: 8px
// Spacing - Section padding (vertical)
$bds-cards-featured-padding-y-sm: 48px; // Mobile
$bds-cards-featured-padding-y-md: 64px; // Tablet
$bds-cards-featured-padding-y-lg: 80px; // Desktop
// Spacing - Section padding (horizontal) - handled by PageGrid
// Colors - Light Mode (default)
$bds-cards-featured-heading-color: $black; // #141414 - Neutral black
$bds-cards-featured-description-color: $black; // #141414 - Neutral black
// Colors - Dark Mode (from Figma node 27020-3045)
$bds-cards-featured-heading-color-dark: $white; // #FFFFFF - Neutral white
$bds-cards-featured-description-color-dark: $white; // #FFFFFF - Neutral white
// =============================================================================
// Section Container
// =============================================================================
.bds-cards-featured {
width: 100%;
padding-top: $bds-cards-featured-padding-y-sm;
padding-bottom: $bds-cards-featured-padding-y-sm;
@include media-breakpoint-up(md) {
padding-top: $bds-cards-featured-padding-y-md;
padding-bottom: $bds-cards-featured-padding-y-md;
}
@include media-breakpoint-up(lg) {
padding-top: $bds-cards-featured-padding-y-lg;
padding-bottom: $bds-cards-featured-padding-y-lg;
}
}
// =============================================================================
// Header Section
// =============================================================================
.bds-cards-featured__header {
display: flex;
flex-direction: column;
gap: $bds-cards-featured-header-gap-sm;
@include media-breakpoint-up(md) {
gap: $bds-cards-featured-header-gap-md;
}
@include media-breakpoint-up(lg) {
gap: $bds-cards-featured-header-gap-lg;
}
}
.bds-cards-featured__heading {
margin: 0;
// Typography handled by .h-md class from _font.scss
}
.bds-cards-featured__description {
margin: 0;
// Typography handled by .body-l class from _font.scss
}
// =============================================================================
// Cards Grid
// =============================================================================
.bds-cards-featured__cards {
display: grid;
grid-template-columns: 1fr;
column-gap: $bds-cards-featured-cards-gap-sm;
row-gap: 48px;
width: 100%;
margin-top: $bds-cards-featured-section-gap-sm;
@include media-breakpoint-up(md) {
grid-template-columns: repeat(2, 1fr);
column-gap: $bds-cards-featured-cards-gap-md;
row-gap: 52px;
margin-top: $bds-cards-featured-section-gap-md;
}
@include media-breakpoint-up(lg) {
grid-template-columns: repeat(3, 1fr);
column-gap: $bds-cards-featured-cards-gap-lg;
row-gap: 56px;
margin-top: $bds-cards-featured-section-gap-lg;
}
}
.bds-cards-featured__card-wrapper {
display: flex;
min-width: 0; // Allow flex child to shrink below content size
width: 100%; // Ensure wrapper fills grid cell
// Ensure CardImage fills the wrapper
.bds-card-image {
width: 100%;
}
}
// =============================================================================
// Light Mode Styles (from Figma node 27020-3048)
// =============================================================================
html.light {
.bds-cards-featured {
background-color: $white;
}
.bds-cards-featured__heading {
color: $bds-cards-featured-heading-color;
}
.bds-cards-featured__description {
color: $bds-cards-featured-description-color;
}
}
// =============================================================================
// Dark Mode Styles (from Figma node 27020-3045)
// =============================================================================
html.dark {
.bds-cards-featured__heading {
color: $bds-cards-featured-heading-color-dark;
}
.bds-cards-featured__description {
color: $bds-cards-featured-description-color-dark;
}
}

View File

@@ -1,122 +0,0 @@
import React from 'react';
import clsx from 'clsx';
import { CardImage, CardImageProps } from '../../components/CardImage';
import { PageGrid } from '../../components/PageGrid/page-grid';
/**
* Configuration for a single card in the CardsFeatured pattern
*/
export type CardsFeaturedCardConfig = CardImageProps;
/**
* Props for the CardsFeatured pattern component
*/
export interface CardsFeaturedProps extends React.ComponentPropsWithoutRef<'section'> {
/** Section heading text */
heading: React.ReactNode;
/** Section description text */
description: React.ReactNode;
/** Array of card configurations (uses CardImageProps) */
cards: readonly CardsFeaturedCardConfig[];
}
/**
* Generates a stable key for a card based on its properties.
* Falls back to index if no stable identifier is available.
*/
const getCardKey = (card: CardsFeaturedCardConfig, index: number): string | number => {
if (card.href) return card.href;
if (card.title) return `${card.title}-${index}`;
return index;
};
/**
* CardsFeatured Pattern Component
*
* A section pattern that displays a heading, description, and a responsive grid
* of CardImage components. Follows the "Logo Rectangle Grid" pattern from Figma.
*
* Features:
* - Responsive grid layout (1 column mobile, 2 tablet, 3 desktop)
* - Heading with `heading-md` typography (Tobias Light)
* - Description with `body-l` typography (Booton Light)
* - Proper spacing using PageGrid for container and alignment
* - Full dark mode support
*
* @example
* ```tsx
* <CardsFeatured
* heading="Trusted by Leaders in Real-World Asset"
* description="Powering institutions and builders who are bringing real world assets on chain at global scale."
* cards={[
* {
* image: "/img/docs.png",
* imageAlt: "Documentation",
* title: "Documentation",
* subtitle: "Access everything you need to get started working with the XRPL.",
* buttonLabel: "Get Started",
* href: "/docs"
* },
* // ... more cards
* ]}
* />
* ```
*/
export const CardsFeatured = React.forwardRef<HTMLElement, CardsFeaturedProps>(
(props, ref) => {
const { heading, description, cards, className, ...rest } = props;
// Early return for empty cards array
if (cards.length === 0) {
console.warn('CardsFeatured: No cards provided');
return null;
}
return (
<section
ref={ref}
className={clsx('bds-cards-featured', className)}
{...rest}
>
<PageGrid>
{/* Header content row */}
<PageGrid.Row>
<PageGrid.Col
span={{
base: 'fill',
md: 6,
lg: 8,
}}
>
<div className="bds-cards-featured__header">
<h2 className="bds-cards-featured__heading h-md">{heading}</h2>
<p className="bds-cards-featured__description body-l">{description}</p>
</div>
</PageGrid.Col>
</PageGrid.Row>
{/* Cards grid row */}
<PageGrid.Row>
<PageGrid.Col span="fill">
<div className="bds-cards-featured__cards">
{cards.map((card, index) => (
<div
key={getCardKey(card, index)}
className="bds-cards-featured__card-wrapper"
>
<CardImage {...card} fullBleed />
</div>
))}
</div>
</PageGrid.Col>
</PageGrid.Row>
</PageGrid>
</section>
);
}
);
CardsFeatured.displayName = 'CardsFeatured';
export default CardsFeatured;

View File

@@ -1,3 +0,0 @@
export { CardsFeatured, type CardsFeaturedProps, type CardsFeaturedCardConfig } from './CardsFeatured';
export { default } from './CardsFeatured';

View File

@@ -0,0 +1,216 @@
# FeatureTwoColumn Pattern
A feature section pattern that pairs editorial content with a media element in a two-column layout. Designed for showcasing features, products, or use cases with flexible button configurations based on the number of links.
## Overview
FeatureTwoColumn supports four color theme variants (neutral, lilac, yellow, green) and adapts responsively across desktop, tablet, and mobile breakpoints. The button rendering automatically adjusts based on the number of links provided.
## When to Use
- Highlighting a specific feature, product, or use case
- Presenting content with supporting visual media
- Creating visual variety with alternating left/right arrangements
- When 1-5 action links are needed with appropriate button hierarchy
## Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `color` | `'neutral' \| 'lilac' \| 'yellow' \| 'green'` | `'neutral'` | Background color theme variant |
| `arrange` | `'left' \| 'right'` | `'left'` | Controls whether content appears on the left or right side |
| `title` | `string` | *required* | Feature title text (heading-md typography) |
| `description` | `string` | *required* | Feature description text (body-l typography) |
| `links` | `FeatureTwoColumnLink[]` | *required* | Array of 1-5 links (see button behavior below) |
| `media` | `{ src: string; alt: string }` | *required* | Feature media (image) configuration |
| `className` | `string` | - | Additional CSS classes |
### FeatureTwoColumnLink
| Property | Type | Description |
|----------|------|-------------|
| `label` | `string` | Link label text |
| `href` | `string` | Link URL |
## Button Behavior
The component automatically renders buttons based on the number of links provided:
| Link Count | Button Configuration |
|------------|---------------------|
| 1 link | Secondary button |
| 2 links | Primary button + Tertiary button |
| 3-5 links | Primary + Tertiary (row), Secondary, then Tertiary links |
## Variants
### Color Themes
- **Neutral**: White background (dark mode: black)
- **Lilac**: Light purple background ($lilac-100, dark mode: $lilac-500)
- **Yellow**: Light yellow background ($yellow-100, dark mode: $yellow-500)
- **Green**: Light green background ($green-100, dark mode: $green-500)
### Arrangement
- **Left** (default): Content on the left, media on the right
- **Right**: Content on the right, media on the left
## Basic Usage
```tsx
import { FeatureTwoColumn } from '@/shared/patterns/FeatureTwoColumn';
function MyPage() {
return (
<FeatureTwoColumn
color="lilac"
arrange="left"
title="Institutions"
description="Banks, asset managers, PSPs, and fintechs use XRPL to build financial products and DeFi solutions efficiently and with more flexibility."
links={[
{ label: "Get Started", href: "/docs" },
{ label: "Learn More", href: "/about" }
]}
media={{ src: "/img/institutions.png", alt: "Institutions illustration" }}
/>
);
}
```
## Examples
### Single Link (Secondary Button)
```tsx
<FeatureTwoColumn
color="green"
arrange="right"
title="Developers"
description="Build powerful applications on XRPL with comprehensive documentation and tools."
links={[{ label: "View Documentation", href: "/docs" }]}
media={{ src: "/img/dev.png", alt: "Developer tools" }}
/>
```
### Two Links (Primary + Tertiary)
```tsx
<FeatureTwoColumn
color="yellow"
arrange="left"
title="Enterprise Solutions"
description="Scale your business with blockchain technology."
links={[
{ label: "Contact Sales", href: "/contact" },
{ label: "Learn More", href: "/enterprise" }
]}
media={{ src: "/img/enterprise.png", alt: "Enterprise" }}
/>
```
### Multiple Links (3-5 Tertiary)
```tsx
<FeatureTwoColumn
color="neutral"
arrange="left"
title="Explore XRPL"
description="Discover all the ways to interact with the XRP Ledger."
links={[
{ label: "Documentation", href: "/docs" },
{ label: "Tutorials", href: "/tutorials" },
{ label: "API Reference", href: "/api" },
{ label: "Community", href: "/community" },
{ label: "GitHub", href: "/github" }
]}
media={{ src: "/img/explore.png", alt: "Explore XRPL" }}
/>
```
## Responsive Behavior
### Desktop (≥992px)
- Side-by-side layout with content and media columns (6/12 columns each)
- Media uses 1:1 (square) aspect ratio
- Vertical padding: 96px
- Text gap (title to description): 16px
- CTA gap (between buttons): 25px
### Tablet (576px - 991px)
- Stacked layout (content above media, 8/8 columns = full width)
- Media uses 16:9 aspect ratio
- Vertical padding: 80px
- Text gap: 8px
- Content to CTA gap: 32px
- CTA gap: 16px
### Mobile (<576px)
- Stacked layout (content above media, 4/4 columns = full width)
- Media uses 1:1 aspect ratio
- Vertical padding: 64px
- Text gap: 8px
- Content to CTA gap: 24px
- CTA gap: 16px
## Anatomy
```
FeatureTwoColumn
├── PageGrid Container (responsive padding)
│ └── PageGrid.Row (flex layout)
│ ├── PageGrid.Col (content column, 6/12 on desktop)
│ │ └── Content
│ │ ├── TextGroup
│ │ │ ├── Title (h2, heading-md)
│ │ │ └── Description (p, body-l)
│ │ └── CTA (button configuration varies by link count)
│ │ ├── 1 link: Secondary Button
│ │ ├── 2 links: Primary + Tertiary Buttons
│ │ └── 3-5 links: Primary + Tertiary (row), Secondary, Tertiary list
│ └── PageGrid.Col (media column, 6/12 on desktop)
│ └── Media
│ └── Image (object-fit: cover)
```
## CSS Classes
| Class | Description |
|-------|-------------|
| `.bds-feature-two-column` | Root element |
| `.bds-feature-two-column--neutral` | Neutral color theme |
| `.bds-feature-two-column--lilac` | Lilac color theme |
| `.bds-feature-two-column--yellow` | Yellow color theme |
| `.bds-feature-two-column--green` | Green color theme |
| `.bds-feature-two-column--left` | Content left arrangement |
| `.bds-feature-two-column--right` | Content right arrangement |
| `.bds-feature-two-column__container` | PageGrid container |
| `.bds-feature-two-column__row` | PageGrid.Row wrapper |
| `.bds-feature-two-column__content-col` | Content column wrapper |
| `.bds-feature-two-column__content` | Content container |
| `.bds-feature-two-column__text-group` | Title + description container |
| `.bds-feature-two-column__title` | Title heading |
| `.bds-feature-two-column__description` | Description text |
| `.bds-feature-two-column__cta` | CTA buttons container |
| `.bds-feature-two-column__cta--single` | Single button variant |
| `.bds-feature-two-column__cta--double` | Two button variant |
| `.bds-feature-two-column__cta--multiple` | Multiple buttons variant |
| `.bds-feature-two-column__media-col` | Media column wrapper |
| `.bds-feature-two-column__media` | Media container |
| `.bds-feature-two-column__media-img` | Media image |
## Accessibility
- Uses semantic `<section>` element for the pattern container
- Title uses `<h2>` heading for proper document structure
- Media requires `alt` text for screen readers
- Buttons inherit accessible labels from the Button component
- Color contrast ratios meet WCAG 2.1 AA standards
## Design References
- **Figma Design**: [Pattern - Feature - Two Column](https://www.figma.com/design/3tmqxMrEvOVvpYhgOCxv2D/Pattern-Feature---Two-Column?node-id=20017-3501&m=dev)
- **Component Location**: `shared/patterns/FeatureTwoColumn/`
- **Color Tokens**: `styles/_colors.scss`
- **Typography**: `styles/_font.scss`

View File

@@ -0,0 +1,482 @@
// FeatureTwoColumn Pattern Styles
// =============================================================================
// A feature section pattern with two-column layout for content and media.
// Supports color themes (neutral, lilac, yellow, green) and arrangement variants.
// =============================================================================
// Design Tokens
// =============================================================================
// Background colors for each color variant (light mode)
// From styles/_colors.scss - Design tokens
$bds-feature-neutral-bg: $gray-100; // #F0F3F7 (Neutral-100)
$bds-feature-lilac-bg: $lilac-200; // #D9CAFF (Primary-Lilac-200)
$bds-feature-yellow-bg: $yellow-100; // #F3F1EB (Secondary-Yellow-100)
$bds-feature-green-bg: $green-300; // #21E46B (Primary-Green-300default)
// Background colors for dark mode
// From styles/_colors.scss - Design tokens
$bds-feature-neutral-bg-dark: $gray-200; // #E6EAF0 (Neutral-200)
$bds-feature-lilac-bg-dark: $lilac-200; // #D9CAFF (Primary-Lilac-200)
$bds-feature-yellow-bg-dark: $yellow-100; // #F3F1EB (Secondary-Yellow-100)
$bds-feature-green-bg-dark: $green-300; // #21E46B (Primary-Green-300default)
// Text colors - same for light and dark modes
// From styles/_colors.scss: $black = #141414 (Neutral-black)
$bds-feature-title-color: $black; // #141414 (Neutral-black)
$bds-feature-title-color-dark: $black; // #141414 (same in dark mode)
$bds-feature-description-color: $black; // #141414 (Neutral-black)
$bds-feature-description-color-dark: $black; // #141414 (same in dark mode)
// Spacing - Desktop (≥992px) - based on Figma 1280px design
$bds-feature-desktop-py: 96px;
$bds-feature-desktop-text-gap: 16px;
$bds-feature-desktop-cta-gap-col: 0; // Gap between button rows
$bds-feature-desktop-content-gap: 0; // Gap between text-group and cta (space-between handles this)
$bds-feature-desktop-button-gap: 16px; // Gap between buttons in ButtonGroup (consistent across all sizes)
// Spacing - Tablet (576px - 991px) - based on Figma 768px design
$bds-feature-tablet-py: 80px;
$bds-feature-tablet-pl: 115px; // Left padding from Figma
$bds-feature-tablet-pr: 107px; // Right padding from Figma
$bds-feature-tablet-text-gap: 8px;
$bds-feature-tablet-cta-gap-row: 16px; // Gap between buttons in row from Figma
$bds-feature-tablet-cta-gap-col: 0;
$bds-feature-tablet-content-gap: 32px;
$bds-feature-tablet-button-gap: 16px; // Gap between buttons in ButtonGroup (consistent across all sizes)
// Spacing - Mobile (<576px) - based on Figma 375px design
$bds-feature-mobile-py: 64px;
$bds-feature-mobile-px: 16px;
$bds-feature-mobile-text-gap: 8px;
$bds-feature-mobile-cta-gap: 16px; // Gap between stacked buttons from Figma
$bds-feature-mobile-content-gap: 24px;
$bds-feature-mobile-button-gap: 16px; // Gap between buttons in ButtonGroup (consistent across all sizes)
// Grid gutter - consistent with PageGrid
$bds-grid-gutter: 8px;
// =============================================================================
// Base Styles
// =============================================================================
.bds-feature-two-column__button-group {
.bds-btn--tertiary {
padding-top: 0px !important;
padding-bottom: 0px !important;
}
}
.bds-feature-two-column__cta-row{
.bds-btn--tertiary {
padding-top: 16px !important;
}
}
.bds-feature-two-column {
width: 100%;
// Extra large screens (>1280px): constrain component width and center
// Background color stays within 1280px, parent section background shows beyond
@include media-breakpoint-up(lg) {
max-width: 1280px;
margin: 0 auto;
}
// Desktop layout - hidden on mobile/tablet, shown on desktop
&__desktop-layout {
display: none;
@include media-breakpoint-up(lg) {
display: flex;
width: 100%;
align-items: stretch; // Both columns match height
}
}
// Mobile layout - shown on mobile/tablet, hidden on desktop
&__mobile-layout {
display: block;
@include media-breakpoint-up(lg) {
display: none;
}
}
// Container - uses PageGrid with wide variant (for mobile layout)
// Override all PageGrid padding - content columns have their own padding
&__container {
padding: 0 !important; // Override PageGrid default padding at all breakpoints
}
// Row - uses PageGrid.Row (for mobile layout)
&__row {
gap: 0 !important; // No gap between content and media sections, override PageGrid
}
// Content column wrapper
&__content-col {
display: flex;
flex-direction: column;
// Mobile: vertical padding, no horizontal padding (grid handles positioning)
padding: $bds-feature-mobile-py 0;
// Tablet: vertical padding, no horizontal padding (grid handles positioning)
@include media-breakpoint-up(md) {
padding: $bds-feature-tablet-py 0;
}
// Desktop: 50% width, vertical padding (grid handles horizontal positioning)
@include media-breakpoint-up(lg) {
width: 50%;
padding: $bds-feature-desktop-py 0;
// Match height of media column (which has aspect-ratio 1/1)
aspect-ratio: 1 / 1;
}
}
// Content grid - positions content within column using grid system
// Desktop: 6-column grid within the content half, content spans cols 2-5 (offset-1, span-4)
// Tablet: 8-column grid, content spans cols 2-7 (offset-1, span-6)
// Mobile: 4-column grid, content spans cols 1-4 (no offset, span-4)
&__content-grid {
display: grid;
width: 100%;
height: 100%;
// Mobile: 4 columns, content full width
grid-template-columns: repeat(4, 1fr);
gap: $bds-grid-gutter;
padding: 0 16px; // Mobile edge padding
// Tablet: 8 columns
@include media-breakpoint-up(md) {
grid-template-columns: repeat(8, 1fr);
padding: 0 24px; // Tablet edge padding
}
// Desktop: 6 columns (within the 50% content half)
@include media-breakpoint-up(lg) {
grid-template-columns: repeat(6, 1fr);
padding: 0 32px; // Desktop edge padding
}
}
// Content wrapper - positioned within the grid
&__content-wrapper {
// Mobile: span all 4 columns (cols 1-4)
grid-column: 1 / -1;
// Tablet: start at col 2, span 6 columns (cols 2-7)
@include media-breakpoint-up(md) {
grid-column: 2 / span 6;
}
// Desktop: start at col 2, span 4 columns (cols 2-5)
@include media-breakpoint-up(lg) {
grid-column: 2 / span 4;
}
}
// Media column wrapper - desktop layout (background image)
&__media-col {
display: flex;
flex-direction: column;
// Desktop: 50% width with background image, square aspect ratio
@include media-breakpoint-up(lg) {
width: 50%;
aspect-ratio: 1 / 1;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
}
// Mobile media column
&__media-col--mobile {
display: flex;
flex-direction: column;
}
// Content
&__content {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: space-between;
height: 100%;
gap: $bds-feature-mobile-content-gap;
@include media-breakpoint-up(md) {
gap: $bds-feature-tablet-content-gap;
}
@include media-breakpoint-up(lg) {
gap: $bds-feature-desktop-content-gap;
}
}
// Content with multiple links
// Mobile: 24px gap between text-group and button-group
// Tablet: 32px gap between text-group and button-group
// Desktop: space-between with no gap (auto distribution between text-group and button-group)
&__content--multiple {
// Mobile: no gap since we only have 2 items (text-group and button-group)
// The 24px gap is handled via button-group margin or flex gap
gap: 0;
justify-content: flex-start;
@include media-breakpoint-up(lg) {
gap: 0; // Desktop uses space-between for auto distribution
justify-content: space-between;
}
// Secondary button should not stretch - keep intrinsic width
>.bds-btn--secondary {
align-self: flex-start;
}
}
// Button group - contains all buttons in the multiple links layout
// 16px gap between buttons on ALL screen sizes
&__button-group {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: $bds-feature-mobile-button-gap; // 16px on mobile
margin-top: $bds-feature-mobile-content-gap; // 24px spacing from text-group on mobile
@include media-breakpoint-up(md) {
gap: $bds-feature-tablet-button-gap; // 16px on tablet
margin-top: $bds-feature-tablet-content-gap; // 32px spacing from text-group on tablet
}
@include media-breakpoint-up(lg) {
gap: $bds-feature-desktop-button-gap; // 16px on desktop
margin-top: 0; // Desktop uses space-between, no explicit margin needed
}
// Tertiary links need left padding removed to align text with title
>.bds-btn--tertiary {
padding-left: 0 !important;
margin-left: 0;
&:hover:not(:disabled):not(.bds-btn--disabled),
&:focus:not(:disabled):not(.bds-btn--disabled),
&:focus-visible:not(:disabled):not(.bds-btn--disabled),
&:active:not(:disabled):not(.bds-btn--disabled) {
padding-left: 0 !important;
}
}
}
// Text group - title + description
&__text-group {
display: flex;
flex-direction: column;
gap: $bds-feature-mobile-text-gap;
@include media-breakpoint-up(md) {
gap: $bds-feature-tablet-text-gap;
}
@include media-breakpoint-up(lg) {
gap: $bds-feature-desktop-text-gap;
}
}
// Title - Heading MD from styles/_font.scss
// Font: Tobias (secondary), Size: 40px, Weight: 300, Line-height: 46px, Letter-spacing: -1px
&__title {
@include type(heading-md);
color: $bds-feature-title-color; // #141414 (Neutral-black) - same in light/dark
margin: 0;
}
// Description - Body L from styles/_font.scss
// Font: Booton (primary), Size: 18px, Weight: 300, Line-height: 26.1px, Letter-spacing: -0.5px
&__description {
@include type(body-l);
color: $bds-feature-description-color; // #141414 (Neutral-black) - same in light/dark
margin: 0;
}
// CTA container - base styles
&__cta {
display: flex;
flex-direction: column;
align-items: flex-start;
@include media-breakpoint-up(md) {
flex-direction: row;
flex-wrap: wrap;
}
}
// CTA variants
&__cta--single {
// Single secondary button - vertical on mobile
flex-direction: column;
}
&__cta--double {
// Primary + tertiary - horizontal on tablet+
@include media-breakpoint-up(md) {
flex-direction: row;
align-items: center;
}
}
// CTA row - for first two buttons in multiple links layout (Primary + Tertiary)
&__cta-row {
display: flex;
flex-direction: column;
align-items: flex-start;
@include media-breakpoint-up(md) {
flex-direction: row;
align-items: center;
}
@include media-breakpoint-up(lg) {
flex-direction: row;
align-items: center;
}
}
// Tertiary group - groups remaining tertiary links together as a single unit
// No gap between tertiary links - they stack tightly as a group
&__tertiary-group {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 0; // No spacing between tertiary links in the group
// Tertiary links need left padding removed to align text with title
.bds-btn--tertiary {
padding-left: 0 !important;
margin-left: 0;
&:hover:not(:disabled):not(.bds-btn--disabled),
&:focus:not(:disabled):not(.bds-btn--disabled),
&:focus-visible:not(:disabled):not(.bds-btn--disabled),
&:active:not(:disabled):not(.bds-btn--disabled) {
padding-left: 0 !important;
}
}
}
// Media container
&__media {
width: 100%;
overflow: hidden;
// Mobile - 1:1 aspect ratio
aspect-ratio: 1 / 1;
// Tablet - 16:9 aspect ratio
@include media-breakpoint-up(md) {
aspect-ratio: 16 / 9;
}
// Desktop - 1:1 aspect ratio (square)
@include media-breakpoint-up(lg) {
aspect-ratio: 1 / 1;
}
}
// Media image
&__media-img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
}
}
// =============================================================================
// Color Theme Modifiers
// =============================================================================
// Neutral variant (default white/black)
.bds-feature-two-column--neutral {
background-color: $bds-feature-neutral-bg;
}
// Lilac variant
.bds-feature-two-column--lilac {
background-color: $bds-feature-lilac-bg;
}
// Yellow variant
.bds-feature-two-column--yellow {
background-color: $bds-feature-yellow-bg;
}
// Green variant
.bds-feature-two-column--green {
background-color: $bds-feature-green-bg;
}
// =============================================================================
// Dark Mode Theme Overrides
// =============================================================================
html.dark {
.bds-feature-two-column {
&__title {
color: $bds-feature-title-color-dark;
}
&__description {
color: $bds-feature-description-color-dark;
}
}
.bds-feature-two-column--neutral {
background-color: $bds-feature-neutral-bg-dark;
}
.bds-feature-two-column--lilac {
background-color: $bds-feature-lilac-bg-dark;
}
.bds-feature-two-column--yellow {
background-color: $bds-feature-yellow-bg-dark;
}
.bds-feature-two-column--green {
background-color: $bds-feature-green-bg-dark;
}
}
// =============================================================================
// Layout Modifiers (Arrange)
// =============================================================================
// Right arrangement - content on right, media on left (media first on mobile/tablet)
// Use flex-direction to swap columns on all screen sizes
.bds-feature-two-column--right {
// Mobile/Tablet layout - reverse the column order to show media first
.bds-feature-two-column__row {
flex-direction: column-reverse !important;
}
// Desktop layout - reverse the flex direction for side-by-side
.bds-feature-two-column__desktop-layout {
@include media-breakpoint-up(lg) {
flex-direction: row-reverse;
}
}
// Desktop content wrapper - mirror the grid positioning for right layout
// Content should start from col 2 and span 4 cols (same as left, grid handles positioning)
.bds-feature-two-column__content-wrapper {
@include media-breakpoint-up(lg) {
// Same positioning as left layout - grid alignment handles visual positioning
grid-column: 2 / span 4;
}
}
}

View File

@@ -0,0 +1,214 @@
import React from 'react';
import clsx from 'clsx';
import { Button } from '../../components/Button/Button';
import { PageGrid } from '../../components/PageGrid/page-grid';
export interface FeatureTwoColumnLink {
/** Link label text */
label: string;
/** Link URL */
href: string;
}
export interface FeatureTwoColumnProps {
/** Color theme variant */
color?: 'neutral' | 'lilac' | 'yellow' | 'green';
/** Content arrangement - left places content on left side, right places content on right side */
arrange?: 'left' | 'right';
/** Feature title text (heading-md typography) */
title: string;
/** Feature description text (body-l typography) */
description: string;
/** Array of links (1-5 links supported)
* - 1 link: renders as secondary button
* - 2 links: renders as primary + tertiary buttons
* - 3-5 links: renders all as tertiary buttons
*/
links: FeatureTwoColumnLink[];
/** Feature media (image) configuration */
media: {
src: string;
alt: string;
};
/** Additional CSS classes */
className?: string;
}
/**
* FeatureTwoColumn Pattern
*
* A feature section pattern that pairs editorial content with a media element
* in a two-column layout. Designed for showcasing features, products, or use cases.
*
* Uses the PageGrid component system for responsive layout:
* - Mobile: Stacked layout (content above media)
* - Tablet: Stacked layout (content above media)
* - Desktop: Side-by-side (6/12 columns each)
*
* Button behavior based on link count:
* - 1 link: Secondary button
* - 2 links: Primary button (first) + Tertiary button (second)
* - 3-5 links: All tertiary buttons (first is filled, rest are text-only)
*/
export const FeatureTwoColumn: React.FC<FeatureTwoColumnProps> = ({
color = 'neutral',
arrange = 'left',
title,
description,
links = [],
media,
className,
}) => {
// Build root class names
const rootClasses = clsx(
'bds-feature-two-column',
`bds-feature-two-column--${color}`,
`bds-feature-two-column--${arrange}`,
className
);
// Determine button color based on background
// Rule: Black buttons must be used for all backgrounds (including neutral)
const buttonColor = 'black';
const forceColor = true;
// Render content section with appropriate CTA layout based on link count
// For 3-5 links, items are direct children for space-between distribution
const renderContent = () => {
const linkCount = links.length;
// 1 link: Secondary button
if (linkCount === 1) {
return (
<div className="bds-feature-two-column__content">
<div className="bds-feature-two-column__text-group">
<h2 className="bds-feature-two-column__title">{title}</h2>
<p className="bds-feature-two-column__description">{description}</p>
</div>
<div className="bds-feature-two-column__cta bds-feature-two-column__cta--single">
<Button variant="secondary" color={buttonColor} forceColor={forceColor} href={links[0].href}>
{links[0].label}
</Button>
</div>
</div>
);
}
// 2 links: Primary + Tertiary in a row
if (linkCount === 2) {
return (
<div className="bds-feature-two-column__content">
<div className="bds-feature-two-column__text-group">
<h2 className="bds-feature-two-column__title">{title}</h2>
<p className="bds-feature-two-column__description">{description}</p>
</div>
<div className="bds-feature-two-column__cta bds-feature-two-column__cta--double">
<Button variant="primary" color={buttonColor} forceColor={forceColor} href={links[0].href}>
{links[0].label}
</Button>
<Button variant="tertiary" color={buttonColor} forceColor={forceColor} href={links[1].href}>
{links[1].label}
</Button>
</div>
</div>
);
}
// 3-5 links: Text group + Button group (contains all buttons with consistent 16px spacing)
// Desktop: space-between distribution between text-group and button-group
// Tablet: 32px gap, Mobile: 24px gap
return (
<div className="bds-feature-two-column__content bds-feature-two-column__content--multiple">
<div className="bds-feature-two-column__text-group">
<h2 className="bds-feature-two-column__title">{title}</h2>
<p className="bds-feature-two-column__description">{description}</p>
</div>
{/* Button group - all buttons grouped with 16px spacing between them */}
<div className="bds-feature-two-column__button-group">
{/* First two links in a row: Primary + Tertiary */}
<div className="bds-feature-two-column__cta-row">
<Button variant="primary" color={buttonColor} forceColor={forceColor} href={links[0].href}>
{links[0].label}
</Button>
{links[1] && (
<Button variant="tertiary" color={buttonColor} forceColor={forceColor} href={links[1].href}>
{links[1].label}
</Button>
)}
</div>
{/* Secondary button */}
{links[2] && (
<Button variant="secondary" color={buttonColor} forceColor={forceColor} href={links[2].href}>
{links[2].label}
</Button>
)}
{/* Remaining tertiary links */}
{links.slice(3).map((link, index) => (
<Button key={index} variant="tertiary" color={buttonColor} forceColor={forceColor} href={link.href}>
{link.label}
</Button>
))}
</div>
</div>
);
};
// Render media section (for mobile/tablet stacked layout)
const renderMedia = () => (
<div className="bds-feature-two-column__media">
<img
src={media.src}
alt={media.alt}
className="bds-feature-two-column__media-img"
/>
</div>
);
return (
<section className={rootClasses}>
{/* Desktop layout - simple two-column flex with background image */}
<div className="bds-feature-two-column__desktop-layout">
<div className="bds-feature-two-column__content-col">
<div className="bds-feature-two-column__content-grid">
<div className="bds-feature-two-column__content-wrapper">
{renderContent()}
</div>
</div>
</div>
<div
className="bds-feature-two-column__media-col"
style={{ backgroundImage: `url(${media.src})` }}
role="img"
aria-label={media.alt}
/>
</div>
{/* Mobile/Tablet layout - stacked with PageGrid */}
<div className="bds-feature-two-column__mobile-layout">
<PageGrid className="bds-feature-two-column__container" containerType="wide">
<PageGrid.Row className="bds-feature-two-column__row">
<PageGrid.Col
span={{ base: 4, md: 8 }}
className="bds-feature-two-column__content-col"
>
<div className="bds-feature-two-column__content-grid">
<div className="bds-feature-two-column__content-wrapper">
{renderContent()}
</div>
</div>
</PageGrid.Col>
<PageGrid.Col
span={{ base: 4, md: 8 }}
className="bds-feature-two-column__media-col--mobile"
>
{renderMedia()}
</PageGrid.Col>
</PageGrid.Row>
</PageGrid>
</div>
</section>
);
};
export default FeatureTwoColumn;

View File

@@ -0,0 +1,3 @@
export { FeatureTwoColumn, type FeatureTwoColumnProps, type FeatureTwoColumnLink } from './FeatureTwoColumn';
export { default } from './FeatureTwoColumn';

View File

@@ -12666,6 +12666,262 @@ html.dark .bds-btn.bds-btn.bds-btn--tertiary.bds-btn--tertiary.bds-btn--black.bd
}
}
.bds-btn--force-color.bds-btn--black.bds-btn--primary {
color: #FFFFFF !important;
background-color: #141414 !important;
}
.bds-btn--force-color.bds-btn--black.bds-btn--primary::before {
background-color: rgba(20, 20, 20, 0.8) !important;
}
.bds-btn--force-color.bds-btn--black.bds-btn--primary .bds-btn__icon,
.bds-btn--force-color.bds-btn--black.bds-btn--primary .bds-btn__icon-line,
.bds-btn--force-color.bds-btn--black.bds-btn--primary .bds-btn__icon-chevron {
color: #FFFFFF !important;
stroke: #FFFFFF !important;
}
.bds-btn--force-color.bds-btn--black.bds-btn--primary:hover:not(:disabled):not(.bds-btn--disabled), .bds-btn--force-color.bds-btn--black.bds-btn--primary:focus-visible:not(:disabled):not(.bds-btn--disabled), .bds-btn--force-color.bds-btn--black.bds-btn--primary:active:not(:disabled):not(.bds-btn--disabled) {
color: #FFFFFF !important;
}
.bds-btn--force-color.bds-btn--black.bds-btn--primary:hover:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon,
.bds-btn--force-color.bds-btn--black.bds-btn--primary:hover:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-line,
.bds-btn--force-color.bds-btn--black.bds-btn--primary:hover:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-chevron, .bds-btn--force-color.bds-btn--black.bds-btn--primary:focus-visible:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon,
.bds-btn--force-color.bds-btn--black.bds-btn--primary:focus-visible:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-line,
.bds-btn--force-color.bds-btn--black.bds-btn--primary:focus-visible:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-chevron, .bds-btn--force-color.bds-btn--black.bds-btn--primary:active:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon,
.bds-btn--force-color.bds-btn--black.bds-btn--primary:active:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-line,
.bds-btn--force-color.bds-btn--black.bds-btn--primary:active:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-chevron {
color: #FFFFFF !important;
stroke: #FFFFFF !important;
}
.bds-btn--force-color.bds-btn--black.bds-btn--primary:focus-visible:not(:disabled):not(.bds-btn--disabled) {
outline-color: #141414 !important;
}
.bds-btn--force-color.bds-btn--black.bds-btn--secondary {
color: #141414 !important;
border-color: #141414 !important;
}
.bds-btn--force-color.bds-btn--black.bds-btn--secondary::before {
background-color: rgba(20, 20, 20, 0.15) !important;
}
.bds-btn--force-color.bds-btn--black.bds-btn--secondary .bds-btn__icon,
.bds-btn--force-color.bds-btn--black.bds-btn--secondary .bds-btn__icon-line,
.bds-btn--force-color.bds-btn--black.bds-btn--secondary .bds-btn__icon-chevron {
color: #141414 !important;
stroke: #141414 !important;
}
.bds-btn--force-color.bds-btn--black.bds-btn--secondary:hover:not(:disabled):not(.bds-btn--disabled), .bds-btn--force-color.bds-btn--black.bds-btn--secondary:focus-visible:not(:disabled):not(.bds-btn--disabled), .bds-btn--force-color.bds-btn--black.bds-btn--secondary:active:not(:disabled):not(.bds-btn--disabled) {
color: #141414 !important;
border-color: #141414 !important;
}
.bds-btn--force-color.bds-btn--black.bds-btn--secondary:hover:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon,
.bds-btn--force-color.bds-btn--black.bds-btn--secondary:hover:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-line,
.bds-btn--force-color.bds-btn--black.bds-btn--secondary:hover:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-chevron, .bds-btn--force-color.bds-btn--black.bds-btn--secondary:focus-visible:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon,
.bds-btn--force-color.bds-btn--black.bds-btn--secondary:focus-visible:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-line,
.bds-btn--force-color.bds-btn--black.bds-btn--secondary:focus-visible:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-chevron, .bds-btn--force-color.bds-btn--black.bds-btn--secondary:active:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon,
.bds-btn--force-color.bds-btn--black.bds-btn--secondary:active:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-line,
.bds-btn--force-color.bds-btn--black.bds-btn--secondary:active:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-chevron {
color: #141414 !important;
stroke: #141414 !important;
}
.bds-btn--force-color.bds-btn--black.bds-btn--secondary:focus-visible:not(:disabled):not(.bds-btn--disabled) {
outline-color: #141414 !important;
}
.bds-btn--force-color.bds-btn--black.bds-btn--tertiary {
color: #141414 !important;
}
.bds-btn--force-color.bds-btn--black.bds-btn--tertiary .bds-btn__icon,
.bds-btn--force-color.bds-btn--black.bds-btn--tertiary .bds-btn__icon-line,
.bds-btn--force-color.bds-btn--black.bds-btn--tertiary .bds-btn__icon-chevron {
color: #141414 !important;
stroke: #141414 !important;
}
.bds-btn--force-color.bds-btn--black.bds-btn--tertiary:hover:not(:disabled):not(.bds-btn--disabled), .bds-btn--force-color.bds-btn--black.bds-btn--tertiary:focus-visible:not(:disabled):not(.bds-btn--disabled), .bds-btn--force-color.bds-btn--black.bds-btn--tertiary:active:not(:disabled):not(.bds-btn--disabled) {
color: #141414 !important;
}
.bds-btn--force-color.bds-btn--black.bds-btn--tertiary:hover:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon,
.bds-btn--force-color.bds-btn--black.bds-btn--tertiary:hover:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-line,
.bds-btn--force-color.bds-btn--black.bds-btn--tertiary:hover:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-chevron, .bds-btn--force-color.bds-btn--black.bds-btn--tertiary:focus-visible:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon,
.bds-btn--force-color.bds-btn--black.bds-btn--tertiary:focus-visible:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-line,
.bds-btn--force-color.bds-btn--black.bds-btn--tertiary:focus-visible:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-chevron, .bds-btn--force-color.bds-btn--black.bds-btn--tertiary:active:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon,
.bds-btn--force-color.bds-btn--black.bds-btn--tertiary:active:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-line,
.bds-btn--force-color.bds-btn--black.bds-btn--tertiary:active:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-chevron {
color: #141414 !important;
stroke: #141414 !important;
}
.bds-btn--force-color.bds-btn--black.bds-btn--tertiary:focus-visible:not(:disabled):not(.bds-btn--disabled) {
outline-color: #141414 !important;
}
html.dark .bds-btn.bds-btn.bds-btn--primary.bds-btn--primary.bds-btn--black.bds-btn--force-color {
color: #FFFFFF !important;
background-color: #141414 !important;
}
html.dark .bds-btn.bds-btn.bds-btn--primary.bds-btn--primary.bds-btn--black.bds-btn--force-color::before {
background-color: rgba(20, 20, 20, 0.8) !important;
}
html.dark .bds-btn.bds-btn.bds-btn--primary.bds-btn--primary.bds-btn--black.bds-btn--force-color .bds-btn__icon,
html.dark .bds-btn.bds-btn.bds-btn--primary.bds-btn--primary.bds-btn--black.bds-btn--force-color .bds-btn__icon-line,
html.dark .bds-btn.bds-btn.bds-btn--primary.bds-btn--primary.bds-btn--black.bds-btn--force-color .bds-btn__icon-chevron {
color: #FFFFFF !important;
stroke: #FFFFFF !important;
}
html.dark .bds-btn.bds-btn.bds-btn--primary.bds-btn--primary.bds-btn--black.bds-btn--force-color:hover:not(:disabled):not(.bds-btn--disabled), html.dark .bds-btn.bds-btn.bds-btn--primary.bds-btn--primary.bds-btn--black.bds-btn--force-color:focus-visible:not(:disabled):not(.bds-btn--disabled), html.dark .bds-btn.bds-btn.bds-btn--primary.bds-btn--primary.bds-btn--black.bds-btn--force-color:active:not(:disabled):not(.bds-btn--disabled) {
color: #FFFFFF !important;
}
html.dark .bds-btn.bds-btn.bds-btn--primary.bds-btn--primary.bds-btn--black.bds-btn--force-color:hover:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon,
html.dark .bds-btn.bds-btn.bds-btn--primary.bds-btn--primary.bds-btn--black.bds-btn--force-color:hover:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-line,
html.dark .bds-btn.bds-btn.bds-btn--primary.bds-btn--primary.bds-btn--black.bds-btn--force-color:hover:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-chevron, html.dark .bds-btn.bds-btn.bds-btn--primary.bds-btn--primary.bds-btn--black.bds-btn--force-color:focus-visible:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon,
html.dark .bds-btn.bds-btn.bds-btn--primary.bds-btn--primary.bds-btn--black.bds-btn--force-color:focus-visible:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-line,
html.dark .bds-btn.bds-btn.bds-btn--primary.bds-btn--primary.bds-btn--black.bds-btn--force-color:focus-visible:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-chevron, html.dark .bds-btn.bds-btn.bds-btn--primary.bds-btn--primary.bds-btn--black.bds-btn--force-color:active:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon,
html.dark .bds-btn.bds-btn.bds-btn--primary.bds-btn--primary.bds-btn--black.bds-btn--force-color:active:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-line,
html.dark .bds-btn.bds-btn.bds-btn--primary.bds-btn--primary.bds-btn--black.bds-btn--force-color:active:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-chevron {
color: #FFFFFF !important;
stroke: #FFFFFF !important;
}
html.dark .bds-btn.bds-btn.bds-btn--primary.bds-btn--primary.bds-btn--black.bds-btn--force-color:focus-visible:not(:disabled):not(.bds-btn--disabled) {
outline-color: #FFFFFF !important;
}
html.dark .bds-btn.bds-btn.bds-btn--secondary.bds-btn--secondary.bds-btn--black.bds-btn--force-color {
color: #141414 !important;
border-color: #141414 !important;
background-color: transparent !important;
}
html.dark .bds-btn.bds-btn.bds-btn--secondary.bds-btn--secondary.bds-btn--black.bds-btn--force-color::before {
background-color: rgba(20, 20, 20, 0.15) !important;
}
html.dark .bds-btn.bds-btn.bds-btn--secondary.bds-btn--secondary.bds-btn--black.bds-btn--force-color .bds-btn__icon,
html.dark .bds-btn.bds-btn.bds-btn--secondary.bds-btn--secondary.bds-btn--black.bds-btn--force-color .bds-btn__icon-line,
html.dark .bds-btn.bds-btn.bds-btn--secondary.bds-btn--secondary.bds-btn--black.bds-btn--force-color .bds-btn__icon-chevron {
color: #141414 !important;
stroke: #141414 !important;
}
html.dark .bds-btn.bds-btn.bds-btn--secondary.bds-btn--secondary.bds-btn--black.bds-btn--force-color:hover:not(:disabled):not(.bds-btn--disabled), html.dark .bds-btn.bds-btn.bds-btn--secondary.bds-btn--secondary.bds-btn--black.bds-btn--force-color:focus-visible:not(:disabled):not(.bds-btn--disabled), html.dark .bds-btn.bds-btn.bds-btn--secondary.bds-btn--secondary.bds-btn--black.bds-btn--force-color:active:not(:disabled):not(.bds-btn--disabled) {
color: #141414 !important;
border-color: #141414 !important;
}
html.dark .bds-btn.bds-btn.bds-btn--secondary.bds-btn--secondary.bds-btn--black.bds-btn--force-color:hover:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon,
html.dark .bds-btn.bds-btn.bds-btn--secondary.bds-btn--secondary.bds-btn--black.bds-btn--force-color:hover:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-line,
html.dark .bds-btn.bds-btn.bds-btn--secondary.bds-btn--secondary.bds-btn--black.bds-btn--force-color:hover:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-chevron, html.dark .bds-btn.bds-btn.bds-btn--secondary.bds-btn--secondary.bds-btn--black.bds-btn--force-color:focus-visible:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon,
html.dark .bds-btn.bds-btn.bds-btn--secondary.bds-btn--secondary.bds-btn--black.bds-btn--force-color:focus-visible:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-line,
html.dark .bds-btn.bds-btn.bds-btn--secondary.bds-btn--secondary.bds-btn--black.bds-btn--force-color:focus-visible:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-chevron, html.dark .bds-btn.bds-btn.bds-btn--secondary.bds-btn--secondary.bds-btn--black.bds-btn--force-color:active:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon,
html.dark .bds-btn.bds-btn.bds-btn--secondary.bds-btn--secondary.bds-btn--black.bds-btn--force-color:active:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-line,
html.dark .bds-btn.bds-btn.bds-btn--secondary.bds-btn--secondary.bds-btn--black.bds-btn--force-color:active:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-chevron {
color: #141414 !important;
stroke: #141414 !important;
}
html.dark .bds-btn.bds-btn.bds-btn--secondary.bds-btn--secondary.bds-btn--black.bds-btn--force-color:focus-visible:not(:disabled):not(.bds-btn--disabled) {
outline-color: #FFFFFF !important;
}
html.dark .bds-btn.bds-btn.bds-btn--tertiary.bds-btn--tertiary.bds-btn--black.bds-btn--force-color {
color: #141414 !important;
background-color: transparent !important;
}
html.dark .bds-btn.bds-btn.bds-btn--tertiary.bds-btn--tertiary.bds-btn--black.bds-btn--force-color .bds-btn__icon,
html.dark .bds-btn.bds-btn.bds-btn--tertiary.bds-btn--tertiary.bds-btn--black.bds-btn--force-color .bds-btn__icon-line,
html.dark .bds-btn.bds-btn.bds-btn--tertiary.bds-btn--tertiary.bds-btn--black.bds-btn--force-color .bds-btn__icon-chevron {
color: #141414 !important;
stroke: #141414 !important;
}
html.dark .bds-btn.bds-btn.bds-btn--tertiary.bds-btn--tertiary.bds-btn--black.bds-btn--force-color:hover:not(:disabled):not(.bds-btn--disabled), html.dark .bds-btn.bds-btn.bds-btn--tertiary.bds-btn--tertiary.bds-btn--black.bds-btn--force-color:focus-visible:not(:disabled):not(.bds-btn--disabled), html.dark .bds-btn.bds-btn.bds-btn--tertiary.bds-btn--tertiary.bds-btn--black.bds-btn--force-color:active:not(:disabled):not(.bds-btn--disabled) {
color: #141414 !important;
}
html.dark .bds-btn.bds-btn.bds-btn--tertiary.bds-btn--tertiary.bds-btn--black.bds-btn--force-color:hover:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon,
html.dark .bds-btn.bds-btn.bds-btn--tertiary.bds-btn--tertiary.bds-btn--black.bds-btn--force-color:hover:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-line,
html.dark .bds-btn.bds-btn.bds-btn--tertiary.bds-btn--tertiary.bds-btn--black.bds-btn--force-color:hover:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-chevron, html.dark .bds-btn.bds-btn.bds-btn--tertiary.bds-btn--tertiary.bds-btn--black.bds-btn--force-color:focus-visible:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon,
html.dark .bds-btn.bds-btn.bds-btn--tertiary.bds-btn--tertiary.bds-btn--black.bds-btn--force-color:focus-visible:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-line,
html.dark .bds-btn.bds-btn.bds-btn--tertiary.bds-btn--tertiary.bds-btn--black.bds-btn--force-color:focus-visible:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-chevron, html.dark .bds-btn.bds-btn.bds-btn--tertiary.bds-btn--tertiary.bds-btn--black.bds-btn--force-color:active:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon,
html.dark .bds-btn.bds-btn.bds-btn--tertiary.bds-btn--tertiary.bds-btn--black.bds-btn--force-color:active:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-line,
html.dark .bds-btn.bds-btn.bds-btn--tertiary.bds-btn--tertiary.bds-btn--black.bds-btn--force-color:active:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-chevron {
color: #141414 !important;
stroke: #141414 !important;
}
html.dark .bds-btn.bds-btn.bds-btn--tertiary.bds-btn--tertiary.bds-btn--black.bds-btn--force-color:focus-visible:not(:disabled):not(.bds-btn--disabled) {
outline-color: #FFFFFF !important;
}
html.dark a.bds-btn.bds-btn--force-color.bds-btn--primary.bds-btn--black {
color: #FFFFFF !important;
background-color: #141414 !important;
}
html.dark a.bds-btn.bds-btn--force-color.bds-btn--primary.bds-btn--black .bds-btn__icon,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--primary.bds-btn--black .bds-btn__icon-line,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--primary.bds-btn--black .bds-btn__icon-chevron {
color: #FFFFFF !important;
stroke: #FFFFFF !important;
}
html.dark a.bds-btn.bds-btn--force-color.bds-btn--primary.bds-btn--black:hover, html.dark a.bds-btn.bds-btn--force-color.bds-btn--primary.bds-btn--black:focus, html.dark a.bds-btn.bds-btn--force-color.bds-btn--primary.bds-btn--black:focus-visible, html.dark a.bds-btn.bds-btn--force-color.bds-btn--primary.bds-btn--black:active, html.dark a.bds-btn.bds-btn--force-color.bds-btn--primary.bds-btn--black:visited {
color: #FFFFFF !important;
background-color: #141414 !important;
}
html.dark a.bds-btn.bds-btn--force-color.bds-btn--primary.bds-btn--black:hover .bds-btn__icon,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--primary.bds-btn--black:hover .bds-btn__icon-line,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--primary.bds-btn--black:hover .bds-btn__icon-chevron, html.dark a.bds-btn.bds-btn--force-color.bds-btn--primary.bds-btn--black:focus .bds-btn__icon,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--primary.bds-btn--black:focus .bds-btn__icon-line,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--primary.bds-btn--black:focus .bds-btn__icon-chevron, html.dark a.bds-btn.bds-btn--force-color.bds-btn--primary.bds-btn--black:focus-visible .bds-btn__icon,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--primary.bds-btn--black:focus-visible .bds-btn__icon-line,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--primary.bds-btn--black:focus-visible .bds-btn__icon-chevron, html.dark a.bds-btn.bds-btn--force-color.bds-btn--primary.bds-btn--black:active .bds-btn__icon,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--primary.bds-btn--black:active .bds-btn__icon-line,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--primary.bds-btn--black:active .bds-btn__icon-chevron, html.dark a.bds-btn.bds-btn--force-color.bds-btn--primary.bds-btn--black:visited .bds-btn__icon,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--primary.bds-btn--black:visited .bds-btn__icon-line,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--primary.bds-btn--black:visited .bds-btn__icon-chevron {
color: #FFFFFF !important;
stroke: #FFFFFF !important;
}
html.dark a.bds-btn.bds-btn--force-color.bds-btn--secondary.bds-btn--black {
color: #141414 !important;
border-color: #141414 !important;
background-color: transparent !important;
}
html.dark a.bds-btn.bds-btn--force-color.bds-btn--secondary.bds-btn--black .bds-btn__icon,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--secondary.bds-btn--black .bds-btn__icon-line,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--secondary.bds-btn--black .bds-btn__icon-chevron {
color: #141414 !important;
stroke: #141414 !important;
}
html.dark a.bds-btn.bds-btn--force-color.bds-btn--secondary.bds-btn--black:hover, html.dark a.bds-btn.bds-btn--force-color.bds-btn--secondary.bds-btn--black:focus, html.dark a.bds-btn.bds-btn--force-color.bds-btn--secondary.bds-btn--black:focus-visible, html.dark a.bds-btn.bds-btn--force-color.bds-btn--secondary.bds-btn--black:active, html.dark a.bds-btn.bds-btn--force-color.bds-btn--secondary.bds-btn--black:visited {
color: #141414 !important;
border-color: #141414 !important;
}
html.dark a.bds-btn.bds-btn--force-color.bds-btn--secondary.bds-btn--black:hover .bds-btn__icon,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--secondary.bds-btn--black:hover .bds-btn__icon-line,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--secondary.bds-btn--black:hover .bds-btn__icon-chevron, html.dark a.bds-btn.bds-btn--force-color.bds-btn--secondary.bds-btn--black:focus .bds-btn__icon,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--secondary.bds-btn--black:focus .bds-btn__icon-line,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--secondary.bds-btn--black:focus .bds-btn__icon-chevron, html.dark a.bds-btn.bds-btn--force-color.bds-btn--secondary.bds-btn--black:focus-visible .bds-btn__icon,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--secondary.bds-btn--black:focus-visible .bds-btn__icon-line,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--secondary.bds-btn--black:focus-visible .bds-btn__icon-chevron, html.dark a.bds-btn.bds-btn--force-color.bds-btn--secondary.bds-btn--black:active .bds-btn__icon,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--secondary.bds-btn--black:active .bds-btn__icon-line,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--secondary.bds-btn--black:active .bds-btn__icon-chevron, html.dark a.bds-btn.bds-btn--force-color.bds-btn--secondary.bds-btn--black:visited .bds-btn__icon,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--secondary.bds-btn--black:visited .bds-btn__icon-line,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--secondary.bds-btn--black:visited .bds-btn__icon-chevron {
color: #141414 !important;
stroke: #141414 !important;
}
html.dark a.bds-btn.bds-btn--force-color.bds-btn--tertiary.bds-btn--black {
color: #141414 !important;
background-color: transparent !important;
}
html.dark a.bds-btn.bds-btn--force-color.bds-btn--tertiary.bds-btn--black .bds-btn__icon,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--tertiary.bds-btn--black .bds-btn__icon-line,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--tertiary.bds-btn--black .bds-btn__icon-chevron {
color: #141414 !important;
stroke: #141414 !important;
}
html.dark a.bds-btn.bds-btn--force-color.bds-btn--tertiary.bds-btn--black:hover, html.dark a.bds-btn.bds-btn--force-color.bds-btn--tertiary.bds-btn--black:focus, html.dark a.bds-btn.bds-btn--force-color.bds-btn--tertiary.bds-btn--black:focus-visible, html.dark a.bds-btn.bds-btn--force-color.bds-btn--tertiary.bds-btn--black:active, html.dark a.bds-btn.bds-btn--force-color.bds-btn--tertiary.bds-btn--black:visited {
color: #141414 !important;
}
html.dark a.bds-btn.bds-btn--force-color.bds-btn--tertiary.bds-btn--black:hover .bds-btn__icon,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--tertiary.bds-btn--black:hover .bds-btn__icon-line,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--tertiary.bds-btn--black:hover .bds-btn__icon-chevron, html.dark a.bds-btn.bds-btn--force-color.bds-btn--tertiary.bds-btn--black:focus .bds-btn__icon,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--tertiary.bds-btn--black:focus .bds-btn__icon-line,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--tertiary.bds-btn--black:focus .bds-btn__icon-chevron, html.dark a.bds-btn.bds-btn--force-color.bds-btn--tertiary.bds-btn--black:focus-visible .bds-btn__icon,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--tertiary.bds-btn--black:focus-visible .bds-btn__icon-line,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--tertiary.bds-btn--black:focus-visible .bds-btn__icon-chevron, html.dark a.bds-btn.bds-btn--force-color.bds-btn--tertiary.bds-btn--black:active .bds-btn__icon,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--tertiary.bds-btn--black:active .bds-btn__icon-line,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--tertiary.bds-btn--black:active .bds-btn__icon-chevron, html.dark a.bds-btn.bds-btn--force-color.bds-btn--tertiary.bds-btn--black:visited .bds-btn__icon,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--tertiary.bds-btn--black:visited .bds-btn__icon-line,
html.dark a.bds-btn.bds-btn--force-color.bds-btn--tertiary.bds-btn--black:visited .bds-btn__icon-chevron {
color: #141414 !important;
stroke: #141414 !important;
}
.bds-btn--tertiary {
color: #0DAA3E;
background-color: transparent;
@@ -18580,7 +18836,9 @@ html.light .bds-card-offgrid--disabled .bds-card-offgrid__icon-container {
flex-direction: column;
gap: 24px;
width: 100%;
height: 620px;
background-color: #FFFFFF;
overflow: hidden;
cursor: pointer;
}
.bds-grid__col .bds-card-image {
@@ -18620,15 +18878,6 @@ html.light .bds-card-offgrid--disabled .bds-card-offgrid__icon-container {
transition: transform 150ms cubic-bezier(0.98, 0.12, 0.12, 0.98);
}
.bds-card-image--full-bleed {
height: auto;
width: 100%;
}
.bds-card-image--full-bleed .bds-card-image__image-container {
width: 100%;
height: auto;
aspect-ratio: 1/1;
}
.bds-card-image--full-bleed .bds-card-image__image {
width: 100%;
height: 100%;
@@ -18677,17 +18926,6 @@ html.light .bds-card-offgrid--disabled .bds-card-offgrid__icon-container {
.bds-card-image__content .bds-btn {
align-self: flex-start;
flex-shrink: 0;
margin-top: 24px;
}
@media (min-width: 576px) {
.bds-card-image__content .bds-btn {
margin-top: 24px;
}
}
@media (min-width: 992px) {
.bds-card-image__content .bds-btn {
margin-top: 32px;
}
}
.bds-card-image--hovered:not(.bds-card-image--disabled) .bds-card-image__image,
@@ -18706,7 +18944,8 @@ html.light .bds-card-offgrid--disabled .bds-card-offgrid__icon-container {
@media (max-width: 991.98px) {
.bds-card-image {
gap: 16px;
height: 560px;
gap: 20px;
}
.bds-card-image__image-container {
height: 280px;
@@ -18720,6 +18959,7 @@ html.light .bds-card-offgrid--disabled .bds-card-offgrid__icon-container {
}
@media (max-width: 575.98px) {
.bds-card-image {
height: 536px;
gap: 16px;
}
.bds-card-image__image-container {
@@ -18729,7 +18969,7 @@ html.light .bds-card-offgrid--disabled .bds-card-offgrid__icon-container {
padding: 0 8px;
}
.bds-card-image__text {
gap: 8px;
gap: 4px;
}
}
html.light .bds-card-image:focus {
@@ -19604,99 +19844,6 @@ html.light .bds-hero-split-media--accent .bds-hero-split-media__subtitle {
gap: 0;
}
.bds-cards-featured {
width: 100%;
padding-top: 48px;
padding-bottom: 48px;
}
@media (min-width: 576px) {
.bds-cards-featured {
padding-top: 64px;
padding-bottom: 64px;
}
}
@media (min-width: 992px) {
.bds-cards-featured {
padding-top: 80px;
padding-bottom: 80px;
}
}
.bds-cards-featured__header {
display: flex;
flex-direction: column;
gap: 8px;
}
@media (min-width: 576px) {
.bds-cards-featured__header {
gap: 8px;
}
}
@media (min-width: 992px) {
.bds-cards-featured__header {
gap: 16px;
}
}
.bds-cards-featured__heading {
margin: 0;
}
.bds-cards-featured__description {
margin: 0;
}
.bds-cards-featured__cards {
display: grid;
grid-template-columns: 1fr;
column-gap: 48px;
row-gap: 48px;
width: 100%;
margin-top: 24px;
}
@media (min-width: 576px) {
.bds-cards-featured__cards {
grid-template-columns: repeat(2, 1fr);
column-gap: 8px;
row-gap: 52px;
margin-top: 32px;
}
}
@media (min-width: 992px) {
.bds-cards-featured__cards {
grid-template-columns: repeat(3, 1fr);
column-gap: 8px;
row-gap: 56px;
margin-top: 40px;
}
}
.bds-cards-featured__card-wrapper {
display: flex;
min-width: 0;
width: 100%;
}
.bds-cards-featured__card-wrapper .bds-card-image {
width: 100%;
}
html.light .bds-cards-featured {
background-color: #FFFFFF;
}
html.light .bds-cards-featured__heading {
color: #141414;
}
html.light .bds-cards-featured__description {
color: #141414;
}
html.dark .bds-cards-featured__heading {
color: #FFFFFF;
}
html.dark .bds-cards-featured__description {
color: #FFFFFF;
}
.bds-callout-media-banner {
box-sizing: border-box;
min-height: 280px;
@@ -19938,6 +20085,364 @@ html.light .bds-callout-media-banner--image-text-black .bds-callout-media-banner
color: #141414 !important;
}
.bds-feature-two-column__button-group .bds-btn--tertiary {
padding-top: 0px !important;
padding-bottom: 0px !important;
}
.bds-feature-two-column__cta-row .bds-btn--tertiary {
padding-top: 16px !important;
}
.bds-feature-two-column {
width: 100%;
}
@media (min-width: 992px) {
.bds-feature-two-column {
max-width: 1280px;
margin: 0 auto;
}
}
.bds-feature-two-column__desktop-layout {
display: none;
}
@media (min-width: 992px) {
.bds-feature-two-column__desktop-layout {
display: flex;
width: 100%;
align-items: stretch;
}
}
.bds-feature-two-column__mobile-layout {
display: block;
}
@media (min-width: 992px) {
.bds-feature-two-column__mobile-layout {
display: none;
}
}
.bds-feature-two-column__container {
padding: 0 !important;
}
.bds-feature-two-column__row {
gap: 0 !important;
}
.bds-feature-two-column__content-col {
display: flex;
flex-direction: column;
padding: 64px 0;
}
@media (min-width: 576px) {
.bds-feature-two-column__content-col {
padding: 80px 0;
}
}
@media (min-width: 992px) {
.bds-feature-two-column__content-col {
width: 50%;
padding: 96px 0;
aspect-ratio: 1/1;
}
}
.bds-feature-two-column__content-grid {
display: grid;
width: 100%;
height: 100%;
grid-template-columns: repeat(4, 1fr);
gap: 8px;
padding: 0 16px;
}
@media (min-width: 576px) {
.bds-feature-two-column__content-grid {
grid-template-columns: repeat(8, 1fr);
padding: 0 24px;
}
}
@media (min-width: 992px) {
.bds-feature-two-column__content-grid {
grid-template-columns: repeat(6, 1fr);
padding: 0 32px;
}
}
.bds-feature-two-column__content-wrapper {
grid-column: 1/-1;
}
@media (min-width: 576px) {
.bds-feature-two-column__content-wrapper {
grid-column: 2/span 6;
}
}
@media (min-width: 992px) {
.bds-feature-two-column__content-wrapper {
grid-column: 2/span 4;
}
}
.bds-feature-two-column__media-col {
display: flex;
flex-direction: column;
}
@media (min-width: 992px) {
.bds-feature-two-column__media-col {
width: 50%;
aspect-ratio: 1/1;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}
}
.bds-feature-two-column__media-col--mobile {
display: flex;
flex-direction: column;
}
.bds-feature-two-column__content {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: space-between;
height: 100%;
gap: 24px;
}
@media (min-width: 576px) {
.bds-feature-two-column__content {
gap: 32px;
}
}
@media (min-width: 992px) {
.bds-feature-two-column__content {
gap: 0;
}
}
.bds-feature-two-column__content--multiple {
gap: 0;
justify-content: flex-start;
}
@media (min-width: 992px) {
.bds-feature-two-column__content--multiple {
gap: 0;
justify-content: space-between;
}
}
.bds-feature-two-column__content--multiple > .bds-btn--secondary {
align-self: flex-start;
}
.bds-feature-two-column__button-group {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 16px;
margin-top: 24px;
}
@media (min-width: 576px) {
.bds-feature-two-column__button-group {
gap: 16px;
margin-top: 32px;
}
}
@media (min-width: 992px) {
.bds-feature-two-column__button-group {
gap: 16px;
margin-top: 0;
}
}
.bds-feature-two-column__button-group > .bds-btn--tertiary {
padding-left: 0 !important;
margin-left: 0;
}
.bds-feature-two-column__button-group > .bds-btn--tertiary:hover:not(:disabled):not(.bds-btn--disabled), .bds-feature-two-column__button-group > .bds-btn--tertiary:focus:not(:disabled):not(.bds-btn--disabled), .bds-feature-two-column__button-group > .bds-btn--tertiary:focus-visible:not(:disabled):not(.bds-btn--disabled), .bds-feature-two-column__button-group > .bds-btn--tertiary:active:not(:disabled):not(.bds-btn--disabled) {
padding-left: 0 !important;
}
.bds-feature-two-column__text-group {
display: flex;
flex-direction: column;
gap: 8px;
}
@media (min-width: 576px) {
.bds-feature-two-column__text-group {
gap: 8px;
}
}
@media (min-width: 992px) {
.bds-feature-two-column__text-group {
gap: 16px;
}
}
.bds-feature-two-column__title {
font-family: "Tobias", "Noto Serif", monospace;
font-weight: 300;
font-size: 32px;
line-height: 40px;
letter-spacing: 0px;
margin-bottom: 16px;
}
@media (min-width: 576px) {
.bds-feature-two-column__title {
font-size: 36px;
line-height: 45px;
letter-spacing: -0.5px;
margin-bottom: 16px;
}
}
@media (min-width: 992px) {
.bds-feature-two-column__title {
font-size: 40px;
line-height: 46px;
letter-spacing: -1px;
margin-bottom: 16px;
}
}
.bds-feature-two-column__title {
color: #141414;
margin: 0;
}
.bds-feature-two-column__description {
font-family: "Booton", "Noto Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
font-weight: 300;
font-size: 16px;
line-height: 23.2px;
letter-spacing: 0px;
margin-bottom: 16px;
}
@media (min-width: 576px) {
.bds-feature-two-column__description {
font-size: 16px;
line-height: 23.2px;
letter-spacing: 0px;
margin-bottom: 16px;
}
}
@media (min-width: 992px) {
.bds-feature-two-column__description {
font-size: 18px;
line-height: 26.1px;
letter-spacing: -0.5px;
margin-bottom: 16px;
}
}
.bds-feature-two-column__description {
color: #141414;
margin: 0;
}
.bds-feature-two-column__cta {
display: flex;
flex-direction: column;
align-items: flex-start;
}
@media (min-width: 576px) {
.bds-feature-two-column__cta {
flex-direction: row;
flex-wrap: wrap;
}
}
.bds-feature-two-column__cta--single {
flex-direction: column;
}
@media (min-width: 576px) {
.bds-feature-two-column__cta--double {
flex-direction: row;
align-items: center;
}
}
.bds-feature-two-column__cta-row {
display: flex;
flex-direction: column;
align-items: flex-start;
}
@media (min-width: 576px) {
.bds-feature-two-column__cta-row {
flex-direction: row;
align-items: center;
}
}
@media (min-width: 992px) {
.bds-feature-two-column__cta-row {
flex-direction: row;
align-items: center;
}
}
.bds-feature-two-column__tertiary-group {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 0;
}
.bds-feature-two-column__tertiary-group .bds-btn--tertiary {
padding-left: 0 !important;
margin-left: 0;
}
.bds-feature-two-column__tertiary-group .bds-btn--tertiary:hover:not(:disabled):not(.bds-btn--disabled), .bds-feature-two-column__tertiary-group .bds-btn--tertiary:focus:not(:disabled):not(.bds-btn--disabled), .bds-feature-two-column__tertiary-group .bds-btn--tertiary:focus-visible:not(:disabled):not(.bds-btn--disabled), .bds-feature-two-column__tertiary-group .bds-btn--tertiary:active:not(:disabled):not(.bds-btn--disabled) {
padding-left: 0 !important;
}
.bds-feature-two-column__media {
width: 100%;
overflow: hidden;
aspect-ratio: 1/1;
}
@media (min-width: 576px) {
.bds-feature-two-column__media {
aspect-ratio: 16/9;
}
}
@media (min-width: 992px) {
.bds-feature-two-column__media {
aspect-ratio: 1/1;
}
}
.bds-feature-two-column__media-img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
}
.bds-feature-two-column--neutral {
background-color: #F0F3F7;
}
.bds-feature-two-column--lilac {
background-color: #D9CAFF;
}
.bds-feature-two-column--yellow {
background-color: #F3F1EB;
}
.bds-feature-two-column--green {
background-color: #21E46B;
}
html.dark .bds-feature-two-column__title {
color: #141414;
}
html.dark .bds-feature-two-column__description {
color: #141414;
}
html.dark .bds-feature-two-column--neutral {
background-color: #E6EAF0;
}
html.dark .bds-feature-two-column--lilac {
background-color: #D9CAFF;
}
html.dark .bds-feature-two-column--yellow {
background-color: #F3F1EB;
}
html.dark .bds-feature-two-column--green {
background-color: #21E46B;
}
.bds-feature-two-column--right .bds-feature-two-column__row {
flex-direction: column-reverse !important;
}
@media (min-width: 992px) {
.bds-feature-two-column--right .bds-feature-two-column__desktop-layout {
flex-direction: row-reverse;
}
}
@media (min-width: 992px) {
.bds-feature-two-column--right .bds-feature-two-column__content-wrapper {
grid-column: 2/span 4;
}
}
pre {
color: #FFFFFF;
background-color: #232325;

View File

@@ -99,8 +99,8 @@ $line-height-base: 1.5;
@import "../shared/components/CardIcon/CardIcon.scss";
@import "../shared/components/SmallTilesSection/_small-tiles-section.scss";
@import "../shared/patterns/HeaderHeroSplitMedia/HeaderHeroSplitMedia.scss";
@import "../shared/patterns/CardsFeatured/CardsFeatured.scss";
@import "../shared/patterns/CalloutMediaBanner/CalloutMediaBanner.scss";
@import "../shared/patterns/FeatureTwoColumn/FeatureTwoColumn.scss";
@import "_code-tabs.scss";
@import "_code-walkthrough.scss";
@import "_diagrams.scss";