170 lines
5.7 KiB
SCSS
170 lines
5.7 KiB
SCSS
// ============================================================================
|
|
// OpenClaw Control Center — Utility Mixins
|
|
// ============================================================================
|
|
// Reusable patterns that enforce design-system consistency.
|
|
// Components should @use this module and include mixins rather than
|
|
// writing repetitive CSS blocks.
|
|
// ============================================================================
|
|
|
|
@use 'tokens' as *;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Elevation / Surface Card
|
|
// Applies consistent card styling using design tokens.
|
|
// Usage: @include utils.card-surface();
|
|
// ---------------------------------------------------------------------------
|
|
@mixin card-surface($elevation: 1) {
|
|
background-color: var(--cc-surface-medium);
|
|
border-radius: var(--cc-card-radius);
|
|
border: 1px solid var(--cc-surface-lighter);
|
|
box-shadow: var(--cc-shadow-#{$elevation});
|
|
transition: box-shadow var(--cc-duration-short) var(--cc-easing-standard);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Elevated card on hover
|
|
// ---------------------------------------------------------------------------
|
|
@mixin card-hover($elevation: 2) {
|
|
&:hover {
|
|
box-shadow: var(--cc-shadow-#{$elevation});
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Status-aware left border
|
|
// Applies colored left border based on agent status.
|
|
// Usage: @include utils.status-border('active');
|
|
// ---------------------------------------------------------------------------
|
|
@mixin status-border($status) {
|
|
$status-map: (
|
|
'active': var(--cc-status-active),
|
|
'idle': var(--cc-status-idle),
|
|
'thinking': var(--cc-status-thinking),
|
|
'error': var(--cc-status-error),
|
|
'offline': var(--cc-status-offline),
|
|
);
|
|
$color: map-get($status-map, $status);
|
|
@if not $color {
|
|
$color: var(--cc-status-offline);
|
|
}
|
|
border-left: 4px solid $color;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Status badge / pill
|
|
// ---------------------------------------------------------------------------
|
|
@mixin status-badge($status) {
|
|
$fg-map: (
|
|
'active': var(--cc-status-active),
|
|
'idle': var(--cc-status-idle),
|
|
'thinking': var(--cc-status-thinking),
|
|
'error': var(--cc-status-error),
|
|
'offline': var(--cc-status-offline),
|
|
);
|
|
$bg-map: (
|
|
'active': var(--cc-status-active-bg),
|
|
'idle': var(--cc-status-idle-bg),
|
|
'thinking': var(--cc-status-thinking-bg),
|
|
'error': var(--cc-status-error-bg),
|
|
'offline': var(--cc-status-offline-bg),
|
|
);
|
|
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
height: $badge-height;
|
|
padding: 0 8px;
|
|
border-radius: $badge-border-radius;
|
|
background-color: map-get($bg-map, $status);
|
|
color: map-get($fg-map, $status);
|
|
font-size: $font-size-label-medium;
|
|
font-weight: $font-weight-medium;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Glass surface (frosted glass effect)
|
|
// ---------------------------------------------------------------------------
|
|
@mixin glass-surface {
|
|
background-color: rgba(19, 22, 26, 0.8);
|
|
backdrop-filter: blur(8px);
|
|
-webkit-backdrop-filter: blur(8px);
|
|
border: 1px solid var(--cc-surface-lighter);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Responsive grid
|
|
// Creates a responsive grid that adapts from 1-col to 2-col.
|
|
// ---------------------------------------------------------------------------
|
|
@mixin responsive-grid($min-col-width: $card-min-width, $gap: $spacing-card-gap) {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax($min-col-width, 1fr));
|
|
gap: $gap;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Scroll container
|
|
// ---------------------------------------------------------------------------
|
|
@mixin scroll-container($direction: 'y') {
|
|
@if $direction == 'y' {
|
|
overflow-y: auto;
|
|
overflow-x: hidden;
|
|
} @else {
|
|
overflow-x: auto;
|
|
overflow-y: hidden;
|
|
}
|
|
-webkit-overflow-scrolling: touch;
|
|
|
|
// Custom scrollbar (tactical dark)
|
|
&::-webkit-scrollbar {
|
|
width: 6px;
|
|
height: 6px;
|
|
}
|
|
&::-webkit-scrollbar-track {
|
|
background: var(--cc-surface-dark);
|
|
}
|
|
&::-webkit-scrollbar-thumb {
|
|
background: var(--cc-surface-lighter);
|
|
border-radius: 3px;
|
|
&:hover {
|
|
background: var(--cc-on-surface-variant);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Page container
|
|
// Standard page padding and layout
|
|
// ---------------------------------------------------------------------------
|
|
@mixin page-container {
|
|
padding: $spacing-section;
|
|
min-height: 400px;
|
|
overflow-x: hidden;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Transition helpers
|
|
// ---------------------------------------------------------------------------
|
|
@mixin transition-colors($duration: $duration-short) {
|
|
transition: color #{$duration} $easing-standard,
|
|
background-color #{$duration} $easing-standard,
|
|
border-color #{$duration} $easing-standard;
|
|
}
|
|
|
|
@mixin transition-transform($duration: $duration-medium) {
|
|
transition: transform #{$duration} $easing-standard;
|
|
}
|
|
|
|
@mixin transition-opacity($duration: $duration-short) {
|
|
transition: opacity #{$duration} $easing-standard;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Reduced motion
|
|
// Wraps content in a reduced-motion media query.
|
|
// ---------------------------------------------------------------------------
|
|
@mixin reduced-motion {
|
|
@media (prefers-reduced-motion: reduce) {
|
|
@content;
|
|
}
|
|
} |