fixing button spacing + image background

This commit is contained in:
Calvin Jhunjhuwala
2026-01-09 15:29:22 -08:00
committed by akcodez
parent 0d0fc38344
commit 1fcc294ffb
6 changed files with 190 additions and 51 deletions

View File

@@ -14,8 +14,11 @@ export default function CalloutMediaBannerShowcase() {
console.log(`CalloutMediaBanner button clicked: ${message}`);
};
// Sample background image (placeholder)
const sampleBackgroundImage = "data:image/svg+xml,%3Csvg width='1280' height='400' xmlns='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3ClinearGradient id='grad' x1='0%25' y1='0%25' x2='100%25' y2='100%25'%3E%3Cstop offset='0%25' style='stop-color:%2321E46B;stop-opacity:1' /%3E%3Cstop offset='100%25' style='stop-color:%230DAA3E;stop-opacity:1' /%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='1280' height='400' fill='url(%23grad)' /%3E%3C/svg%3E";
// Sample background images (placeholders)
// To load an image from the `public` folder in Next.js (or Create React App), use the path relative to the `public` directory, starting with a slash.
// For example, if you have `/public/backgrounds/Callout.jpg`, use:
const sampleBackgroundImage = "/img/backgrounds/Callout.jpg";
const sampleLightBackgroundImage = "data:image/svg+xml,%3Csvg width='1280' height='400' xmlns='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3ClinearGradient id='grad' x1='0%25' y1='0%25' x2='100%25' y2='100%25'%3E%3Cstop offset='0%25' style='stop-color:%2370EE97;stop-opacity:1' /%3E%3Cstop offset='100%25' style='stop-color:%23C0A7FF;stop-opacity:1' /%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='1280' height='400' fill='url(%23grad)' /%3E%3C/svg%3E";
return (
<div className="landing">
@@ -218,6 +221,7 @@ export default function CalloutMediaBannerShowcase() {
<p className="mb-4">
When <code>backgroundImage</code> is provided, it overrides the <code>variant</code> prop.
The component automatically adds a gradient overlay to ensure text remains readable.
You can also specify <code>textColor</code> to fix the text color across both light and dark modes.
</p>
<div className="p-4 mb-6" style={{ backgroundColor: 'rgba(114, 119, 126, 0.1)', borderRadius: '8px' }}>
@@ -226,26 +230,63 @@ export default function CalloutMediaBannerShowcase() {
<li><strong>If backgroundImage is provided:</strong> Image is used, variant color is ignored</li>
<li><strong>If only variant is provided:</strong> Solid color background is applied</li>
<li><strong>If neither:</strong> Defaults to white background (default variant)</li>
<li><strong>Text color:</strong> Always white when using background image for readability</li>
<li><strong>Text color:</strong> Defaults to white, or set to black via <code>textColor="black"</code></li>
<li><strong>Fixed text color:</strong> Text color remains consistent across light and dark modes</li>
<li><strong>Overlay gradient:</strong> Dark overlay for white text, light overlay for black text</li>
</ul>
</div>
</PageGridCol>
</PageGridRow>
</PageGrid>
<CalloutMediaBanner
backgroundImage={sampleBackgroundImage}
heading="Build the Future of Finance"
subheading="Create powerful decentralized applications with XRPL's fast, efficient, and sustainable blockchain technology."
primaryButton={{ label: "Start Building", onClick: () => handleClick('image-primary') }}
tertiaryButton={{ label: "Explore Features", onClick: () => handleClick('image-tertiary') }}
/>
{/* White Text Example */}
<div className="mb-5">
<PageGrid>
<PageGridRow>
<PageGridCol span={12}>
<div className="mb-3">
<strong>White Text (Default)</strong> - <code>textColor="white"</code>
<br />
<small className="text-muted">Best for dark or colorful images. Includes dark overlay gradient.</small>
</div>
</PageGridCol>
</PageGridRow>
</PageGrid>
<CalloutMediaBanner
backgroundImage={sampleBackgroundImage}
subheading="A decentralized public Layer 1 blockchain for creating, transferring, and exchanging digital assets with a focus on compliance."
primaryButton={{ label: "Start Building", onClick: () => handleClick('image-white-primary') }}
/>
</div>
{/* Black Text Example */}
<div className="mb-5">
<PageGrid>
<PageGridRow>
<PageGridCol span={12}>
<div className="mb-3">
<strong>Black Text</strong> - <code>textColor="black"</code>
<br />
<small className="text-muted">Best for light or bright images. Includes light overlay gradient. Text remains black in both light and dark modes.</small>
</div>
</PageGridCol>
</PageGridRow>
</PageGrid>
<CalloutMediaBanner
backgroundImage={sampleLightBackgroundImage}
textColor="black"
heading="Build the Future of Finance"
subheading="Create powerful decentralized applications with XRPL's fast, efficient, and sustainable blockchain technology."
primaryButton={{ label: "Start Building", onClick: () => handleClick('image-black-primary') }}
tertiaryButton={{ label: "Explore Features", onClick: () => handleClick('image-black-tertiary') }}
/>
</div>
<PageGrid className="mb-5">
<PageGridRow>
<PageGridCol span={12}>
<p className="text-muted small">
<em>Note: The image variant includes an automatic gradient overlay (dark to light) to maintain text legibility.</em>
<em>Note: The image variant includes an automatic gradient overlay. White text gets a dark overlay, black text gets a light overlay. Text colors remain fixed across both light and dark modes.</em>
</p>
</PageGridCol>
</PageGridRow>
@@ -499,6 +540,14 @@ export default function CalloutMediaBannerShowcase() {
<div style={{ flex: '1 1 0', minWidth: 0 }}>Background image URL - overrides variant color</div>
</div>
{/* textColor */}
<div className="d-flex flex-row py-3" style={{ gap: '1rem', borderBottom: '1px solid var(--bs-border-color, #dee2e6)' }}>
<div style={{ width: '140px', flexShrink: 0 }}><code>textColor</code></div>
<div style={{ flex: '1 1 0', minWidth: 0 }}><code>'white' | 'black'</code></div>
<div style={{ width: '120px', flexShrink: 0 }}><code>'white'</code></div>
<div style={{ flex: '1 1 0', minWidth: 0 }}>Text color for image variant - fixed across light/dark modes (only used when backgroundImage is provided)</div>
</div>
{/* heading */}
<div className="d-flex flex-row py-3" style={{ gap: '1rem', borderBottom: '1px solid var(--bs-border-color, #dee2e6)' }}>
<div style={{ width: '140px', flexShrink: 0 }}><code>heading</code></div>

View File

@@ -8,7 +8,8 @@
// .bds-callout-media-banner--lilac - Lilac variant
// .bds-callout-media-banner--green - Green variant
// .bds-callout-media-banner--gray - Gray variant
// .bds-callout-media-banner--image - Background image variant
// .bds-callout-media-banner--image - Background image variant (white text by default)
// .bds-callout-media-banner--image-text-black - Image variant with black text (fixed across light/dark)
// .bds-callout-media-banner--centered - Centered content modifier (no buttons or no heading)
// .bds-callout-media-banner__content - Content wrapper
// .bds-callout-media-banner__text - Text content container
@@ -83,7 +84,7 @@ $bds-cmb-image-overlay: rgba(0, 0, 0, 0.3);
}
// Desktop breakpoint
@include media-breakpoint-up(xl) {
@include media-breakpoint-up(lg) {
padding: $bds-cmb-padding-desktop;
min-height: 360px;
}
@@ -152,7 +153,7 @@ $bds-cmb-image-overlay: rgba(0, 0, 0, 0.3);
// Typography - Heading MD token (Tobias Light)
@include type(heading-md);
margin: 0;
color: inherit;
color: inherit !important;
}
.bds-callout-media-banner__subheading {
@@ -164,14 +165,20 @@ $bds-cmb-image-overlay: rgba(0, 0, 0, 0.3);
// =============================================================================
// Action Buttons
// =============================================================================
// ==================================================================== c=========
.bds-callout-media-banner__actions {
display: flex;
flex-direction: row;
align-items: center;
gap: $bds-cmb-button-gap;
flex-direction: column;
align-items: flex-start;
flex-wrap: wrap;
gap: 8px;
// Tablet breakpoint
@include media-breakpoint-up(md) {
flex-direction: row;
align-items: center;
gap: 0px;
}
}
// =============================================================================
@@ -212,7 +219,7 @@ $bds-cmb-image-overlay: rgba(0, 0, 0, 0.3);
// No background-color (image takes precedence)
background-color: transparent;
// Add overlay gradient for text readability
// Add overlay gradient for text readability (default: dark overlay for white text)
&::before {
content: '';
position: absolute;
@@ -229,10 +236,24 @@ $bds-cmb-image-overlay: rgba(0, 0, 0, 0.3);
z-index: 0;
pointer-events: none;
}
}
// Image variant with black text modifier
// Fixed black text across both light and dark modes
.bds-callout-media-banner--image-text-black {
// Light overlay for black text readability
&::before {
background: linear-gradient(
135deg,
rgba(255, 255, 255, 0.4) 0%,
rgba(255, 255, 255, 0.2) 50%,
rgba(255, 255, 255, 0.1) 100%
);
}
// Ensure text is readable over image
// Force black text in both light and dark modes
.bds-callout-media-banner__text {
color: $white;
color: $black !important;
}
}
@@ -286,12 +307,19 @@ html.dark {
}
}
// Image variant remains the same (overlay already provides contrast)
// Image variant with white text remains white
.bds-callout-media-banner--image {
.bds-callout-media-banner__text {
color: $white;
}
}
// Image variant with black text remains black (fixed across modes)
.bds-callout-media-banner--image-text-black {
.bds-callout-media-banner__text {
color: $black !important;
}
}
}
// =============================================================================
@@ -344,11 +372,18 @@ html.light {
}
}
// Image variant
// Image variant with white text remains white
.bds-callout-media-banner--image {
.bds-callout-media-banner__text {
color: $white;
}
}
// Image variant with black text remains black (fixed across modes)
.bds-callout-media-banner--image-text-black {
.bds-callout-media-banner__text {
color: $black !important;
}
}
}

