mirror of
https://github.com/XRPLF/xrpl-dev-portal.git
synced 2025-12-06 17:27:57 +00:00
456
about/button-showcase-primary.page.tsx
Normal file
456
about/button-showcase-primary.page.tsx
Normal file
@@ -0,0 +1,456 @@
|
||||
import * as React from 'react';
|
||||
import { Button } from 'shared/components/Button';
|
||||
import { PageGrid, PageGridCol, PageGridRow } from 'shared/components/PageGrid/page-grid';
|
||||
|
||||
export const frontmatter = {
|
||||
seo: {
|
||||
title: 'BDS Button Component Showcase',
|
||||
description: 'Interactive showcase of the Brand Design System Button component with all states and variants.',
|
||||
},
|
||||
};
|
||||
|
||||
export default function ButtonShowcase() {
|
||||
const [clickCount, setClickCount] = React.useState(0);
|
||||
|
||||
const handleClick = () => {
|
||||
setClickCount((prev) => prev + 1);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="landing">
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse col-lg-8 mx-auto">
|
||||
<h1 className="mb-0">BDS Button Component</h1>
|
||||
<h6 className="eyebrow mb-3">Brand Design System</h6>
|
||||
</div>
|
||||
<p className="col-lg-8 mx-auto mt-10">
|
||||
A scalable button component following the XRPL Brand Design System. This showcase demonstrates all states,
|
||||
responsive behavior, and accessibility features of the Primary button variant.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{/* Basic Usage */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Basic Usage</h2>
|
||||
<h6 className="eyebrow mb-3">Primary Variant</h6>
|
||||
</div>
|
||||
<div className="d-flex flex-wrap align-items-center">
|
||||
<Button variant="primary" onClick={handleClick} className="me-4 mb-4">
|
||||
Get Started
|
||||
</Button>
|
||||
<Button variant="primary" onClick={handleClick} className="me-4 mb-4">
|
||||
Submit Form
|
||||
</Button>
|
||||
<Button variant="primary" onClick={handleClick} className="mb-4">
|
||||
Continue
|
||||
</Button>
|
||||
</div>
|
||||
{clickCount > 0 && (
|
||||
<p className="mt-4 text-muted">Button clicked {clickCount} time{clickCount !== 1 ? 's' : ''}</p>
|
||||
)}
|
||||
</section>
|
||||
|
||||
{/* States */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Button States</h2>
|
||||
<h6 className="eyebrow mb-3">Interactive States</h6>
|
||||
</div>
|
||||
<PageGrid>
|
||||
<PageGridRow>
|
||||
<PageGridCol span={{ base: 4, lg: 6 }}>
|
||||
<div className="p-6-sm p-10-until-sm br-8" style={{ backgroundColor: '#f5f5f7' }}>
|
||||
<h5 className="mb-4">Enabled State</h5>
|
||||
<p className="mb-4 text-muted">Default state when button is ready for interaction.</p>
|
||||
<Button variant="primary" onClick={handleClick}>
|
||||
Enabled Button
|
||||
</Button>
|
||||
</div>
|
||||
</PageGridCol>
|
||||
<PageGridCol span={{ base: 4, lg: 6 }}>
|
||||
<div className="p-6-sm p-10-until-sm br-8" style={{ backgroundColor: '#f5f5f7' }}>
|
||||
<h5 className="mb-4">Disabled State</h5>
|
||||
<p className="mb-4 text-muted">Button cannot be interacted with.</p>
|
||||
<Button variant="primary" disabled>
|
||||
Disabled Button
|
||||
</Button>
|
||||
</div>
|
||||
</PageGridCol>
|
||||
</PageGridRow>
|
||||
</PageGrid>
|
||||
<div className="mt-10">
|
||||
<h5 className="mb-4">Hover & Focus States</h5>
|
||||
<p className="mb-4 text-muted">
|
||||
Hover over the buttons below or use Tab to focus them. Notice the background color change and icon swap.
|
||||
</p>
|
||||
<div className="d-flex flex-wrap">
|
||||
<Button variant="primary" onClick={handleClick} className="me-4 mb-4">
|
||||
Hover Me
|
||||
</Button>
|
||||
<Button variant="primary" onClick={handleClick} className="mb-4">
|
||||
Focus Me (Tab)
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Black Color Variant */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Black Color Variant</h2>
|
||||
<h6 className="eyebrow mb-3">Color Theme</h6>
|
||||
</div>
|
||||
<p className="mb-4 text-muted">
|
||||
Primary buttons can use a black color theme for dark backgrounds or alternative styling needs.
|
||||
</p>
|
||||
<div className="d-flex flex-wrap align-items-center">
|
||||
<Button variant="primary" color="black" onClick={handleClick} className="me-4 mb-4">
|
||||
Black Primary
|
||||
</Button>
|
||||
<Button variant="primary" color="black" onClick={handleClick} className="me-4 mb-4">
|
||||
Dark Button
|
||||
</Button>
|
||||
<Button variant="primary" color="black" onClick={handleClick} className="mb-4">
|
||||
Get Started
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Black Variant States */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Black Variant States</h2>
|
||||
<h6 className="eyebrow mb-3">Interactive States</h6>
|
||||
</div>
|
||||
<PageGrid>
|
||||
<PageGridRow>
|
||||
<PageGridCol span={{ base: 4, lg: 6 }}>
|
||||
<div className="p-6-sm p-10-until-sm br-8" style={{ backgroundColor: '#f5f5f7' }}>
|
||||
<h5 className="mb-4">Enabled State</h5>
|
||||
<p className="mb-4 text-muted">Black background with white text.</p>
|
||||
<Button variant="primary" color="black" onClick={handleClick}>
|
||||
Enabled Button
|
||||
</Button>
|
||||
</div>
|
||||
</PageGridCol>
|
||||
<PageGridCol span={{ base: 4, lg: 6 }}>
|
||||
<div className="p-6-sm p-10-until-sm br-8" style={{ backgroundColor: '#f5f5f7' }}>
|
||||
<h5 className="mb-4">Disabled State</h5>
|
||||
<p className="mb-4 text-muted">Same disabled styling as green variant.</p>
|
||||
<Button variant="primary" color="black" disabled>
|
||||
Disabled Button
|
||||
</Button>
|
||||
</div>
|
||||
</PageGridCol>
|
||||
</PageGridRow>
|
||||
</PageGrid>
|
||||
<div className="mt-10">
|
||||
<h5 className="mb-4">Hover & Focus States</h5>
|
||||
<p className="mb-4 text-muted">
|
||||
Hover over the buttons or use Tab to focus them. Notice the background darkens slightly on hover.
|
||||
</p>
|
||||
<div className="d-flex flex-wrap">
|
||||
<Button variant="primary" color="black" onClick={handleClick} className="me-4 mb-4">
|
||||
Hover Me
|
||||
</Button>
|
||||
<Button variant="primary" color="black" onClick={handleClick} className="mb-4">
|
||||
Focus Me (Tab)
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Green vs Black Comparison */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Green vs Black Comparison</h2>
|
||||
<h6 className="eyebrow mb-3">Color Themes</h6>
|
||||
</div>
|
||||
<p className="mb-4 text-muted">Compare the green (default) and black color themes side by side.</p>
|
||||
<div className="d-flex flex-wrap align-items-center">
|
||||
<Button variant="primary" color="green" onClick={handleClick} className="me-4 mb-4">
|
||||
Green Primary
|
||||
</Button>
|
||||
<Button variant="primary" color="black" onClick={handleClick} className="mb-4">
|
||||
Black Primary
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Without Icon */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Without Icon</h2>
|
||||
<h6 className="eyebrow mb-3">Icon Control</h6>
|
||||
</div>
|
||||
<p className="mb-4 text-muted">Buttons can be rendered without the arrow icon when needed.</p>
|
||||
<div className="d-flex flex-wrap">
|
||||
<Button variant="primary" showIcon={false} onClick={handleClick} className="me-4 mb-4">
|
||||
No Icon Button
|
||||
</Button>
|
||||
<Button variant="primary" showIcon={true} onClick={handleClick} className="mb-4">
|
||||
With Icon Button
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Button Types */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Button Types</h2>
|
||||
<h6 className="eyebrow mb-3">Form Integration</h6>
|
||||
</div>
|
||||
<p className="mb-4 text-muted">Different button types for form submission and actions.</p>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
alert('Form submitted!');
|
||||
}}
|
||||
className="d-flex flex-wrap"
|
||||
>
|
||||
<Button variant="primary" type="submit" className="me-4 mb-4">
|
||||
Submit Button
|
||||
</Button>
|
||||
<Button variant="primary" type="reset" className="me-4 mb-4">
|
||||
Reset Button
|
||||
</Button>
|
||||
<Button variant="primary" type="button" onClick={handleClick} className="mb-4">
|
||||
Regular Button
|
||||
</Button>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
{/* Responsive Behavior */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Responsive Behavior</h2>
|
||||
<h6 className="eyebrow mb-3">Breakpoint Adjustments</h6>
|
||||
</div>
|
||||
<p className="mb-4 text-muted">
|
||||
Button padding adjusts automatically across breakpoints. Resize your browser window to see the changes:
|
||||
</p>
|
||||
<ul className="mb-4">
|
||||
<li>
|
||||
<strong>Desktop (≥1024px):</strong> Padding: 8px 19px 8px 20px, Gap: 16px
|
||||
</li>
|
||||
<li>
|
||||
<strong>Tablet/Mobile (≤1023px):</strong> Padding: 8px 15px 8px 16px, Gap: 16px
|
||||
</li>
|
||||
<li>
|
||||
<strong>Hover/Focus:</strong> Gap increases (22px desktop, 21px mobile) with adjusted padding to maintain
|
||||
button width
|
||||
</li>
|
||||
</ul>
|
||||
<div className="d-flex flex-wrap">
|
||||
<Button variant="primary" onClick={handleClick} className="me-4 mb-4">
|
||||
Responsive Button
|
||||
</Button>
|
||||
<Button variant="primary" onClick={handleClick} className="mb-4">
|
||||
Long Button Label Example
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Accessibility */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Accessibility Features</h2>
|
||||
<h6 className="eyebrow mb-3">WCAG Compliance</h6>
|
||||
</div>
|
||||
<PageGrid>
|
||||
<PageGridRow>
|
||||
<PageGridCol span={{ base: 4, lg: 6 }}>
|
||||
<h5 className="mb-4">Keyboard Navigation</h5>
|
||||
<ul>
|
||||
<li>Tab to focus buttons</li>
|
||||
<li>Enter or Space to activate</li>
|
||||
<li>Focus indicator: 2px black border</li>
|
||||
<li>Disabled buttons are not focusable</li>
|
||||
</ul>
|
||||
</PageGridCol>
|
||||
<PageGridCol span={{ base: 4, lg: 6 }}>
|
||||
<h5 className="mb-4">Screen Reader Support</h5>
|
||||
<ul>
|
||||
<li>Button labels are announced</li>
|
||||
<li>Disabled state communicated via aria-disabled</li>
|
||||
<li>Icons are hidden from screen readers (aria-hidden)</li>
|
||||
<li>Semantic button element used</li>
|
||||
</ul>
|
||||
</PageGridCol>
|
||||
</PageGridRow>
|
||||
</PageGrid>
|
||||
<div className="mt-10">
|
||||
<h5 className="mb-4">Color Contrast</h5>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Enabled:</strong> Black text (#141414) on Green 300 (#21E46B) = 9.06:1 (AAA)
|
||||
</li>
|
||||
<li>
|
||||
<strong>Hover:</strong> Black text (#141414) on Green 200 (#70EE97) = 10.23:1 (AAA)
|
||||
</li>
|
||||
<li>
|
||||
<strong>Disabled:</strong> Gray 500 (#838386) on Gray 200 (#E0E0E1) = 2.12:1 (acceptable for disabled
|
||||
state)
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Code Examples */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Code Examples</h2>
|
||||
<h6 className="eyebrow mb-3">Implementation</h6>
|
||||
</div>
|
||||
<div className="p-6-sm p-10-until-sm br-8" style={{ backgroundColor: '#1e1e1e', color: '#d4d4d4' }}>
|
||||
<pre style={{ margin: 0, overflow: 'auto' }}>
|
||||
<code>{`import { Button } from 'shared/components/Button';
|
||||
|
||||
// Basic usage (green theme - default)
|
||||
<Button variant="primary" onClick={handleClick}>
|
||||
Get Started
|
||||
</Button>
|
||||
|
||||
// Black color theme
|
||||
<Button variant="primary" color="black" onClick={handleClick}>
|
||||
Dark Button
|
||||
</Button>
|
||||
|
||||
// Disabled state
|
||||
<Button variant="primary" disabled>
|
||||
Submit
|
||||
</Button>
|
||||
|
||||
// Without icon
|
||||
<Button variant="primary" showIcon={false}>
|
||||
Continue
|
||||
</Button>
|
||||
|
||||
// Form integration
|
||||
<Button variant="primary" type="submit">
|
||||
Submit Form
|
||||
</Button>`}</code>
|
||||
</pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Design Specifications */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Design Specifications</h2>
|
||||
<h6 className="eyebrow mb-3">Visual Details</h6>
|
||||
</div>
|
||||
<PageGrid>
|
||||
<PageGridRow>
|
||||
<PageGridCol span={{ base: 4, lg: 6 }}>
|
||||
<h5 className="mb-4">Typography</h5>
|
||||
<ul>
|
||||
<li>Font: Booton, sans-serif</li>
|
||||
<li>Size: 16px</li>
|
||||
<li>Weight: 400</li>
|
||||
<li>Line Height: 23.2px</li>
|
||||
<li>Letter Spacing: 0px</li>
|
||||
</ul>
|
||||
</PageGridCol>
|
||||
<PageGridCol span={{ base: 4, lg: 6 }}>
|
||||
<h5 className="mb-4">Spacing & Layout</h5>
|
||||
<ul>
|
||||
<li>Border Radius: 100px (fully rounded)</li>
|
||||
<li>Icon Size: 15px × 14px</li>
|
||||
<li>Icon Gap: 16px (default), 22px (hover/focus desktop), 21px (hover/focus mobile)</li>
|
||||
<li>Min Height: 40px (touch target)</li>
|
||||
</ul>
|
||||
</PageGridCol>
|
||||
</PageGridRow>
|
||||
</PageGrid>
|
||||
<div className="mt-10">
|
||||
<h5 className="mb-4">State Colors - Green Theme</h5>
|
||||
<div style={{ width: '100%', backgroundColor: '#FFFFFF' }}>
|
||||
{/* Header */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '2px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>State</div>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Text Color</div>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Background Color</div>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Border</div>
|
||||
</div>
|
||||
{/* Rows */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Enabled</div>
|
||||
<div style={{ padding: '12px' }}>#141414 (Neutral Black)</div>
|
||||
<div style={{ padding: '12px' }}>#21E46B (Green 300)</div>
|
||||
<div style={{ padding: '12px' }}>None</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Hover</div>
|
||||
<div style={{ padding: '12px' }}>#141414 (Neutral Black)</div>
|
||||
<div style={{ padding: '12px' }}>#70EE97 (Green 200)</div>
|
||||
<div style={{ padding: '12px' }}>None</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Focus</div>
|
||||
<div style={{ padding: '12px' }}>#141414 (Neutral Black)</div>
|
||||
<div style={{ padding: '12px' }}>#70EE97 (Green 200)</div>
|
||||
<div style={{ padding: '12px' }}>2px solid #141414</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Active</div>
|
||||
<div style={{ padding: '12px' }}>#141414 (Neutral Black)</div>
|
||||
<div style={{ padding: '12px' }}>#21E46B (Green 300)</div>
|
||||
<div style={{ padding: '12px' }}>None</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr' }}>
|
||||
<div style={{ padding: '12px' }}>Disabled</div>
|
||||
<div style={{ padding: '12px' }}>#838386 (Gray 500)</div>
|
||||
<div style={{ padding: '12px' }}>#E0E0E1 (Gray 200)</div>
|
||||
<div style={{ padding: '12px' }}>None</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-10">
|
||||
<h5 className="mb-4">State Colors - Black Theme</h5>
|
||||
<div style={{ width: '100%', backgroundColor: '#FFFFFF' }}>
|
||||
{/* Header */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '2px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>State</div>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Text Color</div>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Background Color</div>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Border</div>
|
||||
</div>
|
||||
{/* Rows */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Enabled</div>
|
||||
<div style={{ padding: '12px' }}>#FFFFFF (White)</div>
|
||||
<div style={{ padding: '12px' }}>#141414 (Neutral Black)</div>
|
||||
<div style={{ padding: '12px' }}>None</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Hover</div>
|
||||
<div style={{ padding: '12px' }}>#FFFFFF (White)</div>
|
||||
<div style={{ padding: '12px' }}>rgba(20, 20, 20, 0.8) (80% Black)</div>
|
||||
<div style={{ padding: '12px' }}>None</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Focus</div>
|
||||
<div style={{ padding: '12px' }}>#FFFFFF (White)</div>
|
||||
<div style={{ padding: '12px' }}>rgba(20, 20, 20, 0.8) (80% Black)</div>
|
||||
<div style={{ padding: '12px' }}>2px solid #141414</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Active</div>
|
||||
<div style={{ padding: '12px' }}>#FFFFFF (White)</div>
|
||||
<div style={{ padding: '12px' }}>#141414 (Neutral Black)</div>
|
||||
<div style={{ padding: '12px' }}>None</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr' }}>
|
||||
<div style={{ padding: '12px' }}>Disabled</div>
|
||||
<div style={{ padding: '12px' }}>#838386 (Gray 500)</div>
|
||||
<div style={{ padding: '12px' }}>#E0E0E1 (Gray 200)</div>
|
||||
<div style={{ padding: '12px' }}>None</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
528
about/button-showcase-secondary.page.tsx
Normal file
528
about/button-showcase-secondary.page.tsx
Normal file
@@ -0,0 +1,528 @@
|
||||
import * as React from 'react';
|
||||
import { Button } from 'shared/components/Button';
|
||||
import { PageGrid, PageGridCol, PageGridRow } from 'shared/components/PageGrid/page-grid';
|
||||
|
||||
export const frontmatter = {
|
||||
seo: {
|
||||
title: 'BDS Secondary Button Component Showcase',
|
||||
description: 'Interactive showcase of the Brand Design System Secondary Button component with all states and variants.',
|
||||
},
|
||||
};
|
||||
|
||||
export default function ButtonShowcaseSecondary() {
|
||||
const [clickCount, setClickCount] = React.useState(0);
|
||||
|
||||
const handleClick = () => {
|
||||
setClickCount((prev) => prev + 1);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="landing">
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse col-lg-8 mx-auto">
|
||||
<h1 className="mb-0">BDS Secondary Button</h1>
|
||||
<h6 className="eyebrow mb-3">Brand Design System</h6>
|
||||
</div>
|
||||
<p className="col-lg-8 mx-auto mt-10">
|
||||
The Secondary button is an outline-style button used for secondary actions. It features a transparent
|
||||
background with a green stroke/border, providing visual hierarchy below the Primary button while maintaining
|
||||
brand consistency.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{/* Basic Usage */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Basic Usage</h2>
|
||||
<h6 className="eyebrow mb-3">Secondary Variant</h6>
|
||||
</div>
|
||||
<div className="d-flex flex-wrap align-items-center">
|
||||
<Button variant="secondary" onClick={handleClick} className="me-4 mb-4">
|
||||
Learn More
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={handleClick} className="me-4 mb-4">
|
||||
View Details
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={handleClick} className="mb-4">
|
||||
Explore
|
||||
</Button>
|
||||
</div>
|
||||
{clickCount > 0 && (
|
||||
<p className="mt-4 text-muted">
|
||||
Button clicked {clickCount} time{clickCount !== 1 ? 's' : ''}
|
||||
</p>
|
||||
)}
|
||||
</section>
|
||||
|
||||
{/* Primary vs Secondary Comparison */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Primary vs Secondary</h2>
|
||||
<h6 className="eyebrow mb-3">Visual Hierarchy</h6>
|
||||
</div>
|
||||
<p className="mb-4 text-muted">
|
||||
Use Primary for main actions and Secondary for supporting actions to create clear visual hierarchy.
|
||||
</p>
|
||||
<div className="d-flex flex-wrap align-items-center">
|
||||
<Button variant="primary" onClick={handleClick} className="me-4 mb-4">
|
||||
Get Started
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={handleClick} className="mb-4">
|
||||
Learn More
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* States */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Button States</h2>
|
||||
<h6 className="eyebrow mb-3">Interactive States</h6>
|
||||
</div>
|
||||
<PageGrid>
|
||||
<PageGridRow>
|
||||
<PageGridCol span={{ base: 4, lg: 6 }}>
|
||||
<div className="p-6-sm p-10-until-sm br-8" style={{ backgroundColor: '#f5f5f7' }}>
|
||||
<h5 className="mb-4">Enabled State</h5>
|
||||
<p className="mb-4 text-muted">Default outline style with green border and text.</p>
|
||||
<Button variant="secondary" onClick={handleClick}>
|
||||
Enabled Button
|
||||
</Button>
|
||||
</div>
|
||||
</PageGridCol>
|
||||
<PageGridCol span={{ base: 4, lg: 6 }}>
|
||||
<div className="p-6-sm p-10-until-sm br-8" style={{ backgroundColor: '#f5f5f7' }}>
|
||||
<h5 className="mb-4">Disabled State</h5>
|
||||
<p className="mb-4 text-muted">Gray border and text indicate non-interactive state.</p>
|
||||
<Button variant="secondary" disabled>
|
||||
Disabled Button
|
||||
</Button>
|
||||
</div>
|
||||
</PageGridCol>
|
||||
</PageGridRow>
|
||||
</PageGrid>
|
||||
<div className="mt-10">
|
||||
<h5 className="mb-4">Hover & Focus States</h5>
|
||||
<p className="mb-4 text-muted">
|
||||
Hover over the buttons or use Tab to focus them. Notice the light green background fill and darker green
|
||||
border on hover/focus.
|
||||
</p>
|
||||
<div className="d-flex flex-wrap">
|
||||
<Button variant="secondary" onClick={handleClick} className="me-4 mb-4">
|
||||
Hover Me
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={handleClick} className="mb-4">
|
||||
Focus Me (Tab)
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Black Color Variant */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Black Color Variant</h2>
|
||||
<h6 className="eyebrow mb-3">Color Theme</h6>
|
||||
</div>
|
||||
<p className="mb-4 text-muted">
|
||||
Secondary buttons can use a black color theme with black text and border instead of green.
|
||||
</p>
|
||||
<div className="d-flex flex-wrap align-items-center">
|
||||
<Button variant="secondary" color="black" onClick={handleClick} className="me-4 mb-4">
|
||||
Black Secondary
|
||||
</Button>
|
||||
<Button variant="secondary" color="black" onClick={handleClick} className="me-4 mb-4">
|
||||
Learn More
|
||||
</Button>
|
||||
<Button variant="secondary" color="black" onClick={handleClick} className="mb-4">
|
||||
View Details
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Black Variant States */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Black Variant States</h2>
|
||||
<h6 className="eyebrow mb-3">Interactive States</h6>
|
||||
</div>
|
||||
<PageGrid>
|
||||
<PageGridRow>
|
||||
<PageGridCol span={{ base: 4, lg: 6 }}>
|
||||
<div className="p-6-sm p-10-until-sm br-8" style={{ backgroundColor: '#f5f5f7' }}>
|
||||
<h5 className="mb-4">Enabled State</h5>
|
||||
<p className="mb-4 text-muted">Black border and text with transparent background.</p>
|
||||
<Button variant="secondary" color="black" onClick={handleClick}>
|
||||
Enabled Button
|
||||
</Button>
|
||||
</div>
|
||||
</PageGridCol>
|
||||
<PageGridCol span={{ base: 4, lg: 6 }}>
|
||||
<div className="p-6-sm p-10-until-sm br-8" style={{ backgroundColor: '#f5f5f7' }}>
|
||||
<h5 className="mb-4">Disabled State</h5>
|
||||
<p className="mb-4 text-muted">Same disabled styling as green variant.</p>
|
||||
<Button variant="secondary" color="black" disabled>
|
||||
Disabled Button
|
||||
</Button>
|
||||
</div>
|
||||
</PageGridCol>
|
||||
</PageGridRow>
|
||||
</PageGrid>
|
||||
<div className="mt-10">
|
||||
<h5 className="mb-4">Hover & Focus States</h5>
|
||||
<p className="mb-4 text-muted">
|
||||
Hover over the buttons or use Tab to focus them. Notice the subtle black background fill on hover.
|
||||
</p>
|
||||
<div className="d-flex flex-wrap">
|
||||
<Button variant="secondary" color="black" onClick={handleClick} className="me-4 mb-4">
|
||||
Hover Me
|
||||
</Button>
|
||||
<Button variant="secondary" color="black" onClick={handleClick} className="mb-4">
|
||||
Focus Me (Tab)
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Green vs Black Comparison */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Green vs Black Comparison</h2>
|
||||
<h6 className="eyebrow mb-3">Color Themes</h6>
|
||||
</div>
|
||||
<p className="mb-4 text-muted">Compare the green (default) and black color themes side by side.</p>
|
||||
<div className="d-flex flex-wrap align-items-center">
|
||||
<Button variant="secondary" color="green" onClick={handleClick} className="me-4 mb-4">
|
||||
Green Secondary
|
||||
</Button>
|
||||
<Button variant="secondary" color="black" onClick={handleClick} className="mb-4">
|
||||
Black Secondary
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Without Icon */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Without Icon</h2>
|
||||
<h6 className="eyebrow mb-3">Icon Control</h6>
|
||||
</div>
|
||||
<p className="mb-4 text-muted">Secondary buttons can also be rendered without the arrow icon.</p>
|
||||
<div className="d-flex flex-wrap">
|
||||
<Button variant="secondary" showIcon={false} onClick={handleClick} className="me-4 mb-4">
|
||||
No Icon Button
|
||||
</Button>
|
||||
<Button variant="secondary" showIcon={true} onClick={handleClick} className="mb-4">
|
||||
With Icon Button
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Button Types */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Button Types</h2>
|
||||
<h6 className="eyebrow mb-3">Form Integration</h6>
|
||||
</div>
|
||||
<p className="mb-4 text-muted">Secondary buttons can be used for form actions like cancel or reset.</p>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
alert('Form submitted!');
|
||||
}}
|
||||
className="d-flex flex-wrap"
|
||||
>
|
||||
<Button variant="primary" type="submit" className="me-4 mb-4">
|
||||
Submit
|
||||
</Button>
|
||||
<Button variant="secondary" type="reset" className="me-4 mb-4">
|
||||
Reset
|
||||
</Button>
|
||||
<Button variant="secondary" type="button" onClick={() => alert('Cancelled!')} className="mb-4">
|
||||
Cancel
|
||||
</Button>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
{/* Responsive Behavior */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Responsive Behavior</h2>
|
||||
<h6 className="eyebrow mb-3">Breakpoint Adjustments</h6>
|
||||
</div>
|
||||
<p className="mb-4 text-muted">
|
||||
Button padding adjusts automatically across breakpoints. Resize your browser window to see the changes:
|
||||
</p>
|
||||
<ul className="mb-4">
|
||||
<li>
|
||||
<strong>Desktop (≥1024px):</strong> Padding: 6px 17px 6px 18px (compensates for 2px border)
|
||||
</li>
|
||||
<li>
|
||||
<strong>Tablet/Mobile (≤1023px):</strong> Padding: 6px 13px 6px 14px
|
||||
</li>
|
||||
<li>
|
||||
<strong>Hover/Focus:</strong> Gap increases (22px desktop, 21px mobile) with adjusted padding
|
||||
</li>
|
||||
</ul>
|
||||
<div className="d-flex flex-wrap">
|
||||
<Button variant="secondary" onClick={handleClick} className="me-4 mb-4">
|
||||
Responsive Button
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={handleClick} className="mb-4">
|
||||
Long Button Label Example
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Accessibility */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Accessibility Features</h2>
|
||||
<h6 className="eyebrow mb-3">WCAG Compliance</h6>
|
||||
</div>
|
||||
<PageGrid>
|
||||
<PageGridRow>
|
||||
<PageGridCol span={{ base: 4, lg: 6 }}>
|
||||
<h5 className="mb-4">Keyboard Navigation</h5>
|
||||
<ul>
|
||||
<li>Tab to focus buttons</li>
|
||||
<li>Enter or Space to activate</li>
|
||||
<li>Focus indicator: 2px black outline (additional to green border)</li>
|
||||
<li>Disabled buttons are not focusable</li>
|
||||
</ul>
|
||||
</PageGridCol>
|
||||
<PageGridCol span={{ base: 4, lg: 6 }}>
|
||||
<h5 className="mb-4">Screen Reader Support</h5>
|
||||
<ul>
|
||||
<li>Button labels are announced</li>
|
||||
<li>Disabled state communicated via aria-disabled</li>
|
||||
<li>Icons are hidden from screen readers (aria-hidden)</li>
|
||||
<li>Semantic button element used</li>
|
||||
</ul>
|
||||
</PageGridCol>
|
||||
</PageGridRow>
|
||||
</PageGrid>
|
||||
<div className="mt-10">
|
||||
<h5 className="mb-4">Color Contrast</h5>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Enabled:</strong> Green 400 (#0DAA3E) on White = 4.52:1 (AA for large text)
|
||||
</li>
|
||||
<li>
|
||||
<strong>Hover:</strong> Green 500 (#078139) on Green 100 (#EAFCF1) = 4.87:1 (AA)
|
||||
</li>
|
||||
<li>
|
||||
<strong>Disabled:</strong> Gray 400 (#A2A2A4) on White = reduced contrast (acceptable for disabled state)
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Code Examples */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Code Examples</h2>
|
||||
<h6 className="eyebrow mb-3">Implementation</h6>
|
||||
</div>
|
||||
<div className="p-6-sm p-10-until-sm br-8" style={{ backgroundColor: '#1e1e1e', color: '#d4d4d4' }}>
|
||||
<pre style={{ margin: 0, overflow: 'auto' }}>
|
||||
<code>{`import { Button } from 'shared/components/Button';
|
||||
|
||||
// Basic secondary button (green theme - default)
|
||||
<Button variant="secondary" onClick={handleClick}>
|
||||
Learn More
|
||||
</Button>
|
||||
|
||||
// Black color theme
|
||||
<Button variant="secondary" color="black" onClick={handleClick}>
|
||||
Learn More
|
||||
</Button>
|
||||
|
||||
// Disabled state
|
||||
<Button variant="secondary" disabled>
|
||||
Unavailable
|
||||
</Button>
|
||||
|
||||
// Without icon
|
||||
<Button variant="secondary" showIcon={false}>
|
||||
Cancel
|
||||
</Button>
|
||||
|
||||
// Primary + Secondary pairing
|
||||
<Button variant="primary" type="submit">
|
||||
Submit
|
||||
</Button>
|
||||
<Button variant="secondary" type="button">
|
||||
Cancel
|
||||
</Button>`}</code>
|
||||
</pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Design Specifications */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Design Specifications</h2>
|
||||
<h6 className="eyebrow mb-3">Visual Details</h6>
|
||||
</div>
|
||||
<PageGrid>
|
||||
<PageGridRow>
|
||||
<PageGridCol span={{ base: 4, lg: 6 }}>
|
||||
<h5 className="mb-4">Typography</h5>
|
||||
<ul>
|
||||
<li>Font: Booton, sans-serif</li>
|
||||
<li>Size: 16px</li>
|
||||
<li>Weight: 400</li>
|
||||
<li>Line Height: 23.2px</li>
|
||||
<li>Letter Spacing: 0px</li>
|
||||
</ul>
|
||||
</PageGridCol>
|
||||
<PageGridCol span={{ base: 4, lg: 6 }}>
|
||||
<h5 className="mb-4">Spacing & Layout</h5>
|
||||
<ul>
|
||||
<li>Border Radius: 100px (fully rounded)</li>
|
||||
<li>Border Width: 2px solid</li>
|
||||
<li>Icon Size: 15px × 14px</li>
|
||||
<li>Icon Gap: 16px (default), 22px (hover/focus desktop), 21px (hover/focus mobile)</li>
|
||||
<li>Max Height: 40px</li>
|
||||
</ul>
|
||||
</PageGridCol>
|
||||
</PageGridRow>
|
||||
</PageGrid>
|
||||
<div className="mt-10">
|
||||
<h5 className="mb-4">State Colors - Green Theme</h5>
|
||||
<div style={{ width: '100%', backgroundColor: '#FFFFFF' }}>
|
||||
{/* Header */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '2px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>State</div>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Text Color</div>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Background</div>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Border</div>
|
||||
</div>
|
||||
{/* Rows */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Enabled</div>
|
||||
<div style={{ padding: '12px' }}>#0DAA3E (Green 400)</div>
|
||||
<div style={{ padding: '12px' }}>Transparent</div>
|
||||
<div style={{ padding: '12px' }}>2px #0DAA3E (Green 400)</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Hover</div>
|
||||
<div style={{ padding: '12px' }}>#078139 (Green 500)</div>
|
||||
<div style={{ padding: '12px' }}>#EAFCF1 (Green 100)</div>
|
||||
<div style={{ padding: '12px' }}>2px #078139 (Green 500)</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Focus</div>
|
||||
<div style={{ padding: '12px' }}>#078139 (Green 500)</div>
|
||||
<div style={{ padding: '12px' }}>#EAFCF1 (Green 100)</div>
|
||||
<div style={{ padding: '12px' }}>2px #078139 + 2px #141414 outline</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Active</div>
|
||||
<div style={{ padding: '12px' }}>#0DAA3E (Green 400)</div>
|
||||
<div style={{ padding: '12px' }}>Transparent</div>
|
||||
<div style={{ padding: '12px' }}>2px #0DAA3E (Green 400)</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr' }}>
|
||||
<div style={{ padding: '12px' }}>Disabled</div>
|
||||
<div style={{ padding: '12px' }}>#A2A2A4 (Gray 400)</div>
|
||||
<div style={{ padding: '12px' }}>Transparent</div>
|
||||
<div style={{ padding: '12px' }}>2px #A2A2A4 (Gray 400)</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-10">
|
||||
<h5 className="mb-4">State Colors - Black Theme</h5>
|
||||
<div style={{ width: '100%', backgroundColor: '#FFFFFF' }}>
|
||||
{/* Header */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '2px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>State</div>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Text Color</div>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Background</div>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Border</div>
|
||||
</div>
|
||||
{/* Rows */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Enabled</div>
|
||||
<div style={{ padding: '12px' }}>#141414 (Neutral Black)</div>
|
||||
<div style={{ padding: '12px' }}>Transparent</div>
|
||||
<div style={{ padding: '12px' }}>2px #141414 (Neutral Black)</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Hover</div>
|
||||
<div style={{ padding: '12px' }}>#141414 (Neutral Black)</div>
|
||||
<div style={{ padding: '12px' }}>rgba(20, 20, 20, 0.15) (15% Black)</div>
|
||||
<div style={{ padding: '12px' }}>2px #141414 (Neutral Black)</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Focus</div>
|
||||
<div style={{ padding: '12px' }}>#141414 (Neutral Black)</div>
|
||||
<div style={{ padding: '12px' }}>rgba(20, 20, 20, 0.15) (15% Black)</div>
|
||||
<div style={{ padding: '12px' }}>2px #141414 + 2px #141414 outline</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Active</div>
|
||||
<div style={{ padding: '12px' }}>#141414 (Neutral Black)</div>
|
||||
<div style={{ padding: '12px' }}>Transparent</div>
|
||||
<div style={{ padding: '12px' }}>2px #141414 (Neutral Black)</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr' }}>
|
||||
<div style={{ padding: '12px' }}>Disabled</div>
|
||||
<div style={{ padding: '12px' }}>#A2A2A4 (Gray 400)</div>
|
||||
<div style={{ padding: '12px' }}>Transparent</div>
|
||||
<div style={{ padding: '12px' }}>2px #A2A2A4 (Gray 400)</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Key Differences from Primary */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Key Differences from Primary</h2>
|
||||
<h6 className="eyebrow mb-3">Comparison</h6>
|
||||
</div>
|
||||
<div style={{ width: '100%', backgroundColor: '#FFFFFF' }}>
|
||||
{/* Header */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', borderBottom: '2px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Aspect</div>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Primary</div>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Secondary</div>
|
||||
</div>
|
||||
{/* Rows */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Background (Enabled)</div>
|
||||
<div style={{ padding: '12px' }}>Green 300 (#21E46B)</div>
|
||||
<div style={{ padding: '12px' }}>Transparent</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Background (Hover)</div>
|
||||
<div style={{ padding: '12px' }}>Green 200 (#70EE97)</div>
|
||||
<div style={{ padding: '12px' }}>Green 100 (#EAFCF1)</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Border (Enabled)</div>
|
||||
<div style={{ padding: '12px' }}>None</div>
|
||||
<div style={{ padding: '12px' }}>2px Green 400</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Text Color (Enabled)</div>
|
||||
<div style={{ padding: '12px' }}>Black (#141414)</div>
|
||||
<div style={{ padding: '12px' }}>Green 400 (#0DAA3E)</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Disabled Background</div>
|
||||
<div style={{ padding: '12px' }}>Gray 200 (#E0E0E1)</div>
|
||||
<div style={{ padding: '12px' }}>Transparent</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr' }}>
|
||||
<div style={{ padding: '12px' }}>Arrow Icon</div>
|
||||
<div style={{ padding: '12px' }}>✅ Shared</div>
|
||||
<div style={{ padding: '12px' }}>✅ Shared</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
561
about/button-showcase-tertiary.page.tsx
Normal file
561
about/button-showcase-tertiary.page.tsx
Normal file
@@ -0,0 +1,561 @@
|
||||
import * as React from 'react';
|
||||
import { Button } from 'shared/components/Button';
|
||||
import { PageGrid, PageGridCol, PageGridRow } from 'shared/components/PageGrid/page-grid';
|
||||
|
||||
export const frontmatter = {
|
||||
seo: {
|
||||
title: 'BDS Tertiary Button Component Showcase',
|
||||
description: 'Interactive showcase of the Brand Design System Tertiary Button component with all states and variants.',
|
||||
},
|
||||
};
|
||||
|
||||
export default function ButtonShowcaseTertiary() {
|
||||
const [clickCount, setClickCount] = React.useState(0);
|
||||
|
||||
const handleClick = () => {
|
||||
setClickCount((prev) => prev + 1);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="landing">
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse col-lg-8 mx-auto">
|
||||
<h1 className="mb-0">BDS Tertiary Button</h1>
|
||||
<h6 className="eyebrow mb-3">Brand Design System</h6>
|
||||
</div>
|
||||
<p className="col-lg-8 mx-auto mt-10">
|
||||
The Tertiary button is a text-only button style used for low-emphasis or contextual actions. It features no
|
||||
background fill or border, appearing as a simple text link with optional arrow icon. This variant provides the
|
||||
lowest visual emphasis while maintaining brand consistency through green text colors.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
{/* Basic Usage */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Basic Usage</h2>
|
||||
<h6 className="eyebrow mb-3">Tertiary Variant</h6>
|
||||
</div>
|
||||
<div className="d-flex flex-wrap align-items-center">
|
||||
<Button variant="tertiary" onClick={handleClick} className="me-4 mb-4">
|
||||
View Details
|
||||
</Button>
|
||||
<Button variant="tertiary" onClick={handleClick} className="me-4 mb-4">
|
||||
Learn More
|
||||
</Button>
|
||||
<Button variant="tertiary" onClick={handleClick} className="mb-4">
|
||||
Read More
|
||||
</Button>
|
||||
</div>
|
||||
{clickCount > 0 && (
|
||||
<p className="mt-4 text-muted">
|
||||
Button clicked {clickCount} time{clickCount !== 1 ? 's' : ''}
|
||||
</p>
|
||||
)}
|
||||
</section>
|
||||
|
||||
{/* Primary vs Secondary vs Tertiary Comparison */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Primary vs Secondary vs Tertiary</h2>
|
||||
<h6 className="eyebrow mb-3">Visual Hierarchy</h6>
|
||||
</div>
|
||||
<p className="mb-4 text-muted">
|
||||
Use Primary for main actions, Secondary for supporting actions, and Tertiary for low-emphasis or contextual
|
||||
actions to create clear visual hierarchy.
|
||||
</p>
|
||||
<div className="d-flex flex-wrap align-items-center">
|
||||
<Button variant="primary" onClick={handleClick} className="me-4 mb-4">
|
||||
Get Started
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={handleClick} className="me-4 mb-4">
|
||||
Learn More
|
||||
</Button>
|
||||
<Button variant="tertiary" onClick={handleClick} className="mb-4">
|
||||
View Details
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* States */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Button States</h2>
|
||||
<h6 className="eyebrow mb-3">Interactive States</h6>
|
||||
</div>
|
||||
<PageGrid>
|
||||
<PageGridRow>
|
||||
<PageGridCol span={{ base: 4, lg: 6 }}>
|
||||
<div className="p-6-sm p-10-until-sm br-8" style={{ backgroundColor: '#f5f5f7' }}>
|
||||
<h5 className="mb-4">Enabled State</h5>
|
||||
<p className="mb-4 text-muted">Text-only style with green text color, no background or border.</p>
|
||||
<Button variant="tertiary" onClick={handleClick}>
|
||||
Enabled Button
|
||||
</Button>
|
||||
</div>
|
||||
</PageGridCol>
|
||||
<PageGridCol span={{ base: 4, lg: 6 }}>
|
||||
<div className="p-6-sm p-10-until-sm br-8" style={{ backgroundColor: '#f5f5f7' }}>
|
||||
<h5 className="mb-4">Disabled State</h5>
|
||||
<p className="mb-4 text-muted">Gray text indicates non-interactive state. Icon is hidden.</p>
|
||||
<Button variant="tertiary" disabled>
|
||||
Disabled Button
|
||||
</Button>
|
||||
</div>
|
||||
</PageGridCol>
|
||||
</PageGridRow>
|
||||
</PageGrid>
|
||||
<div className="mt-10">
|
||||
<h5 className="mb-4">Hover & Focus States</h5>
|
||||
<p className="mb-4 text-muted">
|
||||
Hover over the buttons or use Tab to focus them. Notice the underline appears and text color darkens to
|
||||
Green 500. The focus state adds a green outline around the text.
|
||||
</p>
|
||||
<div className="d-flex flex-wrap">
|
||||
<Button variant="tertiary" onClick={handleClick} className="me-4 mb-4">
|
||||
Hover Me
|
||||
</Button>
|
||||
<Button variant="tertiary" onClick={handleClick} className="mb-4">
|
||||
Focus Me (Tab)
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Black Color Variant */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Black Color Variant</h2>
|
||||
<h6 className="eyebrow mb-3">Color Theme</h6>
|
||||
</div>
|
||||
<p className="mb-4 text-muted">
|
||||
Tertiary buttons can use a black color theme with black text instead of green.
|
||||
</p>
|
||||
<div className="d-flex flex-wrap align-items-center">
|
||||
<Button variant="tertiary" color="black" onClick={handleClick} className="me-4 mb-4">
|
||||
Black Tertiary
|
||||
</Button>
|
||||
<Button variant="tertiary" color="black" onClick={handleClick} className="me-4 mb-4">
|
||||
View Details
|
||||
</Button>
|
||||
<Button variant="tertiary" color="black" onClick={handleClick} className="mb-4">
|
||||
Learn More
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Black Variant States */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Black Variant States</h2>
|
||||
<h6 className="eyebrow mb-3">Interactive States</h6>
|
||||
</div>
|
||||
<PageGrid>
|
||||
<PageGridRow>
|
||||
<PageGridCol span={{ base: 4, lg: 6 }}>
|
||||
<div className="p-6-sm p-10-until-sm br-8" style={{ backgroundColor: '#f5f5f7' }}>
|
||||
<h5 className="mb-4">Enabled State</h5>
|
||||
<p className="mb-4 text-muted">Black text with transparent background.</p>
|
||||
<Button variant="tertiary" color="black" onClick={handleClick}>
|
||||
Enabled Button
|
||||
</Button>
|
||||
</div>
|
||||
</PageGridCol>
|
||||
<PageGridCol span={{ base: 4, lg: 6 }}>
|
||||
<div className="p-6-sm p-10-until-sm br-8" style={{ backgroundColor: '#f5f5f7' }}>
|
||||
<h5 className="mb-4">Disabled State</h5>
|
||||
<p className="mb-4 text-muted">Same disabled styling as green variant.</p>
|
||||
<Button variant="tertiary" color="black" disabled>
|
||||
Disabled Button
|
||||
</Button>
|
||||
</div>
|
||||
</PageGridCol>
|
||||
</PageGridRow>
|
||||
</PageGrid>
|
||||
<div className="mt-10">
|
||||
<h5 className="mb-4">Hover & Focus States</h5>
|
||||
<p className="mb-4 text-muted">
|
||||
Hover over the buttons or use Tab to focus them. Notice the underline appears on hover/focus.
|
||||
</p>
|
||||
<div className="d-flex flex-wrap">
|
||||
<Button variant="tertiary" color="black" onClick={handleClick} className="me-4 mb-4">
|
||||
Hover Me
|
||||
</Button>
|
||||
<Button variant="tertiary" color="black" onClick={handleClick} className="mb-4">
|
||||
Focus Me (Tab)
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Green vs Black Comparison */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Green vs Black Comparison</h2>
|
||||
<h6 className="eyebrow mb-3">Color Themes</h6>
|
||||
</div>
|
||||
<p className="mb-4 text-muted">Compare the green (default) and black color themes side by side.</p>
|
||||
<div className="d-flex flex-wrap align-items-center">
|
||||
<Button variant="tertiary" color="green" onClick={handleClick} className="me-4 mb-4">
|
||||
Green Tertiary
|
||||
</Button>
|
||||
<Button variant="tertiary" color="black" onClick={handleClick} className="mb-4">
|
||||
Black Tertiary
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Without Icon */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Without Icon</h2>
|
||||
<h6 className="eyebrow mb-3">Icon Control</h6>
|
||||
</div>
|
||||
<p className="mb-4 text-muted">Tertiary buttons can also be rendered without the arrow icon.</p>
|
||||
<div className="d-flex flex-wrap">
|
||||
<Button variant="tertiary" showIcon={false} onClick={handleClick} className="me-4 mb-4">
|
||||
No Icon Button
|
||||
</Button>
|
||||
<Button variant="tertiary" showIcon={true} onClick={handleClick} className="mb-4">
|
||||
With Icon Button
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Button Types */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Button Types</h2>
|
||||
<h6 className="eyebrow mb-3">Form Integration</h6>
|
||||
</div>
|
||||
<p className="mb-4 text-muted">Tertiary buttons can be used for form actions like cancel or reset.</p>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
alert('Form submitted!');
|
||||
}}
|
||||
className="d-flex flex-wrap"
|
||||
>
|
||||
<Button variant="primary" type="submit" className="me-4 mb-4">
|
||||
Submit
|
||||
</Button>
|
||||
<Button variant="tertiary" type="reset" className="me-4 mb-4">
|
||||
Reset
|
||||
</Button>
|
||||
<Button variant="tertiary" type="button" onClick={() => alert('Cancelled!')} className="mb-4">
|
||||
Cancel
|
||||
</Button>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
{/* Responsive Behavior */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Responsive Behavior</h2>
|
||||
<h6 className="eyebrow mb-3">Breakpoint Adjustments</h6>
|
||||
</div>
|
||||
<p className="mb-4 text-muted">
|
||||
Button padding adjusts automatically across breakpoints. Resize your browser window to see the changes:
|
||||
</p>
|
||||
<ul className="mb-4">
|
||||
<li>
|
||||
<strong>Desktop (≥1024px):</strong> Padding: 8px 20px, Gap: 16px
|
||||
</li>
|
||||
<li>
|
||||
<strong>Tablet/Mobile (≤1023px):</strong> Padding: 8px 16px, Gap: 16px
|
||||
</li>
|
||||
<li>
|
||||
<strong>Hover/Focus:</strong> Gap increases (22px desktop, 21px mobile) with adjusted padding
|
||||
</li>
|
||||
</ul>
|
||||
<div className="d-flex flex-wrap">
|
||||
<Button variant="tertiary" onClick={handleClick} className="me-4 mb-4">
|
||||
Responsive Button
|
||||
</Button>
|
||||
<Button variant="tertiary" onClick={handleClick} className="mb-4">
|
||||
Long Button Label Example
|
||||
</Button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Accessibility */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Accessibility Features</h2>
|
||||
<h6 className="eyebrow mb-3">WCAG Compliance</h6>
|
||||
</div>
|
||||
<PageGrid>
|
||||
<PageGridRow>
|
||||
<PageGridCol span={{ base: 4, lg: 6 }}>
|
||||
<h5 className="mb-4">Keyboard Navigation</h5>
|
||||
<ul>
|
||||
<li>Tab to focus buttons</li>
|
||||
<li>Enter or Space to activate</li>
|
||||
<li>Focus indicator: 2px green outline (Green 500)</li>
|
||||
<li>Disabled buttons are not focusable</li>
|
||||
</ul>
|
||||
</PageGridCol>
|
||||
<PageGridCol span={{ base: 4, lg: 6 }}>
|
||||
<h5 className="mb-4">Screen Reader Support</h5>
|
||||
<ul>
|
||||
<li>Button labels are announced</li>
|
||||
<li>Disabled state communicated via aria-disabled</li>
|
||||
<li>Icons are hidden from screen readers (aria-hidden)</li>
|
||||
<li>Semantic button element used</li>
|
||||
</ul>
|
||||
</PageGridCol>
|
||||
</PageGridRow>
|
||||
</PageGrid>
|
||||
<div className="mt-10">
|
||||
<h5 className="mb-4">Color Contrast</h5>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Enabled:</strong> Green 400 (#0DAA3E) on White = 4.52:1 (AA for large text)
|
||||
</li>
|
||||
<li>
|
||||
<strong>Hover/Focus:</strong> Green 500 (#078139) on White = 5.12:1 (AA)
|
||||
</li>
|
||||
<li>
|
||||
<strong>Disabled:</strong> Gray 400 (#A2A2A4) on White = reduced contrast (acceptable for disabled state)
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Code Examples */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Code Examples</h2>
|
||||
<h6 className="eyebrow mb-3">Implementation</h6>
|
||||
</div>
|
||||
<div className="p-6-sm p-10-until-sm br-8" style={{ backgroundColor: '#1e1e1e', color: '#d4d4d4' }}>
|
||||
<pre style={{ margin: 0, overflow: 'auto' }}>
|
||||
<code>{`import { Button } from 'shared/components/Button';
|
||||
|
||||
// Basic tertiary button (green theme - default)
|
||||
<Button variant="tertiary" onClick={handleClick}>
|
||||
View Details
|
||||
</Button>
|
||||
|
||||
// Black color theme
|
||||
<Button variant="tertiary" color="black" onClick={handleClick}>
|
||||
View Details
|
||||
</Button>
|
||||
|
||||
// Disabled state
|
||||
<Button variant="tertiary" disabled>
|
||||
Unavailable
|
||||
</Button>
|
||||
|
||||
// Without icon
|
||||
<Button variant="tertiary" showIcon={false}>
|
||||
Cancel
|
||||
</Button>
|
||||
|
||||
// Primary + Secondary + Tertiary pairing
|
||||
<Button variant="primary" type="submit">
|
||||
Submit
|
||||
</Button>
|
||||
<Button variant="secondary" type="button">
|
||||
Learn More
|
||||
</Button>
|
||||
<Button variant="tertiary" type="button">
|
||||
Cancel
|
||||
</Button>`}</code>
|
||||
</pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Design Specifications */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Design Specifications</h2>
|
||||
<h6 className="eyebrow mb-3">Visual Details</h6>
|
||||
</div>
|
||||
<PageGrid>
|
||||
<PageGridRow>
|
||||
<PageGridCol span={{ base: 4, lg: 6 }}>
|
||||
<h5 className="mb-4">Typography</h5>
|
||||
<ul>
|
||||
<li>Font: Booton, sans-serif</li>
|
||||
<li>Size: 18px (Body R token - different from Primary/Secondary)</li>
|
||||
<li>Weight: 400</li>
|
||||
<li>Line Height: 26.1px</li>
|
||||
<li>Letter Spacing: -0.5px</li>
|
||||
</ul>
|
||||
</PageGridCol>
|
||||
<PageGridCol span={{ base: 4, lg: 6 }}>
|
||||
<h5 className="mb-4">Spacing & Layout</h5>
|
||||
<ul>
|
||||
<li>Border Radius: 100px (fully rounded - inherited but not visually apparent)</li>
|
||||
<li>Border: None</li>
|
||||
<li>Background: Transparent</li>
|
||||
<li>Icon Size: 15px × 14px</li>
|
||||
<li>Icon Gap: 16px (default), 22px (hover/focus desktop), 21px (hover/focus mobile)</li>
|
||||
<li>Max Height: 40px</li>
|
||||
</ul>
|
||||
</PageGridCol>
|
||||
</PageGridRow>
|
||||
</PageGrid>
|
||||
<div className="mt-10">
|
||||
<h5 className="mb-4">State Colors - Green Theme</h5>
|
||||
<div style={{ width: '100%', backgroundColor: '#FFFFFF' }}>
|
||||
{/* Header */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '2px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>State</div>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Text Color</div>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Background</div>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Text Decoration</div>
|
||||
</div>
|
||||
{/* Rows */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Enabled</div>
|
||||
<div style={{ padding: '12px' }}>#0DAA3E (Green 400)</div>
|
||||
<div style={{ padding: '12px' }}>Transparent</div>
|
||||
<div style={{ padding: '12px' }}>None</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Hover</div>
|
||||
<div style={{ padding: '12px' }}>#078139 (Green 500)</div>
|
||||
<div style={{ padding: '12px' }}>Transparent</div>
|
||||
<div style={{ padding: '12px' }}>Underline</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Focus</div>
|
||||
<div style={{ padding: '12px' }}>#078139 (Green 500)</div>
|
||||
<div style={{ padding: '12px' }}>Transparent</div>
|
||||
<div style={{ padding: '12px' }}>Underline + 2px Green 500 outline</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Active</div>
|
||||
<div style={{ padding: '12px' }}>#0DAA3E (Green 400)</div>
|
||||
<div style={{ padding: '12px' }}>Transparent</div>
|
||||
<div style={{ padding: '12px' }}>Underline</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr' }}>
|
||||
<div style={{ padding: '12px' }}>Disabled</div>
|
||||
<div style={{ padding: '12px' }}>#A2A2A4 (Gray 400)</div>
|
||||
<div style={{ padding: '12px' }}>Transparent</div>
|
||||
<div style={{ padding: '12px' }}>None</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-10">
|
||||
<h5 className="mb-4">State Colors - Black Theme</h5>
|
||||
<div style={{ width: '100%', backgroundColor: '#FFFFFF' }}>
|
||||
{/* Header */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '2px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>State</div>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Text Color</div>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Background</div>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Text Decoration</div>
|
||||
</div>
|
||||
{/* Rows */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Enabled</div>
|
||||
<div style={{ padding: '12px' }}>#141414 (Neutral Black)</div>
|
||||
<div style={{ padding: '12px' }}>Transparent</div>
|
||||
<div style={{ padding: '12px' }}>None</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Hover</div>
|
||||
<div style={{ padding: '12px' }}>#141414 (Neutral Black)</div>
|
||||
<div style={{ padding: '12px' }}>Transparent</div>
|
||||
<div style={{ padding: '12px' }}>Underline</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Focus</div>
|
||||
<div style={{ padding: '12px' }}>#141414 (Neutral Black)</div>
|
||||
<div style={{ padding: '12px' }}>Transparent</div>
|
||||
<div style={{ padding: '12px' }}>Underline + 2px Black outline</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Active</div>
|
||||
<div style={{ padding: '12px' }}>#141414 (Neutral Black)</div>
|
||||
<div style={{ padding: '12px' }}>Transparent</div>
|
||||
<div style={{ padding: '12px' }}>Underline</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr' }}>
|
||||
<div style={{ padding: '12px' }}>Disabled</div>
|
||||
<div style={{ padding: '12px' }}>#A2A2A4 (Gray 400)</div>
|
||||
<div style={{ padding: '12px' }}>Transparent</div>
|
||||
<div style={{ padding: '12px' }}>None</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Key Differences from Primary/Secondary */}
|
||||
<section className="container-new py-26">
|
||||
<div className="d-flex flex-column-reverse">
|
||||
<h2 className="h4 mb-8">Key Differences from Primary/Secondary</h2>
|
||||
<h6 className="eyebrow mb-3">Comparison</h6>
|
||||
</div>
|
||||
<div style={{ width: '100%', backgroundColor: '#FFFFFF' }}>
|
||||
{/* Header */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '2px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Aspect</div>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Primary</div>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Secondary</div>
|
||||
<div style={{ padding: '12px', fontWeight: 'bold' }}>Tertiary</div>
|
||||
</div>
|
||||
{/* Rows */}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Background (Enabled)</div>
|
||||
<div style={{ padding: '12px' }}>Green 300 (#21E46B)</div>
|
||||
<div style={{ padding: '12px' }}>Transparent</div>
|
||||
<div style={{ padding: '12px' }}>Transparent</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Background (Hover)</div>
|
||||
<div style={{ padding: '12px' }}>Green 200 (#70EE97)</div>
|
||||
<div style={{ padding: '12px' }}>Green 100 (#EAFCF1)</div>
|
||||
<div style={{ padding: '12px' }}>Transparent</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Border (Enabled)</div>
|
||||
<div style={{ padding: '12px' }}>None</div>
|
||||
<div style={{ padding: '12px' }}>2px Green 400</div>
|
||||
<div style={{ padding: '12px' }}>None</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Text Color (Enabled)</div>
|
||||
<div style={{ padding: '12px' }}>Black (#141414)</div>
|
||||
<div style={{ padding: '12px' }}>Green 400 (#0DAA3E)</div>
|
||||
<div style={{ padding: '12px' }}>Green 400 (#0DAA3E)</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Text Decoration</div>
|
||||
<div style={{ padding: '12px' }}>None</div>
|
||||
<div style={{ padding: '12px' }}>None</div>
|
||||
<div style={{ padding: '12px' }}>Underline (hover/focus/active)</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Typography Token</div>
|
||||
<div style={{ padding: '12px' }}>Label R (16px)</div>
|
||||
<div style={{ padding: '12px' }}>Label R (16px)</div>
|
||||
<div style={{ padding: '12px' }}>Body R (18px)</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Focus Indicator</div>
|
||||
<div style={{ padding: '12px' }}>2px Black border</div>
|
||||
<div style={{ padding: '12px' }}>2px Black outline</div>
|
||||
<div style={{ padding: '12px' }}>2px Green 500 outline</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', borderBottom: '1px solid #E0E0E1' }}>
|
||||
<div style={{ padding: '12px' }}>Disabled Background</div>
|
||||
<div style={{ padding: '12px' }}>Gray 200 (#E0E0E1)</div>
|
||||
<div style={{ padding: '12px' }}>Transparent</div>
|
||||
<div style={{ padding: '12px' }}>Transparent</div>
|
||||
</div>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr' }}>
|
||||
<div style={{ padding: '12px' }}>Arrow Icon</div>
|
||||
<div style={{ padding: '12px' }}>✅ Shared</div>
|
||||
<div style={{ padding: '12px' }}>✅ Shared</div>
|
||||
<div style={{ padding: '12px' }}>✅ Shared</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -6,9 +6,9 @@
|
||||
"description": "The XRP Ledger Dev Portal is the authoritative source for XRP Ledger documentation, including the `rippled` server, client libraries, and other open-source XRP Ledger software.",
|
||||
"scripts": {
|
||||
"analyze-css": "node scripts/analyze-css.js",
|
||||
"build-css": "sass --load-path styles/scss styles/xrpl.scss ./static/css/devportal2024-v1.tmp.css && NODE_ENV=production postcss ./static/css/devportal2024-v1.tmp.css -o ./static/css/devportal2024-v1.css && rm -f ./static/css/devportal2024-v1.tmp.css",
|
||||
"build-css:dev": "sass --load-path styles/scss styles/xrpl.scss ./static/css/devportal2024-v1.tmp.css --source-map && postcss ./static/css/devportal2024-v1.tmp.css -o ./static/css/devportal2024-v1.css && rm -f ./static/css/devportal2024-v1.tmp.css",
|
||||
"build-css:watch": "sass --watch --load-path styles/scss --silence-deprecation=import --silence-deprecation=global-builtin --silence-deprecation=color-functions styles/xrpl.scss ./static/css/devportal2024-v1.css --source-map",
|
||||
"build-css": "sass --load-path styles/scss --load-path . styles/xrpl.scss ./static/css/devportal2024-v1.tmp.css && NODE_ENV=production postcss ./static/css/devportal2024-v1.tmp.css -o ./static/css/devportal2024-v1.css && rm -f ./static/css/devportal2024-v1.tmp.css",
|
||||
"build-css:dev": "sass --load-path styles/scss --load-path . styles/xrpl.scss ./static/css/devportal2024-v1.tmp.css --source-map && postcss ./static/css/devportal2024-v1.tmp.css -o ./static/css/devportal2024-v1.css && rm -f ./static/css/devportal2024-v1.tmp.css",
|
||||
"build-css:watch": "sass --watch --load-path styles/scss --load-path . styles/xrpl.scss:static/css/devportal2024-v1.css --source-map",
|
||||
"start": "realm develop"
|
||||
},
|
||||
"keywords": [],
|
||||
|
||||
459
shared/components/Button/Button.md
Normal file
459
shared/components/Button/Button.md
Normal file
@@ -0,0 +1,459 @@
|
||||
# Button Component Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
The Button component is a scalable, accessible button implementation following the XRPL Brand Design System (BDS). It supports three visual variants (Primary, Secondary, Tertiary) and two color themes (Green, Black), with comprehensive state management and smooth animations.
|
||||
|
||||
## Features
|
||||
|
||||
- **Three Variants**: Primary (solid), Secondary (outline), Tertiary (text-only)
|
||||
- **Two Color Themes**: Green (default) and Black
|
||||
- **Animated Arrow Icon**: Optional icon with smooth hover animations
|
||||
- **Full State Support**: Enabled, Hover, Focus, Active, and Disabled states
|
||||
- **Responsive Design**: Adaptive padding and spacing across breakpoints
|
||||
- **Accessibility**: WCAG compliant with keyboard navigation and screen reader support
|
||||
- **Smooth Animations**: 150ms transitions with custom bezier timing
|
||||
|
||||
## Props API
|
||||
|
||||
```typescript
|
||||
interface ButtonProps {
|
||||
/** Button variant - determines visual style */
|
||||
variant?: 'primary' | 'secondary' | 'tertiary';
|
||||
/** Color theme - green (default) or black */
|
||||
color?: 'green' | 'black';
|
||||
/** Button content/label */
|
||||
children: React.ReactNode;
|
||||
/** Click handler */
|
||||
onClick?: () => void;
|
||||
/** Disabled state */
|
||||
disabled?: boolean;
|
||||
/** Button type attribute */
|
||||
type?: 'button' | 'submit' | 'reset';
|
||||
/** Additional CSS classes */
|
||||
className?: string;
|
||||
/** Whether to show the arrow icon */
|
||||
showIcon?: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
### Default Values
|
||||
|
||||
- `variant`: `'primary'`
|
||||
- `color`: `'green'`
|
||||
- `disabled`: `false`
|
||||
- `type`: `'button'`
|
||||
- `className`: `''`
|
||||
- `showIcon`: `true`
|
||||
|
||||
## Variants
|
||||
|
||||
### Primary Button
|
||||
|
||||
The Primary button is used for the main call-to-action on a page. It features a solid background that fills from bottom-to-top on hover.
|
||||
|
||||
**Visual Characteristics:**
|
||||
- Solid background (Green 300 / Black)
|
||||
- High visual emphasis
|
||||
- Background color transitions on hover
|
||||
- Black text on green background, white text on black background
|
||||
|
||||
**Usage:**
|
||||
```tsx
|
||||
<Button variant="primary" onClick={handleClick}>
|
||||
Get Started
|
||||
</Button>
|
||||
```
|
||||
|
||||
### Secondary Button
|
||||
|
||||
The Secondary button is used for supporting actions. It features an outline style with a transparent background that fills on hover.
|
||||
|
||||
**Visual Characteristics:**
|
||||
- Transparent background with 2px border
|
||||
- Medium visual emphasis
|
||||
- Background fills from bottom-to-top on hover
|
||||
- Green/Black text and border
|
||||
|
||||
**Usage:**
|
||||
```tsx
|
||||
<Button variant="secondary" onClick={handleClick}>
|
||||
Learn More
|
||||
</Button>
|
||||
```
|
||||
|
||||
### Tertiary Button
|
||||
|
||||
The Tertiary button is used for low-emphasis or contextual actions. It appears as text-only with optional underline on hover.
|
||||
|
||||
**Visual Characteristics:**
|
||||
- Text-only, no background or border
|
||||
- Lowest visual emphasis
|
||||
- Underline appears on hover/focus
|
||||
- Different typography (Body R token vs Label R)
|
||||
|
||||
**Usage:**
|
||||
```tsx
|
||||
<Button variant="tertiary" onClick={handleClick}>
|
||||
View Details
|
||||
</Button>
|
||||
```
|
||||
|
||||
## Color Themes
|
||||
|
||||
### Green Theme (Default)
|
||||
|
||||
The green theme uses the XRPL brand green colors:
|
||||
- **Primary**: Green 300 background (#21E46B), Green 200 hover (#70EE97)
|
||||
- **Secondary**: Green 400 text/border (#0DAA3E), Green 500 hover (#078139)
|
||||
- **Tertiary**: Green 400 text (#0DAA3E), Green 500 hover (#078139)
|
||||
|
||||
### Black Theme
|
||||
|
||||
The black theme provides an alternative color scheme:
|
||||
- **Primary**: Black background (#141414), 80% black hover
|
||||
- **Secondary**: Black text/border (#141414), 15% black hover fill
|
||||
- **Tertiary**: Black text (#141414)
|
||||
|
||||
**Usage:**
|
||||
```tsx
|
||||
<Button variant="primary" color="black" onClick={handleClick}>
|
||||
Dark Button
|
||||
</Button>
|
||||
```
|
||||
|
||||
## States
|
||||
|
||||
### Enabled State
|
||||
|
||||
The default interactive state of the button. All variants display their base styling.
|
||||
|
||||
### Hover State
|
||||
|
||||
Triggered when the user hovers over the button with a mouse:
|
||||
- **Primary/Secondary**: Background fills from bottom-to-top
|
||||
- **Tertiary**: Underline appears, text color darkens
|
||||
- **All Variants**: Arrow icon line shrinks, gap increases (with icon)
|
||||
|
||||
### Focus State
|
||||
|
||||
Triggered when the button receives keyboard focus (Tab key):
|
||||
- Similar visual changes to hover state
|
||||
- Additional focus outline (2px border/outline)
|
||||
- Ensures keyboard accessibility
|
||||
|
||||
### Active State
|
||||
|
||||
Triggered when the button is being pressed:
|
||||
- Returns to default padding/gap
|
||||
- Background resets (for Primary/Secondary)
|
||||
- Maintains visual feedback during press
|
||||
|
||||
### Disabled State
|
||||
|
||||
When `disabled={true}`:
|
||||
- Icon is automatically hidden
|
||||
- Gray text and background (Primary) or border (Secondary)
|
||||
- Cursor changes to `not-allowed`
|
||||
- `pointer-events: none` prevents interaction
|
||||
- `aria-disabled` attribute set for screen readers
|
||||
|
||||
**Usage:**
|
||||
```tsx
|
||||
<Button variant="primary" disabled>
|
||||
Unavailable
|
||||
</Button>
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
### Component Structure
|
||||
|
||||
The Button component uses BEM (Block Element Modifier) naming convention with the `bds` namespace:
|
||||
|
||||
- `.bds-btn` - Base button class
|
||||
- `.bds-btn--primary` - Primary variant modifier
|
||||
- `.bds-btn--secondary` - Secondary variant modifier
|
||||
- `.bds-btn--tertiary` - Tertiary variant modifier
|
||||
- `.bds-btn--green` - Green color theme (default)
|
||||
- `.bds-btn--black` - Black color theme
|
||||
- `.bds-btn--disabled` - Disabled state modifier
|
||||
- `.bds-btn--no-icon` - No icon modifier
|
||||
- `.bds-btn__label` - Label element
|
||||
- `.bds-btn__icon` - Icon container
|
||||
- `.bds-btn__icon-line` - Arrow horizontal line
|
||||
- `.bds-btn__icon-chevron` - Arrow chevron
|
||||
|
||||
### Background Animation
|
||||
|
||||
Primary and Secondary variants use a shared animation pattern:
|
||||
|
||||
1. **Pseudo-element (`::before`)**: Creates the hover background fill
|
||||
2. **Transform Origin**: Set to `bottom center` for bottom-to-top fill
|
||||
3. **Initial State**: `scaleY(0)` - background hidden
|
||||
4. **Hover/Focus**: `scaleY(1)` - background fills from bottom
|
||||
5. **Active**: `scaleY(0)` - background resets during press
|
||||
|
||||
This creates a smooth, directional fill animation that feels natural and responsive.
|
||||
|
||||
### Arrow Icon Animation
|
||||
|
||||
The arrow icon consists of two parts:
|
||||
1. **Horizontal Line**: Shrinks from right to left (`scaleX(0)`) on hover/focus
|
||||
2. **Chevron**: Stays visible, shifts right via increased gap
|
||||
|
||||
The gap between label and icon increases on hover/focus:
|
||||
- **Default**: 16px (desktop), 16px (mobile)
|
||||
- **Hover/Focus**: 22px (desktop), 21px (mobile)
|
||||
|
||||
This creates the illusion of the arrow "moving forward" as the line disappears.
|
||||
|
||||
### Padding Adjustments
|
||||
|
||||
On hover/focus, padding adjusts to accommodate the increased gap:
|
||||
- **Primary**: `8px 19px 8px 20px` → `8px 13px 8px 20px` (desktop)
|
||||
- **Secondary**: `6px 17px 6px 18px` → `6px 11px 6px 18px` (desktop)
|
||||
- **Tertiary**: `8px 20px` → `8px 14px 8px 20px` (desktop)
|
||||
|
||||
These adjustments maintain visual balance while allowing the icon animation to work smoothly.
|
||||
|
||||
### Responsive Behavior
|
||||
|
||||
The component adapts to screen size at the `1023px` breakpoint:
|
||||
|
||||
**Desktop (≥1024px):**
|
||||
- Larger padding values
|
||||
- 22px gap on hover/focus
|
||||
|
||||
**Tablet/Mobile (≤1023px):**
|
||||
- Reduced padding values
|
||||
- 21px gap on hover/focus
|
||||
|
||||
All transitions remain smooth across breakpoints.
|
||||
|
||||
## Typography
|
||||
|
||||
### Primary & Secondary Variants
|
||||
- **Font**: Booton, sans-serif
|
||||
- **Size**: 16px (Label R token)
|
||||
- **Weight**: 400
|
||||
- **Line Height**: 23.2px
|
||||
- **Letter Spacing**: 0px
|
||||
|
||||
### Tertiary Variant
|
||||
- **Font**: Booton, sans-serif
|
||||
- **Size**: 18px (Body R token)
|
||||
- **Weight**: 400
|
||||
- **Line Height**: 26.1px
|
||||
- **Letter Spacing**: -0.5px
|
||||
|
||||
## Spacing & Layout
|
||||
|
||||
- **Border Radius**: 100px (fully rounded)
|
||||
- **Max Height**: 40px
|
||||
- **Icon Size**: 15px × 14px
|
||||
- **Transitions**: 150ms with `cubic-bezier(0.98, 0.12, 0.12, 0.98)`
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```tsx
|
||||
import { Button } from 'shared/components/Button';
|
||||
|
||||
// Primary button (default)
|
||||
<Button onClick={handleClick}>
|
||||
Get Started
|
||||
</Button>
|
||||
|
||||
// Secondary button
|
||||
<Button variant="secondary" onClick={handleClick}>
|
||||
Learn More
|
||||
</Button>
|
||||
|
||||
// Tertiary button
|
||||
<Button variant="tertiary" onClick={handleClick}>
|
||||
View Details
|
||||
</Button>
|
||||
```
|
||||
|
||||
### Form Integration
|
||||
|
||||
```tsx
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Button variant="primary" type="submit">
|
||||
Submit
|
||||
</Button>
|
||||
<Button variant="tertiary" type="reset">
|
||||
Reset
|
||||
</Button>
|
||||
<Button variant="tertiary" type="button" onClick={handleCancel}>
|
||||
Cancel
|
||||
</Button>
|
||||
</form>
|
||||
```
|
||||
|
||||
### Without Icon
|
||||
|
||||
```tsx
|
||||
<Button variant="primary" showIcon={false} onClick={handleClick}>
|
||||
No Arrow
|
||||
</Button>
|
||||
```
|
||||
|
||||
### Disabled State
|
||||
|
||||
```tsx
|
||||
<Button variant="primary" disabled>
|
||||
Unavailable
|
||||
</Button>
|
||||
```
|
||||
|
||||
### Color Themes
|
||||
|
||||
```tsx
|
||||
{/* Green theme (default) */}
|
||||
<Button variant="primary" color="green" onClick={handleClick}>
|
||||
Green Button
|
||||
</Button>
|
||||
|
||||
{/* Black theme */}
|
||||
<Button variant="primary" color="black" onClick={handleClick}>
|
||||
Black Button
|
||||
</Button>
|
||||
```
|
||||
|
||||
### Visual Hierarchy
|
||||
|
||||
```tsx
|
||||
{/* Use variants to create clear visual hierarchy */}
|
||||
<Button variant="primary" onClick={handlePrimaryAction}>
|
||||
Main Action
|
||||
</Button>
|
||||
<Button variant="secondary" onClick={handleSecondaryAction}>
|
||||
Secondary Action
|
||||
</Button>
|
||||
<Button variant="tertiary" onClick={handleTertiaryAction}>
|
||||
Tertiary Action
|
||||
</Button>
|
||||
```
|
||||
|
||||
## Accessibility
|
||||
|
||||
### Keyboard Navigation
|
||||
|
||||
- **Tab**: Focus next button
|
||||
- **Shift+Tab**: Focus previous button
|
||||
- **Enter/Space**: Activate button
|
||||
- **Focus Indicator**: Visible outline/border (2px)
|
||||
- **Disabled buttons**: Not focusable
|
||||
|
||||
### Screen Reader Support
|
||||
|
||||
- Semantic `<button>` element
|
||||
- Button label announced
|
||||
- `aria-disabled` attribute for disabled state
|
||||
- Icon marked with `aria-hidden="true"`
|
||||
|
||||
### Color Contrast
|
||||
|
||||
All variants meet WCAG AA standards:
|
||||
- **Primary**: Black on Green 300 = sufficient contrast
|
||||
- **Secondary/Tertiary**: Green 400/500 on White = 4.52:1 / 5.12:1
|
||||
- **Disabled**: Gray 400/500 indicates non-interactive state
|
||||
|
||||
### Focus Management
|
||||
|
||||
- Focus outline appears on keyboard navigation (`:focus-visible`)
|
||||
- Focus styles match hover styles for consistency
|
||||
- Square corners on Tertiary focus outline for better visibility
|
||||
|
||||
## Design Tokens
|
||||
|
||||
The component uses design tokens from the XRPL Brand Design System:
|
||||
|
||||
### Colors
|
||||
- `$green-100` through `$green-500`
|
||||
- `$gray-200`, `$gray-400`, `$gray-500`
|
||||
- `$white`
|
||||
- Neutral black (`#141414`)
|
||||
|
||||
### Spacing
|
||||
- Border radius: `100px`
|
||||
- Focus border width: `2px`
|
||||
- Responsive breakpoint: `1023px`
|
||||
|
||||
### Motion
|
||||
- Transition duration: `150ms`
|
||||
- Timing function: `cubic-bezier(0.98, 0.12, 0.12, 0.98)`
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Use Primary for main actions**: Reserve primary buttons for the most important action on a page
|
||||
2. **Use Secondary for supporting actions**: Use secondary buttons for actions that support the primary action
|
||||
3. **Use Tertiary for low-emphasis actions**: Use tertiary buttons for cancel, skip, or less important actions
|
||||
4. **Maintain visual hierarchy**: Don't use multiple primary buttons on the same page
|
||||
5. **Provide clear labels**: Button text should clearly indicate the action
|
||||
6. **Handle disabled states**: Always provide feedback when actions are unavailable
|
||||
7. **Test keyboard navigation**: Ensure all buttons are accessible via keyboard
|
||||
8. **Consider context**: Choose color theme based on background and design context
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### Class Name Generation
|
||||
|
||||
The component builds class names dynamically:
|
||||
|
||||
```typescript
|
||||
const classNames = [
|
||||
'bds-btn',
|
||||
`bds-btn--${variant}`,
|
||||
`bds-btn--${color}`,
|
||||
disabled ? 'bds-btn--disabled' : '',
|
||||
!shouldShowIcon ? 'bds-btn--no-icon' : '',
|
||||
className,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' ');
|
||||
```
|
||||
|
||||
### Icon Visibility Logic
|
||||
|
||||
The icon is automatically hidden when:
|
||||
- `showIcon={false}` is passed
|
||||
- `disabled={true}` is set
|
||||
|
||||
This ensures disabled buttons don't show interactive elements.
|
||||
|
||||
### State Management
|
||||
|
||||
The component manages states through CSS classes and props:
|
||||
- **Disabled**: Controlled via `disabled` prop and `aria-disabled` attribute
|
||||
- **Hover/Focus**: Handled by CSS `:hover` and `:focus-visible` pseudo-classes
|
||||
- **Active**: Handled by CSS `:active` pseudo-class
|
||||
|
||||
## Browser Support
|
||||
|
||||
The component uses modern CSS features:
|
||||
- CSS Grid/Flexbox (widely supported)
|
||||
- `:focus-visible` (supported in modern browsers)
|
||||
- CSS transforms and transitions (widely supported)
|
||||
- CSS custom properties (supported in modern browsers)
|
||||
|
||||
For older browser support, consider polyfills or fallbacks as needed.
|
||||
|
||||
## Related Components
|
||||
|
||||
- See showcase pages for interactive examples:
|
||||
- `about/button-showcase-tertiary.page.tsx`
|
||||
- Other variant showcase pages
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
shared/components/Button/
|
||||
├── Button.tsx # Component implementation
|
||||
├── Button.scss # Component styles
|
||||
├── Button.md # This documentation
|
||||
└── index.ts # Exports
|
||||
```
|
||||
1022
shared/components/Button/Button.scss
Normal file
1022
shared/components/Button/Button.scss
Normal file
File diff suppressed because it is too large
Load Diff
137
shared/components/Button/Button.tsx
Normal file
137
shared/components/Button/Button.tsx
Normal file
@@ -0,0 +1,137 @@
|
||||
import React from 'react';
|
||||
|
||||
export interface ButtonProps {
|
||||
/** Button variant - determines visual style */
|
||||
variant?: 'primary' | 'secondary' | 'tertiary';
|
||||
/** Color theme - green (default) or black */
|
||||
color?: 'green' | 'black';
|
||||
/** Button content/label */
|
||||
children: React.ReactNode;
|
||||
/** Click handler */
|
||||
onClick?: () => void;
|
||||
/** Disabled state */
|
||||
disabled?: boolean;
|
||||
/** Button type attribute */
|
||||
type?: 'button' | 'submit' | 'reset';
|
||||
/** Additional CSS classes */
|
||||
className?: string;
|
||||
/** Whether to show the arrow icon */
|
||||
showIcon?: boolean;
|
||||
/** Accessibility label - defaults to button text if not provided */
|
||||
ariaLabel?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Animated Arrow Icon Component
|
||||
* The horizontal line shrinks from left to right on hover/focus,
|
||||
* while the chevron shifts right via the gap change.
|
||||
*/
|
||||
const ArrowIcon: React.FC = () => (
|
||||
<svg
|
||||
className="bds-btn__icon"
|
||||
width="15"
|
||||
height="14"
|
||||
viewBox="0 0 15 14"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden="true"
|
||||
>
|
||||
{/* Horizontal line - shrinks on hover */}
|
||||
<line
|
||||
className="bds-btn__icon-line"
|
||||
x1="0"
|
||||
y1="7"
|
||||
x2="14"
|
||||
y2="7"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.3"
|
||||
strokeMiterlimit="10"
|
||||
/>
|
||||
{/* Chevron - stays visible */}
|
||||
<path
|
||||
className="bds-btn__icon-chevron"
|
||||
d="M8.16755 1.16743L14.0005 7.00038L8.16755 12.8333"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.3"
|
||||
strokeMiterlimit="10"
|
||||
fill="none"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
|
||||
/**
|
||||
* BDS Button Component
|
||||
*
|
||||
* A scalable button component following the XRPL Brand Design System.
|
||||
* Supports Primary, Secondary, and Tertiary variants with green (default) or black color themes.
|
||||
*
|
||||
* @example
|
||||
* <Button variant="primary" onClick={handleClick}>Get Started</Button>
|
||||
* <Button variant="secondary" onClick={handleClick}>Learn More</Button>
|
||||
* <Button variant="tertiary" onClick={handleClick}>View Details</Button>
|
||||
* <Button variant="primary" color="black" onClick={handleClick}>Dark Button</Button>
|
||||
*/
|
||||
/**
|
||||
* Helper function to extract text content from ReactNode
|
||||
*/
|
||||
const getTextFromChildren = (children: React.ReactNode): string => {
|
||||
if (typeof children === 'string' || typeof children === 'number') {
|
||||
return String(children);
|
||||
}
|
||||
if (Array.isArray(children)) {
|
||||
return children.map(getTextFromChildren).join('');
|
||||
}
|
||||
if (React.isValidElement(children)) {
|
||||
const props = children.props as { children?: React.ReactNode };
|
||||
if (props.children) {
|
||||
return getTextFromChildren(props.children);
|
||||
}
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
export const Button: React.FC<ButtonProps> = ({
|
||||
variant = 'primary',
|
||||
color = 'green',
|
||||
children,
|
||||
onClick,
|
||||
disabled = false,
|
||||
type = 'button',
|
||||
className = '',
|
||||
showIcon = true,
|
||||
ariaLabel,
|
||||
}) => {
|
||||
// Hide icon when disabled (per design spec)
|
||||
const shouldShowIcon = showIcon && !disabled;
|
||||
|
||||
// Default ariaLabel to button text if not provided
|
||||
const buttonAriaLabel = ariaLabel || getTextFromChildren(children);
|
||||
|
||||
// Build class names using BEM with bds namespace
|
||||
const classNames = [
|
||||
'bds-btn',
|
||||
`bds-btn--${variant}`,
|
||||
`bds-btn--${color}`,
|
||||
disabled ? 'bds-btn--disabled' : '',
|
||||
!shouldShowIcon ? 'bds-btn--no-icon' : '',
|
||||
className,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' ');
|
||||
|
||||
return (
|
||||
<button
|
||||
type={type}
|
||||
className={classNames}
|
||||
onClick={onClick}
|
||||
disabled={disabled}
|
||||
aria-disabled={disabled}
|
||||
aria-label={buttonAriaLabel}
|
||||
>
|
||||
<span className="bds-btn__label">{children}</span>
|
||||
{shouldShowIcon && <ArrowIcon />}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default Button;
|
||||
2
shared/components/Button/index.ts
Normal file
2
shared/components/Button/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export { Button, type ButtonProps } from './Button';
|
||||
export { default } from './Button';
|
||||
@@ -11145,6 +11145,591 @@ button[disabled=disabled] {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.bds-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
max-height: 40px;
|
||||
font-family: "Booton", sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
line-height: 23.2px;
|
||||
letter-spacing: 0px;
|
||||
white-space: nowrap;
|
||||
border: none;
|
||||
border-radius: 100px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
z-index: 1;
|
||||
transition: color 150ms cubic-bezier(0.98, 0.12, 0.12, 0.98), border-color 150ms cubic-bezier(0.98, 0.12, 0.12, 0.98), padding 150ms cubic-bezier(0.98, 0.12, 0.12, 0.98), gap 150ms cubic-bezier(0.98, 0.12, 0.12, 0.98), transform 150ms cubic-bezier(0.98, 0.12, 0.12, 0.98);
|
||||
}
|
||||
.bds-btn::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: -1;
|
||||
transform: scaleY(0);
|
||||
transform-origin: bottom center;
|
||||
transition: transform 150ms cubic-bezier(0.98, 0.12, 0.12, 0.98);
|
||||
}
|
||||
.bds-btn:hover:not(:disabled):not(.bds-btn--disabled)::before, .bds-btn:focus-visible:not(:disabled):not(.bds-btn--disabled)::before {
|
||||
transform: scaleY(1);
|
||||
}
|
||||
.bds-btn:active:not(:disabled):not(.bds-btn--disabled)::before {
|
||||
transform: scaleY(0);
|
||||
}
|
||||
.bds-btn__label {
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.bds-btn__icon {
|
||||
width: 15px;
|
||||
height: 14px;
|
||||
flex-shrink: 0;
|
||||
transition: opacity 150ms cubic-bezier(0.98, 0.12, 0.12, 0.98);
|
||||
color: currentColor;
|
||||
overflow: visible;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.bds-btn__icon-line {
|
||||
transform-box: fill-box;
|
||||
transform-origin: right center;
|
||||
transform: scaleX(1);
|
||||
transition: transform 150ms cubic-bezier(0.98, 0.12, 0.12, 0.98);
|
||||
}
|
||||
.bds-btn__icon-chevron {
|
||||
transition: transform 150ms cubic-bezier(0.98, 0.12, 0.12, 0.98);
|
||||
}
|
||||
.bds-btn:hover:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-line, .bds-btn:focus-visible:not(:disabled):not(.bds-btn--disabled) .bds-btn__icon-line {
|
||||
transform: scaleX(0);
|
||||
}
|
||||
@media (max-width: 1279.98px) {
|
||||
.bds-btn {
|
||||
font-size: 14px;
|
||||
line-height: 20.1px;
|
||||
}
|
||||
}
|
||||
|
||||
.bds-btn--primary {
|
||||
color: #141414;
|
||||
background-color: #21E46B;
|
||||
}
|
||||
.bds-btn--primary::before {
|
||||
background-color: #70EE97;
|
||||
}
|
||||
.bds-btn--primary {
|
||||
padding: 8px 19px 8px 20px;
|
||||
gap: 16px;
|
||||
}
|
||||
.bds-btn--primary.bds-btn--no-icon {
|
||||
padding: 8px 20px;
|
||||
}
|
||||
.bds-btn--primary:hover:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) {
|
||||
padding: 8px 13px 8px 20px;
|
||||
gap: 22px;
|
||||
}
|
||||
.bds-btn--primary:focus-visible:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) {
|
||||
outline: 2px solid #141414;
|
||||
outline-offset: 2px;
|
||||
padding: 8px 13px 8px 20px;
|
||||
gap: 22px;
|
||||
}
|
||||
.bds-btn--primary:focus-visible:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon {
|
||||
outline: 2px solid #141414;
|
||||
outline-offset: 2px;
|
||||
padding: 8px 20px;
|
||||
}
|
||||
.bds-btn--primary:active:not(:disabled):not(.bds-btn--disabled) {
|
||||
padding: 8px 19px 8px 20px;
|
||||
gap: 16px;
|
||||
}
|
||||
.bds-btn--primary:disabled, .bds-btn--primary.bds-btn--disabled {
|
||||
color: #838386;
|
||||
background-color: #E0E0E1;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
.bds-btn--primary:disabled::before, .bds-btn--primary.bds-btn--disabled::before {
|
||||
display: none;
|
||||
}
|
||||
@media (max-width: 1279.98px) {
|
||||
.bds-btn--primary {
|
||||
padding: 8px 15px 8px 16px;
|
||||
gap: 16px;
|
||||
}
|
||||
.bds-btn--primary.bds-btn--no-icon {
|
||||
padding: 8px 16px;
|
||||
}
|
||||
.bds-btn--primary:hover:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) {
|
||||
padding: 8px 10px 8px 16px;
|
||||
gap: 21px;
|
||||
}
|
||||
.bds-btn--primary:focus-visible:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) {
|
||||
outline: 2px solid #141414;
|
||||
outline-offset: 2px;
|
||||
padding: 8px 10px 8px 16px;
|
||||
gap: 21px;
|
||||
}
|
||||
.bds-btn--primary:focus-visible:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon {
|
||||
outline: 2px solid #141414;
|
||||
outline-offset: 2px;
|
||||
padding: 8px 16px;
|
||||
}
|
||||
.bds-btn--primary:active:not(:disabled):not(.bds-btn--disabled) {
|
||||
padding: 8px 15px 8px 16px;
|
||||
gap: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.bds-btn--secondary {
|
||||
color: #0DAA3E;
|
||||
background-color: transparent;
|
||||
border: 2px solid #0DAA3E;
|
||||
}
|
||||
.bds-btn--secondary::before {
|
||||
background-color: #EAFCF1;
|
||||
}
|
||||
.bds-btn--secondary {
|
||||
padding: 6px 17px 6px 18px;
|
||||
gap: 16px;
|
||||
}
|
||||
.bds-btn--secondary.bds-btn--no-icon {
|
||||
padding: 6px 18px;
|
||||
}
|
||||
.bds-btn--secondary:hover:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) {
|
||||
color: #078139;
|
||||
border-color: #078139;
|
||||
padding: 6px 11px 6px 18px;
|
||||
gap: 22px;
|
||||
}
|
||||
.bds-btn--secondary:hover:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon {
|
||||
color: #078139;
|
||||
border-color: #078139;
|
||||
}
|
||||
.bds-btn--secondary:focus-visible:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) {
|
||||
color: #078139;
|
||||
border: none;
|
||||
outline: 2px solid #141414;
|
||||
outline-offset: 2px;
|
||||
padding: 6px 13px 6px 20px;
|
||||
gap: 22px;
|
||||
}
|
||||
.bds-btn--secondary:focus-visible:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon {
|
||||
color: #078139;
|
||||
border: none;
|
||||
outline: 2px solid #141414;
|
||||
outline-offset: 2px;
|
||||
padding: 6px 20px;
|
||||
}
|
||||
.bds-btn--secondary:active:not(:disabled):not(.bds-btn--disabled) {
|
||||
color: #0DAA3E;
|
||||
border-color: #0DAA3E;
|
||||
padding: 6px 17px 6px 18px;
|
||||
gap: 16px;
|
||||
}
|
||||
.bds-btn--secondary:disabled, .bds-btn--secondary.bds-btn--disabled {
|
||||
color: #A2A2A4;
|
||||
background-color: transparent;
|
||||
border-color: #A2A2A4;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
.bds-btn--secondary:disabled::before, .bds-btn--secondary.bds-btn--disabled::before {
|
||||
display: none;
|
||||
}
|
||||
@media (max-width: 1279.98px) {
|
||||
.bds-btn--secondary {
|
||||
padding: 6px 13px 6px 14px;
|
||||
gap: 16px;
|
||||
}
|
||||
.bds-btn--secondary.bds-btn--no-icon {
|
||||
padding: 6px 14px;
|
||||
}
|
||||
.bds-btn--secondary:hover:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) {
|
||||
padding: 6px 8px 6px 14px;
|
||||
gap: 21px;
|
||||
}
|
||||
.bds-btn--secondary:focus-visible:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) {
|
||||
border: none;
|
||||
outline: 2px solid #141414;
|
||||
outline-offset: 2px;
|
||||
padding: 6px 10px 6px 16px;
|
||||
gap: 21px;
|
||||
}
|
||||
.bds-btn--secondary:focus-visible:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon {
|
||||
border: none;
|
||||
outline: 2px solid #141414;
|
||||
outline-offset: 2px;
|
||||
padding: 6px 16px;
|
||||
}
|
||||
.bds-btn--secondary:active:not(:disabled):not(.bds-btn--disabled) {
|
||||
padding: 6px 13px 6px 14px;
|
||||
gap: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.bds-btn--black.bds-btn--primary {
|
||||
color: #FFFFFF;
|
||||
background-color: #141414;
|
||||
}
|
||||
.bds-btn--black.bds-btn--primary::before {
|
||||
background-color: rgba(20, 20, 20, 0.8);
|
||||
}
|
||||
.bds-btn--black.bds-btn--primary:hover:not(:disabled):not(.bds-btn--disabled) {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
.bds-btn--black.bds-btn--primary:focus-visible:not(:disabled):not(.bds-btn--disabled) {
|
||||
color: #FFFFFF;
|
||||
outline: 2px solid #141414;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
.bds-btn--black.bds-btn--primary:active:not(:disabled):not(.bds-btn--disabled) {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
.bds-btn--black.bds-btn--primary:disabled, .bds-btn--black.bds-btn--primary.bds-btn--disabled {
|
||||
color: #838386;
|
||||
background-color: #E0E0E1;
|
||||
}
|
||||
.bds-btn--black.bds-btn--secondary {
|
||||
color: #141414;
|
||||
border-color: #141414;
|
||||
}
|
||||
.bds-btn--black.bds-btn--secondary::before {
|
||||
background-color: rgba(20, 20, 20, 0.15);
|
||||
}
|
||||
.bds-btn--black.bds-btn--secondary:hover:not(:disabled):not(.bds-btn--disabled) {
|
||||
color: #141414;
|
||||
border-color: #141414;
|
||||
}
|
||||
.bds-btn--black.bds-btn--secondary:focus-visible:not(:disabled):not(.bds-btn--disabled) {
|
||||
color: #141414;
|
||||
border: none;
|
||||
outline: 2px solid #141414;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
.bds-btn--black.bds-btn--secondary:active:not(:disabled):not(.bds-btn--disabled) {
|
||||
color: #141414;
|
||||
border-color: #141414;
|
||||
}
|
||||
.bds-btn--black.bds-btn--secondary:disabled, .bds-btn--black.bds-btn--secondary.bds-btn--disabled {
|
||||
color: #838386;
|
||||
border-color: #A2A2A4;
|
||||
}
|
||||
.bds-btn--black.bds-btn--tertiary {
|
||||
color: #141414;
|
||||
}
|
||||
.bds-btn--black.bds-btn--tertiary:hover:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) {
|
||||
color: #141414 !important;
|
||||
text-decoration: underline;
|
||||
padding: 8px 14px 8px 20px;
|
||||
gap: 22px;
|
||||
}
|
||||
.bds-btn--black.bds-btn--tertiary:hover:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon {
|
||||
color: #141414 !important;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.bds-btn--black.bds-btn--tertiary:focus-visible:not(:disabled):not(.bds-btn--disabled) {
|
||||
color: #141414 !important;
|
||||
text-decoration: underline;
|
||||
border-radius: 0;
|
||||
outline: 2px solid #141414;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
.bds-btn--black.bds-btn--tertiary:active:not(:disabled):not(.bds-btn--disabled) {
|
||||
color: #141414 !important;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.bds-btn--black.bds-btn--tertiary:disabled, .bds-btn--black.bds-btn--tertiary.bds-btn--disabled {
|
||||
color: #838386;
|
||||
}
|
||||
@media (max-width: 1279.98px) {
|
||||
.bds-btn--black.bds-btn--tertiary:hover:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) {
|
||||
color: #141414 !important;
|
||||
padding: 8px 11px 8px 16px;
|
||||
gap: 21px;
|
||||
}
|
||||
}
|
||||
|
||||
.bds-btn--tertiary {
|
||||
color: #0DAA3E;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
text-decoration: none;
|
||||
font-size: 18px;
|
||||
line-height: 26.1px;
|
||||
letter-spacing: -0.5px;
|
||||
padding: 8px 20px;
|
||||
gap: 16px;
|
||||
}
|
||||
.bds-btn--tertiary.bds-btn--no-icon {
|
||||
padding: 8px 20px;
|
||||
}
|
||||
.bds-btn--tertiary::before {
|
||||
display: none;
|
||||
}
|
||||
.bds-btn--tertiary:hover:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) {
|
||||
color: #078139;
|
||||
text-decoration: underline;
|
||||
padding: 8px 14px 8px 20px;
|
||||
gap: 22px;
|
||||
}
|
||||
.bds-btn--tertiary:hover:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon {
|
||||
color: #078139;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.bds-btn--tertiary:focus-visible:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) {
|
||||
color: #078139;
|
||||
text-decoration: underline;
|
||||
border-radius: 0;
|
||||
outline: 2px solid #141414;
|
||||
outline-offset: -2px;
|
||||
padding: 5px 2px 2px;
|
||||
gap: 22px;
|
||||
}
|
||||
.bds-btn--tertiary:focus-visible:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon {
|
||||
color: #078139;
|
||||
text-decoration: underline;
|
||||
border-radius: 0;
|
||||
outline: 2px solid #141414;
|
||||
outline-offset: -2px;
|
||||
padding: 5px 2px 2px;
|
||||
}
|
||||
.bds-btn--tertiary:active:not(:disabled):not(.bds-btn--disabled) {
|
||||
color: #0DAA3E;
|
||||
text-decoration: underline;
|
||||
padding: 8px 20px;
|
||||
gap: 16px;
|
||||
}
|
||||
.bds-btn--tertiary:disabled, .bds-btn--tertiary.bds-btn--disabled {
|
||||
color: #A2A2A4;
|
||||
background-color: transparent;
|
||||
text-decoration: none;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
.bds-btn--tertiary:disabled::before, .bds-btn--tertiary.bds-btn--disabled::before {
|
||||
display: none;
|
||||
}
|
||||
@media (max-width: 1279.98px) {
|
||||
.bds-btn--tertiary {
|
||||
font-size: 16px;
|
||||
line-height: 23.2px;
|
||||
letter-spacing: 0px;
|
||||
padding: 8px 16px;
|
||||
gap: 16px;
|
||||
}
|
||||
.bds-btn--tertiary.bds-btn--no-icon {
|
||||
padding: 8px 16px;
|
||||
}
|
||||
.bds-btn--tertiary:hover:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) {
|
||||
padding: 8px 11px 8px 16px;
|
||||
gap: 21px;
|
||||
}
|
||||
.bds-btn--tertiary:focus-visible:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) {
|
||||
color: #078139;
|
||||
text-decoration: underline;
|
||||
border-radius: 0;
|
||||
outline: 2px solid #141414;
|
||||
outline-offset: -2px;
|
||||
padding: 5px 2px 2px;
|
||||
gap: 21px;
|
||||
}
|
||||
.bds-btn--tertiary:focus-visible:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon {
|
||||
color: #078139;
|
||||
text-decoration: underline;
|
||||
border-radius: 0;
|
||||
outline: 2px solid #141414;
|
||||
outline-offset: -2px;
|
||||
padding: 5px 2px 2px;
|
||||
}
|
||||
.bds-btn--tertiary:active:not(:disabled):not(.bds-btn--disabled) {
|
||||
padding: 8px 16px;
|
||||
gap: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
html.dark .bds-btn--primary:focus-visible:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) {
|
||||
outline: 2px solid #FFFFFF;
|
||||
outline-offset: 2px;
|
||||
padding: 8px 13px 8px 20px;
|
||||
gap: 22px;
|
||||
}
|
||||
html.dark .bds-btn--primary:focus-visible:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon {
|
||||
outline: 2px solid #FFFFFF;
|
||||
outline-offset: 2px;
|
||||
padding: 8px 20px;
|
||||
}
|
||||
@media (max-width: 1279.98px) {
|
||||
html.dark .bds-btn--primary:focus-visible:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) {
|
||||
outline: 2px solid #FFFFFF;
|
||||
outline-offset: 2px;
|
||||
padding: 8px 10px 8px 16px;
|
||||
gap: 21px;
|
||||
}
|
||||
html.dark .bds-btn--primary:focus-visible:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon {
|
||||
outline: 2px solid #FFFFFF;
|
||||
outline-offset: 2px;
|
||||
padding: 8px 16px;
|
||||
}
|
||||
}
|
||||
html.dark .bds-btn--secondary:not(.bds-btn--black) {
|
||||
color: #21E46B;
|
||||
border-color: #21E46B;
|
||||
}
|
||||
html.dark .bds-btn--secondary:not(.bds-btn--black)::before {
|
||||
background-color: #078139;
|
||||
}
|
||||
html.dark .bds-btn--secondary:not(.bds-btn--black):hover:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) {
|
||||
color: #70EE97;
|
||||
border-color: #70EE97;
|
||||
padding: 6px 11px 6px 18px;
|
||||
gap: 22px;
|
||||
}
|
||||
html.dark .bds-btn--secondary:not(.bds-btn--black):hover:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon {
|
||||
color: #70EE97;
|
||||
border-color: #70EE97;
|
||||
}
|
||||
html.dark .bds-btn--secondary:not(.bds-btn--black):focus-visible:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) {
|
||||
color: #70EE97;
|
||||
border: none;
|
||||
outline: 2px solid #FFFFFF;
|
||||
outline-offset: 2px;
|
||||
padding: 6px 13px 6px 20px;
|
||||
gap: 22px;
|
||||
}
|
||||
html.dark .bds-btn--secondary:not(.bds-btn--black):focus-visible:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon {
|
||||
color: #70EE97;
|
||||
border: none;
|
||||
outline: 2px solid #FFFFFF;
|
||||
outline-offset: 2px;
|
||||
padding: 6px 20px;
|
||||
}
|
||||
html.dark .bds-btn--secondary:not(.bds-btn--black):active:not(:disabled):not(.bds-btn--disabled) {
|
||||
color: #21E46B;
|
||||
border-color: #21E46B;
|
||||
padding: 6px 17px 6px 18px;
|
||||
gap: 16px;
|
||||
}
|
||||
html.dark .bds-btn--secondary:not(.bds-btn--black):disabled, html.dark .bds-btn--secondary:not(.bds-btn--black).bds-btn--disabled {
|
||||
color: #A2A2A4;
|
||||
background-color: transparent;
|
||||
border-color: #A2A2A4;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
html.dark .bds-btn--secondary:not(.bds-btn--black):disabled::before, html.dark .bds-btn--secondary:not(.bds-btn--black).bds-btn--disabled::before {
|
||||
display: none;
|
||||
}
|
||||
@media (max-width: 1279.98px) {
|
||||
html.dark .bds-btn--secondary:not(.bds-btn--black):hover:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) {
|
||||
color: #70EE97;
|
||||
border-color: #70EE97;
|
||||
padding: 6px 8px 6px 14px;
|
||||
gap: 21px;
|
||||
}
|
||||
html.dark .bds-btn--secondary:not(.bds-btn--black):focus-visible:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) {
|
||||
color: #70EE97;
|
||||
border: none;
|
||||
outline: 2px solid #FFFFFF;
|
||||
outline-offset: 2px;
|
||||
padding: 6px 10px 6px 16px;
|
||||
gap: 21px;
|
||||
}
|
||||
html.dark .bds-btn--secondary:not(.bds-btn--black):focus-visible:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon {
|
||||
color: #70EE97;
|
||||
border: none;
|
||||
outline: 2px solid #FFFFFF;
|
||||
outline-offset: 2px;
|
||||
padding: 6px 16px;
|
||||
}
|
||||
html.dark .bds-btn--secondary:not(.bds-btn--black):active:not(:disabled):not(.bds-btn--disabled) {
|
||||
color: #21E46B;
|
||||
border-color: #21E46B;
|
||||
padding: 6px 13px 6px 14px;
|
||||
gap: 16px;
|
||||
}
|
||||
}
|
||||
html.dark .bds-btn--tertiary:not(.bds-btn--black) {
|
||||
color: #21E46B;
|
||||
}
|
||||
html.dark .bds-btn--tertiary:not(.bds-btn--black):hover:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) {
|
||||
color: #70EE97;
|
||||
text-decoration: underline;
|
||||
padding: 8px 14px 8px 20px;
|
||||
gap: 22px;
|
||||
}
|
||||
html.dark .bds-btn--tertiary:not(.bds-btn--black):hover:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon {
|
||||
color: #70EE97;
|
||||
text-decoration: underline;
|
||||
}
|
||||
html.dark .bds-btn--tertiary:not(.bds-btn--black):focus-visible:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) {
|
||||
color: #70EE97;
|
||||
text-decoration: underline;
|
||||
border-radius: 0;
|
||||
outline: 2px solid #FFFFFF;
|
||||
outline-offset: -2px;
|
||||
padding: 5px 2px 2px;
|
||||
gap: 22px;
|
||||
}
|
||||
html.dark .bds-btn--tertiary:not(.bds-btn--black):focus-visible:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon {
|
||||
color: #70EE97;
|
||||
text-decoration: underline;
|
||||
border-radius: 0;
|
||||
outline: 2px solid #FFFFFF;
|
||||
outline-offset: -2px;
|
||||
padding: 5px 2px 2px;
|
||||
}
|
||||
html.dark .bds-btn--tertiary:not(.bds-btn--black):active:not(:disabled):not(.bds-btn--disabled) {
|
||||
color: #21E46B;
|
||||
text-decoration: underline;
|
||||
padding: 8px 20px;
|
||||
gap: 16px;
|
||||
}
|
||||
html.dark .bds-btn--tertiary:not(.bds-btn--black):disabled, html.dark .bds-btn--tertiary:not(.bds-btn--black).bds-btn--disabled {
|
||||
color: #A2A2A4;
|
||||
background-color: transparent;
|
||||
text-decoration: none;
|
||||
cursor: not-allowed;
|
||||
pointer-events: none;
|
||||
}
|
||||
@media (max-width: 1279.98px) {
|
||||
html.dark .bds-btn--tertiary:not(.bds-btn--black):hover:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) {
|
||||
color: #70EE97;
|
||||
text-decoration: underline;
|
||||
padding: 8px 11px 8px 16px;
|
||||
gap: 21px;
|
||||
}
|
||||
html.dark .bds-btn--tertiary:not(.bds-btn--black):focus-visible:not(:disabled):not(.bds-btn--disabled):not(.bds-btn--no-icon) {
|
||||
color: #70EE97;
|
||||
text-decoration: underline;
|
||||
border-radius: 0;
|
||||
outline: 2px solid #FFFFFF;
|
||||
outline-offset: -2px;
|
||||
padding: 5px 2px 2px;
|
||||
gap: 21px;
|
||||
}
|
||||
html.dark .bds-btn--tertiary:not(.bds-btn--black):focus-visible:not(:disabled):not(.bds-btn--disabled).bds-btn--no-icon {
|
||||
color: #70EE97;
|
||||
text-decoration: underline;
|
||||
border-radius: 0;
|
||||
outline: 2px solid #FFFFFF;
|
||||
outline-offset: -2px;
|
||||
padding: 5px 2px 2px;
|
||||
}
|
||||
html.dark .bds-btn--tertiary:not(.bds-btn--black):active:not(:disabled):not(.bds-btn--disabled) {
|
||||
color: #21E46B;
|
||||
text-decoration: underline;
|
||||
padding: 8px 16px;
|
||||
gap: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
/* TABLE STYLING */
|
||||
article table {
|
||||
clear: right;
|
||||
|
||||
3
static/img/icons/button/button-arrow-hovered.svg
Normal file
3
static/img/icons/button/button-arrow-hovered.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="8" height="13" viewBox="0 0 8 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0.459602 0.459648L6.29255 6.2926L0.459601 12.1255" stroke="#141414" stroke-width="1.3" stroke-miterlimit="10"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 223 B |
3
static/img/icons/button/button-arrow-right.svg
Normal file
3
static/img/icons/button/button-arrow-right.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="15" height="14" viewBox="0 0 15 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.16755 1.16743L14.0005 7.00038L8.16755 12.8333M13.9991 6.99893L-2.79004e-05 6.99893" stroke="#141414" stroke-width="1.3" stroke-miterlimit="10"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 260 B |
10
styles/_breakpoints.scss
Normal file
10
styles/_breakpoints.scss
Normal file
@@ -0,0 +1,10 @@
|
||||
// Shared breakpoints for responsive design
|
||||
// These values are used by Bootstrap and custom components
|
||||
|
||||
$grid-breakpoints: (
|
||||
xs: 0,
|
||||
sm: 576px,
|
||||
md: 576px,
|
||||
lg: 992px,
|
||||
xl: 1280px
|
||||
);
|
||||
@@ -40,13 +40,7 @@ $font-family-sans-serif: "Booton", "Noto Sans", -apple-system, BlinkMacSystemFon
|
||||
$base-size: 16px;
|
||||
$line-height-base: 1.5;
|
||||
|
||||
$grid-breakpoints: (
|
||||
xs: 0,
|
||||
sm: 576px,
|
||||
md: 576px,
|
||||
lg: 992px,
|
||||
xl: 1280px
|
||||
);
|
||||
@import "_breakpoints.scss";
|
||||
|
||||
// Bootstrap v5 - Import only what we need
|
||||
// Note: Bootstrap still uses @import internally, so we use @import for Bootstrap
|
||||
@@ -86,6 +80,7 @@ $grid-breakpoints: (
|
||||
@import "_side-nav.scss";
|
||||
@import "_helpers.scss";
|
||||
@import "_buttons.scss";
|
||||
@import "../shared/components/Button/Button.scss";
|
||||
@import "_tables.scss";
|
||||
@import "_use-cases.scss";
|
||||
@import "_github-edit.scss";
|
||||
|
||||
Reference in New Issue
Block a user