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:
@@ -117,7 +117,7 @@
|
||||
|
||||
// Results container
|
||||
.dropdown-results {
|
||||
padding: $es-spacing-sm;
|
||||
padding: 0 $es-spacing-sm;
|
||||
}
|
||||
|
||||
// Results count text
|
||||
@@ -609,80 +609,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.tree-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: $es-text-muted;
|
||||
cursor: pointer;
|
||||
transition: transform $es-transition-fast;
|
||||
|
||||
i {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.tree-toggle-placeholder {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.btn-select-children {
|
||||
@include button-reset;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
color: $es-primary;
|
||||
border-radius: $es-radius-sm;
|
||||
transition: all $es-transition-fast;
|
||||
|
||||
&:hover {
|
||||
background: $es-primary-light;
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-select-children-placeholder {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.tree-checkbox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 2px solid $es-border-dark;
|
||||
border-radius: 3px;
|
||||
transition: all $es-transition-fast;
|
||||
|
||||
i {
|
||||
display: none;
|
||||
font-size: 10px;
|
||||
color: $es-white;
|
||||
}
|
||||
}
|
||||
|
||||
.tree-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 16px;
|
||||
color: $es-text-muted;
|
||||
|
||||
i {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
// tree-toggle, btn-select-children, tree-checkbox, tree-icon styles in _tree.scss
|
||||
|
||||
.tree-info {
|
||||
display: flex;
|
||||
@@ -1521,14 +1448,11 @@ body > .target-search-dropdown,
|
||||
color: $es-text-muted;
|
||||
}
|
||||
|
||||
.dropdown-footer-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $es-spacing-sm;
|
||||
}
|
||||
|
||||
.btn-cancel-dropdown {
|
||||
@include button-reset;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
padding: 0.375rem 0.75rem;
|
||||
font-size: $es-font-size-sm;
|
||||
color: $es-text-secondary;
|
||||
@@ -1539,6 +1463,12 @@ body > .target-search-dropdown,
|
||||
|
||||
&:hover {
|
||||
background: $es-bg-hover;
|
||||
color: $es-danger;
|
||||
border-color: $es-danger;
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
kbd {
|
||||
@@ -1566,6 +1496,11 @@ body > .target-search-dropdown,
|
||||
|
||||
&:hover {
|
||||
background: $es-primary-hover;
|
||||
border-color: $es-primary-hover;
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
kbd {
|
||||
@@ -1702,7 +1637,7 @@ body > .target-search-dropdown,
|
||||
|
||||
// Results container
|
||||
.dropdown-results {
|
||||
padding: $es-spacing-sm;
|
||||
padding: 0 $es-spacing-sm;
|
||||
background: $es-white;
|
||||
min-height: 200px;
|
||||
}
|
||||
@@ -1768,16 +1703,16 @@ body > .target-search-dropdown,
|
||||
}
|
||||
}
|
||||
|
||||
// View mode classes (applied to dropdown container)
|
||||
&.view-cols-2 .dropdown-results { @include grid-columns(2); }
|
||||
&.view-cols-3 .dropdown-results { @include grid-columns(3); }
|
||||
&.view-cols-4 .dropdown-results { @include grid-columns(4); }
|
||||
&.view-cols-5 .dropdown-results { @include grid-columns(5); }
|
||||
&.view-cols-6 .dropdown-results { @include grid-columns(6); }
|
||||
&.view-cols-7 .dropdown-results { @include grid-columns(7); }
|
||||
&.view-cols-8 .dropdown-results { @include grid-columns(8); }
|
||||
// View mode classes (applied to dropdown container) - no gap/padding for shared borders
|
||||
&.view-cols-2 .dropdown-results { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0; padding: 0; border-top: 1px solid $es-border-color; border-left: 1px solid $es-border-color; }
|
||||
&.view-cols-3 .dropdown-results { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0; padding: 0; border-top: 1px solid $es-border-color; border-left: 1px solid $es-border-color; }
|
||||
&.view-cols-4 .dropdown-results { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0; padding: 0; border-top: 1px solid $es-border-color; border-left: 1px solid $es-border-color; }
|
||||
&.view-cols-5 .dropdown-results { display: grid; grid-template-columns: repeat(5, 1fr); gap: 0; padding: 0; border-top: 1px solid $es-border-color; border-left: 1px solid $es-border-color; }
|
||||
&.view-cols-6 .dropdown-results { display: grid; grid-template-columns: repeat(6, 1fr); gap: 0; padding: 0; border-top: 1px solid $es-border-color; border-left: 1px solid $es-border-color; }
|
||||
&.view-cols-7 .dropdown-results { display: grid; grid-template-columns: repeat(7, 1fr); gap: 0; padding: 0; border-top: 1px solid $es-border-color; border-left: 1px solid $es-border-color; }
|
||||
&.view-cols-8 .dropdown-results { display: grid; grid-template-columns: repeat(8, 1fr); gap: 0; padding: 0; border-top: 1px solid $es-border-color; border-left: 1px solid $es-border-color; }
|
||||
|
||||
// Grid view item styling (compact cards)
|
||||
// Grid view item styling (compact cards with shared borders)
|
||||
&.view-cols-2,
|
||||
&.view-cols-3,
|
||||
&.view-cols-4,
|
||||
@@ -1789,9 +1724,11 @@ body > .target-search-dropdown,
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
padding: 0;
|
||||
border: 1px solid $es-border-color;
|
||||
border-radius: $es-radius-sm;
|
||||
padding: $es-spacing-sm;
|
||||
border: none;
|
||||
border-right: 1px solid $es-border-color;
|
||||
border-bottom: 1px solid $es-border-color;
|
||||
border-radius: 0;
|
||||
|
||||
.result-checkbox {
|
||||
position: absolute;
|
||||
@@ -1861,6 +1798,15 @@ body > .target-search-dropdown,
|
||||
}
|
||||
}
|
||||
|
||||
// Remove right border from last item in each row (per column count)
|
||||
&.view-cols-2 .dropdown-results .dropdown-item:nth-child(2n) { border-right: none; }
|
||||
&.view-cols-3 .dropdown-results .dropdown-item:nth-child(3n) { border-right: none; }
|
||||
&.view-cols-4 .dropdown-results .dropdown-item:nth-child(4n) { border-right: none; }
|
||||
&.view-cols-5 .dropdown-results .dropdown-item:nth-child(5n) { border-right: none; }
|
||||
&.view-cols-6 .dropdown-results .dropdown-item:nth-child(6n) { border-right: none; }
|
||||
&.view-cols-7 .dropdown-results .dropdown-item:nth-child(7n) { border-right: none; }
|
||||
&.view-cols-8 .dropdown-results .dropdown-item:nth-child(8n) { border-right: none; }
|
||||
|
||||
// Smaller items for higher column counts
|
||||
&.view-cols-5,
|
||||
&.view-cols-6,
|
||||
@@ -2175,80 +2121,7 @@ body > .target-search-dropdown,
|
||||
}
|
||||
}
|
||||
|
||||
.tree-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: $es-text-muted;
|
||||
cursor: pointer;
|
||||
transition: transform $es-transition-fast;
|
||||
|
||||
i {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.tree-toggle-placeholder {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.btn-select-children {
|
||||
@include button-reset;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
color: $es-primary;
|
||||
border-radius: $es-radius-sm;
|
||||
transition: all $es-transition-fast;
|
||||
|
||||
&:hover {
|
||||
background: $es-primary-light;
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-select-children-placeholder {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.tree-checkbox {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 2px solid $es-border-dark;
|
||||
border-radius: 3px;
|
||||
transition: all $es-transition-fast;
|
||||
|
||||
i {
|
||||
display: none;
|
||||
font-size: 10px;
|
||||
color: $es-white;
|
||||
}
|
||||
}
|
||||
|
||||
.tree-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 16px;
|
||||
color: $es-text-muted;
|
||||
|
||||
i {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
// tree-toggle, btn-select-children, tree-checkbox, tree-icon styles in _tree.scss
|
||||
|
||||
.tree-info {
|
||||
display: flex;
|
||||
@@ -2280,7 +2153,7 @@ body > .target-search-dropdown,
|
||||
.dropdown-results {
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
padding: $es-spacing-sm;
|
||||
padding: 0 $es-spacing-sm;
|
||||
@include custom-scrollbar;
|
||||
}
|
||||
|
||||
@@ -2498,6 +2371,7 @@ body > .target-search-dropdown,
|
||||
.entity-search-icon {
|
||||
color: $es-text-muted;
|
||||
flex-shrink: 0;
|
||||
margin-left: $es-spacing-xs;
|
||||
}
|
||||
|
||||
// Override Bootstrap/parent form input styles
|
||||
|
||||
Reference in New Issue
Block a user