merge main brand branch in

This commit is contained in:
akcodez
2025-12-01 12:03:09 -08:00
16 changed files with 352 additions and 210 deletions

View File

@@ -0,0 +1,116 @@
// XRPL Grid
// -----------------------------------------------------------------------------
// A namespaced grid layer that reuses Bootstrap's grid mixins while providing
// XRPL-specific gutters and container padding.
$xrpl-grid-gutter: 8px;
@mixin xrpl-grid-generate-cols($columns, $suffix: null) {
@for $i from 1 through $columns {
$selector: if($suffix, ".xrpl-grid__col-#{$suffix}-#{$i}", ".xrpl-grid__col-#{$i}");
#{$selector} {
@include make-col($i, $columns);
}
}
}
@mixin xrpl-grid-generate-auto($suffix: null) {
$selector: if($suffix, ".xrpl-grid__col-#{$suffix}-auto", ".xrpl-grid__col-auto");
#{$selector} {
@include make-col-auto();
}
}
@mixin xrpl-grid-generate-fill($suffix: null) {
$selector: if($suffix, ".xrpl-grid__col-#{$suffix}", ".xrpl-grid__col");
#{$selector} {
flex: 1 0 0;
}
}
@mixin xrpl-grid-generate-offsets($columns, $suffix: null) {
@for $i from 0 through ($columns - 1) {
$selector: if($suffix, ".xrpl-grid__offset-#{$suffix}-#{$i}", ".xrpl-grid__offset-#{$i}");
#{$selector} {
@include make-col-offset($i, $columns);
}
}
}
.xrpl-grid {
&__container {
width: 100%;
margin-right: auto;
margin-left: auto;
padding-right: 16px;
padding-left: 16px;
box-sizing: border-box;
@include media-breakpoint-up(sm) {
padding-right: 24px;
padding-left: 24px;
}
@include media-breakpoint-up(lg) {
padding-right: 32px;
padding-left: 32px;
}
@media (min-width: 1280px) {
padding-right: 112px;
padding-left: 112px;
max-width: 1440px;
}
}
&__row {
@include make-row($xrpl-grid-gutter);
}
&__col {
@include make-col-ready();
}
}
// Base (0 - 575px) — 4-column grid
@include xrpl-grid-generate-fill();
@include xrpl-grid-generate-cols(4);
@include xrpl-grid-generate-auto();
@include xrpl-grid-generate-offsets(4);
// Tablet (≥576px) — maintain 8-column grid across sm/md ranges
@include media-breakpoint-up(sm) {
@include xrpl-grid-generate-fill('sm');
@include xrpl-grid-generate-cols(8, 'sm');
@include xrpl-grid-generate-auto('sm');
@include xrpl-grid-generate-offsets(8, 'sm');
}
@include media-breakpoint-up(md) {
@include xrpl-grid-generate-fill('md');
@include xrpl-grid-generate-cols(8, 'md');
@include xrpl-grid-generate-auto('md');
@include xrpl-grid-generate-offsets(8, 'md');
}
// Large (≥992px) — 12-column grid
@include media-breakpoint-up(lg) {
@include xrpl-grid-generate-fill('lg');
@include xrpl-grid-generate-cols(12, 'lg');
@include xrpl-grid-generate-auto('lg');
@include xrpl-grid-generate-offsets(12, 'lg');
}
// XL (≥1280px) — retain 12-column grid with wider margins
@include media-breakpoint-up(xl) {
@include xrpl-grid-generate-fill('xl');
@include xrpl-grid-generate-cols(12, 'xl');
@include xrpl-grid-generate-auto('xl');
@include xrpl-grid-generate-offsets(12, 'xl');
}

View File

