diff --git a/app/views/admin/products_v3/_filters.html.haml b/app/views/admin/products_v3/_filters.html.haml index c1d61bf7bf..e413f481d3 100644 --- a/app/views/admin/products_v3/_filters.html.haml +++ b/app/views/admin/products_v3/_filters.html.haml @@ -5,10 +5,14 @@ - if producer_options.many? .producers = label_tag :producer_id, t('.producers.label') - = select_tag :producer_id, options_for_select(producer_options, producer_id), include_blank: t('.all_producers'), "data-controller": "tom-select", "data-tom-select-options-value": '{ "plugins": [] }', class: "fullwidth" + = select_tag :producer_id, options_for_select(producer_options, producer_id), + include_blank: t('.all_producers'), class: "fullwidth", + data: { "controller": "tom-select", 'tom-select-placeholder-value': t('.search_for_producers')} .categories = label_tag :category_id, t('.categories.label') - = select_tag :category_id, options_for_select(category_options, category_id), include_blank: t('.all_categories'), "data-controller": "tom-select", "data-tom-select-options-value": '{ "plugins": [] }', class: "fullwidth" + = select_tag :category_id, options_for_select(category_options, category_id), + include_blank: t('.all_categories'), class: "fullwidth", + data: { "controller": "tom-select", 'tom-select-placeholder-value': t('.search_for_categories')} .submit .search-button = button_tag t(".search"), class: "secondary icon-search relaxed" diff --git a/app/views/admin/products_v3/_sort.html.haml b/app/views/admin/products_v3/_sort.html.haml index d3b4829f84..b89d926cef 100644 --- a/app/views/admin/products_v3/_sort.html.haml +++ b/app/views/admin/products_v3/_sort.html.haml @@ -6,4 +6,4 @@ = t(".pagination.clear_search") %form.with-dropdown = t(".pagination.per_page.show") - = select_tag :per_page, options_for_select([15, 25, 50, 100].collect{|i| [t('.pagination.per_page.per_page', num: i), i]}, pagy.items), data: { reflex: "change->products#change_per_page" } + = select_tag :per_page, options_for_select([15, 25, 50, 100].collect{|i| [t('.pagination.per_page.per_page', num: i), i]}, pagy.items), class: "no-input per-page", data: { reflex: "change->products#change_per_page", controller: "tom-select", "tom-select-options-value": '{ "plugins": [] }'} diff --git a/app/webpacker/controllers/tom_select_controller.js b/app/webpacker/controllers/tom_select_controller.js index 9cf4401fe6..b9bc433f5c 100644 --- a/app/webpacker/controllers/tom_select_controller.js +++ b/app/webpacker/controllers/tom_select_controller.js @@ -2,26 +2,20 @@ import { Controller } from "stimulus"; import TomSelect from "tom-select/dist/esm/tom-select.complete"; export default class extends Controller { - static values = { options: Object }; - static defaults = { - maxItems: 1, - maxOptions: null, - plugins: ["dropdown_input"], - allowEmptyOption: true, - closeAfterSelect: true, - onItemAdd: function () { - this.setTextboxValue(""); - }, - }; + static values = { options: Object, placeholder: String }; connect(options = {}) { - if (this.#placeholder()) { - options.allowEmptyOption = false; - options.placeholder = this.#placeholder(); - } - + console.log(this.element, this.placeholderValue); this.control = new TomSelect(this.element, { - ...this.constructor.defaults, + maxItems: 1, + maxOptions: null, + plugins: ["dropdown_input"], + allowEmptyOption: true, // Show blank option (option with empty value) + closeAfterSelect: true, + placeholder: this.placeholderValue || this.#emptyOption(), + onItemAdd: function () { + this.setTextboxValue(""); + }, ...this.optionsValue, ...options, }); @@ -33,7 +27,7 @@ export default class extends Controller { // private - #placeholder() { + #emptyOption() { const optionsArray = [...this.element.options]; return optionsArray.find((option) => [null, ""].includes(option.value))?.text; } diff --git a/app/webpacker/css/admin/products_v3.scss b/app/webpacker/css/admin/products_v3.scss index 8271602135..1aaf5283ab 100644 --- a/app/webpacker/css/admin/products_v3.scss +++ b/app/webpacker/css/admin/products_v3.scss @@ -198,9 +198,7 @@ display: flex; justify-content: space-between; align-items: center; - } - #sort { line-height: $btn-relaxed-height; height: $btn-relaxed-height; @@ -214,29 +212,21 @@ align-items: center; gap: 10px; } + .per-page { + width: 10em; + } } #filters { - display: grid; - grid-template-columns: repeat(6, 1fr); - grid-template-rows: 1fr; - grid-column-gap: 20px; + display: flex; + column-gap: 20px; align-items: end; margin-bottom: 1rem; .query { - grid-column: 1 / span 3; - } + flex-grow: 1; + min-width: 15em; - .producers, - .categories { - } - - .submit { - grid-column: 6 / span 1; - } - - .query { .search-input { width: 100%; position: relative; @@ -270,10 +260,7 @@ .producers, .categories { - select { - width: 150px; - height: $btn-relaxed-height; - } + width: 15em; } .submit { diff --git a/app/webpacker/css/admin_v3/components/select2.scss b/app/webpacker/css/admin_v3/components/select2.scss index 5751802972..d42fc66d6b 100644 --- a/app/webpacker/css/admin_v3/components/select2.scss +++ b/app/webpacker/css/admin_v3/components/select2.scss @@ -11,7 +11,6 @@ box-shadow: none !important; @include border-radius($border-radius); color: $color-1 !important; - font-size: 90%; height: 31px; line-height: inherit !important; padding: 5px 15px 7px; @@ -23,7 +22,6 @@ .select2-search-choice-close { background-image: none !important; - font-size: 100% !important; @extend .icon-remove; @extend [class^="icon-"], :before; margin-top: 2px; @@ -54,7 +52,6 @@ .select2-search { @extend .icon-search; - font-size: 100%; color: darken($color-border, 15); padding: 0 9px 0 0; @@ -72,7 +69,6 @@ padding: 6px 0 6px 25px; margin: 5px 0 0 5px; font-family: $base-font-family; - font-size: 90%; box-shadow: none; background-image: none; } @@ -102,8 +98,6 @@ padding-left: 0 !important; li { - font-size: 85% !important; - &.select2-highlighted { .select2-result-label { &, @@ -117,7 +111,6 @@ color: $color-body-text; min-height: 22px; clear: both; - overflow: auto; } &.select2-no-results, @@ -160,7 +153,6 @@ border: none; box-shadow: none; color: $color-1 !important; - font-size: 85%; &:hover { background-color: $color-btn-hover-bg; @@ -168,7 +160,6 @@ .select2-search-choice-close { background-image: none !important; - font-size: 85% !important; @extend .icon-remove; @extend [class^="icon-"], :before; margin-left: 2px; @@ -248,7 +239,6 @@ label .select2-container { top: 0; margin: 0; padding: 0; - font-size: 100% !important; } } } diff --git a/app/webpacker/css/admin_v3/components/tom_select.scss b/app/webpacker/css/admin_v3/components/tom_select.scss index cf250c5b94..dae7f18fd8 100644 --- a/app/webpacker/css/admin_v3/components/tom_select.scss +++ b/app/webpacker/css/admin_v3/components/tom_select.scss @@ -4,11 +4,12 @@ &.input-active { .ts-control { - border-color: $lighter-grey; + border-color: $orient; + background-color: $lighter-grey; input { &::placeholder { - color: $light-grey; + color: $medium-light-grey; } } } @@ -22,24 +23,42 @@ @include border-radius($border-radius); input { + font-size: $body-font-size; + height: auto; + &::placeholder { color: $near-black; } } + + .item { + margin-top: 2px; // Ensure it lines up with the input. I have no idea why it's necessary. + } } .ts-dropdown { - @include border-radius($border-radius); + // Unstyled, we style the dropdown-content instead + margin: 0; + background: none; border: none; box-shadow: none; + } + + .ts-dropdown-content { + margin-top: 4px; color: $near-black; + background-color: $color-body-bg; + @include border-radius($border-radius); + box-shadow: $shadow-dropdown; .option { - &.selected { - border-left: 2px solid $orient; - } + padding: 8px; + border-left: 3px solid transparent; + line-height: 20px; + &.selected, &.active { + border-left: 3px solid $orient; background-color: $lighter-grey; color: $near-black; } @@ -47,21 +66,80 @@ } } -.plugin-dropdown_input .dropdown-input { - border-color: $lighter-grey; +.plugin-dropdown_input { + .ts-dropdown { + // Cover up the control with the input + top: 0; + } - &:focus { - border-color: $orient; + .dropdown-input-wrap::after { + position: absolute; + content: "\f077"; // chevron-up + font-family: FontAwesome; + border: none; + top: 0.7rem; + right: 0.7rem; + font-size: 13px; + } + + .dropdown-input { + background-color: $color-body-bg; + border: 1px solid $lighter-grey; + box-shadow: none; + padding: 0.6rem 0.75rem; + + &:focus { + border: 1px solid $orient; + } } } -// For the "single" tom_select, be as clause as native select boxes +// For the "single" tom_select, be as close as possible to native select boxes // without too many options .ts-wrapper.single { max-height: 40px; max-width: 100%; - &.input-active .ts-control { - cursor: pointer; + .ts-control { + padding: 0.5rem 0.75rem; + padding-right: 1rem !important; // ts has a clever variable-based rule here, but it doesn't seem to work right. + overflow: hidden; + + // Icon: Override TS icon with icon-chevron-down + &::after { + content: "\f078"; + font-family: FontAwesome; + border: none; + top: 1em; + } + &:not(.rtl)::after { + right: 1.5rem; + } + + .item { + margin-right: 1rem; + // Hide overflow with an ellipsis if a width has been set + overflow: hidden; + text-overflow: ellipsis; + text-wrap: nowrap; + } + } + + &.dropdown-active .ts-control { + &::after { + content: "\f077"; // chevron-up + } + } +} + +// 'no-input' mode, like a native select (hide text input). +.ts-wrapper.single.no-input { + .ts-dropdown { + position: absolute; + top: 0; // we don't need to see the currently selected option, because it's visible in the dropdown + } + + .ts-dropdown-content { + margin-top: 0; } } diff --git a/app/webpacker/css/admin_v3/globals/palette.scss b/app/webpacker/css/admin_v3/globals/palette.scss index 7779028ad4..225b00b368 100644 --- a/app/webpacker/css/admin_v3/globals/palette.scss +++ b/app/webpacker/css/admin_v3/globals/palette.scss @@ -11,6 +11,7 @@ $yellow: #ff9300 !default; // Yellow $mystic: #d9e8eb !default; // Mystic $lighter-grey: #f8f9fa !default; // Lighter grey $light-grey: #eff1f2 !default; // Light grey (Porcelain) +$medium-light-grey: #babdbe !default; // Silver Sand $medium-grey: #919191 !default; // Medium grey $dark-grey: #2e3132 !default; // Dark Grey $near-black: #191c1d !default; // Near-black (Shark) diff --git a/app/webpacker/css/admin_v3/globals/variables.scss b/app/webpacker/css/admin_v3/globals/variables.scss index 2f60494f8c..feff9ef373 100644 --- a/app/webpacker/css/admin_v3/globals/variables.scss +++ b/app/webpacker/css/admin_v3/globals/variables.scss @@ -74,6 +74,9 @@ $color-action-save-brd: very-light($color-success, 20 ) !default; $color-action-mail-bg: very-light($color-success, 5 ) !default; $color-action-mail-brd: very-light($color-success, 20 ) !default; +// Dropdown styles +$shadow-dropdown: 0px 0px 8px 0px rgba($near-black, 0.25); + // Select2 select field colors $color-sel-bg: $lighter-grey !default; $color-sel-hover-bg: $lighter-grey !default; diff --git a/app/webpacker/css/admin_v3/shared/forms.scss b/app/webpacker/css/admin_v3/shared/forms.scss index 90ae20cf3f..4a4980f0ec 100644 --- a/app/webpacker/css/admin_v3/shared/forms.scss +++ b/app/webpacker/css/admin_v3/shared/forms.scss @@ -19,7 +19,6 @@ fieldset { padding: $vpadding-txt $hpadding-txt; border: 1px solid $lighter-grey; color: $color-txt-text; - font-size: 90%; background-color: $lighter-grey; &:focus { diff --git a/config/locales/en.yml b/config/locales/en.yml index a2d37bb97f..3648158430 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -839,7 +839,9 @@ en: clear_search: Clear search filters: search_products: Search for products + search_for_producers: Search for producers all_producers: All producers + search_for_categories: Search for categories all_categories: All categories producers: label: Producers