diff --git a/Docs/UserTests/2024-08-26 User Test Search.md b/Docs/UserTests/2024-08-26 User Test Search.md index 6cba57527..203dd68f8 100644 --- a/Docs/UserTests/2024-08-26 User Test Search.md +++ b/Docs/UserTests/2024-08-26 User Test Search.md @@ -109,7 +109,7 @@ Success: user sponteanously interacts with the questions! > Then, the 'cuisine' was inspected. As the restaurant they visited is focusing on _vegetarian_ salads, the user wanted to use the freeform to enter 'vegetarian salad' - [ ] Failure: how to properly exp lain this? Move the 'vegetarian' question up? Should some options, such as 'chicken restaurant' be hidden if `vegetarian=only`? + [ ] Failure: how to properly explain this? Move the 'vegetarian' question up? Should some options, such as 'chicken restaurant' be hidden if `vegetarian=only`? [ ] UI: issue: the emojis (especially flags) slightly overlaps with the text on this browser diff --git a/assets/layers/drinking_water/drinking_water.json b/assets/layers/drinking_water/drinking_water.json index b238634ab..deef4447e 100644 --- a/assets/layers/drinking_water/drinking_water.json +++ b/assets/layers/drinking_water/drinking_water.json @@ -24,6 +24,14 @@ "ca": "Una capa que mostra fonts d'aigua potable", "cs": "Vrstva zobrazující fontány s pitnou vodou" }, + "searchTerms": { + "en": [ + "drink","water","fountain","bubbler" + ], + "nl": [ + "drinken","water","drinkwater","waterfontein","fontein","kraan","kraantje" + ] + }, "source": { "osmTags": { "and": [ diff --git a/assets/layers/shops/shops.json b/assets/layers/shops/shops.json index f8368c1bc..812a4282c 100644 --- a/assets/layers/shops/shops.json +++ b/assets/layers/shops/shops.json @@ -40,7 +40,7 @@ ] } }, - "minzoom": 12, + "minzoom": 10, "title": { "render": { "en": "Shop", diff --git a/assets/themes/cyclofix/cyclofix.json b/assets/themes/cyclofix/cyclofix.json index 7b1c1ff37..5eb503733 100644 --- a/assets/themes/cyclofix/cyclofix.json +++ b/assets/themes/cyclofix/cyclofix.json @@ -80,7 +80,7 @@ "override": { "name=": null, "minzoom": 17, - "filter": { + "=filter": { "sameAs": "bike_shop" } } @@ -182,7 +182,7 @@ "builtin": "charging_station", "override": { "name": null, - "filter": { + "=filter": { "sameAs": "charging_station_ebikes" }, "minzoom": 18, @@ -209,7 +209,7 @@ "builtin": "vending_machine", "override": { "name": null, - "filter": { + "=filter": { "sameAs": "vending_machine_bicycle" }, "minzoom": 18, diff --git a/assets/themes/shops/shops.json b/assets/themes/shops/shops.json index 8c0155b2e..66a6d19f1 100644 --- a/assets/themes/shops/shops.json +++ b/assets/themes/shops/shops.json @@ -56,7 +56,7 @@ "trolley_bay" ], "overrideAll": { - "minzoom": 14, + "minzoom": 12, "syncSelection": "theme-only" } } diff --git a/src/Logic/Geocoding/CombinedSearcher.ts b/src/Logic/Search/CombinedSearcher.ts similarity index 100% rename from src/Logic/Geocoding/CombinedSearcher.ts rename to src/Logic/Search/CombinedSearcher.ts diff --git a/src/Logic/Geocoding/CoordinateSearch.ts b/src/Logic/Search/CoordinateSearch.ts similarity index 100% rename from src/Logic/Geocoding/CoordinateSearch.ts rename to src/Logic/Search/CoordinateSearch.ts diff --git a/src/Logic/Geocoding/FilterSearch.ts b/src/Logic/Search/FilterSearch.ts similarity index 79% rename from src/Logic/Geocoding/FilterSearch.ts rename to src/Logic/Search/FilterSearch.ts index 1324f7935..196fcc3cc 100644 --- a/src/Logic/Geocoding/FilterSearch.ts +++ b/src/Logic/Search/FilterSearch.ts @@ -5,6 +5,9 @@ import { Utils } from "../../Utils" import Locale from "../../UI/i18n/Locale" import Constants from "../../Models/Constants" +/** + * Searches matching filters + */ export default class FilterSearch implements GeocodingProvider { private readonly _state: SpecialVisualizationState @@ -13,18 +16,9 @@ export default class FilterSearch implements GeocodingProvider { } async search(query: string): Promise { - return this.searchDirectlyWrapped(query) + return this.searchDirectly(query) } - - 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[] { + public searchDirectly(query: string): FilterResult[] { if (query.length === 0) { return [] } @@ -34,11 +28,14 @@ export default class FilterSearch implements GeocodingProvider { } return query }).filter(q => q.length > 0) - const possibleFilters: FilterPayload[] = [] + const possibleFilters: FilterResult[] = [] for (const layer of this._state.layout.layers) { if (!Array.isArray(layer.filters)) { continue } + if (layer.filterIsSameAs !== undefined) { + continue + } for (const filter of layer.filters ?? []) { for (let i = 0; i < filter.options.length; i++) { const option = filter.options[i] @@ -64,7 +61,14 @@ export default class FilterSearch implements GeocodingProvider { if (levehnsteinD > 0.25) { continue } - possibleFilters.push({ option, layer, filter, index: i }) + possibleFilters.push({ + category: "filter", + osm_id: layer.id + "/" + filter.id + "/" + i, + payload: { + option, layer, filter, index: + i, + }, + }) } } } @@ -72,7 +76,7 @@ export default class FilterSearch implements GeocodingProvider { } suggest(query: string, options?: GeocodingOptions): Store { - return new ImmutableStore(this.searchDirectlyWrapped(query)) + return new ImmutableStore(this.searchDirectly(query)) } @@ -85,7 +89,7 @@ export default class FilterSearch implements GeocodingProvider { if (!Array.isArray(filteredLayer.layerDef.filters)) { continue } - if (Constants.priviliged_layers.indexOf(id) >= 0) { + if (Constants.priviliged_layers.indexOf( id) >= 0) { continue } for (const filter of filteredLayer.layerDef.filters) { @@ -99,14 +103,14 @@ export default class FilterSearch implements GeocodingProvider { option, filter, index: i, - layer: filteredLayer.layerDef + layer: filteredLayer.layerDef, }) } Utils.shuffle(singleFilterResults) - result.push(...singleFilterResults.slice(0,3)) + result.push(...singleFilterResults.slice(0, 3)) } } Utils.shuffle(result) - return result.slice(0,6) + return result.slice(0, 6) } } diff --git a/src/Logic/Geocoding/GeocodingFeatureSource.ts b/src/Logic/Search/GeocodingFeatureSource.ts similarity index 100% rename from src/Logic/Geocoding/GeocodingFeatureSource.ts rename to src/Logic/Search/GeocodingFeatureSource.ts diff --git a/src/Logic/Geocoding/GeocodingProvider.ts b/src/Logic/Search/GeocodingProvider.ts similarity index 97% rename from src/Logic/Geocoding/GeocodingProvider.ts rename to src/Logic/Search/GeocodingProvider.ts index 819b28a90..245884d5f 100644 --- a/src/Logic/Geocoding/GeocodingProvider.ts +++ b/src/Logic/Search/GeocodingProvider.ts @@ -46,9 +46,11 @@ export type GeocodeResult = { } export type FilterPayload = { option: FilterConfigOption, filter: FilterConfig, layer: LayerConfig, index: number } export type FilterResult = { category: "filter", osm_id: string, payload: FilterPayload } +export type LayerResult = {category: "layer", osm_id: string, payload: LayerConfig} export type SearchResult = | FilterResult | { category: "theme", osm_id: string, payload: MinimalLayoutInformation } + | LayerResult | GeocodeResult export interface GeocodingOptions { diff --git a/src/Logic/Search/LayerSearch.ts b/src/Logic/Search/LayerSearch.ts new file mode 100644 index 000000000..65cbb0ddb --- /dev/null +++ b/src/Logic/Search/LayerSearch.ts @@ -0,0 +1,53 @@ +import GeocodingProvider, { GeocodingOptions, LayerResult, SearchResult } from "./GeocodingProvider" +import { SpecialVisualizationState } from "../../UI/SpecialVisualization" +import MoreScreen from "../../UI/BigComponents/MoreScreen" +import { ImmutableStore, Store } from "../UIEventSource" +import Constants from "../../Models/Constants" + +export default class LayerSearch implements GeocodingProvider { + + private readonly _state: SpecialVisualizationState + private readonly _suggestionLimit: number + private readonly _layerWhitelist : Set + constructor(state: SpecialVisualizationState, suggestionLimit: number) { + this._state = state + this._layerWhitelist = new Set(state.layout.layers.map(l => l.id).filter(id => Constants.added_by_default.indexOf( id) < 0)) + this._suggestionLimit = suggestionLimit + } + + async search(query: string): Promise { + return this.searchWrapped(query, 99) + } + + suggest(query: string, options?: GeocodingOptions): Store { + return new ImmutableStore(this.searchWrapped(query, this._suggestionLimit ?? 4)) + } + + + private searchWrapped(query: string, limit: number): LayerResult[] { + return this.searchDirect(query, limit) + } + + public searchDirect(query: string, limit: number): LayerResult[] { + if (query.length < 1) { + return [] + } + const scores = MoreScreen.scoreLayers(query, this._layerWhitelist) + const asList:(LayerResult & {score:number})[] = [] + for (const layer in scores) { + asList.push({ + category: "layer", + payload: this._state.layout.getLayer(layer), + osm_id: layer, + score: scores[layer] + }) + } + asList.sort((a, b) => a.score - b.score) + + return asList + .filter(sorted => sorted.score < 2) + .slice(0, limit) + } + + +} diff --git a/src/Logic/Geocoding/LocalElementSearch.ts b/src/Logic/Search/LocalElementSearch.ts similarity index 100% rename from src/Logic/Geocoding/LocalElementSearch.ts rename to src/Logic/Search/LocalElementSearch.ts diff --git a/src/Logic/Geocoding/NominatimGeocoding.ts b/src/Logic/Search/NominatimGeocoding.ts similarity index 100% rename from src/Logic/Geocoding/NominatimGeocoding.ts rename to src/Logic/Search/NominatimGeocoding.ts diff --git a/src/Logic/Geocoding/OpenStreetMapIdSearch.ts b/src/Logic/Search/OpenStreetMapIdSearch.ts similarity index 100% rename from src/Logic/Geocoding/OpenStreetMapIdSearch.ts rename to src/Logic/Search/OpenStreetMapIdSearch.ts diff --git a/src/Logic/Geocoding/PhotonSearch.ts b/src/Logic/Search/PhotonSearch.ts similarity index 100% rename from src/Logic/Geocoding/PhotonSearch.ts rename to src/Logic/Search/PhotonSearch.ts diff --git a/src/Logic/Geocoding/ThemeSearch.ts b/src/Logic/Search/ThemeSearch.ts similarity index 100% rename from src/Logic/Geocoding/ThemeSearch.ts rename to src/Logic/Search/ThemeSearch.ts diff --git a/src/Logic/State/LayerState.ts b/src/Logic/State/LayerState.ts index 346a5251d..b3bf0db2e 100644 --- a/src/Logic/State/LayerState.ts +++ b/src/Logic/State/LayerState.ts @@ -8,6 +8,7 @@ import Translations from "../../UI/i18n/Translations" import { RegexTag } from "../Tags/RegexTag" import { Or } from "../Tags/Or" import FilterConfig from "../../Models/ThemeConfig/FilterConfig" +import Constants from "../../Models/Constants" export type ActiveFilter = { layer: LayerConfig, @@ -35,6 +36,10 @@ export default class LayerState { private readonly _activeFilters: UIEventSource = new UIEventSource([]) public readonly activeFilters: Store = this._activeFilters + private readonly _activeLayers: UIEventSource = new UIEventSource(undefined) + public readonly activeLayers: Store = this._activeLayers + private readonly _nonactiveLayers: UIEventSource = new UIEventSource(undefined) + public readonly nonactiveLayers: Store = this._nonactiveLayers private readonly osmConnection: OsmConnection /** @@ -77,8 +82,16 @@ export default class LayerState { private updateActiveFilters(){ const filters: ActiveFilter[] = [] + const activeLayers: FilteredLayer[] = [] + const nonactiveLayers: FilteredLayer[] = [] this.filteredLayers.forEach(fl => { if(!fl.isDisplayed.data){ + nonactiveLayers.push(fl) + return + } + activeLayers.push(fl) + + if(fl.layerDef.filterIsSameAs){ return } for (const [filtername, appliedFilter] of fl.appliedFilters) { @@ -86,6 +99,7 @@ export default class LayerState { continue } const filter = fl.layerDef.filters.find(f => f.id === filtername) + console.log("Updating active filters for flayer", fl.layerDef.id,"with filterconfig",filter) if(typeof appliedFilter.data === "number"){ if(filter.options[appliedFilter.data].osmTags === undefined){ // This is probably the first, generic option which doesn't _actually_ filter @@ -99,6 +113,8 @@ export default class LayerState { }) } }) + this._activeLayers.set(activeLayers) + this._nonactiveLayers.set(nonactiveLayers) this._activeFilters.set(filters) } diff --git a/src/Logic/State/SearchState.ts b/src/Logic/State/SearchState.ts index e717bb0ff..4daca15d6 100644 --- a/src/Logic/State/SearchState.ts +++ b/src/Logic/State/SearchState.ts @@ -1,25 +1,26 @@ import GeocodingProvider, { - FilterPayload, + FilterPayload, FilterResult, GeocodeResult, - GeocodingUtils, - type SearchResult -} from "../Geocoding/GeocodingProvider" + GeocodingUtils, LayerResult, + type SearchResult, +} from "../Search/GeocodingProvider" import { ImmutableStore, 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 CombinedSearcher from "../Search/CombinedSearcher" +import FilterSearch from "../Search/FilterSearch" +import LocalElementSearch from "../Search/LocalElementSearch" +import CoordinateSearch from "../Search/CoordinateSearch" +import ThemeSearch from "../Search/ThemeSearch" +import OpenStreetMapIdSearch from "../Search/OpenStreetMapIdSearch" +import PhotonSearch from "../Search/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 GeocodingFeatureSource from "../Search/GeocodingFeatureSource" import ShowDataLayer from "../../UI/Map/ShowDataLayer" +import LayerSearch from "../Search/LayerSearch" export default class SearchState { @@ -28,8 +29,9 @@ export default class SearchState { public readonly searchTerm: UIEventSource = new UIEventSource("") public readonly searchIsFocused = new UIEventSource(false) public readonly suggestions: Store - public readonly filterSuggestions: Store + public readonly filterSuggestions: Store public readonly themeSuggestions: Store + public readonly layerSuggestions: Store public readonly locationSearchers: ReadonlyArray> private readonly state: ThemeViewState @@ -43,7 +45,7 @@ export default class SearchState { // new LocalElementSearch(state, 5), new CoordinateSearch(), new OpenStreetMapIdSearch(state), - new PhotonSearch() // new NominatimGeocoding(), + new PhotonSearch(), // new NominatimGeocoding(), ] const bounds = state.mapProperties.bounds @@ -53,33 +55,36 @@ export default class SearchState { } return this.locationSearchers.map(ls => ls.suggest(search, { bbox: bounds.data })) - }, [bounds] + }, [bounds], ) - this.suggestionsSearchRunning = suggestionsList.bind(suggestions => { - if(suggestions === undefined){ + this.suggestionsSearchRunning = suggestionsList.bind(suggestions => { + if (suggestions === undefined) { return new ImmutableStore(true) } return Stores.concat(suggestions).map(suggestions => suggestions.some(list => list === undefined)) }) this.suggestions = suggestionsList.bindD(suggestions => - Stores.concat(suggestions).map(suggestions => CombinedSearcher.merge(suggestions)) + Stores.concat(suggestions).map(suggestions => CombinedSearcher.merge(suggestions)), ) const themeSearch = new ThemeSearch(state, 3) this.themeSuggestions = this.searchTerm.mapD(query => themeSearch.searchDirect(query, 3)) + const layerSearch = new LayerSearch(state, 5) + this.layerSuggestions = this.searchTerm.mapD(query => layerSearch.searchDirect(query, 5)) 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) + this.filterSuggestions = this.searchTerm.stabilized(50) + .mapD(query => filterSearch.searchDirectly(query)) + .mapD(filterResult => { + const active = state.layerState.activeFilters.data + return filterResult.filter(({ payload: { 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]) + return !foundMatch + }) + }, [state.layerState.activeFilters]) const geocodedFeatures = new GeocodingFeatureSource(this.suggestions.stabilized(250)) state.featureProperties.trackFeatureSource(geocodedFeatures) @@ -88,8 +93,8 @@ export default class SearchState { { layer: GeocodingUtils.searchLayer, features: geocodedFeatures, - selectedElement: state.selectedElement - } + selectedElement: state.selectedElement, + }, ) this.showSearchDrawer = new UIEventSource(false) @@ -103,21 +108,31 @@ export default class SearchState { } - - 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) + public async apply(result: FilterResult | LayerResult) { + if (result.category === "filter") { + return this.applyFilter(result.payload) } + if (result.category === "layer") { + return this.applyLayer(result) + } + } + private async applyLayer(layer: LayerResult) { + for (const [name, otherLayer] of this.state.layerState.filteredLayers) { + otherLayer.isDisplayed.setData(name === layer.osm_id) + } + } + + private async applyFilter(payload: FilterPayload) { + const state = this.state + + const { layer, filter, index } = payload + for (const [name, otherLayer] of state.layerState.filteredLayers) { + otherLayer.isDisplayed.setData(name === layer.id) + } + const flayer = state.layerState.filteredLayers.get(layer.id) + flayer.isDisplayed.set(true) + const filtercontrol = flayer.appliedFilters.get(filter.id) console.log("Could not apply", layer.id, ".", filter.id, index) if (filtercontrol.data === index) { filtercontrol.setData(undefined) @@ -126,76 +141,4 @@ export default class SearchState { } } - /** - * 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 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 - let poi: SearchResult - if(this.suggestions.data){ - poi = this.suggestions.data[0] - }else{ - const results = GeocodingUtils.mergeSimilarResults([].concat(...await Promise.all(this.locationSearchers.map(ls => ls.search(query, { bbox: bounds.data }))))) - poi = results[0] - } - - if (poi.category === "theme") { - const theme = poi.payload - const url = MoreScreen.createUrlFor(theme) - 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/State/UserRelatedState.ts b/src/Logic/State/UserRelatedState.ts index 21ecec2b8..69a977a5e 100644 --- a/src/Logic/State/UserRelatedState.ts +++ b/src/Logic/State/UserRelatedState.ts @@ -20,7 +20,7 @@ import { ThemeMetaTagging } from "./UserSettingsMetaTagging" import { MapProperties } from "../../Models/MapProperties" import Showdown from "showdown" import { LocalStorageSource } from "../Web/LocalStorageSource" -import { GeocodeResult } from "../Geocoding/GeocodingProvider" +import { GeocodeResult } from "../Search/GeocodingProvider" export class OptionallySyncedHistory { @@ -42,8 +42,6 @@ export class OptionallySyncedHistory { "preference-" + key + "-history", "sync", ) - console.log(">>>",key, this.syncPreference) - const synced = this.synced = UIEventSource.asObject(osmconnection.GetLongPreference(key + "-history"), []) const local = this.local = LocalStorageSource.GetParsed(key + "-history", []) const thisSession = this.thisSession = new UIEventSource([], "optionally-synced:"+key+"(session only)") @@ -91,7 +89,6 @@ export class OptionallySyncedHistory { if (this._isSame) { oldList = oldList.filter(x => !this._isSame(t, x)) } - console.log("Setting new history:", store, [t, ...oldList]) store.set([t, ...oldList].slice(0, this._maxHistory)) } @@ -198,7 +195,6 @@ export default class UserRelatedState { this.showTags = this.osmConnection.GetPreference("show_tags") this.showCrosshair = this.osmConnection.GetPreference("show_crosshair") this.fixateNorth = this.osmConnection.GetPreference("fixate-north") - console.log("Fixate north is:", this.fixateNorth) this.morePrivacy = this.osmConnection.GetPreference("more_privacy", "no") this.a11y = this.osmConnection.GetPreference("a11y") diff --git a/src/Models/ThemeConfig/LayerConfig.ts b/src/Models/ThemeConfig/LayerConfig.ts index b484626ff..1a6ab09d7 100644 --- a/src/Models/ThemeConfig/LayerConfig.ts +++ b/src/Models/ThemeConfig/LayerConfig.ts @@ -641,4 +641,18 @@ export default class LayerConfig extends WithContextLoader { } return mostShadowed ?? matchingPresets[0] } + + public isNormal(){ + if(this.id.startsWith("note_import")){ + return false + } + + if(Constants.added_by_default.indexOf( this.id) >=0){ + return false + } + if(this.filterIsSameAs !== undefined){ + return false + } + return true + } } diff --git a/src/Models/ThemeViewState.ts b/src/Models/ThemeViewState.ts index 46f2aecd3..27d6da45c 100644 --- a/src/Models/ThemeViewState.ts +++ b/src/Models/ThemeViewState.ts @@ -67,7 +67,7 @@ import { LayerConfigJson } from "./ThemeConfig/Json/LayerConfigJson" import Hash from "../Logic/Web/Hash" import { GeoOperations } from "../Logic/GeoOperations" import { CombinedFetcher } from "../Logic/Web/NearbyImagesSearch" -import { GeocodeResult, GeocodingUtils } from "../Logic/Geocoding/GeocodingProvider" +import { GeocodeResult, GeocodingUtils } from "../Logic/Search/GeocodingProvider" import SearchState from "../Logic/State/SearchState" /** diff --git a/src/UI/Base/SelectedElementPanel.svelte b/src/UI/Base/SelectedElementPanel.svelte index db274f649..617801eb1 100644 --- a/src/UI/Base/SelectedElementPanel.svelte +++ b/src/UI/Base/SelectedElementPanel.svelte @@ -8,7 +8,7 @@ import Loading from "./Loading.svelte" import { onDestroy } from "svelte" import LayerConfig from "../../Models/ThemeConfig/LayerConfig" - import { GeocodingUtils } from "../../Logic/Geocoding/GeocodingProvider" + import { GeocodingUtils } from "../../Logic/Search/GeocodingProvider" import ThemeViewState from "../../Models/ThemeViewState" export let state: SpecialVisualizationState diff --git a/src/UI/BigComponents/MoreScreen.ts b/src/UI/BigComponents/MoreScreen.ts index b3db72c84..c8f79e354 100644 --- a/src/UI/BigComponents/MoreScreen.ts +++ b/src/UI/BigComponents/MoreScreen.ts @@ -66,7 +66,7 @@ export default class MoreScreen { return Infinity } language ??= Locale.language.data - const queryParts = query.split(" ").map(q => Utils.simplifyStringForSearch(q)) + const queryParts = query.trim().split(" ").map(q => Utils.simplifyStringForSearch(q)) let terms: string[] if (Array.isArray(keywords)) { terms = keywords @@ -90,9 +90,12 @@ export default class MoreScreen { return distanceSummed } - public static scoreLayers(query: string): Record { + public static scoreLayers(query: string, layerWhitelist?: Set): Record { const result: Record = {} for (const id in this.officialThemes.layers) { + if(layerWhitelist !== undefined && !layerWhitelist.has(id)){ + continue + } const keywords = this.officialThemes.layers[id] const distance = this.scoreKeywords(query, keywords) result[id] = distance diff --git a/src/UI/BigComponents/ReverseGeocoding.svelte b/src/UI/BigComponents/ReverseGeocoding.svelte index 90e91b69f..8a85edfc5 100644 --- a/src/UI/BigComponents/ReverseGeocoding.svelte +++ b/src/UI/BigComponents/ReverseGeocoding.svelte @@ -3,7 +3,7 @@ * Shows the current address when shaken **/ import Motion from "../../Sensors/Motion" - import { NominatimGeocoding } from "../../Logic/Geocoding/NominatimGeocoding" + import { NominatimGeocoding } from "../../Logic/Search/NominatimGeocoding" import Hotkeys from "../Base/Hotkeys" import Translations from "../i18n/Translations" import Locale from "../i18n/Locale" diff --git a/src/UI/Search/ActiveFilter.svelte b/src/UI/Search/ActiveFilter.svelte index fd43da9a0..78ea31b56 100644 --- a/src/UI/Search/ActiveFilter.svelte +++ b/src/UI/Search/ActiveFilter.svelte @@ -1,8 +1,8 @@ -{#if activeFilters.length > 0} + +{#if activeFilters.length > 0 || $activeLayers.length === 1 || $nonactiveLayers.length > 0} -

Active filters

- - {#if loading} - - {:else} -
- - {#each activeFilters as activeFilter (activeFilter)} -
- -
- {/each} -
+
+

Active filters

+
+ {#if loading} + + {:else} + +
+ {#if $activeLayers.length === 1} + enableAllLayers()}> +
+ +
+ + + +
+ {:else if $nonactiveLayers.length > 0} + {#each $nonactiveLayers as nonActive (nonActive.layerDef.id)} + nonActive.isDisplayed.set(true)}> +
+ +
+ + + +
+ {/each} + {/if} + + + {#each activeFilters as activeFilter (activeFilter)} +
+ +
+ {/each} +
+ + {/if}
diff --git a/src/UI/Search/FilterResult.svelte b/src/UI/Search/FilterResult.svelte index 1f64955c9..90fac40c1 100644 --- a/src/UI/Search/FilterResult.svelte +++ b/src/UI/Search/FilterResult.svelte @@ -1,27 +1,36 @@ diff --git a/src/UI/Search/FilterToggle.svelte b/src/UI/Search/FilterToggle.svelte new file mode 100644 index 000000000..827a55cf0 --- /dev/null +++ b/src/UI/Search/FilterToggle.svelte @@ -0,0 +1,9 @@ + +
+ + +
diff --git a/src/UI/Search/GeocodeResult.svelte b/src/UI/Search/GeocodeResult.svelte index 3ab188863..03b46d723 100644 --- a/src/UI/Search/GeocodeResult.svelte +++ b/src/UI/Search/GeocodeResult.svelte @@ -1,6 +1,6 @@
- + - {#if $searchTerm.length > 0 && $filterResults.length > 0} + {#if $searchTerm.length === 0 && $filterResults.length === 0 && $activeFilters.length === 0 && $recentThemes.length === 0} +
+ Use the search bar above to search for locations, filters and other maps +
+ {/if} + + {#if $searchTerm.length > 0 && ($filterResults.length > 0 || $layerResults.length > 0)}

Pick a filter below

- {#each $filterResults as filterResult (filterResult)} - + {#each $filterResultsClipped as filterResult (filterResult)} + {/each}
+ {#if $filterResults.length + $layerResults.length > $filterResultsClipped.length} +
+ ... and {$filterResults.length + $layerResults.length - $filterResultsClipped.length} more ... +
+ {/if}
{/if} @@ -68,7 +96,7 @@ {:else if !$isSearching} - + "+$searchTerm+""})} /> {/if} @@ -88,8 +116,16 @@ {/if} + {#if $searchTerm.length === 0 && $recentlySeen?.length === 0 && $recentThemes.length === 0} + +

- {#if $searchTerm.length == 0 && $recentlySeen?.length > 0} + Suggestions +

+ +
+ {/if} + {#if $searchTerm.length === 0 && $recentlySeen?.length > 0}
diff --git a/src/UI/ThemeViewGUI.svelte b/src/UI/ThemeViewGUI.svelte index f8399e9f5..83cedf3a8 100644 --- a/src/UI/ThemeViewGUI.svelte +++ b/src/UI/ThemeViewGUI.svelte @@ -326,7 +326,7 @@
+ class="flex bg-black-light-transparent pointer-events-auto items-center justify-between px-4 py-1 flex-wrap">
@@ -361,7 +361,7 @@ {/if} -
+
diff --git a/src/index.css b/src/index.css index f09f30443..057ab84da 100644 --- a/src/index.css +++ b/src/index.css @@ -391,8 +391,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); }