@@ -0,0 +1,277 @@
# PageGrid Component
A responsive grid system component for creating flexible layouts with support for multiple breakpoints.
## Overview
The PageGrid component provides a flexible grid layout system with three main components:
- `PageGrid` - The container component
- `PageGrid.Row` - Row component for grouping columns
- `PageGrid.Col` - Column component with responsive sizing and offset support
## Breakpoints
The grid system supports the following breakpoints:
- `base` - Default/mobile (applies to all sizes)
- `sm` - Small screens
- `md` - Medium screens
- `lg` - Large screens
- `xl` - Extra large screens
## Basic Usage
```tsx
import { PageGrid } from '@/shared/components/PageGrid/page-grid';
function MyComponent() {
return (
<PageGrid>
<PageGrid.Row>
<PageGrid.Col span={6}>
Column 1
</PageGrid.Col>
<PageGrid.Col span={6}>
Column 2
</PageGrid.Col>
</PageGrid.Row>
</PageGrid>
);
}
```
## PageGrid Props
The root `PageGrid` component accepts all standard HTML div attributes:
| Prop | Type | Description |
|------|------|-------------|
| `className` | `string` | Additional CSS classes to apply |
| `...rest` | `HTMLDivElement attributes` | Any other HTML div attributes |
## PageGrid.Row Props
The `PageGrid.Row` component accepts all standard HTML div attributes:
| Prop | Type | Description |
|------|------|-------------|
| `className` | `string` | Additional CSS classes to apply |
| `...rest` | `HTMLDivElement attributes` | Any other HTML div attributes |
## PageGrid.Col Props
| Prop | Type | Description |
|------|------|-------------|
| `span` | `number \| "auto" \| "fill" \| ResponsiveValue` | Column span width |
| `offset` | `number \| ResponsiveValue` | Column offset (left margin) |
| `className` | `string` | Additional CSS classes to apply |
| `...rest` | `HTMLDivElement attributes` | Any other HTML div attributes |
### Span Values
- **Number** (e.g., `1-12`): Fixed column width
- **"auto"**: Column takes up only the space it needs
- **"fill"**: Column fills remaining available space
- **Responsive Object**: Different spans for different breakpoints
### Offset Values
- **Number** (e.g., `1-12`): Number of columns to offset
- **Responsive Object**: Different offsets for different breakpoints
## Examples
### Fixed Column Widths
```tsx
<PageGrid>
<PageGrid.Row>
<PageGrid.Col span={4}>Sidebar</PageGrid.Col>
<PageGrid.Col span={8}>Main Content</PageGrid.Col>
</PageGrid.Row>
</PageGrid>
```
### Auto and Fill
```tsx
<PageGrid>
<PageGrid.Row>
<PageGrid.Col span="auto">Minimal Width</PageGrid.Col>
<PageGrid.Col span="fill">Takes Remaining Space</PageGrid.Col>
<PageGrid.Col span="auto">Another Auto</PageGrid.Col>
</PageGrid.Row>
</PageGrid>
```
### Responsive Layout
Create layouts that adapt to different screen sizes:
```tsx
<PageGrid>
<PageGrid.Row>
<PageGrid.Col
span={{
base: 12, // Full width on mobile
sm: 12, // Full width on small screens
md: 6, // Half width on medium screens
lg: 4, // Third width on large screens
xl: 3 // Quarter width on extra large screens
}}
>
Responsive Column
</PageGrid.Col>
</PageGrid.Row>
</PageGrid>
```
### Using Offsets
Center content or create spacing with offsets:
```tsx
<PageGrid>
<PageGrid.Row>
{/* Center an 8-column element */}
<PageGrid.Col span={8} offset={2}>
Centered Content
</PageGrid.Col>
</PageGrid.Row>
</PageGrid>
```
### Responsive Offsets
```tsx
<PageGrid>
<PageGrid.Row>
<PageGrid.Col
span={6}
offset={{
base: 0, // No offset on mobile
md: 3 // Offset by 3 columns on medium+ screens
}}
>
Content
</PageGrid.Col>
</PageGrid.Row>
</PageGrid>
```
### Complex Responsive Layout
```tsx
<PageGrid>
<PageGrid.Row>
{/* Hero section */}
<PageGrid.Col span={12}>
<h1>Page Title</h1>
</PageGrid.Col>
</PageGrid.Row>
<PageGrid.Row>
{/* Sidebar - full width on mobile, 1/3 on desktop */}
<PageGrid.Col
span={{
base: 12,
lg: 4
}}
>
<aside>Sidebar</aside>
</PageGrid.Col>
{/* Main content - full width on mobile, 2/3 on desktop */}
<PageGrid.Col
span={{
base: 12,
lg: 8
}}
>
<main>Main Content</main>
</PageGrid.Col>
</PageGrid.Row>
</PageGrid>
```
### Multiple Columns with Equal Width
```tsx
<PageGrid>
<PageGrid.Row>
<PageGrid.Col span={3}>Column 1</PageGrid.Col>
<PageGrid.Col span={3}>Column 2</PageGrid.Col>
<PageGrid.Col span={3}>Column 3</PageGrid.Col>
<PageGrid.Col span={3}>Column 4</PageGrid.Col>
</PageGrid.Row>
</PageGrid>
```
### Nested Grids
```tsx
<PageGrid>
<PageGrid.Row>
<PageGrid.Col span={12}>
<PageGrid>
<PageGrid.Row>
<PageGrid.Col span={6}>Nested Column 1</PageGrid.Col>
<PageGrid.Col span={6}>Nested Column 2</PageGrid.Col>
</PageGrid.Row>
</PageGrid>
</PageGrid.Col>
</PageGrid.Row>
</PageGrid>
```
## CSS Classes Generated
The component generates the following CSS classes:
### Container
- `xrpl-grid__container`
### Row
- `xrpl-grid__row`
### Column Spans
- `xrpl-grid__col-{number}` (e.g., `xrpl-grid__col-6`)
- `xrpl-grid__col-auto`
- `xrpl-grid__col` (for fill)
- `xrpl-grid__col-{breakpoint}-{number}` (e.g., `xrpl-grid__col-md-6`)
- `xrpl-grid__col-{breakpoint}-auto`
- `xrpl-grid__col-{breakpoint}` (for fill)
### Column Offsets
- `xrpl-grid__offset-{number}` (e.g., `xrpl-grid__offset-2`)
- `xrpl-grid__offset-{breakpoint}-{number}` (e.g., `xrpl-grid__offset-md-2`)
## TypeScript Types
```typescript
type PageGridBreakpoint = "base" | "sm" | "md" | "lg" | "xl";
type ResponsiveValue<T> = T | Partial<Record<PageGridBreakpoint, T>>;
type PageGridSpanValue = number | "auto" | "fill";
type PageGridOffsetValue = number;
interface PageGridColProps {
span?: ResponsiveValue<PageGridSpanValue>;
offset?: ResponsiveValue<PageGridOffsetValue>;
className?: string;
// ... plus all HTMLDivElement attributes
}
```
## Best Practices
1. **Use semantic HTML**: Wrap content in appropriate semantic elements within columns
2. **Mobile-first**: Start with base/mobile layout and progressively enhance for larger screens
3. **Keep it simple**: Avoid overly complex nested grid structures when possible
4. **Test responsiveness**: Verify layouts work well at all breakpoint transitions
5. **Accessibility**: Ensure grid layouts maintain logical reading order for screen readers
## Notes
- The total columns in the grid system is typically 12 (though this depends on your CSS implementation)
- Responsive values cascade - if you don't specify a value for a breakpoint, it inherits from the previous breakpoint
- All components forward refs, allowing you to attach refs to the underlying DOM elements

View File

@@ -2,7 +2,11 @@ import React from "react";
import clsx from "clsx";
type PageGridElementProps = React.HTMLAttributes<HTMLDivElement>;
// Define the standard PageGrid breakpoints
type PageGridBreakpoint = "base" | "sm" | "md" | "lg" | "xl";
// Define the ResponsiveValue type using Partial<Record> for breakpoints
type ResponsiveValue<T> = T | Partial<Record<PageGridBreakpoint, T>>;
export interface PageGridProps extends PageGridElementProps {}
@@ -17,24 +21,50 @@ export interface PageGridColProps extends PageGridElementProps {
offset?: ResponsiveValue<PageGridOffsetValue>;
}
// Keys used for iteration and generating responsive class prefixes
const breakpointKeys: Array<Exclude<PageGridBreakpoint, "base">> = ["sm", "md", "lg", "xl"];
const classForSpan = (prefix: string | null, value: PageGridSpanValue) => {
/**
* Helper function to construct the column span CSS class string.
* This function relies on the corresponding classes being pre-generated in SCSS.
* @param prefix The breakpoint prefix (e.g., 'md' or null for base).
* @param value The span value (number, "auto", or "fill").
* @returns The full CSS class string.
*/
const classForSpan = (prefix: string | null, value: PageGridSpanValue): string => {
const prefixStr = prefix ? `-${prefix}` : "";
if (value === "auto") {
return prefix ? `xrpl-grid__col-${prefix}-auto` : "xrpl-grid__col-auto";
// Generates xrpl-grid__col-auto or xrpl-grid__col-md-auto
return `xrpl-grid__col${prefixStr}-auto`;
}
if (value === "fill") {
return prefix ? `xrpl-grid__col-${prefix}` : "xrpl-grid__col";
// Generates xrpl-grid__col or xrpl-grid__col-md (based on documentation)
// Note: The documentation states 'xrpl-grid__col' for fill, and 'xrpl-grid__col-{breakpoint}' for fill
// The implementation below aligns with the documentation's example logic:
return prefix ? `xrpl-grid__col${prefixStr}` : "xrpl-grid__col";
}
return prefix ? `xrpl-grid__col-${prefix}-${value}` : `xrpl-grid__col-${value}`;
// Generates xrpl-grid__col-6 or xrpl-grid__col-md-6
return `xrpl-grid__col${prefixStr}-${value}`;
};
const classForOffset = (prefix: string | null, value: PageGridOffsetValue) => {
return prefix ? `xrpl-grid__offset-${prefix}-${value}` : `xrpl-grid__offset-${value}`;
/**
* Helper function to construct the column offset CSS class string.
* This function relies on the corresponding classes being pre-generated in SCSS.
* @param prefix The breakpoint prefix (e.g., 'md' or null for base).
* @param value The offset value (number).
* @returns The full CSS class string.
*/
const classForOffset = (prefix: string | null, value: PageGridOffsetValue): string => {
const prefixStr = prefix ? `-${prefix}` : "";
// Generates xrpl-grid__offset-2 or xrpl-grid__offset-md-2
return `xrpl-grid__offset${prefixStr}-${value}`;
};
// --- PageGrid Root Component ---
const PageGridRoot = React.forwardRef<HTMLDivElement, PageGridProps>(
({ className, ...rest }, ref) => (
<div ref={ref} className={clsx("xrpl-grid__container", className)} {...rest} />
@@ -43,59 +73,74 @@ const PageGridRoot = React.forwardRef<HTMLDivElement, PageGridProps>(
PageGridRoot.displayName = "PageGrid";
// --- PageGrid.Row Component ---
const PageGridRow = React.forwardRef<HTMLDivElement, PageGridRowProps>(
({ className, ...rest }, ref) => (
<div ref={ref} className={clsx("xrpl-grid__row", className)} {...rest} />
)
);
PageGridRoot.displayName = "PageGrid";
PageGridRow.displayName = "PageGridRow"; // Renamed display name for clarity
// --- PageGrid.Col Component ---
const PageGridCol = React.forwardRef<HTMLDivElement, PageGridColProps>((props, ref) => {
const { className, span, offset, ...rest } = props;
const spanClasses: string[] = [];
const offsetClasses: string[] = [];
// --- Span Logic ---
if (typeof span === "number" || typeof span === "string") {
// Handles fixed/base span={6} or span="auto"
spanClasses.push(classForSpan(null, span as PageGridSpanValue));
} else if (span && typeof span === "object") {
// Handles base breakpoint (no prefix)
const baseSpan = "base" in span ? span.base : undefined;
if (baseSpan) {
spanClasses.push(classForSpan(null, baseSpan));
}
// Handles sm, md, lg, xl breakpoints (with prefix)
breakpointKeys.forEach((key) => {
const value = span[key];
if (value) {
// Generates classes like xrpl-grid__col-md-6
spanClasses.push(classForSpan(key, value));
}
});
}
// --- Offset Logic ---
if (typeof offset === "number") {
// Handles fixed offset={2}
offsetClasses.push(classForOffset(null, offset));
} else if (offset && typeof offset === "object") {
// Handles base offset (no prefix)
const baseOffset = "base" in offset ? offset.base : undefined;
if (baseOffset !== undefined) {
offsetClasses.push(classForOffset(null, baseOffset));
}
// Handles sm, md, lg, xl offsets (with prefix)
breakpointKeys.forEach((key) => {
const value = offset[key];
if (value !== undefined) {
// Generates classes like xrpl-grid__offset-md-3
offsetClasses.push(classForOffset(key, value));
}
});
}
// Ensure the base class is always applied for styling
return (
<div
ref={ref}
className={clsx("xrpl-grid__col", className, spanClasses, offsetClasses)}
// Note: Added "xrpl-grid__col" base class for consistent column initialization
className={clsx("xrpl-grid__col", className, spanClasses, offsetClasses)}
{...rest}
/>
);
@@ -103,6 +148,8 @@ const PageGridCol = React.forwardRef<HTMLDivElement, PageGridColProps>((props, r
PageGridCol.displayName = "PageGridCol";
// --- Component Composition ---
type PageGridComponent = typeof PageGridRoot & {
Row: typeof PageGridRow;
Col: typeof PageGridCol;

View File

@@ -42,7 +42,7 @@ export const BenefitsSection: React.FC<BenefitsSectionProps> = ({
{cards.map(card => (
<li className="col ls-none" key={card.id}>
{showImages && <img id={card.id} alt={card.title + ' Icon'} />}
<h4 className="sh-md-l">{translate(card.title)}</h4>
<h4 className="sh-md-r">{translate(card.title)}</h4>
<p className="body-l mt-3">
{typeof card.description === 'string' ? translate(card.description) : card.description}
</p>