From cd5f7b09db8278811c79cafd06b3810e3aa5a1f8 Mon Sep 17 00:00:00 2001 From: David Featherston Date: Fri, 27 Dec 2024 15:50:09 +1100 Subject: [PATCH 1/6] feat(@dpc-sdp/ripple-tide-search): search listing updates add filters sidebar and results heading, update filters toggle layout --- .../features/search-listing/filters.feature | 1 + .../search-listing/no-results.feature | 2 + .../search-listing/search-query.feature | 20 ++ .../search-listing/sidebar-filters.feature | 129 +++++++ .../filters/filters-sidebar.json | 274 ++++++++++++++ .../filters/request-sidebar.json | 90 +++++ .../nuxt-ripple/components/TideBaseLayout.vue | 5 +- .../step_definitions/content-types/listing.ts | 80 ++++- .../components/TideSearchAboveResults.vue | 25 +- .../components/TideSearchFilterHeader.vue | 40 +++ .../components/TideSearchFilterToggle.vue | 45 +++ .../components/TideSearchFilters.vue | 27 +- .../components/TideSearchListingPage.vue | 164 ++++++--- .../components/TideSearchPage.vue | 51 +-- .../components/TideSearchResultsHeading.vue | 22 ++ .../global/TideCustomCollection.vue | 339 ++++++++++-------- .../global/TideSearchFilterDateRange.vue | 6 + .../global/TideSearchFilterDependent.vue | 18 +- .../composables/useTideSearch.ts | 9 + packages/ripple-tide-search/types.ts | 6 +- .../src/components/layout/RplLayout.css | 10 +- .../src/components/layout/RplLayout.vue | 16 +- .../RplFormActions/RplFormActions.css | 9 + .../RplFormActions/RplFormActions.vue | 8 +- .../RplFormDateRange/RplFormDateRange.css | 8 + .../RplFormDateRange.stories.mdx | 12 + .../RplFormDateRange/RplFormDateRange.vue | 19 +- .../RplFormDropdown/MultiValueLabel.vue | 2 +- .../RplFormDropdown/MultiValueTagList.vue | 2 +- .../RplFormOptions/RplFormCheckboxGroup.vue | 3 +- .../RplFormOptions/RplFormOption.vue | 12 +- .../ripple-ui-forms/src/inputs/dateRange.ts | 14 +- 32 files changed, 1188 insertions(+), 280 deletions(-) create mode 100644 examples/nuxt-app/test/features/search-listing/sidebar-filters.feature create mode 100644 examples/nuxt-app/test/fixtures/search-listing/filters/filters-sidebar.json create mode 100644 examples/nuxt-app/test/fixtures/search-listing/filters/request-sidebar.json create mode 100644 packages/ripple-tide-search/components/TideSearchFilterHeader.vue create mode 100644 packages/ripple-tide-search/components/TideSearchFilterToggle.vue create mode 100644 packages/ripple-tide-search/components/TideSearchResultsHeading.vue diff --git a/examples/nuxt-app/test/features/search-listing/filters.feature b/examples/nuxt-app/test/features/search-listing/filters.feature index 0866a0d89a..4c26ded77a 100644 --- a/examples/nuxt-app/test/features/search-listing/filters.feature +++ b/examples/nuxt-app/test/features/search-listing/filters.feature @@ -218,6 +218,7 @@ Feature: Search listing - Filter Then the search listing dropdown field labelled "Terms filter example" should have the value "Purple" Then the search listing dropdown field labelled "Custom function filter example" should have the value "Open" And the search listing checkbox field labelled "Show archived content" should be checked + And the search listing checkbox field labelled "Weekdays" should be checked When I clear the search filters diff --git a/examples/nuxt-app/test/features/search-listing/no-results.feature b/examples/nuxt-app/test/features/search-listing/no-results.feature index 2bf2af3028..8395a54f83 100644 --- a/examples/nuxt-app/test/features/search-listing/no-results.feature +++ b/examples/nuxt-app/test/features/search-listing/no-results.feature @@ -13,6 +13,7 @@ Feature: No results And the search network request is stubbed with fixture "/search-listing/errors/response-empty" and status 200 When I visit the page "/search-list-grid" Then the search listing page should have 0 results + And the no results component should be display "Sorry! We couldn't find any matches" @mockserver Example: Empty response with custom component @@ -20,3 +21,4 @@ Feature: No results And the search network request is stubbed with fixture "/search-listing/errors/response-empty" and status 200 When I visit the page "/search-list-custom" Then the search listing page should have 0 results + And the no results component should be display "This is a custom component" diff --git a/examples/nuxt-app/test/features/search-listing/search-query.feature b/examples/nuxt-app/test/features/search-listing/search-query.feature index 218033fbbe..c64b885785 100644 --- a/examples/nuxt-app/test/features/search-listing/search-query.feature +++ b/examples/nuxt-app/test/features/search-listing/search-query.feature @@ -4,6 +4,26 @@ Feature: Search Queries Given the site endpoint returns fixture "/site/reference" with status 200 And I am using a "macbook-16" device + @mockserver + Example: The search term is displayed after submitting a search with results + Given the page endpoint for path "/" returns fixture "/search-listing/search-query/page" with status 200 + And the search network request is stubbed with fixture "/search-listing/search-query/response" and status 200 + + When I visit the page "/" + Then I type "Grant" into the search input + And I click the search button + Then the search results heading should show "Search results for 'Grant'" + + @mockserver + Example: The search term is not displayed after submitting a search with no results + Given the page endpoint for path "/" returns fixture "/search-listing/search-query/page" with status 200 + And the search network request is stubbed with fixture "/search-listing/errors/response-empty" and status 200 + + When I visit the page "/" + Then I type "Zoo" into the search input + And I click the search button + Then the search results heading should not be displayed + @mockserver Example: The search term query can be extended and a custom query config supplied Given the page endpoint for path "/" returns fixture "/search-listing/search-query/page" with status 200 diff --git a/examples/nuxt-app/test/features/search-listing/sidebar-filters.feature b/examples/nuxt-app/test/features/search-listing/sidebar-filters.feature new file mode 100644 index 0000000000..4c970114c3 --- /dev/null +++ b/examples/nuxt-app/test/features/search-listing/sidebar-filters.feature @@ -0,0 +1,129 @@ +Feature: Search listing - Sidebar filters + + Background: + Given the site endpoint returns fixture "/site/reference" with status 200 + And the search autocomplete request is stubbed with "/search-listing/suggestions/none" fixture + + @mockserver + Example: Sidebar filters are visible open on page load (desktop) + Given I am using a "macbook-16" device + Then the page endpoint for path "/filters" returns fixture "/search-listing/filters/filters-sidebar" with status 200 + And the search network request is stubbed with fixture "/search-listing/filters/response" and status 200 + + When I visit the page "/filters" + Then the search listing filters section should be open + And the search listing filters should be within the sidebar + + @mockserver + Example: Sidebar filters are collapsed open on page load (mobile) + Given I am using a "iphone-x" device + Then the page endpoint for path "/filters" returns fixture "/search-listing/filters/filters-sidebar" with status 200 + And the search network request is stubbed with fixture "/search-listing/filters/response" and status 200 + + When I visit the page "/filters" + Then the search listing filters section should not be open + + @mockserver + Example: Submitting the search bar scrolls to results + Given the page endpoint for path "/filters" returns fixture "/search-listing/filters/filters-sidebar" with status 200 + And the search network request is stubbed with fixture "/search-listing/search-query/response" and status 200 + + When I visit the page "/filters" + And I type "The" into the search input + And I click the search button + Then I should be scrolled to the search results with an offset of 32 + + @mockserver + Example: Sidebar filters update the URL and tally when the filters are applied + Given the page endpoint for path "/filters" returns fixture "/search-listing/filters/filters-sidebar" with status 200 + And the search network request is stubbed with fixture "/search-listing/filters/response" and status 200 + + When I visit the page "/filters" + Then the search listing page should have 2 results + And the sidebar filters heading should show 0 applied filters + And the search network request should be called with the "/search-listing/filters/request-clear-empty" fixture + + When I type "the" into the search input + And I click the search listing dropdown field labelled "Term filter example" + Then I click the option labelled "Blue" in the selected dropdown + + When I click the search listing dropdown field labelled "Terms filter example" + Then I click the option labelled "Purple" in the selected dropdown + And I click the option labelled "Yellow" in the selected dropdown + And I click the search listing dropdown field labelled "Terms filter example" + + When I click the search listing dropdown field labelled "Terms dependent example" + And I click the option labelled "Mammals" in the selected dropdown + When I click the search listing dropdown field labelled "Terms dependent child example" + And I click the option labelled "Dogs" in the selected dropdown + When I click the search listing dropdown field labelled "Terms dependent grandchild example" + And I click the option labelled "Beagle" in the selected dropdown + And I click the option labelled "Spaniel" in the selected dropdown + Then I click the search listing dropdown field labelled "Terms dependent grandchild example" + + And I click the search listing checkbox field labelled "Show archived content" + And I click the search listing checkbox field labelled "Weekdays" + And I click the search listing checkbox field labelled "Weekends" + + Then I enter the range from "2025-02-22" to "2026-06-03" in the date range field labelled "Date range example" + + When I submit the search filters + Then the URL should reflect that the current active filters are as follows: + | id | value | index | + | q | the | 0 | + | termFilter | Blue | 0 | + | termsFilter | Purple | 0 | + | termsFilter | Yellow | 1 | + | dependentFilter | dependentFilter-1:Mammals | 0 | + | dependentFilter | dependentFilter-2:Dogs | 1 | + | dependentFilter | dependentFilter-3:Beagle,Spaniel | 2 | + | checkboxFilter | Archived | | + | checkboxFilterGroup | Weekdays | 0 | + | checkboxFilterGroup | Weekends | 1 | + | dateRangeFilter | from:2025-02-22 | 0 | + | dateRangeFilter | to:2026-06-03 | 1 | + And the sidebar filters heading should show 8 applied filters + + @mockserver + Example: Sidebar filters reflect values from the URL + Given the page endpoint for path "/filters" returns fixture "/search-listing/filters/filters-sidebar" with status 200 + And the search network request is stubbed with fixture "/search-listing/filters/response" and status 200 + + When I visit the page "/filters?q=the&termFilter=Blue&termsFilter=Purple&termsFilter=Yellow&dependentFilter=dependentFilter-1:Mammals&dependentFilter=dependentFilter-2:Dogs&dependentFilter=dependentFilter-3:Beagle,Spaniel&checkboxFilter=Archived&checkboxFilterGroup=Weekends&dateRangeFilter=from:2025-02-22&dateRangeFilter=to:2026-06-03" + And the search network request should be called with the "/search-listing/filters/request-sidebar" fixture + And the sidebar filters heading should show 8 applied filters + + Then the search input should have the value "the" + Then the search listing dropdown field labelled "Term filter example" should have the value "Blue" + Then the search listing dropdown field labelled "Terms filter example" should have the value "Purple, Yellow" + Then the search listing dropdown field labelled "Terms dependent example" should have the value "Mammals" + Then the search listing dropdown field labelled "Terms dependent child example" should have the value "Dogs" + Then the search listing dropdown field labelled "Terms dependent grandchild example" should have the value "Beagle, Spaniel" + And the search listing checkbox field labelled "Show archived content" should be checked + And the search listing checkbox field labelled "Weekends" should be checked + And the search listing date range field labelled "Date range example" should have the values + | from | to | + | 2025-02-22 | 2026-06-03 | + + When I clear the search filters + And the sidebar filters heading should show 0 applied filters + Then the URL should reflect that the current active filters are as follows: + | id | + | q | + | termFilter | + | termsFilter | + | dependentFilter | + | checkboxFilter | + | checkboxFilterGroup | + | dateRangeFilter | + Then the search input should have the value "" + Then the search listing dropdown field labelled "Term filter example" should have the value "Select a colour" + Then the search listing dropdown field labelled "Terms filter example" should have the value "Select a colour" + Then the search listing dropdown field labelled "Terms dependent example" should have the value "Select a species" + Then the search listing dropdown field labelled "Terms dependent child example" should have the value "All sub species" + Then the search listing dropdown field labelled "Terms dependent grandchild example" should have the value "All sub sub species" + And the search listing checkbox field labelled "Show archived content" should not be checked + And the search listing checkbox group labelled "Checkbox group" should not have any options checked + And the search listing date range field labelled "Date range example" should have the values + | from | to | + | | | diff --git a/examples/nuxt-app/test/fixtures/search-listing/filters/filters-sidebar.json b/examples/nuxt-app/test/fixtures/search-listing/filters/filters-sidebar.json new file mode 100644 index 0000000000..0a950c0129 --- /dev/null +++ b/examples/nuxt-app/test/fixtures/search-listing/filters/filters-sidebar.json @@ -0,0 +1,274 @@ +{ + "title": "Filters sidebar", + "changed": "2022-11-02T12:47:29+11:00", + "created": "2022-11-02T12:47:29+11:00", + "type": "tide_search_listing", + "nid": "11dede11-10c0-111e1-1100-000000000330", + "showTopicTags": true, + "summary": "", + "config": { + "searchListingConfig": { + "resultsPerPage": 10, + "filtersInSidebar": true + }, + "queryConfig": { + "multi_match": { + "query": "{{query}}", + "fields": [ + "title^3", + "field_landing_page_summary^2", + "body", + "field_paragraph_body", + "summary_processed" + ] + } + }, + "results": { + "layout": { + "component": "TideSearchResultsList" + }, + "item": { + "grant": { + "component": "TideGrantSearchResult" + } + } + }, + "globalFilters": [ + { "terms": { "type": ["grant"] } }, + { "terms": { "field_node_site": [8888] } } + ], + "userFilters": [ + { + "id": "termFilter", + "component": "TideSearchFilterDropdown", + "filter": { + "type": "term", + "multiple": false, + "value": "termFilter.keyword" + }, + "aggregations": { + "field": "termFilter", + "source": "taxonomy" + }, + "props": { + "id": "termFilter", + "label": "Term filter example", + "placeholder": "Select a colour", + "multiple": false, + "options": [ + { + "id": "1", + "label": "Red", + "value": "Red" + }, + { + "id": "2", + "label": "Green", + "value": "Green" + }, + { + "id": "3", + "label": "Blue", + "value": "Blue" + } + ] + } + }, + { + "id": "termsFilter", + "component": "TideSearchFilterDropdown", + "filter": { + "type": "terms", + "value": "termsFilter.keyword" + }, + "aggregations": { + "field": "termsFilter", + "source": "taxonomy" + }, + "props": { + "id": "termsFilter", + "label": "Terms filter example", + "placeholder": "Select a colour", + "multiple": true, + "options": [ + { + "id": "1", + "label": "Orange", + "value": "Orange" + }, + { + "id": "2", + "label": "Purple", + "value": "Purple" + }, + { + "id": "3", + "label": "Yellow", + "value": "Yellow" + } + ] + } + }, + { + "id": "dependentFilter", + "component": "TideSearchFilterDependent", + "columns": "rpl-grid--inherit", + "filter": { + "type": "dependent", + "multiple": false, + "value": "field_species_name" + }, + "aggregations": { + "field": "species", + "source": "taxonomy" + }, + "props": { + "id": "dependentFilter", + "levels": [ + { + "label": "Terms dependent example", + "placeholder": "Select a species", + "multiple": false + }, + { + "label": "Terms dependent child example", + "placeholder": "All sub species", + "multiple": false + }, + { + "label": "Terms dependent grandchild example", + "placeholder": "All sub sub species", + "multiple": true + } + ], + "options": [ + { + "id": 1, + "label": "Mammals", + "value": "Mammals", + "parent": null + }, + { + "id": 2, + "label": "Dogs", + "value": "Dogs", + "parent": 1 + }, + { + "id": 3, + "label": "Birds", + "value": "Birds", + "parent": null + }, + { + "id": 4, + "label": "Cats", + "value": "Cats", + "parent": 1 + }, + { + "id": 5, + "label": "Parrots", + "value": "Parrots", + "parent": 3 + }, + { + "id": 6, + "label": "Eagles", + "value": "Eagles", + "parent": 3 + }, + { + "id": 7, + "label": "Cockatoos", + "value": "Cockatoos", + "parent": 5 + }, + { + "id": 8, + "label": "Budgerigars", + "value": "Budgerigars", + "parent": 5 + }, + { + "id": 9, + "label": "Foxes", + "value": "Foxes", + "parent": 1 + }, + { + "id": 10, + "label": "Beagle", + "value": "Beagle", + "parent": 2 + }, + { + "id": 11, + "label": "Spaniel", + "value": "Spaniel", + "parent": 2 + } + ] + } + }, + { + "id": "checkboxFilter", + "component": "TideSearchFilterCheckbox", + "filter": { + "type": "terms", + "value": "checkboxFilter.keyword", + "multiple": false + }, + "props": { + "id": "checkboxFilter", + "label": "Checkbox example", + "checkboxLabel": "Show archived content", + "onValue": "Archived" + } + }, + { + "id": "checkboxFilterGroup", + "component": "TideSearchFilterCheckboxGroup", + "filter": { + "type": "terms", + "value": "checkboxFilterGroup.keyword", + "multiple": true + }, + "props": { + "id": "checkboxFilterGroup", + "label": "Checkbox group", + "layout": "inline", + "options": [ + { + "id": "Weekdays", + "label": "Weekdays", + "value": "Weekdays" + }, + { + "id": "Weekends", + "label": "Weekends", + "value": "Weekends" + } + ] + } + }, + { + "id": "dateRangeFilter", + "component": "TideSearchFilterDateRange", + "filter": { + "type": "range", + "value": "changed", + "multiple": false, + "countAsSingle": true, + "valueIsObject": true + }, + "props": { + "id": "dateRangeFilter", + "label": "Date range example", + "min": "2024-07-01", + "max": "2084-06-30" + } + } + ] + } +} diff --git a/examples/nuxt-app/test/fixtures/search-listing/filters/request-sidebar.json b/examples/nuxt-app/test/fixtures/search-listing/filters/request-sidebar.json new file mode 100644 index 0000000000..b1fa16fbec --- /dev/null +++ b/examples/nuxt-app/test/fixtures/search-listing/filters/request-sidebar.json @@ -0,0 +1,90 @@ +{ + "query": { + "bool": { + "must": { + "multi_match": { + "query": "the", + "fields": [ + "title^3", + "field_landing_page_summary^2", + "body", + "field_paragraph_body", + "summary_processed" + ] + } + }, + "filter": [ + { + "terms": { + "type": [ + "grant" + ] + } + }, + { + "terms": { + "field_node_site": [ + 8888 + ] + } + }, + { + "terms": { + "field_species_name": [ + "Beagle", + "Spaniel" + ] + } + }, + { + "range": { + "changed": { + "time_zone": "Australia/Melbourne", + "gte": "2025-02-22", + "lte": "2026-06-03" + } + } + }, + { + "terms": { + "termFilter.keyword": [ + "Blue" + ] + } + }, + { + "terms": { + "termsFilter.keyword": [ + "Purple", + "Yellow" + ] + } + }, + { + "terms": { + "checkboxFilter.keyword": [ + "Archived" + ] + } + }, + { + "terms": { + "checkboxFilterGroup.keyword": [ + "Weekends" + ] + } + } + ] + } + }, + "size": 10, + "from": 0, + "sort": [ + { + "_score": "desc" + }, + { + "_doc": "desc" + } + ] +} diff --git a/packages/nuxt-ripple/components/TideBaseLayout.vue b/packages/nuxt-ripple/components/TideBaseLayout.vue index 398959f507..b4bda3e804 100644 --- a/packages/nuxt-ripple/components/TideBaseLayout.vue +++ b/packages/nuxt-ripple/components/TideBaseLayout.vue @@ -3,6 +3,7 @@ :background="background" :direction="direction" :language="language" + :sideBarPlacement="sideBarPlacement" > @@ -36,12 +32,17 @@ withDefaults(defineProps(), { display: flex; flex-direction: column; gap: var(--rpl-sp-4); + margin-bottom: var(--rpl-sp-6); @media (--rpl-bp-m) { flex-direction: row; justify-content: space-between; align-items: baseline; } + + @media (--rpl-bp-xl) { + margin-bottom: var(--rpl-sp-7); + } } .tide-search-listing-above-result__left { @@ -52,17 +53,23 @@ withDefaults(defineProps(), { @media (--rpl-bp-m) { width: 360px; } + + &:empty { + display: none; + } } .tide-search-listing-above-result--compact { @media (--rpl-bp-m) { flex-direction: column; - .tide-search-listing-above-result__left, - .tide-search-listing-above-result__right { - flex-grow: 1; + .tide-search-listing-above-result__left { width: 100%; } + + .tide-search-listing-above-result__right { + align-self: flex-end; + } } } diff --git a/packages/ripple-tide-search/components/TideSearchFilterHeader.vue b/packages/ripple-tide-search/components/TideSearchFilterHeader.vue new file mode 100644 index 0000000000..aca5d80b8c --- /dev/null +++ b/packages/ripple-tide-search/components/TideSearchFilterHeader.vue @@ -0,0 +1,40 @@ + + + + + diff --git a/packages/ripple-tide-search/components/TideSearchFilterToggle.vue b/packages/ripple-tide-search/components/TideSearchFilterToggle.vue new file mode 100644 index 0000000000..c49cdf6a26 --- /dev/null +++ b/packages/ripple-tide-search/components/TideSearchFilterToggle.vue @@ -0,0 +1,45 @@ + + + + + diff --git a/packages/ripple-tide-search/components/TideSearchFilters.vue b/packages/ripple-tide-search/components/TideSearchFilters.vue index 317479f368..e9eb7f4e52 100644 --- a/packages/ripple-tide-search/components/TideSearchFilters.vue +++ b/packages/ripple-tide-search/components/TideSearchFilters.vue @@ -4,14 +4,19 @@ :title="title" @submit="handleFilterSubmit" > -
-
+
+
@@ -58,6 +65,7 @@ interface Props { resetLabel?: string | boolean reverseStyling?: boolean isBusy?: boolean + display?: 'inline' | 'block' } const emit = defineEmits<{ @@ -68,7 +76,8 @@ const emit = defineEmits<{ const props = withDefaults(defineProps(), { submitLabel: 'Apply search filters', resetLabel: 'Clear search filters', - reverseStyling: false + reverseStyling: false, + display: 'inline' }) const handleFilterReset = (event: rplEventPayload) => { @@ -83,3 +92,9 @@ const handleFilterSubmit = (formValues) => { }) } + + diff --git a/packages/ripple-tide-search/components/TideSearchListingPage.vue b/packages/ripple-tide-search/components/TideSearchListingPage.vue index f706ea837f..b4807aa5ad 100644 --- a/packages/ripple-tide-search/components/TideSearchListingPage.vue +++ b/packages/ripple-tide-search/components/TideSearchListingPage.vue @@ -7,7 +7,7 @@ import { computed } from '#imports' import { submitForm } from '@formkit/vue' -import { useDebounceFn } from '@vueuse/core' +import { useBreakpoints, useDebounceFn } from '@vueuse/core' import useTideSearch from './../composables/useTideSearch' import type { TidePageBase, TideSiteData } from '@dpc-sdp/ripple-tide-api/types' import type { @@ -16,7 +16,7 @@ import type { TideSearchListingConfig } from './../types' import type { ITideSecondaryCampaign } from '@dpc-sdp/ripple-tide-landing-page/mapping/secondary-campaign/secondary-campaign-mapping' -import { useRippleEvent } from '@dpc-sdp/ripple-ui-core' +import { bpMin, useRippleEvent } from '@dpc-sdp/ripple-ui-core' import type { rplEventPayload } from '@dpc-sdp/ripple-ui-core' import { watch } from 'vue' @@ -79,6 +79,7 @@ const props = withDefaults(defineProps(), { }, showFiltersOnLoad: false, showFiltersOnly: false, + filtersInSidebar: false, scrollToResultsOnSubmit: true }) as any, resultsLayout: () => ({ @@ -117,10 +118,15 @@ const emit = defineEmits<{ const { emitRplEvent } = useRippleEvent('tide-search', emit) -const filtersExpanded = ref( +const breakpoints = useBreakpoints(bpMin) +const isMobile = breakpoints.smaller('m') + +const initialFiltersState = + props.searchListingConfig?.filtersInSidebar || props.searchListingConfig?.showFiltersOnLoad || - props.searchListingConfig?.showFiltersOnly -) + props.searchListingConfig?.showFiltersOnly + +const filtersExpanded = ref(Boolean(initialFiltersState)) const { isBusy, @@ -128,6 +134,7 @@ const { getSuggestions, clearSuggestions, searchTerm, + appliedSearchTerm, results, suggestions, filterForm, @@ -206,7 +213,15 @@ onAggregationUpdateHook.value = (aggs: any) => { }) } -const resultsContainer = '.rpl-layout__body-wrap' +const resultsContainer = computed((): string => { + return props.searchListingConfig?.filtersInSidebar + ? '.rpl-layout__main' + : '.rpl-layout__body-wrap' +}) + +const resultsScrollOffset = computed((): number => { + return props.searchListingConfig?.filtersInSidebar ? 32 : 0 +}) const emitSearchEvent = (event: any) => { emitRplEvent( @@ -232,7 +247,7 @@ const handleSearchSubmit = (event: any) => { // If there's no filters in the form, we need to just do the search without submitting the filter form submitSearch() if (event?.type === 'button') { - scrollToResults(resultsContainer) + scrollToResults(resultsContainer.value, resultsScrollOffset.value) } emitSearchEvent({ ...event, ...baseEvent() }) } @@ -246,7 +261,7 @@ const handleFilterSubmit = (event: any) => { !cachedSubmitEvent.value?.type || cachedSubmitEvent.value?.type === 'button' ) { - scrollToResults(resultsContainer) + scrollToResults(resultsContainer.value, resultsScrollOffset.value) } emitSearchEvent({ ...event, ...cachedSubmitEvent.value, ...baseEvent() }) @@ -313,15 +328,15 @@ const handleSortChange = (sortId: any) => { changeSortOrder(sortId) } -const handleToggleFilters = () => { +const handleToggleFilters = (event: rplEventPayload) => { filtersExpanded.value = !filtersExpanded.value emitRplEvent( 'toggleFilters', { ...baseEvent(), - action: filtersExpanded.value ? 'open' : 'close', - text: toggleFiltersLabel.value + ...event, + action: filtersExpanded.value ? 'open' : 'close' }, { global: true } ) @@ -331,14 +346,6 @@ const numAppliedFilters = computed(() => { return getActiveFiltersTally(appliedFilters.value, props.userFilters) }) -const toggleFiltersLabel = computed(() => { - let label = 'Filters' - - return numAppliedFilters.value - ? `${label} (${numAppliedFilters.value})` - : label -}) - watch( () => isBusy.value, (loading, prevLoading) => { @@ -354,6 +361,12 @@ watch( } } ) + +onMounted(() => { + if (props.searchListingConfig?.filtersInSidebar && isMobile.value) { + filtersExpanded.value = false + } +})
+ diff --git a/packages/ripple-tide-search/components/global/TideSearchFilterDependent.vue b/packages/ripple-tide-search/components/global/TideSearchFilterDependent.vue index 656378f6df..5016c4cd76 100644 --- a/packages/ripple-tide-search/components/global/TideSearchFilterDependent.vue +++ b/packages/ripple-tide-search/components/global/TideSearchFilterDependent.vue @@ -7,6 +7,7 @@ interface Props { options?: any[] variant?: string columns?: string + display?: 'inline' | 'block' levels: { label: string placeholder: string @@ -18,7 +19,8 @@ const props = withDefaults(defineProps(), { options: () => [], multiple: false, variant: 'default', - columns: 'rpl-col-6-m', + columns: undefined, + display: 'inline', levels: () => [] }) @@ -124,15 +126,19 @@ watch( }, { deep: true } ) + +const columns = computed(() => { + if (props.columns) { + return `rpl-col-12 ${props.columns}` + } + + return props.display === 'block' ? 'rpl-col-12' : 'rpl-col-12 rpl-col-6-m' +})