diff --git a/src/open_inwoner/components/templates/components/Filter/Filter.html b/src/open_inwoner/components/templates/components/Filter/Filter.html index 31546f24bb..21988d56c3 100644 --- a/src/open_inwoner/components/templates/components/Filter/Filter.html +++ b/src/open_inwoner/components/templates/components/Filter/Filter.html @@ -1,9 +1,10 @@ -{% load i18n filter_tags icon_tags form_tags %} +{% load i18n filter_tags icon_tags button_tags form_tags %}
-
+
+ {% button href="#" icon="expand_more" icon_position="after" extra_classes="filter__mobile filter--toggle" bordered=False text=field.label %} - {{ field.label }} + {{ field.label }}
{% for option in field.field.choices %} @@ -11,5 +12,5 @@ {% endfor %}
-
+
diff --git a/src/open_inwoner/configurations/admin.py b/src/open_inwoner/configurations/admin.py index bb69c97f62..c5e8886e71 100644 --- a/src/open_inwoner/configurations/admin.py +++ b/src/open_inwoner/configurations/admin.py @@ -162,6 +162,16 @@ class SiteConfigurarionAdmin(OrderedInlineModelAdminMixin, SingletonModelAdmin): ), }, ), + ( + _("Search filter options"), + { + "fields": ( + "search_filter_categories", + "search_filter_tags", + "search_filter_organizations", + ) + }, + ), (_("Emails"), {"fields": ("email_new_message",)}), ( _("Openid Connect"), diff --git a/src/open_inwoner/configurations/migrations/0052_siteconfiguration_search_filters.py b/src/open_inwoner/configurations/migrations/0052_siteconfiguration_search_filters.py new file mode 100644 index 0000000000..92b460ace0 --- /dev/null +++ b/src/open_inwoner/configurations/migrations/0052_siteconfiguration_search_filters.py @@ -0,0 +1,40 @@ +# Generated by Django 3.2.20 on 2023-09-18 10:09 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("configurations", "0051_merge_20230907_1800"), + ] + + operations = [ + migrations.AddField( + model_name="siteconfiguration", + name="search_filter_categories", + field=models.BooleanField( + default=True, + help_text="Whether to show category-checkboxes in order to filter the search result.", + verbose_name="Add category filter for search results", + ), + ), + migrations.AddField( + model_name="siteconfiguration", + name="search_filter_organizations", + field=models.BooleanField( + default=True, + help_text="Whether to show organization-checkboxes in order to filter the search result.", + verbose_name="Add organization filter for search results", + ), + ), + migrations.AddField( + model_name="siteconfiguration", + name="search_filter_tags", + field=models.BooleanField( + default=True, + help_text="Whether to show tag-checkboxes in order to filter the search result.", + verbose_name="Add tag filter for search results", + ), + ), + ] diff --git a/src/open_inwoner/configurations/models.py b/src/open_inwoner/configurations/models.py index e9c0955ea1..ef03af5fc3 100644 --- a/src/open_inwoner/configurations/models.py +++ b/src/open_inwoner/configurations/models.py @@ -316,6 +316,31 @@ class SiteConfiguration(SingletonModel): verbose_name=_("Plan help"), help_text=_("The help text for the plan page."), ) + + # search filters + search_filter_categories = models.BooleanField( + verbose_name=_("Add category filter for search results"), + default=True, + help_text=_( + "Whether to show category-checkboxes in order to filter the search result." + ), + ) + search_filter_tags = models.BooleanField( + verbose_name=_("Add tag filter for search results"), + default=True, + help_text=_( + "Whether to show tag-checkboxes in order to filter the search result." + ), + ) + search_filter_organizations = models.BooleanField( + verbose_name=_("Add organization filter for search results"), + default=True, + help_text=_( + "Whether to show organization-checkboxes in order to filter the search result." + ), + ) + + # email notifications email_new_message = models.BooleanField( verbose_name=_("Send email about a new message"), default=True, diff --git a/src/open_inwoner/js/components/search/filter-mobile.js b/src/open_inwoner/js/components/search/filter-mobile.js new file mode 100644 index 0000000000..b34aeccada --- /dev/null +++ b/src/open_inwoner/js/components/search/filter-mobile.js @@ -0,0 +1,34 @@ +export class FilterMobile { + static selector = '.filter--toggle' + + constructor(node) { + this.node = node + this.node.addEventListener('click', this.toggleOpen.bind(this)) + document.addEventListener('keydown', this.filterClosing.bind(this), false) + } + + toggleOpen(event) { + event.preventDefault() + console.log('this is mobile') + const filterParent = this.node.parentElement + if (filterParent) { + filterParent.classList.toggle('filter--open') + } + } + + filterClosing(event) { + if (event.type === 'keydown' && event.key === 'Escape') { + const filterParent = this.node.parentElement + if (filterParent) { + filterParent.classList.remove('filter--open') + } + } + } +} + +/** + * Controls the toggling of filter lists on mobile to view more + */ +document + .querySelectorAll(FilterMobile.selector) + .forEach((filterToggle) => new FilterMobile(filterToggle)) diff --git a/src/open_inwoner/js/components/search/filter-options.js b/src/open_inwoner/js/components/search/filter-options.js new file mode 100644 index 0000000000..26de0cdd6f --- /dev/null +++ b/src/open_inwoner/js/components/search/filter-options.js @@ -0,0 +1,28 @@ +const radioButtons = document.querySelectorAll( + '.feedback__options .button-radio__input' +) + +;[...radioButtons].forEach((radioButton) => { + radioButton.addEventListener('click', (event) => { + const feedbackRemarks = document.querySelectorAll('.feedback__remark') + ;[...feedbackRemarks].forEach((feedbackRemark) => + feedbackRemark.classList.add('feedback__remark--show') + ) + }) +}) + +let timerId = null + +const searchForm = document.getElementById('search-form') + +const filterButtons = document.querySelectorAll('.filter .checkbox__input') +;[...filterButtons].forEach((checkbox) => { + checkbox.addEventListener('change', (event) => { + clearTimeout(timerId) + + // Set a new interval + timerId = setTimeout(() => { + searchForm.submit() + }, 250) + }) +}) diff --git a/src/open_inwoner/js/components/search/index.js b/src/open_inwoner/js/components/search/index.js index 7a06c26c79..2f8febe1b3 100644 --- a/src/open_inwoner/js/components/search/index.js +++ b/src/open_inwoner/js/components/search/index.js @@ -1,28 +1,2 @@ -const radioButtons = document.querySelectorAll( - '.feedback__options .button-radio__input' -) - -;[...radioButtons].forEach((radioButton) => { - radioButton.addEventListener('click', (event) => { - const feedbackRemarks = document.querySelectorAll('.feedback__remark') - ;[...feedbackRemarks].forEach((feedbackRemark) => - feedbackRemark.classList.add('feedback__remark--show') - ) - }) -}) - -let timerId = null - -const searchForm = document.getElementById('search-form') - -const filterButtons = document.querySelectorAll('.filter .checkbox__input') -;[...filterButtons].forEach((checkbox) => { - checkbox.addEventListener('change', (event) => { - clearTimeout(timerId) - - // Set a new timeout - timerId = setTimeout(() => { - searchForm.submit() - }, 250) - }) -}) +import './filter-mobile' +import './filter-options' diff --git a/src/open_inwoner/scss/components/Divider/Divider.scss b/src/open_inwoner/scss/components/Divider/Divider.scss index 4e785e7137..0fb79667bd 100644 --- a/src/open_inwoner/scss/components/Divider/Divider.scss +++ b/src/open_inwoner/scss/components/Divider/Divider.scss @@ -6,6 +6,10 @@ margin: var(--spacing-large) 0; } + &--tiny { + margin: var(--spacing-medium) 0; + } + @media (min-width: 768px) { margin: var(--spacing-giant) 0; } diff --git a/src/open_inwoner/scss/components/Filter/Filter.scss b/src/open_inwoner/scss/components/Filter/Filter.scss index 9df009eba7..ce68df4f84 100644 --- a/src/open_inwoner/scss/components/Filter/Filter.scss +++ b/src/open_inwoner/scss/components/Filter/Filter.scss @@ -1,12 +1,36 @@ .filter { border: 0 solid transparent; + margin: 0; + padding: 0; - &--open { - .filter__list { + @media (min-width: 768px) { + padding: 0 var(--spacing-large) var(--spacing-large) var(--spacing-large); + } + + &__list { + padding-top: 0; + padding-bottom: var(--spacing-large); + display: none; + grid-template-columns: 1fr; + gap: var(--spacing-large); + + @media (min-width: 768px) { display: grid; + padding-top: var(--spacing-large); + padding-bottom: 0; + } + + .checkbox .checkbox__label { + cursor: pointer; } } + .button { + color: var(--font-color-body); + font-weight: bold; + padding: 0; + } + &__title { color: var(--font-color-heading-4); font-family: var(--font-family-heading); @@ -14,14 +38,69 @@ font-weight: bold; letter-spacing: 0; line-height: 21px; - cursor: pointer; display: flex; } - &__list { - padding-top: var(--spacing-large); - display: none; - grid-template-columns: 1fr; - gap: var(--spacing-large); + &__legend { + &-label { + display: none; + @media (min-width: 768px) { + display: inline; + } + } + } + + .divider { + background-color: yellow; + border: red solid 5px !important; + &--small { + display: none; + @media (min-width: 768px) { + display: block; + } + } + &--tiny { + display: block; + @media (min-width: 768px) { + display: none; + } + } + } + + &__mobile { + @media (min-width: 768px) { + display: none; + } + } + + //toggling dropdows + &.filter--open { + .button { + color: var(--color-secondary); + padding: 0; + } + + .button--textless [class*='icon'] { + display: inline-block; + right: var(--spacing-large); + top: 0; + transform: rotate(180deg); + transition: all 0.3s; + } + + .filter__list { + display: grid; + } + } +} + +.grid__filters { + .h2 { + border-bottom: 2px solid var(--color-gray-light); + display: block; + padding-bottom: var(--spacing-large); + @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 cc3a587c3c..57e003162b 100644 --- a/src/open_inwoner/templates/pages/search.html +++ b/src/open_inwoner/templates/pages/search.html @@ -18,10 +18,20 @@

{% trans "Zoeken naar " %} "{{ form.query.value }}"

{# facets and results section #} {% if paginator.count %}
-