- Unified _setBadgeCount for ALL badge updates - target-conditions-trait → entity-selector-trait - target-* → es-* class rename (20+ classes) - SCSS recompiled: zero duplicate selectors - CSS transitions replace jQuery slideDown/slideUp - Serialize cache, method swap cache - Badge: no-matches gray, consistent hover, no blending - Inline condition count always visible - Preview popover refreshes in-place on sort change - Categories add chips immediately - Entity type icons on chips - Consistent info_outline icons via buildHelpIcon - Method dropdown text clipping fix (line-height) - mpr-input-compact on all inputs - Dropdown padding fixed in SCSS source - Chips wrapper: same container always - Reusable helpers: _buildEmptyState, _buildSearchBoxHtml, _buildInfoTooltip - Asset path: uses $this->module->getPathUri() not reflection - Debug logs removed Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
410 lines
9.6 KiB
SCSS
410 lines
9.6 KiB
SCSS
/**
|
|
* Entity Selector - Main Component Styles
|
|
* Wrapper, header, body, tabs, blocks
|
|
*/
|
|
|
|
@use '../variables' as *;
|
|
@use '../mixins' as *;
|
|
|
|
// Main wrapper (supports both .entity-selector-trait and .entity-selector-trait)
|
|
.entity-selector-trait {
|
|
position: relative;
|
|
overflow: visible;
|
|
background: $es-white;
|
|
border: 1px solid $es-border-color;
|
|
border-radius: $es-radius-lg;
|
|
|
|
// Trait Header (collapsible)
|
|
.condition-trait-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
flex-wrap: wrap;
|
|
gap: $es-spacing-md;
|
|
padding: 0.875rem $es-spacing-md;
|
|
background: $es-bg-header;
|
|
border-bottom: 1px solid $es-border-color;
|
|
border-radius: $es-radius-lg $es-radius-lg 0 0;
|
|
cursor: pointer;
|
|
user-select: none;
|
|
transition: background-color $es-transition-fast;
|
|
|
|
&:hover {
|
|
background: $es-bg-hover;
|
|
}
|
|
}
|
|
|
|
.trait-header-left {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.75rem;
|
|
min-width: 0;
|
|
flex: 1;
|
|
}
|
|
|
|
.trait-icon {
|
|
font-size: $es-font-size-lg;
|
|
color: $es-text-muted;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.trait-title-group {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.125rem;
|
|
min-width: 0;
|
|
}
|
|
|
|
.trait-title {
|
|
font-size: $es-font-size-sm;
|
|
font-weight: $es-font-weight-semibold;
|
|
color: $es-text-primary;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.trait-subtitle {
|
|
font-size: $es-font-size-xs;
|
|
color: $es-text-muted;
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
// Total count badge in header
|
|
.trait-total-count {
|
|
@include count-badge($es-primary);
|
|
margin-left: $es-spacing-sm;
|
|
}
|
|
|
|
// Show all toggle switch
|
|
.trait-show-all-toggle {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: $es-spacing-sm;
|
|
margin-right: 0.75rem;
|
|
padding: 0.25rem $es-spacing-sm;
|
|
border-radius: $es-radius-sm;
|
|
cursor: pointer;
|
|
user-select: none;
|
|
transition: background-color $es-transition-fast;
|
|
|
|
&:hover {
|
|
background: rgba(0, 0, 0, 0.05);
|
|
}
|
|
|
|
.toggle-label {
|
|
font-size: $es-font-size-xs;
|
|
font-weight: $es-font-weight-medium;
|
|
color: $es-text-muted;
|
|
}
|
|
|
|
.show-all-checkbox {
|
|
display: none;
|
|
}
|
|
|
|
.toggle-slider {
|
|
position: relative;
|
|
width: 36px;
|
|
height: 20px;
|
|
background: $es-slate-300;
|
|
border-radius: $es-radius-full;
|
|
transition: background-color $es-transition-normal;
|
|
|
|
&::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: 2px;
|
|
left: 2px;
|
|
width: 16px;
|
|
height: 16px;
|
|
background: $es-white;
|
|
border-radius: 50%;
|
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
|
transition: transform $es-transition-normal;
|
|
}
|
|
}
|
|
|
|
.show-all-checkbox:checked + .toggle-slider {
|
|
background: $es-success;
|
|
|
|
&::after {
|
|
transform: translateX(16px);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Validation error states
|
|
&.has-validation-error {
|
|
border-color: $es-danger;
|
|
box-shadow: 0 0 0 3px rgba($es-danger, 0.1);
|
|
|
|
.condition-trait-header {
|
|
border-bottom-color: $es-danger;
|
|
}
|
|
}
|
|
|
|
.trait-validation-error {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: $es-spacing-sm;
|
|
padding: 0.625rem $es-spacing-md;
|
|
background: $es-danger-light;
|
|
color: #b91c1c;
|
|
font-size: $es-font-size-sm;
|
|
font-weight: $es-font-weight-medium;
|
|
border-bottom: 1px solid #fecaca;
|
|
|
|
i {
|
|
color: $es-danger;
|
|
}
|
|
}
|
|
|
|
// Required indicator
|
|
&.trait-required .trait-title::after {
|
|
content: ' *';
|
|
color: $es-danger;
|
|
}
|
|
|
|
// Body
|
|
.condition-trait-body {
|
|
padding: 0;
|
|
background: $es-white;
|
|
border-radius: 0 0 $es-radius-lg $es-radius-lg;
|
|
}
|
|
|
|
// Block type tabs
|
|
.es-block-tabs {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 0;
|
|
padding: 0;
|
|
background: $es-slate-100;
|
|
border-bottom: 1px solid $es-border-color;
|
|
}
|
|
|
|
.es-block-tab {
|
|
position: relative;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: $es-spacing-sm;
|
|
flex: none;
|
|
min-width: 0;
|
|
padding: 0.625rem $es-spacing-md;
|
|
margin-bottom: -1px;
|
|
background: transparent;
|
|
border: 0;
|
|
border-bottom: 2px solid transparent;
|
|
color: $es-text-muted;
|
|
font-size: $es-font-size-sm;
|
|
font-weight: $es-font-weight-medium;
|
|
cursor: pointer;
|
|
transition: all $es-transition-fast;
|
|
|
|
&:hover {
|
|
background: $es-slate-200;
|
|
color: $es-slate-700;
|
|
}
|
|
|
|
&.active {
|
|
background: $es-white;
|
|
border-bottom-color: $es-cyan-500;
|
|
color: $es-primary;
|
|
}
|
|
|
|
i {
|
|
font-size: $es-font-size-sm;
|
|
}
|
|
|
|
.tab-label {
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.tab-badge {
|
|
@include count-badge($es-primary);
|
|
}
|
|
|
|
&.has-data:not(.active) .tab-badge {
|
|
@include count-badge($es-slate-400);
|
|
}
|
|
}
|
|
|
|
// Tabs row with actions (form-content layout)
|
|
.entity-selector-tabs-row {
|
|
display: flex;
|
|
align-items: stretch;
|
|
background: $es-slate-100;
|
|
border-bottom: 1px solid $es-border-color;
|
|
border-radius: $es-radius-lg $es-radius-lg 0 0;
|
|
|
|
.es-block-tabs {
|
|
flex: 1;
|
|
border-bottom: 0;
|
|
border-radius: $es-radius-lg 0 0 0;
|
|
}
|
|
}
|
|
|
|
// Expand/collapse toggle area (entire section is clickable)
|
|
.entity-selector-actions.btn-toggle-blocks {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 0 $es-spacing-md;
|
|
background: $es-slate-100;
|
|
border-left: 1px solid $es-border-color;
|
|
color: $es-slate-400;
|
|
cursor: pointer;
|
|
transition: all $es-transition-fast;
|
|
|
|
&:hover {
|
|
background: $es-slate-200;
|
|
color: $es-primary;
|
|
}
|
|
|
|
.material-icons {
|
|
font-size: 20px !important;
|
|
}
|
|
}
|
|
|
|
// When expanded - highlight the toggle area
|
|
.entity-selector-trait:not(.blocks-collapsed) .entity-selector-actions.btn-toggle-blocks {
|
|
background: $es-primary-light;
|
|
border-left-color: $es-primary;
|
|
color: $es-primary;
|
|
}
|
|
|
|
// Blocks content wrapper (for form-content layout collapse)
|
|
.entity-selector-blocks-content {
|
|
// Inherits styles from condition-trait-body context
|
|
}
|
|
|
|
// Block container
|
|
.es-block-container {
|
|
display: none;
|
|
|
|
&.active {
|
|
display: block;
|
|
}
|
|
}
|
|
|
|
.es-block-content {
|
|
padding: $es-spacing-md;
|
|
}
|
|
|
|
.es-block-groups {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: $es-spacing-md;
|
|
}
|
|
|
|
// Block header (for standalone blocks)
|
|
.es-block-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: $es-spacing-sm $es-spacing-md;
|
|
background: $es-bg-header;
|
|
border-bottom: 1px solid $es-border-color;
|
|
}
|
|
|
|
// Empty state
|
|
.es-block-empty {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: $es-spacing-sm;
|
|
padding: $es-spacing-xl;
|
|
text-align: center;
|
|
color: $es-text-muted;
|
|
|
|
i {
|
|
font-size: 2rem;
|
|
opacity: 0.5;
|
|
}
|
|
|
|
p {
|
|
margin: 0;
|
|
font-size: $es-font-size-sm;
|
|
}
|
|
}
|
|
|
|
// Collapse toggle
|
|
.trait-collapse-toggle,
|
|
.collapse-toggle {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
width: 24px;
|
|
height: 24px;
|
|
color: $es-text-muted;
|
|
cursor: pointer;
|
|
transition: transform $es-transition-normal;
|
|
|
|
&.collapsed {
|
|
transform: rotate(-90deg);
|
|
}
|
|
}
|
|
|
|
// Header actions
|
|
.trait-header-right {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: $es-spacing-sm;
|
|
}
|
|
|
|
// Collapsed state
|
|
&.collapsed {
|
|
.condition-trait-body {
|
|
display: none;
|
|
}
|
|
|
|
.condition-trait-header {
|
|
border-radius: $es-radius-lg;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Single mode specific styles
|
|
.entity-selector-trait.single-mode,
|
|
.entity-selector-trait.single-mode {
|
|
.es-block-tabs {
|
|
display: none;
|
|
}
|
|
|
|
.es-block-container {
|
|
display: block;
|
|
}
|
|
}
|
|
|
|
// Header action buttons
|
|
.entity-selector-trait {
|
|
.header-actions {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: $es-spacing-xs;
|
|
}
|
|
|
|
.header-action-btn {
|
|
@include button-reset;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.25rem;
|
|
padding: 0.25rem $es-spacing-sm;
|
|
font-size: $es-font-size-xs;
|
|
font-weight: $es-font-weight-medium;
|
|
color: $es-text-muted;
|
|
background: transparent;
|
|
border-radius: $es-radius-sm;
|
|
transition: all $es-transition-fast;
|
|
|
|
&:hover {
|
|
background: $es-slate-200;
|
|
color: $es-text-secondary;
|
|
}
|
|
|
|
i {
|
|
font-size: 12px;
|
|
}
|
|
}
|
|
}
|