Add hierarchical tree view for category selection
Features: - Tree view mode for categories with expand/collapse - Product count badges with clickable preview popover - Select parent with all children button - Client-side tree filtering (refine search) - Keyboard shortcuts: Ctrl+A (select all), Ctrl+D (clear) - View mode switching between tree/list/columns - Tree view as default for categories, respects user preference Backend: - Add previewCategoryProducts and previewCategoryPages AJAX handlers - Support pagination and filtering in category previews Styling: - Consistent count-badge styling across tree and other views - Loading and popover-open states for count badges Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -319,22 +319,13 @@
|
||||
border-top: 1px dashed $es-border-color;
|
||||
}
|
||||
|
||||
// Legacy exclude-rows (if used elsewhere)
|
||||
.exclude-rows {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $es-spacing-sm;
|
||||
}
|
||||
|
||||
.exclude-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: $es-spacing-sm;
|
||||
padding: $es-spacing-sm;
|
||||
background: rgba($es-danger, 0.05);
|
||||
border: 1px solid rgba($es-danger, 0.2);
|
||||
border-radius: $es-radius-md;
|
||||
}
|
||||
|
||||
.exclude-row-content {
|
||||
flex: 1;
|
||||
}
|
||||
@@ -534,9 +525,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Group include section
|
||||
// Group include section - green accent to distinguish from exclude
|
||||
.group-include {
|
||||
margin-bottom: $es-spacing-md;
|
||||
padding: $es-spacing-sm;
|
||||
background: rgba($es-success, 0.03);
|
||||
border: 1px solid rgba($es-success, 0.2);
|
||||
border-radius: $es-radius-md;
|
||||
}
|
||||
|
||||
.section-row {
|
||||
@@ -565,32 +560,81 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
// Lock indicator for method selector (when excludes are present)
|
||||
.selector-locked {
|
||||
.include-method-select {
|
||||
opacity: 0.7;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.lock-indicator {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
color: $es-warning;
|
||||
cursor: help;
|
||||
|
||||
i {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.mpr-tooltip {
|
||||
display: none;
|
||||
position: absolute;
|
||||
bottom: calc(100% + 8px);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
padding: $es-spacing-xs $es-spacing-sm;
|
||||
background: $es-slate-800;
|
||||
color: $es-white;
|
||||
font-size: $es-font-size-xs;
|
||||
font-weight: $es-font-weight-normal;
|
||||
white-space: nowrap;
|
||||
border-radius: $es-radius-sm;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
&:hover .mpr-tooltip {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
// Group excludes section
|
||||
.group-excludes {
|
||||
margin-top: $es-spacing-md;
|
||||
|
||||
&.has-excludes {
|
||||
padding-top: $es-spacing-md;
|
||||
border-top: 1px dashed $es-border-color;
|
||||
}
|
||||
}
|
||||
|
||||
.except-separator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: $es-spacing-sm;
|
||||
gap: $es-spacing-sm;
|
||||
margin: 0 0 $es-spacing-sm 0;
|
||||
|
||||
// Lines on both sides
|
||||
&::before,
|
||||
&::after {
|
||||
content: '';
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background: rgba($es-danger, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
.except-label {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
padding: 0.25rem 0.5rem;
|
||||
padding: 0.25rem 0.75rem;
|
||||
background: $es-danger-light;
|
||||
color: $es-danger;
|
||||
font-size: $es-font-size-xs;
|
||||
font-weight: $es-font-weight-semibold;
|
||||
border-radius: $es-radius-sm;
|
||||
border-radius: $es-radius-full;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
|
||||
i {
|
||||
font-size: 10px;
|
||||
@@ -604,17 +648,36 @@
|
||||
}
|
||||
|
||||
.exclude-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: $es-spacing-sm;
|
||||
background: rgba($es-danger, 0.03);
|
||||
border: 1px solid rgba($es-danger, 0.15);
|
||||
border-radius: $es-radius-md;
|
||||
|
||||
// Value picker inside exclude row - full width
|
||||
.value-picker {
|
||||
width: 100%;
|
||||
margin-top: $es-spacing-sm;
|
||||
}
|
||||
}
|
||||
|
||||
.exclude-header-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: $es-spacing-sm;
|
||||
margin-bottom: $es-spacing-sm;
|
||||
width: 100%;
|
||||
|
||||
.method-selector-wrapper {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
// Delete button at the far right
|
||||
.btn-remove-exclude-row {
|
||||
flex-shrink: 0;
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-remove-exclude-row {
|
||||
@@ -680,9 +743,14 @@
|
||||
gap: 0.375rem;
|
||||
}
|
||||
|
||||
// Common height for all modifier controls
|
||||
$modifier-height: 26px;
|
||||
|
||||
.group-modifier-limit {
|
||||
width: 60px;
|
||||
padding: 0.25rem 0.5rem;
|
||||
width: 50px;
|
||||
max-width: 50px;
|
||||
height: $modifier-height;
|
||||
padding: 0 0.375rem;
|
||||
font-size: $es-font-size-xs;
|
||||
text-align: center;
|
||||
border: 1px solid $es-border-color;
|
||||
@@ -694,8 +762,59 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Sort modifier - input group style (select + button glued together)
|
||||
.modifier-sort {
|
||||
gap: 0; // Remove gap to glue select + button together
|
||||
|
||||
.modifier-label {
|
||||
margin-right: 0.375rem; // Keep space between label and input group
|
||||
}
|
||||
|
||||
.group-modifier-sort {
|
||||
height: $modifier-height;
|
||||
padding: 0 0.5rem;
|
||||
font-size: $es-font-size-xs;
|
||||
border: 1px solid $es-border-color;
|
||||
border-radius: $es-radius-sm 0 0 $es-radius-sm;
|
||||
border-right: none;
|
||||
cursor: pointer;
|
||||
|
||||
&:focus {
|
||||
border-color: $es-primary;
|
||||
outline: none;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-sort-dir {
|
||||
@include button-reset;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: $modifier-height;
|
||||
height: $modifier-height;
|
||||
color: $es-text-muted;
|
||||
background: $es-slate-100;
|
||||
border: 1px solid $es-border-color;
|
||||
border-radius: 0 $es-radius-sm $es-radius-sm 0;
|
||||
transition: all $es-transition-fast;
|
||||
|
||||
&:hover {
|
||||
background: $es-slate-200;
|
||||
color: $es-text-secondary;
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback for elements outside .modifier-sort context
|
||||
.group-modifier-sort {
|
||||
padding: 0.25rem 0.5rem;
|
||||
height: $modifier-height;
|
||||
padding: 0 0.5rem;
|
||||
font-size: $es-font-size-xs;
|
||||
border: 1px solid $es-border-color;
|
||||
border-radius: $es-radius-sm;
|
||||
@@ -712,8 +831,8 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
width: $modifier-height;
|
||||
height: $modifier-height;
|
||||
color: $es-text-muted;
|
||||
border: 1px solid $es-border-color;
|
||||
border-radius: $es-radius-sm;
|
||||
|
||||
Reference in New Issue
Block a user