View File

@@ -8,6 +8,8 @@ export interface CalloutMediaBannerProps {
variant?: 'default' | 'light-gray' | 'lilac' | 'green' | 'gray';
/** Background image URL - overrides variant color when provided */
backgroundImage?: string;
/** Text color for image variant - fixes text color across light/dark modes (only applicable when backgroundImage is provided) */
textColor?: 'white' | 'black';
/** Main heading text */
heading?: string;
/** Subheading/description text */
@@ -45,17 +47,28 @@ export interface CalloutMediaBannerProps {
* />
*
* @example
* // With background image
* // With background image (white text - default)
* <CalloutMediaBanner
* backgroundImage="/images/hero-bg.jpg"
* heading="Build on XRPL"
* subheading="Start building your next project"
* primaryButton={{ label: "Start Building", onClick: handleClick }}
* />
*
* @example
* // With background image and black text (fixed across light/dark modes)
* <CalloutMediaBanner
* backgroundImage="/images/light-hero-bg.jpg"
* textColor="black"
* heading="Build on XRPL"
* subheading="Start building your next project"
* primaryButton={{ label: "Start Building", onClick: handleClick }}
* />
*/
export const CalloutMediaBanner: React.FC<CalloutMediaBannerProps> = ({
variant = 'default',
backgroundImage,
textColor = 'white',
heading,
subheading,
primaryButton,
@@ -79,6 +92,8 @@ export const CalloutMediaBanner: React.FC<CalloutMediaBannerProps> = ({
!backgroundImage && `bds-callout-media-banner--${variant}`,
// Add image class when backgroundImage is provided
backgroundImage && 'bds-callout-media-banner--image',
// Add text color modifier for image variant
backgroundImage && textColor === 'black' && 'bds-callout-media-banner--image-text-black',
// Add centered class when content should be centered
shouldCenter && 'bds-callout-media-banner--centered',
className

View File

@@ -34,7 +34,8 @@ The component automatically adapts its spacing and typography based on viewport
| `lilac` | Lilac 300 (#C0A7FF) | Black (#141414) | Black |
| `green` | Green 200 (#70EE97) | Black (#141414) | Black |
| `gray` | Gray 300 (#CAD4DF) | Black (#141414) | Black |
| `image` | Background Image | White (#FFFFFF) | Green |
| `image` (textColor='white') | Background Image | White (#FFFFFF) | Green |
| `image` (textColor='black') | Background Image | Black (#141414) | Green |
### Dark Mode
@@ -45,7 +46,8 @@ The component automatically adapts its spacing and typography based on viewport
| `lilac` | Lilac 400 (#7649E3) | White (#FFFFFF) | Black |
| `green` | Green 300 (#21E46B) | Black (#141414) | Black |
| `gray` | Gray 600 (#454549) | White (#FFFFFF) | Black |
| `image` | Background Image | White (#FFFFFF) | Green |
| `image` (textColor='white') | Background Image | White (#FFFFFF) | Green |
| `image` (textColor='black') | Background Image | Black (#141414) | Green |
## Props API
@@ -55,6 +57,8 @@ interface CalloutMediaBannerProps {
variant?: 'default' | 'light-gray' | 'lilac' | 'green' | 'gray';
/** Background image URL - overrides variant color when provided */
backgroundImage?: string;
/** Text color for image variant - fixes text color across light/dark modes (only applicable when backgroundImage is provided) */
textColor?: 'white' | 'black';
/** Main heading text */
heading?: string;
/** Subheading/description text */
@@ -80,6 +84,7 @@ interface CalloutMediaBannerProps {
- `variant`: `'default'`
- `backgroundImage`: `undefined`
- `textColor`: `'white'` (only used when `backgroundImage` is provided)
- `primaryButton`: `undefined`
- `tertiaryButton`: `undefined`
- `className`: `''`
@@ -100,7 +105,7 @@ import { CalloutMediaBanner } from 'shared/patterns/CalloutMediaBanner';
/>
```
### With Background Image
### With Background Image (White Text - Default)
```tsx
<CalloutMediaBanner
@@ -111,6 +116,18 @@ import { CalloutMediaBanner } from 'shared/patterns/CalloutMediaBanner';
/>
```
### With Background Image (Black Text)
```tsx
<CalloutMediaBanner
backgroundImage="/images/light-hero-bg.jpg"
textColor="black"
heading="Build on XRPL"
subheading="Start building your next project on the XRP Ledger with black text that remains consistent across light and dark modes."
primaryButton={{ label: "Start Building", onClick: handleClick }}
/>
```
### Single Button
```tsx
@@ -154,8 +171,9 @@ import { CalloutMediaBanner } from 'shared/patterns/CalloutMediaBanner';
When `backgroundImage` is provided, it **overrides** the `variant` prop:
- Image is used as background
- No solid color background is applied
- Text color is always white for readability
- Gradient overlay is automatically added
- Text color defaults to white (can be set to black via `textColor` prop)
- Text color remains fixed across both light and dark modes
- Gradient overlay is automatically added (dark overlay for white text, light overlay for black text)
### Button Color Logic
@@ -194,19 +212,20 @@ The component **already wraps content in PageGrid structure**. Do not nest it in
### BEM Class Structure
```scss
.bds-callout-media-banner // Base banner
.bds-callout-media-banner--default // White background variant
.bds-callout-media-banner--light-gray // Light gray variant
.bds-callout-media-banner--lilac // Lilac variant
.bds-callout-media-banner--green // Green variant
.bds-callout-media-banner--gray // Gray variant
.bds-callout-media-banner--image // Background image variant
.bds-callout-media-banner--no-actions // No buttons modifier
.bds-callout-media-banner__content // Content wrapper
.bds-callout-media-banner__text // Text container
.bds-callout-media-banner__heading // Heading element
.bds-callout-media-banner__subheading // Subheading element
.bds-callout-media-banner__actions // Button container
.bds-callout-media-banner // Base banner
.bds-callout-media-banner--default // White background variant
.bds-callout-media-banner--light-gray // Light gray variant
.bds-callout-media-banner--lilac // Lilac variant
.bds-callout-media-banner--green // Green variant
.bds-callout-media-banner--gray // Gray variant
.bds-callout-media-banner--image // Background image variant (white text)
.bds-callout-media-banner--image-text-black // Background image with black text (fixed across modes)
.bds-callout-media-banner--centered // Centered content modifier
.bds-callout-media-banner__content // Content wrapper
.bds-callout-media-banner__text // Text container
.bds-callout-media-banner__heading // Heading element
.bds-callout-media-banner__subheading // Subheading element
.bds-callout-media-banner__actions // Button container
```
### Typography Tokens
@@ -271,8 +290,12 @@ $gray-600 // Gray (dark)
- Minimum recommended resolution: 1920x600px for sharp display
- Use images with clear focal points on the left/center
- Ensure sufficient contrast for white text readability
- Test with the automatic gradient overlay
- **Text Color Selection**:
- Use `textColor="white"` (default) for dark or colorful images
- Use `textColor="black"` for light or bright images
- Text color remains fixed across both light and dark modes
- Ensure sufficient contrast between image and text
- Test with the automatic gradient overlay (dark for white text, light for black text)
## Files

View File

@@ -16903,7 +16903,7 @@ html.light .bds-hero-split-media--accent .bds-hero-split-media__subtitle {
padding: 24px;
}
}
@media (min-width: 1280px) {
@media (min-width: 992px) {
.bds-callout-media-banner {
padding: 40px 32px;
min-height: 360px;
@@ -16978,7 +16978,7 @@ html.light .bds-hero-split-media--accent .bds-hero-split-media__subtitle {
}
.bds-callout-media-banner__heading {
margin: 0;
color: inherit;
color: inherit !important;
}
.bds-callout-media-banner__subheading {
@@ -17012,10 +17012,17 @@ html.light .bds-hero-split-media--accent .bds-hero-split-media__subtitle {
.bds-callout-media-banner__actions {
display: flex;
flex-direction: row;
align-items: center;
gap: 24px;
flex-direction: column;
align-items: flex-start;
flex-wrap: wrap;
gap: 8px;
}
@media (min-width: 576px) {
.bds-callout-media-banner__actions {
flex-direction: row;
align-items: center;
gap: 0px;
}
}
.bds-callout-media-banner--default {
@@ -17052,8 +17059,12 @@ html.light .bds-hero-split-media--accent .bds-hero-split-media__subtitle {
z-index: 0;
pointer-events: none;
}
.bds-callout-media-banner--image .bds-callout-media-banner__text {
color: #FFFFFF;
.bds-callout-media-banner--image-text-black::before {
background: linear-gradient(135deg, rgba(255, 255, 255, 0.4) 0%, rgba(255, 255, 255, 0.2) 50%, rgba(255, 255, 255, 0.1) 100%);
}
.bds-callout-media-banner--image-text-black .bds-callout-media-banner__text {
color: #141414 !important;
}
html.dark .bds-callout-media-banner--default {
@@ -17089,6 +17100,9 @@ html.dark .bds-callout-media-banner--gray .bds-callout-media-banner__text {
html.dark .bds-callout-media-banner--image .bds-callout-media-banner__text {
color: #FFFFFF;
}
html.dark .bds-callout-media-banner--image-text-black .bds-callout-media-banner__text {
color: #141414 !important;
}
html.light .bds-callout-media-banner--default {
background-color: #FFFFFF;
@@ -17123,6 +17137,9 @@ html.light .bds-callout-media-banner--gray .bds-callout-media-banner__text {
html.light .bds-callout-media-banner--image .bds-callout-media-banner__text {
color: #FFFFFF;
}
html.light .bds-callout-media-banner--image-text-black .bds-callout-media-banner__text {
color: #141414 !important;
}
pre {
color: #FFFFFF;

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB