/** * Entity Selector Mixins * Reusable patterns - prefer Bootstrap utilities in HTML where possible */ @use "sass:color"; @use 'variables' as *; // ============================================================================= // Layout // ============================================================================= @mixin flex-center { display: flex; align-items: center; justify-content: center; } @mixin flex-between { display: flex; align-items: center; justify-content: space-between; } @mixin grid-columns($cols) { display: grid; grid-template-columns: repeat($cols, 1fr); gap: $es-spacing-sm; } // ============================================================================= // Text // ============================================================================= @mixin text-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } // ============================================================================= // Interactive Elements // ============================================================================= // Reset button styles @mixin button-reset { padding: 0; margin: 0; background: none; border: none; cursor: pointer; font: inherit; color: inherit; &:focus { outline: none; } } // Focus ring (Bootstrap 4 style) @mixin focus-ring($color: $es-primary) { outline: 0; box-shadow: 0 0 0 0.2rem rgba($color, 0.25); } // Interactive hover state @mixin interactive-item { cursor: pointer; transition: background-color $es-transition-fast, color $es-transition-fast; &:hover { background-color: $es-bg-hover; } } // ============================================================================= // Cards & Containers // ============================================================================= @mixin card { background: $es-white; border: 1px solid $es-border-color; border-radius: $es-radius-lg; } @mixin dropdown-container { position: absolute; z-index: $es-z-dropdown; background: $es-white; border: 1px solid $es-border-color; border-radius: $es-radius-lg; box-shadow: $es-shadow-lg; } // ============================================================================= // Form Elements // ============================================================================= // Reset input styles (for inputs in custom wrappers) @mixin input-reset { padding: 0; margin: 0; background: none; border: none; font: inherit; color: inherit; &:focus { outline: none; } } @mixin input-base { width: 100%; padding: $es-spacing-sm $es-spacing-md; font-size: $es-font-size-sm; line-height: $es-line-height-normal; color: $es-text-primary; background-color: $es-white; border: 1px solid $es-border-color; border-radius: $es-radius-md; transition: border-color $es-transition-fast, box-shadow $es-transition-fast; &:focus { border-color: $es-primary; @include focus-ring($es-primary); } &::placeholder { color: $es-text-light; } } // ============================================================================= // Scrollbar // ============================================================================= @mixin custom-scrollbar { &::-webkit-scrollbar { width: 6px; height: 6px; } &::-webkit-scrollbar-track { background: $es-gray-100; border-radius: 3px; } &::-webkit-scrollbar-thumb { background: $es-gray-300; border-radius: 3px; &:hover { background: $es-gray-400; } } } // ============================================================================= // Badges & Chips // ============================================================================= @mixin badge($bg: $es-gray-200, $color: $es-gray-700) { display: inline-flex; align-items: center; justify-content: center; padding: 0.125rem 0.5rem; font-size: $es-font-size-xs; font-weight: $es-font-weight-medium; line-height: 1; background-color: $bg; color: $color; border-radius: $es-radius-full; } // Count badge with preview icon (used for tab badges, match counts, totals) // Note: Eye icon is provided in HTML via @mixin count-badge($bg: $es-primary) { display: inline-flex; align-items: center; justify-content: center; gap: 0.25rem; min-width: 20px; height: 20px; padding: 0 0.5rem; background: $bg; color: $es-white; font-size: $es-font-size-xs; font-weight: $es-font-weight-semibold; border-radius: $es-radius-full; cursor: pointer; transition: all $es-transition-fast; flex-shrink: 0; &:hover { transform: scale(1.05); box-shadow: 0 2px 8px rgba($bg, 0.4); } // Focus state - maintain styled appearance &:focus { outline: none; box-shadow: 0 0 0 2px rgba($bg, 0.3), 0 2px 8px rgba($bg, 0.4); } // Loading state - spinner icon replaces eye &.loading { cursor: wait; i { font-size: 10px; animation: spin 0.6s linear infinite; } &:hover { transform: none; box-shadow: none; } } // Inactive/empty state &.inactive, &.no-matches { background: $es-slate-400; cursor: default; &:hover { transform: none; box-shadow: none; } } // Popover open state &.popover-open { background: color.adjust($bg, $lightness: -10%); box-shadow: 0 2px 8px rgba($bg, 0.4); } // Icon inside badge (eye, spinner, etc.) i { font-size: 10px; line-height: 1; opacity: 0.8; } &:hover i { opacity: 1; } .preview-count { font-weight: $es-font-weight-bold; } } @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } @mixin chip { display: inline-flex; align-items: center; gap: $es-spacing-xs; padding: $es-spacing-xs $es-spacing-sm; font-size: $es-font-size-xs; font-weight: $es-font-weight-medium; background: $es-gray-200; color: $es-gray-700; border-radius: $es-radius-full; .chip-remove { @include button-reset; @include flex-center; width: 14px; height: 14px; font-size: 10px; color: $es-text-muted; border-radius: 50%; &:hover { background: rgba(0, 0, 0, 0.1); color: $es-danger; } } } // ============================================================================= // Toggle Switch // ============================================================================= @mixin toggle-switch($width: 36px, $height: 20px) { position: relative; width: $width; height: $height; border-radius: $height; background: $es-gray-400; transition: background-color $es-transition-normal; cursor: pointer; &::after { content: ''; position: absolute; top: 2px; left: 2px; width: $height - 4px; height: $height - 4px; background: $es-white; border-radius: 50%; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); transition: transform $es-transition-normal; } &.active { background: $es-success; &::after { transform: translateX($width - $height); } } } // ============================================================================= // Screen Reader Only // ============================================================================= @mixin sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }