Files
xrpl-dev-portal/shared/components/TileLogo/TileLogo.tsx
akcodez 354d0c797b Add TileLogo component with showcase and documentation
- Introduced the TileLogo component, designed for displaying brand logos with interactive states.
- Implemented two shape variants (Square and Rectangle) and two color variants (Neutral and Green), with responsive sizing.
- Created a comprehensive showcase page demonstrating all variants, states, and usage examples.
- Added detailed documentation covering usage guidelines, best practices, and API reference.
- Included SCSS styles for the TileLogo component, ensuring compatibility with both light and dark themes.
2026-06-08 16:49:49 -07:00

141 lines
3.5 KiB
TypeScript

import React, { useState } from 'react';
export interface TileLogoProps {
/** Shape variant: 'square' (default) or 'rectangle' */
shape?: 'square' | 'rectangle';
/** Color variant: 'neutral' (default) or 'green' */
variant?: 'neutral' | 'green';
/** Logo image source (URL or path) */
logo: string;
/** Alt text for accessibility */
alt: string;
/** Click handler - renders as <button> */
onClick?: () => void;
/** Link destination - renders as <a> */
href?: string;
/** Disabled state - prevents interaction */
disabled?: boolean;
/** Additional CSS classes */
className?: string;
}
/**
* TileLogo Component
*
* A tile/card component designed to display brand logos with interactive states.
* Supports two shape variants (Square and Rectangle) and two color variants
* (Neutral and Green) with five interaction states (Default, Hover, Focused,
* Pressed, Disabled).
*
* Features a "window shade" hover animation where the hover color wipes from
* bottom to top on mouse enter, and top to bottom on mouse leave.
*
* Shape sizes are responsive and change based on breakpoints:
* - Square: 1:1 aspect ratio with responsive padding
* - Rectangle: Fixed height (96px SM/MD, 160px LG) with responsive padding
*
* @example
* // Basic usage with link (square shape - default)
* <TileLogo
* variant="neutral"
* logo="/logos/partner-logo.svg"
* alt="Partner Name"
* href="/partners/partner-name"
* />
*
* @example
* // Rectangle shape with click handler
* <TileLogo
* shape="rectangle"
* variant="green"
* logo="/logos/featured-logo.svg"
* alt="Featured Partner"
* onClick={() => openPartnerModal('featured')}
* />
*
* @example
* // Disabled state
* <TileLogo
* variant="neutral"
* logo="/logos/coming-soon.svg"
* alt="Coming Soon"
* disabled
* />
*/
export const TileLogo: React.FC<TileLogoProps> = ({
shape = 'square',
variant = 'neutral',
logo,
alt,
onClick,
href,
disabled = false,
className = '',
}) => {
// Track hover state for animation
const [isHovered, setIsHovered] = useState(false);
// Build class names using BEM convention
const classNames = [
'tile-logo',
`tile-logo--${shape}`,
`tile-logo--${variant}`,
disabled ? 'tile-logo--disabled' : '',
isHovered && !disabled ? 'tile-logo--hovered' : '',
className,
]
.filter(Boolean)
.join(' ');
// Hover handlers
const handleMouseEnter = () => !disabled && setIsHovered(true);
const handleMouseLeave = () => setIsHovered(false);
// Common content (overlay + logo image)
const content = (
<>
{/* Hover overlay for window shade animation */}
<div className="tile-logo__overlay" aria-hidden="true" />
<img
src={logo}
alt={alt}
className="tile-logo__image"
aria-hidden="false"
/>
</>
);
// Render as anchor tag when href is provided
if (href && !disabled) {
return (
<a
href={href}
className={classNames}
aria-label={alt}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
{content}
</a>
);
}
// Render as button (for onClick or disabled state)
return (
<button
type="button"
className={classNames}
onClick={onClick}
disabled={disabled}
aria-disabled={disabled}
aria-label={alt}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
{content}
</button>
);
};
export default TileLogo;