Skip to content

Commit

Permalink
Search: similar filters in different layers are now merged, fix #
Browse files Browse the repository at this point in the history
  • Loading branch information
pietervdvn committed Sep 17, 2024
1 parent 6ebc063 commit 48186aa
Show file tree
Hide file tree
Showing 15 changed files with 156 additions and 63 deletions.
2 changes: 1 addition & 1 deletion Docs/UserTests/2024-09-11 Usertest search Jewelry.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ To validate the 'search with filters', the tester was tasked with searching all

## To improve

[ ] Why are there multiple "Open Now" filters?
[x] Why are there multiple "Open Now" filters? Because of different layers with a similar filter, they are now shown merged
[x] Special layers (e.g. gps location) are disabled as well (fixed now)
1 change: 1 addition & 0 deletions langs/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,7 @@
"error": "Something went wrong…",
"instructions": "Use the search bar above to search for locations, filters or other thematic maps",
"locations": "Locations",
"nMoreFilters": "{n} more",
"nothing": "Nothing found…",
"nothingFor": "No results found for {term}",
"otherMaps": "Other maps",
Expand Down
2 changes: 1 addition & 1 deletion langs/layers/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -7208,7 +7208,7 @@
},
"description": "Obchod",
"filter": {
"1": {
"0": {
"options": {
"0": {
"question": "Zobrazit pouze obchody prodávající použité zboží"
Expand Down
2 changes: 1 addition & 1 deletion langs/layers/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -9087,7 +9087,7 @@
},
"description": "Ein Geschäft",
"filter": {
"1": {
"0": {
"options": {
"0": {
"question": "Nur Second-Hand-Geschäfte anzeigen"
Expand Down
2 changes: 1 addition & 1 deletion langs/layers/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -9122,7 +9122,7 @@
},
"description": "A shop",
"filter": {
"1": {
"0": {
"options": {
"0": {
"question": "Only show shops selling second-hand items"
Expand Down
21 changes: 15 additions & 6 deletions public/css/index-tailwind-output.css
Original file line number Diff line number Diff line change
Expand Up @@ -1188,14 +1188,14 @@ input[type="range"].range-lg::-moz-range-thumb {
left: 25%;
}

.bottom-4 {
bottom: 1rem;
}

.top-6 {
top: 1.5rem;
}

.bottom-4 {
bottom: 1rem;
}

.bottom-5 {
bottom: 1.25rem;
}
Expand Down Expand Up @@ -2760,6 +2760,10 @@ input[type="range"].range-lg::-moz-range-thumb {
overflow-y: auto;
}

.overflow-x-hidden {
overflow-x: hidden;
}

.overflow-y-scroll {
overflow-y: scroll;
}
Expand Down Expand Up @@ -4719,6 +4723,11 @@ input[type="range"].range-lg::-moz-range-thumb {
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}

.shadow-transparent {
--tw-shadow-color: transparent;
--tw-shadow: var(--tw-shadow-colored);
}

.shadow-gray-300 {
--tw-shadow-color: #D1D5DB;
--tw-shadow: var(--tw-shadow-colored);
Expand Down Expand Up @@ -5353,8 +5362,8 @@ h2.group {
align-items: center;
white-space: nowrap;
border-radius: 999rem;
padding-left: 0.5rem;
padding-right: 0.5rem;
padding-left: 0.25rem;
padding-right: 0.25rem;
border: 1px solid var(--subtle-detail-color-light-contrast);
background-color: var(--low-interaction-background);
}
Expand Down
20 changes: 19 additions & 1 deletion src/Logic/Search/FilterSearch.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { SpecialVisualizationState } from "../../UI/SpecialVisualization"
import { Utils } from "../../Utils"
import Locale from "../../UI/i18n/Locale"
import Constants from "../../Models/Constants"
Expand Down Expand Up @@ -110,4 +109,23 @@ export default class FilterSearch {
Utils.shuffle(result)
return result.slice(0, 6)
}

/**
* Partitions the list of filters in such a way that identically appearing filters will be in the same sublist.
*
* Note that this depends on the language and the displayed text. For example, two filters {"en": "A", "nl": "B"} and {"en": "X", "nl": "B"} will be joined for dutch but not for English
*
*/
static mergeSemiIdenticalLayers<T extends FilterSearchResult = FilterSearchResult>(filters: ReadonlyArray<T>, language: string):T[][] {
const results : Record<string, T[]> = {}
for (const filter of filters) {
const txt = filter.option.question.textFor(language)
if(results[txt]){
results[txt].push(filter)
}else{
results[txt] = [filter]
}
}
return Object.values(results)
}
}
36 changes: 21 additions & 15 deletions src/Logic/State/SearchState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export default class SearchState {
return !foundMatch
})
}, [state.layerState.activeFilters])
this.locationResults =new GeocodingFeatureSource(this.suggestions.stabilized(250))
this.locationResults = new GeocodingFeatureSource(this.suggestions.stabilized(250))

this.showSearchDrawer = new UIEventSource(false)

Expand All @@ -92,7 +92,7 @@ export default class SearchState {

}

public async apply(result: FilterSearchResult | LayerConfig) {
public async apply(result: FilterSearchResult[] | LayerConfig) {
if (result instanceof LayerConfig) {
return this.applyLayer(result)
}
Expand All @@ -105,37 +105,43 @@ export default class SearchState {
}
}

private async applyFilter(payload: FilterSearchResult) {
private async applyFilter(payload: FilterSearchResult[]) {
const state = this.state

const { layer, filter, index } = payload
const layers = payload.map(fsr => fsr.layer.id)
for (const [name, otherLayer] of state.layerState.filteredLayers) {
const layer = otherLayer.layerDef
if(!layer.isNormal()){
if (!layer.isNormal()) {
continue
}
otherLayer.isDisplayed.setData(payload.layer.id === layer.id)
if(otherLayer.layerDef.minzoom > state.mapProperties.minzoom.data) {
// Currently not displayed, we don't hide
continue
}
otherLayer.isDisplayed.setData(layers.indexOf(layer.id) > 0)
}
const flayer = state.layerState.filteredLayers.get(layer.id)
flayer.isDisplayed.set(true)
const filtercontrol = flayer.appliedFilters.get(filter.id)
if (filtercontrol.data === index) {
filtercontrol.setData(undefined)
} else {
filtercontrol.setData(index)
for (const { filter, index, layer } of payload) {
const flayer = state.layerState.filteredLayers.get(layer.id)
flayer.isDisplayed.set(true)
const filtercontrol = flayer.appliedFilters.get(filter.id)
if (filtercontrol.data === index) {
filtercontrol.setData(undefined)
} else {
filtercontrol.setData(index)
}
}
}

closeIfFullscreen() {
if(window.innerWidth < 640){
if (window.innerWidth < 640) {
this.showSearchDrawer.set(false)
}
}

clickedOnMap(feature: Feature) {
const osmid = feature.properties.osm_id
const localElement = this.state.indexedFeatures.featuresById.data.get(osmid)
if(localElement){
if (localElement) {
this.state.selectedElement.set(localElement)
return
}
Expand Down
1 change: 1 addition & 0 deletions src/UI/Base/SidebarUnit.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
background: var(--background-color);
padding: 0.5rem;
border-radius: 0.5rem;
overflow-y: auto;
}
:global(.sidebar-unit > h3) {
Expand Down
9 changes: 7 additions & 2 deletions src/UI/Flowbite/AccordionSingle.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@
import { Accordion, AccordionItem } from "flowbite-svelte"
export let expanded = false
export let noBorder = false
let defaultClass: string = undefined
if(noBorder){
defaultClass = "unstyled w-full flex-grow"
}
</script>

<Accordion>
<AccordionItem open={expanded} paddingDefault="p-0" inactiveClass="text-black">
<span slot="header" class="w-full p-2 text-base">
<AccordionItem open={expanded} paddingDefault="p-0" inactiveClass="text-black" {defaultClass}>
<span slot="header" class={!noBorder ? "w-full p-2 text-base" : "w-full"}>
<slot name="header" />
</span>
<div class="low-interaction rounded-b p-2">
Expand Down
19 changes: 15 additions & 4 deletions src/UI/Search/ActiveFilter.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,36 @@
import FilterOption from "./FilterOption.svelte"
import Loading from "../Base/Loading.svelte"
import FilterToggle from "./FilterToggle.svelte"
import type { SpecialVisualizationState } from "../SpecialVisualization"
export let activeFilter: ActiveFilter
let { control, filter } = activeFilter
export let activeFilter: ActiveFilter[]
let { control, filter } = activeFilter[0]
let option = control.map(c => filter.options[c] ?? filter.options[0])
let loading = false
function clear() {
loading = true
requestIdleCallback(() => {
control.setData(undefined)
for (const af of activeFilter) {
af.control.setData(undefined)
}
loading = false
})
}
export let state: SpecialVisualizationState
let debug = state.featureSwitches.featureSwitchIsDebugging
</script>
{#if loading}
<Loading />
{:else }
<FilterToggle on:click={() => clear()}>
<FilterToggle on:click={() => clear()}>
<FilterOption option={$option} />
{#if $debug}
<span class="subtle">
({activeFilter.map(af => af.layer.id).join(", ")})
</span>
{/if}
</FilterToggle>
{/if}
19 changes: 12 additions & 7 deletions src/UI/Search/ActiveFilters.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,17 @@
import FilterToggle from "./FilterToggle.svelte"
import ToSvelte from "../Base/ToSvelte.svelte"
import Tr from "../Base/Tr.svelte"
import { Store } from "../../Logic/UIEventSource"
import { Store, UIEventSource } from "../../Logic/UIEventSource"
import Translations from "../i18n/Translations"
import type { FilterSearchResult } from "../../Logic/Search/FilterSearch"
import FilterSearch from "../../Logic/Search/FilterSearch"
export let activeFilters: ActiveFilter[]
import Locale from "../i18n/Locale"
export let activeFilters: ( FilterSearchResult & ActiveFilter)[]
let language = Locale.language
let mergedActiveFilters = FilterSearch.mergeSemiIdenticalLayers(activeFilters, $language)
$:mergedActiveFilters = FilterSearch.mergeSemiIdenticalLayers(activeFilters, $language)
export let state: SpecialVisualizationState
let loading = false
const t =Translations.t.general.search
Expand All @@ -33,8 +40,6 @@
loading = true
requestIdleCallback(() => {
enableAllLayers()
for (const activeFilter of activeFilters) {
activeFilter.control.setData(undefined)
}
Expand All @@ -44,7 +49,7 @@
}
</script>

{#if activeFilters.length > 0 || $nonactiveLayers.length > 0}
{#if mergedActiveFilters.length > 0 || $nonactiveLayers.length > 0}
<SidebarUnit>
<div class="flex justify-between">
<h3><Tr t={t.activeFilters}/></h3>
Expand Down Expand Up @@ -81,9 +86,9 @@
{/if}


{#each activeFilters as activeFilter (activeFilter)}
{#each mergedActiveFilters as activeFilter (activeFilter)}
<div>
<ActiveFilterSvelte {activeFilter} />
<ActiveFilterSvelte {activeFilter} {state}/>
</div>
{/each}
</div>
Expand Down
23 changes: 16 additions & 7 deletions src/UI/Search/FilterResult.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,19 @@
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
import Loading from "../Base/Loading.svelte"
export let entry: FilterSearchResult | LayerConfig
let isLayer = entry instanceof LayerConfig
let asLayer = <LayerConfig>entry
let asFilter = <FilterSearchResult>entry
export let entry: FilterSearchResult[] | LayerConfig
let asFilter: FilterSearchResult[]
let asLayer: LayerConfig
if(Array.isArray(entry)){
asFilter = entry
}else{
asLayer = <LayerConfig>entry
}
export let state: SpecialVisualizationState
let loading = false
let debug = state.featureSwitches.featureSwitchIsDebugging
function apply() {
loading = true
Expand All @@ -34,16 +40,19 @@
{/if}
<div class="flex flex-col items-start">
<div class="flex items-center gap-x-1">
{#if isLayer}
{#if asLayer}
<div class="w-8 h-8 p-1">
<ToSvelte construct={asLayer.defaultIcon()} />
</div>
<b>
<Tr t={asLayer.name} />
</b>
{:else}
<Icon icon={asFilter.option.icon ?? asFilter.option.emoji} clss="w-4 h-4" emojiHeight="14px" />
<Tr cls="whitespace-nowrap" t={asFilter.option.question} />
<Icon icon={asFilter[0].option.icon ?? asFilter[0].option.emoji} clss="w-4 h-4" emojiHeight="14px" />
<Tr cls="whitespace-nowrap" t={asFilter[0].option.question} />
{#if $debug}
<span class="subtle">({asFilter.map(f => f.layer.id).join(", ")})</span>
{/if}
{/if}
</div>
</div>
Expand Down
Loading

0 comments on commit 48186aa

Please sign in to comment.