From 93f03ddbaf71f87e2559714d5b892c89789ec693 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Fri, 30 Aug 2024 02:18:29 +0200 Subject: [PATCH] Improve search UI --- assets/layers/food/food.json | 2 +- public/css/index-tailwind-output.css | 24 ++- src/Logic/Geocoding/FilterSearch.ts | 55 +++-- src/Logic/Geocoding/GeocodingProvider.ts | 3 +- src/Logic/Geocoding/ThemeSearch.ts | 30 +-- src/Logic/State/SearchState.ts | 189 +++++++++++++++++ src/Logic/UIEventSource.ts | 8 +- src/Models/ThemeConfig/LayoutConfig.ts | 2 +- src/Models/ThemeViewState.ts | 16 +- src/UI/Base/DrawerRight.svelte | 43 ++++ src/UI/BigComponents/ThemeIntroPanel.svelte | 45 +---- src/UI/Popup/MoveWizard.svelte | 3 +- src/UI/Search/ActiveFilter.svelte | 32 ++- src/UI/Search/ActiveFilters.svelte | 31 ++- src/UI/Search/FilterResult.svelte | 10 +- src/UI/Search/Geosearch.svelte | 161 ++------------- src/UI/Search/SearchResult.svelte | 4 +- src/UI/Search/SearchResultUtils.ts | 25 --- src/UI/Search/SearchResults.svelte | 159 +++++++-------- src/UI/Search/ThemeResult.svelte | 4 +- src/UI/SpecialVisualization.ts | 4 +- src/UI/ThemeViewGUI.svelte | 213 ++++++++++---------- 22 files changed, 564 insertions(+), 499 deletions(-) create mode 100644 src/Logic/State/SearchState.ts create mode 100644 src/UI/Base/DrawerRight.svelte delete mode 100644 src/UI/Search/SearchResultUtils.ts diff --git a/assets/layers/food/food.json b/assets/layers/food/food.json index 7445bcdd0..b20a1b6ed 100644 --- a/assets/layers/food/food.json +++ b/assets/layers/food/food.json @@ -537,7 +537,7 @@ }, { "if": "cuisine=mexican ", - "icon": "\uD83C\uDDF2\uD83C\uDDFD", + "icon": "🇲🇽", "then": { "en": "Mexican dishes are served here", "nl": "Dit is een mexicaans restaurant" diff --git a/public/css/index-tailwind-output.css b/public/css/index-tailwind-output.css index 2cd367143..e4b532563 100644 --- a/public/css/index-tailwind-output.css +++ b/public/css/index-tailwind-output.css @@ -1913,6 +1913,10 @@ input[type="range"].range-lg::-moz-range-thumb { max-height: 3rem; } +.max-h-screen { + max-height: 100vh; +} + .max-h-full { max-height: 100%; } @@ -1925,10 +1929,6 @@ input[type="range"].range-lg::-moz-range-thumb { max-height: 16rem; } -.max-h-96 { - max-height: 24rem; -} - .max-h-60 { max-height: 15rem; } @@ -8168,12 +8168,12 @@ svg.apply-fill path { width: 16rem; } - .sm\:w-11 { - width: 2.75rem; + .sm\:w-80 { + width: 20rem; } - .sm\:w-96 { - width: 24rem; + .sm\:w-11 { + width: 2.75rem; } .sm\:w-auto { @@ -8188,6 +8188,10 @@ svg.apply-fill path { width: 1.5rem; } + .sm\:w-96 { + width: 24rem; + } + .sm\:grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); } @@ -8373,6 +8377,10 @@ svg.apply-fill path { height: 100%; } + .md\:w-96 { + width: 24rem; + } + .md\:w-6\/12 { width: 50%; } diff --git a/src/Logic/Geocoding/FilterSearch.ts b/src/Logic/Geocoding/FilterSearch.ts index e9d97f85f..76ec83389 100644 --- a/src/Logic/Geocoding/FilterSearch.ts +++ b/src/Logic/Geocoding/FilterSearch.ts @@ -1,5 +1,5 @@ import { ImmutableStore, Store } from "../UIEventSource" -import GeocodingProvider, { GeocodingOptions, SearchResult } from "./GeocodingProvider" +import GeocodingProvider, { FilterPayload, FilterResult, GeocodingOptions, SearchResult } from "./GeocodingProvider" import { SpecialVisualizationState } from "../../UI/SpecialVisualization" import { Utils } from "../../Utils" import Locale from "../../UI/i18n/Locale" @@ -13,17 +13,29 @@ export default class FilterSearch implements GeocodingProvider { } async search(query: string): Promise { - return this.searchDirectly(query) + return this.searchDirectlyWrapped(query) } - private searchDirectly(query: string): SearchResult[] { - const possibleFilters: SearchResult[] = [] + private searchDirectlyWrapped(query: string): FilterResult[] { + return this.searchDirectly(query).map(payload => ({ + payload, + category: "filter", + osm_id: payload.layer.id + "/" + payload.filter.id + "/" + payload.option.osmTags?.asHumanString() ?? "none" + })) + } + + public searchDirectly(query: string): FilterPayload[] { if (query.length === 0) { return [] } - if(!Utils.isEmoji(query)){ - query = Utils.simplifyStringForSearch(query) - } + const queries = query.split(" ").map(query => { + if (!Utils.isEmoji(query)) { + return Utils.simplifyStringForSearch(query) + } + return query + }).filter(q => q.length > 0) + console.log("Queries:",queries) + const possibleFilters: FilterPayload[] = [] for (const layer of this._state.layout.layers) { if (!Array.isArray(layer.filters)) { continue @@ -34,22 +46,27 @@ export default class FilterSearch implements GeocodingProvider { if (option === undefined) { continue } + if (!option.osmTags) { + continue + } let terms = ([option.question.txt, ...(option.searchTerms?.[Locale.language.data] ?? option.searchTerms?.["en"] ?? [])] - .flatMap(term => [term, ...term?.split(" ")])) + .flatMap(term => [term, ...(term?.split(" ") ?? [])])) terms = terms.map(t => Utils.simplifyStringForSearch(t)) terms.push(option.emoji) Utils.NoNullInplace(terms) - const levehnsteinD = Math.min(... - terms.map(entry => Utils.levenshteinDistance(query, entry.slice(0, query.length)))) - if (levehnsteinD / query.length > 0.25) { + const distances = queries.flatMap(query => terms.map(entry => { + const d = Utils.levenshteinDistance(query, entry.slice(0, query.length)) + console.log(query,"? +",terms, "=",d) + const dRelative = d / query.length + return dRelative + })) + + const levehnsteinD = Math.min(...distances) + if (levehnsteinD > 0.25) { continue } - possibleFilters.push({ - payload: { option, layer, filter, index: i }, - category: "filter", - osm_id: layer.id + "/" + filter.id + "/" + option.osmTags?.asHumanString() ?? "none", - }) + possibleFilters.push({ option, layer, filter, index: i }) } } } @@ -57,11 +74,7 @@ export default class FilterSearch implements GeocodingProvider { } suggest(query: string, options?: GeocodingOptions): Store { - if (Utils.isEmoji(query)) { - return new ImmutableStore(this.searchDirectly(query)) - } - query = Utils.simplifyStringForSearch(query) - return new ImmutableStore(this.searchDirectly(query)) + return new ImmutableStore(this.searchDirectlyWrapped(query)) } diff --git a/src/Logic/Geocoding/GeocodingProvider.ts b/src/Logic/Geocoding/GeocodingProvider.ts index ad7823598..60aa84f95 100644 --- a/src/Logic/Geocoding/GeocodingProvider.ts +++ b/src/Logic/Geocoding/GeocodingProvider.ts @@ -45,8 +45,9 @@ export type GeocodeResult = { source?: string } export type FilterPayload = { option: FilterConfigOption, filter: FilterConfig, layer: LayerConfig, index: number } +export type FilterResult = { category: "filter", osm_id: string, payload: FilterPayload } export type SearchResult = - | { category: "filter", osm_id: string, payload: FilterPayload } + | FilterResult | { category: "theme", osm_id: string, payload: MinimalLayoutInformation } | GeocodeResult diff --git a/src/Logic/Geocoding/ThemeSearch.ts b/src/Logic/Geocoding/ThemeSearch.ts index 8e25a10af..06d30d351 100644 --- a/src/Logic/Geocoding/ThemeSearch.ts +++ b/src/Logic/Geocoding/ThemeSearch.ts @@ -20,31 +20,33 @@ export default class ThemeSearch implements GeocodingProvider { } async search(query: string): Promise { - return this.searchDirect(query, 99) + return this.searchWrapped(query, 99) } suggest(query: string, options?: GeocodingOptions): Store { - return new ImmutableStore(this.searchDirect(query, this._suggestionLimit ?? 4)) + return new ImmutableStore(this.searchWrapped(query, this._suggestionLimit ?? 4)) } - private searchDirect(query: string, limit: number): SearchResult[] { - if(query.length < 1){ - return [] - } - query = Utils.simplifyStringForSearch(query) - const withMatch = ThemeSearch.allThemes - .filter(th => !th.hideFromOverview || this._knownHiddenThemes.data.has(th.id)) - .filter(th => th.id !== this._state.layout.id) - .filter(th => MoreScreen.MatchesLayout(th, query)) - .slice(0, limit) - console.log("Matched", withMatch, limit) - return withMatch.map(match => { + private searchWrapped(query: string, limit: number): SearchResult[] { + return this.searchDirect(query, limit).map(match => { payload: match, category: "theme", osm_id: match.id }) } + public searchDirect(query: string, limit: number): MinimalLayoutInformation[] { + if (query.length < 1) { + return [] + } + query = Utils.simplifyStringForSearch(query) + return ThemeSearch.allThemes + .filter(th => !th.hideFromOverview || this._knownHiddenThemes.data.has(th.id)) + .filter(th => th.id !== this._state.layout.id) + .filter(th => MoreScreen.MatchesLayout(th, query)) + .slice(0, limit) + } + } diff --git a/src/Logic/State/SearchState.ts b/src/Logic/State/SearchState.ts new file mode 100644 index 000000000..4e7b4de5a --- /dev/null +++ b/src/Logic/State/SearchState.ts @@ -0,0 +1,189 @@ +import GeocodingProvider, { FilterPayload, GeocodingUtils, type SearchResult } from "../Geocoding/GeocodingProvider" +import { RecentSearch } from "../Geocoding/RecentSearch" +import { Store, Stores, UIEventSource } from "../UIEventSource" +import CombinedSearcher from "../Geocoding/CombinedSearcher" +import FilterSearch from "../Geocoding/FilterSearch" +import LocalElementSearch from "../Geocoding/LocalElementSearch" +import CoordinateSearch from "../Geocoding/CoordinateSearch" +import ThemeSearch from "../Geocoding/ThemeSearch" +import OpenStreetMapIdSearch from "../Geocoding/OpenStreetMapIdSearch" +import PhotonSearch from "../Geocoding/PhotonSearch" +import ThemeViewState from "../../Models/ThemeViewState" +import Translations from "../../UI/i18n/Translations" +import type { MinimalLayoutInformation } from "../../Models/ThemeConfig/LayoutConfig" +import MoreScreen from "../../UI/BigComponents/MoreScreen" +import { BBox } from "../BBox" +import { Translation } from "../../UI/i18n/Translation" +import GeocodingFeatureSource from "../Geocoding/GeocodingFeatureSource" +import ShowDataLayer from "../../UI/Map/ShowDataLayer" + +export default class SearchState { + + public readonly isSearching = new UIEventSource(false) + public readonly geosearch: GeocodingProvider + public readonly recentlySearched: RecentSearch + public readonly feedback: UIEventSource = new UIEventSource(undefined) + public readonly searchTerm: UIEventSource = new UIEventSource("") + public readonly searchIsFocused = new UIEventSource(false) + public readonly suggestions: Store + public readonly filterSuggestions: Store + public readonly themeSuggestions: Store + + private readonly state: ThemeViewState + public readonly showSearchDrawer: UIEventSource + + constructor(state: ThemeViewState) { + this.state = state + + this.geosearch = new CombinedSearcher( + // new LocalElementSearch(state, 5), + new CoordinateSearch(), + new OpenStreetMapIdSearch(state), + new PhotonSearch() // new NominatimGeocoding(), + ) + + this.recentlySearched = new RecentSearch(state) + const bounds = state.mapProperties.bounds + this.suggestions = this.searchTerm.stabilized(250).bindD(search => { + if (search.length === 0) { + return undefined + } + return Stores.holdDefined(bounds.bindD(bbox => this.geosearch.suggest(search, { bbox }))) + } + ) + + const themeSearch = new ThemeSearch(state, 3) + this.themeSuggestions = this.searchTerm.mapD(query => themeSearch.searchDirect(query, 3)) + + + const filterSearch = new FilterSearch(state) + this.filterSuggestions = this.searchTerm.stabilized(50).mapD(query => + filterSearch.searchDirectly(query) + ).mapD(filterResult => { + const active = state.layerState.activeFilters.data + return filterResult.filter(({ filter, index, layer }) => { + const foundMatch = active.some(active => + active.filter.id === filter.id && layer.id === active.layer.id && active.control.data === index) + + return !foundMatch + }) + }, [state.layerState.activeFilters]) + const geocodedFeatures = new GeocodingFeatureSource(this.suggestions.stabilized(250)) + state.featureProperties.trackFeatureSource(geocodedFeatures) + + new ShowDataLayer( + state.map, + { + layer: GeocodingUtils.searchLayer, + features: geocodedFeatures, + selectedElement: state.selectedElement + } + ) + + this.showSearchDrawer = new UIEventSource(false) + this.suggestions.addCallbackAndRunD(sugg => { + if (sugg.length > 0) { + this.showSearchDrawer.set(true) + } + }) + this.searchIsFocused.addCallbackAndRunD(sugg => { + if (sugg) { + this.showSearchDrawer.set(true) + } + }) + + + } + + + public async apply(payload: FilterPayload) { + const state = this.state + const { layer, filter, index } = payload + + const flayer = state.layerState.filteredLayers.get(layer.id) + const filtercontrol = flayer.appliedFilters.get(filter.id) + for (const [name, otherLayer] of state.layerState.filteredLayers) { + if (name === layer.id) { + otherLayer.isDisplayed.setData(true) + continue + } + otherLayer.isDisplayed.setData(false) + } + + console.log("Could not apply", layer.id, ".", filter.id, index) + if (filtercontrol.data === index) { + filtercontrol.setData(undefined) + } else { + filtercontrol.setData(index) + } + } + + /** + * Tries to search and goto a given location + * Returns 'false' if search failed + */ + public async performSearch(): Promise { + const query = this.searchTerm.data?.trim() ?? "" + if (query === "") { + return + } + const geolocationState = this.state.geolocation.geolocationState + const searcher = this.state.searchState.geosearch + const bounds = this.state.mapProperties.bounds + const bbox = this.state.mapProperties.bounds.data + try { + this.isSearching.set(true) + geolocationState?.allowMoving.setData(true) + geolocationState?.requestMoment.setData(undefined) // If the GPS is still searching for a fix, we say that we don't want tozoom to it anymore + const result = await searcher.search(query, { bbox }) + if (result.length == 0) { + this.feedback.set(Translations.t.general.search.nothing) + return false + } + const poi = result[0] + if (poi.category === "theme") { + const theme = poi.payload + const url = MoreScreen.createUrlFor(theme, false) + window.location = url + return true + } + if (poi.category === "filter") { + await this.apply(poi.payload) + return true + } + if (poi.boundingbox) { + const [lat0, lat1, lon0, lon1] = poi.boundingbox + // Will trigger a 'fly to' + bounds.set( + new BBox([ + [lon0, lat0], + [lon1, lat1] + ]).pad(0.01) + ) + } else if (poi.lon && poi.lat) { + this.state.mapProperties.flyTo(poi.lon, poi.lat, GeocodingUtils.categoryToZoomLevel[poi.category] ?? 16) + } + const perLayer = this.state.perLayer + if (perLayer !== undefined) { + const id = poi.osm_type + "/" + poi.osm_id + const layers = Array.from(perLayer?.values() ?? []) + for (const layer of layers) { + const found = layer.features.data.find((f) => f.properties.id === id) + if (found === undefined) { + continue + } + this.state.selectedElement?.setData(found) + } + } + return true + } catch (e) { + console.error(e) + this.feedback.set(Translations.t.general.search.error) + return false + } finally { + this.isSearching.set(false) + } + } + + +} diff --git a/src/Logic/UIEventSource.ts b/src/Logic/UIEventSource.ts index ff347f02e..66187153a 100644 --- a/src/Logic/UIEventSource.ts +++ b/src/Logic/UIEventSource.ts @@ -238,8 +238,8 @@ export abstract class Store implements Readable { * src.setData(0) * lastValue // => "def" */ - public bind(f: (t: T) => Store): Store { - const mapped = this.map(f) + public bind(f: (t: T) => Store, extraSources: Store[] = []): Store { + const mapped = this.map(f, extraSources) const sink = new UIEventSource(undefined) const seenEventSources = new Set>() mapped.addCallbackAndRun((newEventSource) => { @@ -270,7 +270,7 @@ export abstract class Store implements Readable { return sink } - public bindD(f: (t: Exclude) => Store): Store { + public bindD(f: (t: Exclude) => Store, extraSources: UIEventSource[] =[]): Store { return this.bind((t) => { if (t === null) { return null @@ -279,7 +279,7 @@ export abstract class Store implements Readable { return undefined } return f(>t) - }) + }, extraSources) } public stabilized(millisToStabilize): Store { diff --git a/src/Models/ThemeConfig/LayoutConfig.ts b/src/Models/ThemeConfig/LayoutConfig.ts index dccee99f2..acc4c958b 100644 --- a/src/Models/ThemeConfig/LayoutConfig.ts +++ b/src/Models/ThemeConfig/LayoutConfig.ts @@ -340,7 +340,7 @@ export default class LayoutConfig implements LayoutInformation { } } } - console.trace("Fallthrough: could not find the appropraite layer for an object with tags", tags, "within layout", this) + console.trace("Fallthrough: could not find the appropriate layer for an object with tags", tags, "within layout", this) return undefined } diff --git a/src/Models/ThemeViewState.ts b/src/Models/ThemeViewState.ts index 05ac29c8c..75343cc36 100644 --- a/src/Models/ThemeViewState.ts +++ b/src/Models/ThemeViewState.ts @@ -83,6 +83,7 @@ import PhotonSearch from "../Logic/Geocoding/PhotonSearch" import ThemeSearch from "../Logic/Geocoding/ThemeSearch" import OpenStreetMapIdSearch from "../Logic/Geocoding/OpenStreetMapIdSearch" import FilterSearch from "../Logic/Geocoding/FilterSearch" +import SearchState from "../Logic/State/SearchState" /** * @@ -164,8 +165,7 @@ export default class ThemeViewState implements SpecialVisualizationState { public readonly nearbyImageSearcher: CombinedFetcher - public readonly geosearch: GeocodingProvider - public readonly recentlySearched: RecentSearch + public readonly searchState: SearchState constructor(layout: LayoutConfig, mvtAvailableLayers: Set) { Utils.initDomPurify() @@ -390,16 +390,7 @@ export default class ThemeViewState implements SpecialVisualizationState { this.featureSummary = this.setupSummaryLayer() this.toCacheSavers = layout.enableCache ? this.initSaveToLocalStorage() : undefined - this.geosearch = new CombinedSearcher( - new FilterSearch(this), - new LocalElementSearch(this, 5), - new CoordinateSearch(), - this.featureSwitches.featureSwitchBackToThemeOverview.data ? new ThemeSearch(this, 3) : undefined, - new OpenStreetMapIdSearch(this), - new PhotonSearch(), // new NominatimGeocoding(), - ) - - this.recentlySearched = new RecentSearch(this) + this.searchState = new SearchState(this) this.initActors() this.drawSpecialLayers() @@ -931,7 +922,6 @@ export default class ThemeViewState implements SpecialVisualizationState { /** * Searches the appropriate layer - will first try if a special layer matches; if not, a normal layer will be used by delegating to the layout - * @param tags */ public getMatchingLayer(properties: Record){ diff --git a/src/UI/Base/DrawerRight.svelte b/src/UI/Base/DrawerRight.svelte new file mode 100644 index 000000000..20343e8c6 --- /dev/null +++ b/src/UI/Base/DrawerRight.svelte @@ -0,0 +1,43 @@ + + + + +
+
+
+ +
+
+
+
diff --git a/src/UI/BigComponents/ThemeIntroPanel.svelte b/src/UI/BigComponents/ThemeIntroPanel.svelte index 771a0c726..fe6d8470a 100644 --- a/src/UI/BigComponents/ThemeIntroPanel.svelte +++ b/src/UI/BigComponents/ThemeIntroPanel.svelte @@ -2,17 +2,12 @@ import Translations from "../i18n/Translations" import Tr from "../Base/Tr.svelte" import NextButton from "../Base/NextButton.svelte" - import Geosearch from "../Search/Geosearch.svelte" import ThemeViewState from "../../Models/ThemeViewState" - import { Store, UIEventSource } from "../../Logic/UIEventSource" - import { SearchIcon } from "@rgossiaux/svelte-heroicons/solid" - import { twJoin } from "tailwind-merge" - import { Utils } from "../../Utils" + import { Store } from "../../Logic/UIEventSource" import type { GeolocationPermissionState } from "../../Logic/State/GeoLocationState" import { GeoLocationState } from "../../Logic/State/GeoLocationState" import If from "../Base/If.svelte" import { ExclamationTriangleIcon } from "@babeard/svelte-heroicons/mini" - import ChevronDoubleLeft from "@babeard/svelte-heroicons/solid/ChevronDoubleLeft" import GeolocationIndicator from "./GeolocationIndicator.svelte" /** @@ -20,10 +15,6 @@ */ export let state: ThemeViewState let layout = state.layout - let selectedElement = state.selectedElement - - let triggerSearch: UIEventSource = new UIEventSource(undefined) - let searchEnabled = false let geolocation = state.geolocation.geolocationState let geopermission: Store = geolocation.permission @@ -35,7 +26,7 @@ state.geolocationControl.handleClick() const glstate = state.geolocation.geolocationState if (glstate.currentGPSLocation.data !== undefined) { - const c: GeolocationCoordinates = glstate.currentGPSLocation.data + const c = glstate.currentGPSLocation.data state.guistate.pageStates.about_theme.setData(false) const coor = { lon: c.longitude, lat: c.latitude } state.mapProperties.location.setData(coor) @@ -86,38 +77,6 @@ - - -
-
- state.guistate.pageStates.about_theme.setData(false)} - on:searchIsValid={(event) => { - searchEnabled = event.detail - }} - perLayer={state.perLayer} - {selectedElement} - {triggerSearch} - geolocationState={state.geolocation.geolocationState} - searcher={state.geosearch} - {state} - /> -
- -
-
{#if $currentGPSLocation === undefined && $geopermission === "requested" && GeoLocationState.isSafari()} diff --git a/src/UI/Popup/MoveWizard.svelte b/src/UI/Popup/MoveWizard.svelte index 7d716f466..7a8a0512a 100644 --- a/src/UI/Popup/MoveWizard.svelte +++ b/src/UI/Popup/MoveWizard.svelte @@ -104,8 +104,7 @@ {#if $reason.includeSearch} - searcher={state.geosearch} - + {/if}
diff --git a/src/UI/Search/ActiveFilter.svelte b/src/UI/Search/ActiveFilter.svelte index 88540bc5d..66d9d7a48 100644 --- a/src/UI/Search/ActiveFilter.svelte +++ b/src/UI/Search/ActiveFilter.svelte @@ -1,20 +1,30 @@ -
- - -
+ function clear() { + loading = true + requestIdleCallback(() => { + control.setData(undefined) + loading = false + }) + } + +{#if loading} + +{:else } +
+ + +
+{/if} diff --git a/src/UI/Search/ActiveFilters.svelte b/src/UI/Search/ActiveFilters.svelte index f463c11fd..d7bda7e53 100644 --- a/src/UI/Search/ActiveFilters.svelte +++ b/src/UI/Search/ActiveFilters.svelte @@ -1,24 +1,37 @@ {#if activeFilters.length > 0}
- {#each activeFilters as activeFilter (activeFilter)} - - {/each} +

Active filters

- + {#if loading} + + {:else} + {#each activeFilters as activeFilter (activeFilter)} + + {/each} + + + {/if}
{/if} diff --git a/src/UI/Search/FilterResult.svelte b/src/UI/Search/FilterResult.svelte index 037195ee9..1f64955c9 100644 --- a/src/UI/Search/FilterResult.svelte +++ b/src/UI/Search/FilterResult.svelte @@ -4,19 +4,15 @@ import type { FilterPayload } from "../../Logic/Geocoding/GeocodingProvider" import { createEventDispatcher } from "svelte" import Icon from "../Map/Icon.svelte" - import SearchResultUtils from "./SearchResultUtils" - export let entry: { - category: "filter", - payload: FilterPayload - } - let { option, filter, layer, index } = entry.payload + export let entry: FilterPayload + let { option } = entry export let state: SpecialVisualizationState let dispatch = createEventDispatcher<{ select }>() function apply() { - SearchResultUtils.apply(entry.payload, state) + state.searchState.apply(entry) dispatch("select") } diff --git a/src/UI/Search/Geosearch.svelte b/src/UI/Search/Geosearch.svelte index fac7b8134..029e8c9bf 100644 --- a/src/UI/Search/Geosearch.svelte +++ b/src/UI/Search/Geosearch.svelte @@ -1,53 +1,28 @@ {#if entry.category === "theme"} - + {:else if entry.category === "filter"} - + {:else} {/if} diff --git a/src/UI/Search/SearchResultUtils.ts b/src/UI/Search/SearchResultUtils.ts deleted file mode 100644 index 242238a2a..000000000 --- a/src/UI/Search/SearchResultUtils.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { SpecialVisualizationState } from "../SpecialVisualization" -import { FilterPayload } from "../../Logic/Geocoding/GeocodingProvider" - -export default class SearchResultUtils { - static apply(payload: FilterPayload, state: SpecialVisualizationState) { - const { layer, filter, index, option } = payload - - let flayer = state.layerState.filteredLayers.get(layer.id) - let filtercontrol = flayer.appliedFilters.get(filter.id) - - for (const [name, otherLayer] of state.layerState.filteredLayers) { - if (name === layer.id) { - otherLayer.isDisplayed.setData(true) - continue - } - otherLayer.isDisplayed.setData(false) - } - - if (filtercontrol.data === index) { - filtercontrol.setData(undefined) - } else { - filtercontrol.setData(index) - } - } -} diff --git a/src/UI/Search/SearchResults.svelte b/src/UI/Search/SearchResults.svelte index dbf05a888..d036b4944 100644 --- a/src/UI/Search/SearchResults.svelte +++ b/src/UI/Search/SearchResults.svelte @@ -1,104 +1,99 @@ +
-
- {/if} - -
- - -
- -
- - {console.log("Opening...."); state.guistate.menuIsOpened.setData(true)}} - on:keydown={forwardEventToMap} - > - - - - state.guistate.pageStates.about_theme.set(true)} - on:keydown={forwardEventToMap} - > -
- - - - -
-
-
- - - -
- - { - state.map?.data?.getCanvas()?.focus() - }} - perLayer={state.perLayer} - selectedElement={state.selectedElement} - geolocationState={state.geolocation.geolocationState} - searcher={state.geosearch} - {state} - /> -
-
- -
- -
- - {#if $selectedElement === undefined} -
- -
- {/if} -
- -
-
- - - - - {#if currentViewLayer?.tagRenderings && currentViewLayer.defaultIcon()} - { - state.selectCurrentView() - }} - on:keydown={forwardEventToMap} - > -
- currentViewLayer.defaultIcon()} /> -
-
- {/if} - - - - -
Testmode
-
- {#if state.osmConnection.Backend().startsWith("https://master.apis.dev.openstreetmap.org")} -
Testserver
- {/if} - -
Faking a user (Testmode)
-
-
-
- - - - -
-
-
@@ -380,8 +277,110 @@
+
+ + +
+
+
+ state.searchState.showSearchDrawer.set(false)} /> +
+
+ +
+
+ + +
+ +
+ +
+ + {state.guistate.menuIsOpened.setData(true)}} + on:keydown={forwardEventToMap} + > + + + + state.guistate.pageStates.about_theme.set(true)} + on:keydown={forwardEventToMap} + > +
+ + + + +
+
+
+ + + +
+ +
+
+ +
+ +
+ + {#if $selectedElement === undefined} +
+ +
+ {/if} +
+ +
+
+ + {#if currentViewLayer?.tagRenderings && currentViewLayer.defaultIcon()} + { + state.selectCurrentView() + }} + on:keydown={forwardEventToMap} + > +
+ currentViewLayer.defaultIcon()} /> +
+
+ {/if} + + + + +
Testmode
+
+ {#if state.osmConnection.Backend().startsWith("https://master.apis.dev.openstreetmap.org")} +
Testserver
+ {/if} + +
Faking a user (Testmode)
+
+
+
+ + + + +
+
+ + {#if ($showCrosshair === "yes" && $currentZoom >= 17) || $showCrosshair === "always" || $visualFeedback}