From 7b60c6959a29cdb9e55a54d7af2cba3fa4a86089 Mon Sep 17 00:00:00 2001 From: Jorge Manrubia Date: Thu, 18 Sep 2025 15:02:25 +0200 Subject: [PATCH] WIP with a combobox controller to handle filters with pure JS --- app/assets/stylesheets/filters.css | 10 ++++- .../controllers/combobox_controller.js | 38 ++++++++++++++++ app/views/filters/settings/_controls.html.erb | 17 +++++--- .../filters/settings/_sorted_by.html.erb | 43 ++++++++----------- 4 files changed, 76 insertions(+), 32 deletions(-) create mode 100644 app/javascript/controllers/combobox_controller.js diff --git a/app/assets/stylesheets/filters.css b/app/assets/stylesheets/filters.css index 8ce52d66c..85721621e 100644 --- a/app/assets/stylesheets/filters.css +++ b/app/assets/stylesheets/filters.css @@ -108,7 +108,15 @@ } .quick-filter { - &:not(.default-value):has(.checked) { + .checked { + display: none; + } + + [aria-checked="true"] .checked { + display: block; + } + + &:has([aria-checked="true"]) { .input--select { --input-background: var(--color-selected); } diff --git a/app/javascript/controllers/combobox_controller.js b/app/javascript/controllers/combobox_controller.js new file mode 100644 index 000000000..9d3204b3b --- /dev/null +++ b/app/javascript/controllers/combobox_controller.js @@ -0,0 +1,38 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = [ "label", "item" ] + static values = { selectPropertyName: { type: String, default: "aria-checked" } } + + connect() { + this.labelTarget.textContent = this.#selectedLabel + } + + change(event) { + const item = event.target.closest("[role='checkbox']") + if (item) { + this.#selectedItem = item + } + } + + get #selectedLabel() { + const label = this.#selectedItem.querySelector("[data-combobox-label]") + return label.dataset.comboboxLabel + } + + get #selectedItem() { + return this.itemTargets.find(item => item.getAttribute(this.selectPropertyNameValue) === "true") + } + + set #selectedItem(item) { + this.#clearSelection() + item.setAttribute(this.selectPropertyNameValue, "true") + this.labelTarget.textContent = this.#selectedLabel + } + + #clearSelection() { + this.itemTargets.forEach(target => { + target.setAttribute(this.selectPropertyNameValue, "false") + }) + } +} diff --git a/app/views/filters/settings/_controls.html.erb b/app/views/filters/settings/_controls.html.erb index 755ad1e18..961b1a0d0 100644 --- a/app/views/filters/settings/_controls.html.erb +++ b/app/views/filters/settings/_controls.html.erb @@ -1,6 +1,11 @@ -<%= render "filters/settings/sorted_by", user_filtering: user_filtering %> -<%= render "filters/settings/indexed_by", user_filtering: user_filtering %> -<%= render "filters/settings/tags", user_filtering: user_filtering %> -<%= render "filters/settings/assignees", user_filtering: user_filtering %> -<%= render "filters/settings/creators", user_filtering: user_filtering %> -<%= render "filters/settings/closers", user_filtering: user_filtering %> +<%= form_with url: cards_path, method: :get, data: { controller: "form" } do |form| %> + <%= hidden_field_tag :expand_all, true, disabled: !user_filtering.expanded?, data: { toggle_enable_target: "element" } %> + + + <%= render "filters/settings/sorted_by", user_filtering: user_filtering %> +<%#= render "filters/settings/indexed_by", user_filtering: user_filtering %> +<%#= render "filters/settings/tags", user_filtering: user_filtering %> +<%#= render "filters/settings/assignees", user_filtering: user_filtering %> +<%#= render "filters/settings/creators", user_filtering: user_filtering %> +<%#= render "filters/settings/closers", user_filtering: user_filtering %> +<% end %> diff --git a/app/views/filters/settings/_sorted_by.html.erb b/app/views/filters/settings/_sorted_by.html.erb index 50b308227..e0846a69b 100644 --- a/app/views/filters/settings/_sorted_by.html.erb +++ b/app/views/filters/settings/_sorted_by.html.erb @@ -1,37 +1,30 @@ <% filter = user_filtering.filter %> -<%= tag.div class: class_names("quick-filter position-relative", "default-value": filter.sorted_by.latest?), - data: { controller: "dialog", action: "keydown.esc->dialog#close click@document->dialog#closeOnClickOutside", filter_show: user_filtering.show_sorted_by? } do %> - <%= filter_dialog "Sort by…" do %> Sort by… -