From 0ad0ef25ad23875a00657e3f204511b5ae4b3915 Mon Sep 17 00:00:00 2001 From: jiroghianni Date: Thu, 13 Feb 2025 14:47:03 +0100 Subject: [PATCH 1/2] :construction: [#3018] Refactor filters out of modal into checkbox-lists --- .../components/Filter/SearchFilter.html | 36 ++++++++++ .../FilterBar/multiselect_listbox_checkbox.js | 3 + .../search/filter-dropdown-submit.js | 31 +++++++++ .../js/components/search/filter-dropdown.js | 59 +++++++++++++++++ .../js/components/search/index.js | 2 +- .../scss/components/Filter/Filter.scss | 8 +++ .../components/Filter/FilterDropdown.scss | 65 +++++++++++++++++++ src/open_inwoner/scss/components/_index.scss | 1 + src/open_inwoner/templates/pages/search.html | 50 ++++++++++++++ 9 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 src/open_inwoner/components/templates/components/Filter/SearchFilter.html create mode 100644 src/open_inwoner/js/components/search/filter-dropdown-submit.js create mode 100644 src/open_inwoner/js/components/search/filter-dropdown.js create mode 100644 src/open_inwoner/scss/components/Filter/FilterDropdown.scss diff --git a/src/open_inwoner/components/templates/components/Filter/SearchFilter.html b/src/open_inwoner/components/templates/components/Filter/SearchFilter.html new file mode 100644 index 0000000000..4ab4b13aa3 --- /dev/null +++ b/src/open_inwoner/components/templates/components/Filter/SearchFilter.html @@ -0,0 +1,36 @@ +{% load i18n icon_tags button_tags form_tags %} + +
+
+ + + {{ field.label }} + + + {{ field.label }} + +
+ +
+
+ +
+ + {# No submit button for direct query #} +
+
+ {% button bordered=False text=_("Wis alle filters") id="resetMultiSelectFilters" extra_classes="resetMultiSelectFilters" type="button" transparent=True primary=True %} +
+
+
+ +
+
+
diff --git a/src/open_inwoner/js/components/FilterBar/multiselect_listbox_checkbox.js b/src/open_inwoner/js/components/FilterBar/multiselect_listbox_checkbox.js index 7640fc2abb..ac4b37639d 100644 --- a/src/open_inwoner/js/components/FilterBar/multiselect_listbox_checkbox.js +++ b/src/open_inwoner/js/components/FilterBar/multiselect_listbox_checkbox.js @@ -286,5 +286,8 @@ document.body.addEventListener('htmx:afterSwap', function () { document.addEventListener('click', function (e) { if (e.target && e.target.classList.contains('pagination__link')) { scrollToTopOfWindow() // Scroll up after clicking pagination + setTimeout(function () { + initFilterBar() // Reinitialize filter bar after HTMX swap from pagination + }, 20) } }) diff --git a/src/open_inwoner/js/components/search/filter-dropdown-submit.js b/src/open_inwoner/js/components/search/filter-dropdown-submit.js new file mode 100644 index 0000000000..20186a8a4d --- /dev/null +++ b/src/open_inwoner/js/components/search/filter-dropdown-submit.js @@ -0,0 +1,31 @@ +export class FilterDropdownSubmit { + static selector = '.filter-dropdown' + + constructor(node) { + this.node = node + this.submitButton = node.querySelector('.filter-dropdown__submit') + this.checkboxes = node.querySelectorAll( + '.filter-dropdown__list input[type="checkbox"]' + ) + + if (!this.submitButton || !this.checkboxes.length) return + + this.checkboxes.forEach((checkbox) => { + checkbox.addEventListener('change', this.updateSubmitButton.bind(this)) + }) + } + + updateSubmitButton() { + const selectedCount = this.node.querySelectorAll( + '.filter-dropdown__list input[type="checkbox"]:checked' + ).length + this.submitButton.textContent = `Apply Filters (${selectedCount})` + } +} + +/** + * Initialize only dropdowns with submit buttons + */ +document + .querySelectorAll(FilterDropdownSubmit.selector) + .forEach((dropdown) => new FilterDropdownSubmit(dropdown)) diff --git a/src/open_inwoner/js/components/search/filter-dropdown.js b/src/open_inwoner/js/components/search/filter-dropdown.js new file mode 100644 index 0000000000..2393e8db27 --- /dev/null +++ b/src/open_inwoner/js/components/search/filter-dropdown.js @@ -0,0 +1,59 @@ +export class FilterDropdown { + static selector = '.filter-dropdown' + + constructor(node) { + this.node = node + this.button = node.querySelector('.filter-dropdown__button') + this.menu = node.querySelector('.filter-dropdown__menu') + this.checkboxes = node.querySelectorAll( + '.filter-dropdown__list input[type="checkbox"]' + ) + this.clearButton = node.querySelector('.filter-dropdown__clear') + this.filterCount = node.querySelector('.filter-count') + + if (!this.button || !this.menu || !this.checkboxes.length) return + + this.button.addEventListener('click', this.toggleDropdown.bind(this)) + document.addEventListener('click', this.closeDropdown.bind(this)) + + this.checkboxes.forEach((checkbox) => { + checkbox.addEventListener('change', this.updateFilters.bind(this)) + }) + + if (this.clearButton) { + this.clearButton.addEventListener('click', this.clearFilters.bind(this)) + } + } + + toggleDropdown(event) { + event.preventDefault() + this.node.classList.toggle('open') + } + + closeDropdown(event) { + if (!this.node.contains(event.target)) { + this.node.classList.remove('open') + } + } + + updateFilters() { + const selectedCount = this.node.querySelectorAll( + '.filter-dropdown__list input[type="checkbox"]:checked' + ).length + if (this.filterCount) { + this.filterCount.textContent = `(${selectedCount})` + } + } + + clearFilters() { + this.checkboxes.forEach((checkbox) => (checkbox.checked = false)) + this.updateFilters() + } +} + +/** + * Initialize all dropdowns + */ +document + .querySelectorAll(FilterDropdown.selector) + .forEach((dropdown) => new FilterDropdown(dropdown)) diff --git a/src/open_inwoner/js/components/search/index.js b/src/open_inwoner/js/components/search/index.js index 7e01615f1b..b3263e8736 100644 --- a/src/open_inwoner/js/components/search/index.js +++ b/src/open_inwoner/js/components/search/index.js @@ -1,4 +1,4 @@ -import './filter-mobile' +import './filter-dropdown' import './filter-options' const searchForm = document.getElementById('search-form') diff --git a/src/open_inwoner/scss/components/Filter/Filter.scss b/src/open_inwoner/scss/components/Filter/Filter.scss index b90412c031..7409bcb289 100644 --- a/src/open_inwoner/scss/components/Filter/Filter.scss +++ b/src/open_inwoner/scss/components/Filter/Filter.scss @@ -1,4 +1,8 @@ .filter { + display: none; + @media (min-width: 768px) { + display: block; + } border: 0 solid transparent; margin: 0; padding: 0; @@ -94,6 +98,10 @@ } .grid__filters { + display: none; + @media (min-width: 768px) { + display: block; + } .utrecht-heading-2 { border-bottom: 2px solid var(--color-gray-light); display: block; diff --git a/src/open_inwoner/scss/components/Filter/FilterDropdown.scss b/src/open_inwoner/scss/components/Filter/FilterDropdown.scss new file mode 100644 index 0000000000..30b7434a86 --- /dev/null +++ b/src/open_inwoner/scss/components/Filter/FilterDropdown.scss @@ -0,0 +1,65 @@ +.filter-dropdown { + position: relative; + display: inline-block; + + &__button { + background: var(--color-white); + color: var(--color-body); + border: 1px solid var(--color-gray-dark-900); + border-radius: var(--border-radius); + padding: 10px 15px; + cursor: pointer; + border-radius: 5px; + } + + &__menu { + position: absolute; + top: 100%; + left: 0; + background: white; + border: 1px solid #ccc; + border-radius: 5px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + display: none; + padding: 10px; + width: 200px; + z-index: 100; + } + + &__list { + list-style: none; + padding: 0; + margin: 0; + + li { + margin-bottom: 5px; + } + } + + &__actions { + display: flex; + justify-content: space-between; + margin-top: 10px; + } + + &__submit { + background: var(--color-primary); + color: white; + border: none; + padding: 5px 10px; + cursor: pointer; + border-radius: 3px; + } + + &__clear { + background: none; + border: none; + color: var(--color-primary); + cursor: pointer; + } +} + +// Show dropdown when button is clicked +.filter-dropdown.open .filter-dropdown__menu { + display: block; +} diff --git a/src/open_inwoner/scss/components/_index.scss b/src/open_inwoner/scss/components/_index.scss index ab8e09c14d..8c791d432e 100644 --- a/src/open_inwoner/scss/components/_index.scss +++ b/src/open_inwoner/scss/components/_index.scss @@ -26,6 +26,7 @@ @import './File/File.scss'; @import './File/FileList.scss'; @import './Filter/Filter.scss'; +@import 'Filter/FilterDropdown'; @import './FilterBar/FilterBar.scss'; @import './FilterBar/MultiSelectListbox'; @import './Footer/Footer.scss'; diff --git a/src/open_inwoner/templates/pages/search.html b/src/open_inwoner/templates/pages/search.html index bd10d12e3e..12e3871911 100644 --- a/src/open_inwoner/templates/pages/search.html +++ b/src/open_inwoner/templates/pages/search.html @@ -26,6 +26,56 @@

{% trans "Zoekfilters" %}

{% include "components/Filter/Filter.html" with field=search_form.organizations form_id="search-form" only %} {% endif %} + +
+
+
+ +
+ +
+
+
+

{% trans "Zoekfilters" %}

+
+ + + Gekozen filters +
+

{% trans "Zoekfilters" %}

+ +
+
+
{% endif %} {# end search filters #} {% endif %} From ef50843b94cb93ea68c6384820714d34bd9f4805 Mon Sep 17 00:00:00 2001 From: jiroghianni Date: Tue, 25 Feb 2025 16:45:40 +0100 Subject: [PATCH 2/2] :construction: [#3018] split components --- .../components/Filter/FilterDropdown.html | 30 ++++++++++ .../components/Filter/FilterModal.html | 21 +++++++ .../components/Filter/SearchFilter.html | 36 ----------- .../components/Filter/FilterDropdown.scss | 16 ++--- .../scss/components/Form/_Search.scss | 6 ++ src/open_inwoner/templates/pages/search.html | 60 ++++--------------- 6 files changed, 77 insertions(+), 92 deletions(-) create mode 100644 src/open_inwoner/components/templates/components/Filter/FilterDropdown.html create mode 100644 src/open_inwoner/components/templates/components/Filter/FilterModal.html delete mode 100644 src/open_inwoner/components/templates/components/Filter/SearchFilter.html diff --git a/src/open_inwoner/components/templates/components/Filter/FilterDropdown.html b/src/open_inwoner/components/templates/components/Filter/FilterDropdown.html new file mode 100644 index 0000000000..5f85bdfdf1 --- /dev/null +++ b/src/open_inwoner/components/templates/components/Filter/FilterDropdown.html @@ -0,0 +1,30 @@ +{% load i18n icon_tags button_tags form_tags %} + +
+
+ + + {{ field.label }} + +
+
    + {% for option in field.field.choices %} +
  • {% choice_checkbox choice=option name=field.name data=field.data index=forloop.counter form_id=form_id %}
  • + {% endfor %} +
+ + {% if filter_submit_button %} +
+ + {% if filter_clear_button %} + + {% endif %} +
+ {% endif %} +
+
+
diff --git a/src/open_inwoner/components/templates/components/Filter/FilterModal.html b/src/open_inwoner/components/templates/components/Filter/FilterModal.html new file mode 100644 index 0000000000..14d5e5616f --- /dev/null +++ b/src/open_inwoner/components/templates/components/Filter/FilterModal.html @@ -0,0 +1,21 @@ +{% load i18n form_tags button_tags %} + +
+ {# Wrapper for multiple filters #} +
+
+ {% button icon="close" text=_("Sluiten") hide_text=True icon_outlined=True transparent=True extra_classes="show-controls" %} +
+ +
+
+
+

Filters

+ {% button icon="filter_alt" text=_("Filters") icon_outlined=True transparent=True extra_classes="show-modal" %} +

Status

+
+ {{ contents }} +
+
diff --git a/src/open_inwoner/components/templates/components/Filter/SearchFilter.html b/src/open_inwoner/components/templates/components/Filter/SearchFilter.html deleted file mode 100644 index 4ab4b13aa3..0000000000 --- a/src/open_inwoner/components/templates/components/Filter/SearchFilter.html +++ /dev/null @@ -1,36 +0,0 @@ -{% load i18n icon_tags button_tags form_tags %} - -
-
- - - {{ field.label }} - - - {{ field.label }} - -
- -
-
- -
- - {# No submit button for direct query #} -
-
- {% button bordered=False text=_("Wis alle filters") id="resetMultiSelectFilters" extra_classes="resetMultiSelectFilters" type="button" transparent=True primary=True %} -
-
-
- -
-
-
diff --git a/src/open_inwoner/scss/components/Filter/FilterDropdown.scss b/src/open_inwoner/scss/components/Filter/FilterDropdown.scss index 30b7434a86..daf050bc6a 100644 --- a/src/open_inwoner/scss/components/Filter/FilterDropdown.scss +++ b/src/open_inwoner/scss/components/Filter/FilterDropdown.scss @@ -1,29 +1,31 @@ .filter-dropdown { position: relative; display: inline-block; + border: 0 solid transparent; + margin: 0; + padding: 0; &__button { background: var(--color-white); color: var(--color-body); - border: 1px solid var(--color-gray-dark-900); - border-radius: var(--border-radius); padding: 10px 15px; cursor: pointer; border-radius: 5px; + + @media (min-width: 768px) { + border: 1px solid var(--color-gray-dark-900); + border-radius: var(--border-radius); + } } &__menu { - position: absolute; - top: 100%; - left: 0; background: white; border: 1px solid #ccc; border-radius: 5px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); display: none; padding: 10px; - width: 200px; - z-index: 100; + width: 100%; } &__list { diff --git a/src/open_inwoner/scss/components/Form/_Search.scss b/src/open_inwoner/scss/components/Form/_Search.scss index 480ebb5b65..b3f234a10f 100644 --- a/src/open_inwoner/scss/components/Form/_Search.scss +++ b/src/open_inwoner/scss/components/Form/_Search.scss @@ -5,4 +5,10 @@ .input { margin-top: 0; } + + &__mobile { + @media (min-width: 768px) { + display: none; + } + } } diff --git a/src/open_inwoner/templates/pages/search.html b/src/open_inwoner/templates/pages/search.html index 12e3871911..cb5a36d898 100644 --- a/src/open_inwoner/templates/pages/search.html +++ b/src/open_inwoner/templates/pages/search.html @@ -27,55 +27,17 @@

{% trans "Zoekfilters" %}

{% endif %} -
-
-
- -
- -
-
-
-

{% trans "Zoekfilters" %}

-
- - - Gekozen filters -
-

{% trans "Zoekfilters" %}

- -
-
-
+ {% endif %} {# end search filters #} {% endif %}