mirror of
https://github.com/XRPLF/xrpl-dev-portal.git
synced 2026-04-29 15:37:48 +00:00
317 lines
9.5 KiB
SCSS
317 lines
9.5 KiB
SCSS
// BDS TileLink Component Styles
|
||
// Brand Design System - Tile link component with responsive sizing
|
||
//
|
||
// Naming Convention: BEM with 'bds' namespace
|
||
// .bds-tile-link - Base tile (responsive layout)
|
||
// .bds-tile-link--gray - Gray color variant
|
||
// .bds-tile-link--lilac - Lilac color variant
|
||
// .bds-tile-link--hovered - Hovered state (triggers overlay animation)
|
||
// .bds-tile-link--disabled - Disabled state modifier
|
||
// .bds-tile-link__overlay - Hover gradient overlay (window shade animation)
|
||
// .bds-tile-link__content - Content wrapper (label + arrow)
|
||
// .bds-tile-link__label - Text label
|
||
// .bds-tile-link__arrow - Arrow icon wrapper
|
||
|
||
// =============================================================================
|
||
// Design Tokens
|
||
// =============================================================================
|
||
// Note: Uses centralized spacing tokens from _spacing.scss.
|
||
|
||
// Focus border
|
||
$bds-tile-link-focus-border-color-light: $black;
|
||
$bds-tile-link-focus-border-color-dark: $white;
|
||
$bds-tile-link-focus-border-width: $bds-focus-border-width; // 2px - from _spacing.scss
|
||
|
||
// Animation (matching TileLogo/CardIcon)
|
||
$bds-tile-link-transition-duration: 200ms;
|
||
$bds-tile-link-transition-timing: cubic-bezier(0.98, 0.12, 0.12, 0.98);
|
||
|
||
// -----------------------------------------------------------------------------
|
||
// Responsive Size Tokens
|
||
// -----------------------------------------------------------------------------
|
||
|
||
// SM breakpoint (mobile - default)
|
||
$bds-tile-link-height-base: $bds-space-6xl; // 64px - spacing('6xl')
|
||
$bds-tile-link-padding-sm: $bds-space-md; // 12px - spacing('md')
|
||
$bds-tile-link-font-size-sm: 16px;
|
||
$bds-tile-link-line-height-sm: 26.1px;
|
||
|
||
// MD breakpoint (tablet)
|
||
$bds-tile-link-padding-md: $bds-space-lg; // 16px - spacing('lg')
|
||
$bds-tile-link-font-size-md: 16px;
|
||
$bds-tile-link-line-height-md: 26.1px;
|
||
|
||
// LG breakpoint (desktop)
|
||
$bds-tile-link-padding-lg: $bds-space-xl; // 20px - spacing('xl')
|
||
$bds-tile-link-font-size-lg: 18px;
|
||
$bds-tile-link-line-height-lg: 26.1px;
|
||
|
||
// =============================================================================
|
||
// Color Variants Map
|
||
// =============================================================================
|
||
// Structure: variant-name: (light-bg, light-hover, light-pressed, light-text, dark-bg, dark-hover, dark-pressed, dark-text)
|
||
|
||
$bds-tile-link-variants: (
|
||
'gray': (
|
||
light-bg: $gray-200, // #E6EAF0
|
||
light-hover: $gray-300, // #CAD4DF
|
||
light-pressed: $gray-400, // #A8B4C4
|
||
light-text: $black, // #141414
|
||
dark-bg: $gray-500, // #72777E
|
||
dark-hover: $gray-400, // #8A919A
|
||
dark-pressed: $gray-500-pressed-dark, // #72777E + 70% black → #56595E
|
||
dark-text: $white // #FFFFFF
|
||
),
|
||
'lilac': (
|
||
light-bg: $lilac-100, // Light mode background
|
||
light-hover: $lilac-200, // Light mode hover
|
||
light-pressed: $lilac-300, // Light mode pressed
|
||
light-text: $black, // Light mode text
|
||
dark-bg: $lilac-100, // Dark mode background (same as light)
|
||
dark-hover: $lilac-200, // Dark mode hover (same as light)
|
||
dark-pressed: $lilac-300, // Dark mode pressed (same as light)
|
||
dark-text: $black // Dark mode text (same as light)
|
||
)
|
||
);
|
||
|
||
// =============================================================================
|
||
// Base Tile Styles
|
||
// =============================================================================
|
||
|
||
.bds-tile-link {
|
||
// Reset button/anchor styles
|
||
appearance: none;
|
||
border: none;
|
||
background: none;
|
||
margin: 0;
|
||
font: inherit;
|
||
color: inherit;
|
||
text-decoration: none;
|
||
text-align: left;
|
||
|
||
// Layout
|
||
position: relative;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
overflow: hidden;
|
||
box-sizing: border-box;
|
||
width: 100%;
|
||
|
||
// Responsive sizing - SM (mobile-first)
|
||
height: $bds-tile-link-height-base;
|
||
padding: $bds-tile-link-padding-sm;
|
||
|
||
@media (min-width: map-get($grid-breakpoints, md)) {
|
||
padding: $bds-tile-link-padding-md;
|
||
}
|
||
|
||
@media (min-width: map-get($grid-breakpoints, lg)) {
|
||
padding: $bds-tile-link-padding-lg;
|
||
}
|
||
|
||
// Interaction
|
||
cursor: pointer;
|
||
|
||
// Transitions
|
||
transition:
|
||
background-color $bds-tile-link-transition-duration $bds-tile-link-transition-timing,
|
||
opacity $bds-tile-link-transition-duration $bds-tile-link-transition-timing;
|
||
|
||
// Hover styles - prevent text underline
|
||
&:hover {
|
||
text-decoration: none;
|
||
}
|
||
|
||
// Focus styles (light mode default)
|
||
&:focus {
|
||
outline: $bds-tile-link-focus-border-width solid $bds-tile-link-focus-border-color-light;
|
||
outline-offset: 1px;
|
||
}
|
||
|
||
&:focus:not(:focus-visible) {
|
||
outline: none;
|
||
}
|
||
|
||
&:focus-visible {
|
||
outline: $bds-tile-link-focus-border-width solid $bds-tile-link-focus-border-color-light;
|
||
outline-offset: 2px;
|
||
}
|
||
|
||
// Dark mode focus styles
|
||
@include bds-theme-mode(dark) {
|
||
&:focus {
|
||
outline-color: $bds-tile-link-focus-border-color-dark;
|
||
}
|
||
|
||
&:focus-visible {
|
||
outline-color: $bds-tile-link-focus-border-color-dark;
|
||
}
|
||
}
|
||
}
|
||
|
||
// =============================================================================
|
||
// Overlay (Color wipe animation - "Window Shade" effect)
|
||
// =============================================================================
|
||
|
||
.bds-tile-link__overlay {
|
||
position: absolute;
|
||
inset: 0;
|
||
pointer-events: none;
|
||
z-index: 0;
|
||
|
||
// Default: hidden (shade is "rolled up" at bottom)
|
||
clip-path: inset(100% 0 0 0);
|
||
transition: clip-path $bds-tile-link-transition-duration $bds-tile-link-transition-timing;
|
||
}
|
||
|
||
// Hovered state: shade fully raised (visible)
|
||
.bds-tile-link--hovered .bds-tile-link__overlay {
|
||
clip-path: inset(0 0 0 0);
|
||
}
|
||
|
||
// Keyboard focus: same overlay color as hover (gray/lilac × light/dark set on .bds-tile-link__overlay above)
|
||
.bds-tile-link:focus-visible:not(.bds-tile-link--disabled) .bds-tile-link__overlay {
|
||
clip-path: inset(0 0 0 0);
|
||
}
|
||
|
||
// =============================================================================
|
||
// Content Wrapper
|
||
// =============================================================================
|
||
|
||
.bds-tile-link__content {
|
||
position: relative;
|
||
z-index: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
width: 100%;
|
||
}
|
||
|
||
.bds-tile-link__arrow {
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
// Arrow animation on hover - works for both <a> and <button> elements
|
||
.bds-tile-link:hover .bds-tile-link__arrow .bds-link-icon--internal:not(.bds-link-icon--disabled) svg .arrow-horizontal,
|
||
.bds-tile-link:focus .bds-tile-link__arrow .bds-link-icon--internal:not(.bds-link-icon--disabled) svg .arrow-horizontal,
|
||
.bds-tile-link--hovered .bds-tile-link__arrow .bds-link-icon--internal:not(.bds-link-icon--disabled) svg .arrow-horizontal {
|
||
transform: scaleX(0);
|
||
}
|
||
|
||
// =============================================================================
|
||
// Color Variants (Light Mode - Default)
|
||
// =============================================================================
|
||
|
||
@each $variant-name, $variant-colors in $bds-tile-link-variants {
|
||
.bds-tile-link--#{$variant-name} {
|
||
background-color: map-get($variant-colors, light-bg);
|
||
|
||
.bds-tile-link__label,
|
||
.bds-tile-link__arrow {
|
||
color: map-get($variant-colors, light-text);
|
||
}
|
||
|
||
// Overlay color for hover wipe
|
||
.bds-tile-link__overlay {
|
||
background-color: map-get($variant-colors, light-hover);
|
||
}
|
||
|
||
// Pressed state
|
||
&:active:not(.bds-tile-link--disabled) {
|
||
.bds-tile-link__overlay {
|
||
background-color: map-get($variant-colors, light-pressed);
|
||
clip-path: inset(0 0 0 0);
|
||
}
|
||
}
|
||
|
||
// Dark mode overrides
|
||
@include bds-theme-mode(dark) {
|
||
background-color: map-get($variant-colors, dark-bg);
|
||
|
||
.bds-tile-link__label,
|
||
.bds-tile-link__arrow {
|
||
color: map-get($variant-colors, dark-text);
|
||
}
|
||
|
||
// Overlay color for hover wipe
|
||
.bds-tile-link__overlay {
|
||
background-color: map-get($variant-colors, dark-hover);
|
||
}
|
||
|
||
// Pressed state
|
||
&:active:not(.bds-tile-link--disabled) {
|
||
.bds-tile-link__overlay {
|
||
background-color: map-get($variant-colors, dark-pressed);
|
||
clip-path: inset(0 0 0 0);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// =============================================================================
|
||
// Disabled State
|
||
// =============================================================================
|
||
|
||
.bds-tile-link--disabled {
|
||
cursor: not-allowed;
|
||
pointer-events: none;
|
||
|
||
&:focus,
|
||
&:focus-visible {
|
||
outline: none;
|
||
}
|
||
|
||
// Light mode disabled (default)
|
||
&.bds-tile-link--gray {
|
||
background-color: $gray-100;
|
||
|
||
.bds-tile-link__label,
|
||
.bds-tile-link__arrow {
|
||
color: $gray-400;
|
||
}
|
||
}
|
||
|
||
&.bds-tile-link--lilac {
|
||
background-color: $lilac-100;
|
||
|
||
.bds-tile-link__label,
|
||
.bds-tile-link__arrow {
|
||
color: $gray-400;
|
||
}
|
||
}
|
||
|
||
// Dark mode disabled - 30% opacity
|
||
@include bds-theme-mode(dark) {
|
||
opacity: 0.3;
|
||
|
||
&.bds-tile-link--gray {
|
||
background-color: $gray-500;
|
||
|
||
.bds-tile-link__label,
|
||
.bds-tile-link__arrow {
|
||
color: $white;
|
||
}
|
||
}
|
||
|
||
&.bds-tile-link--lilac {
|
||
background-color: $lilac-400;
|
||
|
||
.bds-tile-link__label,
|
||
.bds-tile-link__arrow {
|
||
color: $white;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// =============================================================================
|
||
// Tablet + mobile: no clip-path transition (instant overlay show/hide)
|
||
// =============================================================================
|
||
@media (max-width: 991px) {
|
||
.bds-tile-link__overlay {
|
||
transition: none;
|
||
}
|
||
}
|