Feature: improve inspectorGui: add search, placeholder, see #2353
This commit is contained in:
parent
0a67668bec
commit
589909ba44
5 changed files with 123 additions and 51 deletions
|
@ -19,7 +19,7 @@
|
|||
let height = 0
|
||||
onMount(() => {
|
||||
let topbar = document.getElementById("top-bar")
|
||||
height = topbar.clientHeight
|
||||
height = topbar?.clientHeight ?? 0
|
||||
})
|
||||
</script>
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
import { MapLibreAdaptor } from "./Map/MapLibreAdaptor"
|
||||
import { Map as MlMap } from "maplibre-gl"
|
||||
import ShowDataLayer from "./Map/ShowDataLayer"
|
||||
|
||||
import StaticFeatureSource from "../Logic/FeatureSource/Sources/StaticFeatureSource"
|
||||
import type { Feature } from "geojson"
|
||||
import Loading from "./Base/Loading.svelte"
|
||||
|
@ -24,9 +23,16 @@
|
|||
import Page from "./Base/Page.svelte"
|
||||
import PreviouslySpiedUsers from "./History/PreviouslySpiedUsers.svelte"
|
||||
import { OsmConnection } from "../Logic/Osm/OsmConnection"
|
||||
import MagnifyingGlassCircle from "@babeard/svelte-heroicons/outline/MagnifyingGlassCircle"
|
||||
import Translations from "./i18n/Translations"
|
||||
import Tr from "./Base/Tr.svelte"
|
||||
import Searchbar from "../UI/Base/Searchbar.svelte"
|
||||
import CombinedSearcher from "../Logic/Search/CombinedSearcher"
|
||||
import CoordinateSearch from "../Logic/Search/CoordinateSearch"
|
||||
import OpenLocationCodeSearch from "../Logic/Search/OpenLocationCodeSearch"
|
||||
import PhotonSearch from "../Logic/Search/PhotonSearch"
|
||||
import GeocodeResults from "./Search/GeocodeResults.svelte"
|
||||
import MagnifyingGlassCircle from "@babeard/svelte-heroicons/mini/MagnifyingGlassCircle"
|
||||
import type { GeocodeResult } from "../Logic/Search/GeocodingProvider"
|
||||
|
||||
console.log("Loading inspector GUI")
|
||||
let username = QueryParameters.GetQueryParameter("user", undefined, "Inspect this user")
|
||||
|
@ -37,16 +43,45 @@
|
|||
let lon = UIEventSource.asFloat(QueryParameters.GetQueryParameter("lon", "0"))
|
||||
let loadingData = false
|
||||
let selectedElement = new UIEventSource<Feature>(undefined)
|
||||
let searchvalue = new UIEventSource<string>("")
|
||||
|
||||
let geocoder = new CombinedSearcher(
|
||||
new CoordinateSearch(),
|
||||
new OpenLocationCodeSearch(),
|
||||
new PhotonSearch(true, 2),
|
||||
new PhotonSearch()
|
||||
)
|
||||
let showSearchDrawer = new UIEventSource(true)
|
||||
let searchIsFocussed = new UIEventSource(false)
|
||||
let searchIsRunning = new UIEventSource(false)
|
||||
let maplibremap: MapLibreAdaptor = new MapLibreAdaptor(map, {
|
||||
zoom,
|
||||
location: new UIEventSource<{ lon: number; lat: number }>({ lat: lat.data, lon: lon.data }),
|
||||
location: new UIEventSource<{ lon: number; lat: number }>({ lat: lat.data, lon: lon.data })
|
||||
})
|
||||
maplibremap.location.stabilized(500).addCallbackAndRunD((l) => {
|
||||
lat.set(l.lat)
|
||||
lon.set(l.lon)
|
||||
})
|
||||
|
||||
let searchSuggestions = searchvalue.bindD(search => {
|
||||
searchIsRunning.set(true)
|
||||
try {
|
||||
return UIEventSource.FromPromise(geocoder.search(search))
|
||||
} finally {
|
||||
searchIsRunning.set(false)
|
||||
}
|
||||
})
|
||||
let state = {
|
||||
mapProperties: maplibremap,
|
||||
searchState: {
|
||||
searchTerm: searchvalue,
|
||||
suggestions: searchSuggestions,
|
||||
suggestionsSearchRunning: searchIsRunning,
|
||||
showSearchDrawer,
|
||||
applyGeocodeResult(geocodeResult: GeocodeResult) {
|
||||
maplibremap.location.set({ lon: geocodeResult.lon, lat: geocodeResult.lat })
|
||||
}
|
||||
}
|
||||
}
|
||||
let allLayers = HistoryUtils.personalTheme.layers
|
||||
let layersNoFixme = allLayers.filter((l) => l.id !== "fixme")
|
||||
let fixme = allLayers.find((l) => l.id === "fixme")
|
||||
|
@ -59,7 +94,7 @@
|
|||
Utils.waitFor(200).then(() => {
|
||||
selectedElement.set(f)
|
||||
})
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
let osmConnection = new OsmConnection()
|
||||
|
@ -91,7 +126,7 @@
|
|||
inspectedData.push({
|
||||
label: undefined,
|
||||
visitedTime: new Date().toISOString(),
|
||||
name: user,
|
||||
name: user
|
||||
})
|
||||
}
|
||||
inspectedContributors.ping()
|
||||
|
@ -101,7 +136,7 @@
|
|||
featuresStore.set([])
|
||||
const overpass = new Overpass(
|
||||
undefined,
|
||||
user.split(";").map((user) => 'nw(user_touched:"' + user + '");'),
|
||||
user.split(";").map((user) => "nw(user_touched:\"" + user + "\");"),
|
||||
Constants.defaultOverpassUrls[0]
|
||||
)
|
||||
if (!maplibremap.bounds.data) {
|
||||
|
@ -137,7 +172,7 @@
|
|||
<h1 class="m-0 mx-2 flex-shrink-0">
|
||||
<Tr t={t.title} />
|
||||
</h1>
|
||||
<ValidatedInput type="string" value={username} on:submit={() => load()} />
|
||||
<ValidatedInput placeholder={t.previouslySpied.username} type="string" value={username} on:submit={() => load()} />
|
||||
{#if loadingData}
|
||||
<Loading />
|
||||
{:else}
|
||||
|
@ -207,8 +242,16 @@
|
|||
</Drawer>
|
||||
{/if}
|
||||
|
||||
<div class="m-1 flex-grow overflow-hidden rounded-xl">
|
||||
|
||||
<div class="relative m-1 flex-grow overflow-hidden rounded-xl">
|
||||
<MaplibreMap {map} mapProperties={maplibremap} autorecovery={true} />
|
||||
<div class="absolute right-0 top-0 w-1/4 p-4">
|
||||
<Searchbar isFocused={searchIsFocussed} value={searchvalue}
|
||||
on:focus={() => state.searchState.showSearchDrawer.set(true)} />
|
||||
{#if $searchSuggestions?.length > 0 || $searchIsFocussed}
|
||||
<GeocodeResults {state} />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{:else if mode === "table"}
|
||||
<div class="m-2 h-full overflow-y-auto">
|
||||
|
|
|
@ -1,25 +1,33 @@
|
|||
<script lang="ts">
|
||||
import { GeocodingUtils } from "../../Logic/Search/GeocodingProvider"
|
||||
import type { GeocodeResult } from "../../Logic/Search/GeocodingProvider"
|
||||
import { GeocodingUtils } from "../../Logic/Search/GeocodingProvider"
|
||||
import { GeoOperations } from "../../Logic/GeoOperations"
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||
import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig"
|
||||
import Icon from "../Map/Icon.svelte"
|
||||
import TagRenderingAnswer from "../Popup/TagRendering/TagRenderingAnswer.svelte"
|
||||
import ArrowUp from "@babeard/svelte-heroicons/mini/ArrowUp"
|
||||
import DefaultIcon from "../Map/DefaultIcon.svelte"
|
||||
import { WithSearchState } from "../../Models/ThemeViewState/WithSearchState"
|
||||
import type { MapProperties } from "../../Models/MapProperties"
|
||||
import ThemeConfig from "../../Models/ThemeConfig/ThemeConfig"
|
||||
import FeaturePropertiesStore from "../../Logic/FeatureSource/Actors/FeaturePropertiesStore"
|
||||
import SearchState from "../../Logic/State/SearchState"
|
||||
import ArrowUp from "@babeard/svelte-heroicons/mini/ArrowUp"
|
||||
|
||||
export let entry: GeocodeResult
|
||||
export let state: WithSearchState
|
||||
export let state: {
|
||||
mapProperties: MapProperties,
|
||||
theme?: ThemeConfig,
|
||||
featureProperties?: FeaturePropertiesStore,
|
||||
searchState: Partial<SearchState>
|
||||
}
|
||||
|
||||
let layer: LayerConfig
|
||||
let tags: UIEventSource<Record<string, string>>
|
||||
let descriptionTr: TagRenderingConfig = undefined
|
||||
if (entry.feature?.properties?.id) {
|
||||
layer = state.theme.getMatchingLayer(entry.feature.properties)
|
||||
tags = state.featureProperties.getStore(entry.feature.properties.id)
|
||||
tags = state.featureProperties?.getStore(entry.feature.properties.id)
|
||||
descriptionTr = layer?.tagRenderings?.find((tr) => tr.labels.indexOf("description") >= 0)
|
||||
}
|
||||
|
||||
|
|
|
@ -3,29 +3,34 @@
|
|||
* Shows all the location-results
|
||||
*/
|
||||
import Translations from "../i18n/Translations"
|
||||
import { Store } from "../../Logic/UIEventSource"
|
||||
import SidebarUnit from "../Base/SidebarUnit.svelte"
|
||||
import Loading from "../Base/Loading.svelte"
|
||||
import { default as GeocodeResultSvelte } from "./GeocodeResult.svelte"
|
||||
import Tr from "../Base/Tr.svelte"
|
||||
import DotMenu from "../Base/DotMenu.svelte"
|
||||
import { CogIcon } from "@rgossiaux/svelte-heroicons/solid"
|
||||
import { TrashIcon } from "@babeard/svelte-heroicons/mini"
|
||||
import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||
import type { GeocodeResult } from "../../Logic/Search/GeocodingProvider"
|
||||
import { WithSearchState } from "../../Models/ThemeViewState/WithSearchState"
|
||||
import type { MapProperties } from "../../Models/MapProperties"
|
||||
|
||||
export let state: WithSearchState
|
||||
export let state: {
|
||||
searchState: {
|
||||
searchTerm: UIEventSource<string>
|
||||
suggestions: Store<GeocodeResult[]>
|
||||
suggestionsSearchRunning: Store<boolean>
|
||||
}, mapProperties: MapProperties
|
||||
}
|
||||
|
||||
let searchTerm = state.searchState.searchTerm
|
||||
let results = state.searchState.suggestions
|
||||
let isSearching = state.searchState.suggestionsSearchRunning
|
||||
let recentlySeen: Store<GeocodeResult[]> = state.userRelatedState.recentlyVisitedSearch.value
|
||||
let isSearching = state.searchState.suggestionsSearchRunning ?? new ImmutableStore(false)
|
||||
|
||||
const t = Translations.t.general.search
|
||||
</script>
|
||||
|
||||
{#if $searchTerm.length > 0}
|
||||
<SidebarUnit>
|
||||
<h3><Tr t={t.locations} /></h3>
|
||||
<h3>
|
||||
<Tr t={t.locations} />
|
||||
</h3>
|
||||
|
||||
{#if $results?.length > 0}
|
||||
{#each $results as entry (entry)}
|
||||
|
@ -41,35 +46,12 @@
|
|||
</div>
|
||||
{/if}
|
||||
|
||||
{#if !$isSearching && $results.length === 0}
|
||||
{#if !$isSearching && $results?.length === 0}
|
||||
<b class="flex justify-center p-4">
|
||||
<Tr t={t.nothingFor.Subs({ term: "<i>" + $searchTerm + "</i>" })} />
|
||||
</b>
|
||||
{/if}
|
||||
</SidebarUnit>
|
||||
{:else if $recentlySeen?.length > 0}
|
||||
<SidebarUnit>
|
||||
<div class="flex justify-between">
|
||||
<h3 class="m-2">
|
||||
<Tr t={t.recents} />
|
||||
</h3>
|
||||
<DotMenu>
|
||||
<button
|
||||
on:click={() => {
|
||||
state.userRelatedState.recentlyVisitedSearch.clear()
|
||||
}}
|
||||
>
|
||||
<TrashIcon />
|
||||
<Tr t={t.deleteSearchHistory} />
|
||||
</button>
|
||||
<button on:click={() => state.guistate.openUsersettings("sync-visited-locations")}>
|
||||
<CogIcon />
|
||||
<Tr t={t.editSearchSyncSettings} />
|
||||
</button>
|
||||
</DotMenu>
|
||||
</div>
|
||||
{#each $recentlySeen as entry (entry)}
|
||||
<GeocodeResultSvelte {entry} {state} on:select />
|
||||
{/each}
|
||||
</SidebarUnit>
|
||||
{:else}
|
||||
<slot name="if-no-results" />
|
||||
{/if}
|
||||
|
|
|
@ -10,6 +10,12 @@
|
|||
import Translations from "../i18n/Translations"
|
||||
import type { FilterSearchResult } from "../../Logic/Search/FilterSearch"
|
||||
import { WithSearchState } from "../../Models/ThemeViewState/WithSearchState"
|
||||
import { TrashIcon } from "@babeard/svelte-heroicons/mini"
|
||||
import { CogIcon } from "@rgossiaux/svelte-heroicons/solid"
|
||||
import SidebarUnit from "../Base/SidebarUnit.svelte"
|
||||
import DotMenu from "../Base/DotMenu.svelte"
|
||||
import type { GeocodeResult } from "../../Logic/Search/GeocodingProvider"
|
||||
import { default as GeocodeResultSvelte } from "./GeocodeResult.svelte"
|
||||
|
||||
export let state: WithSearchState
|
||||
let activeFilters: Store<(ActiveFilter & FilterSearchResult)[]> =
|
||||
|
@ -26,7 +32,9 @@
|
|||
return r
|
||||
})
|
||||
)
|
||||
|
||||
let searchTerm = state.searchState.searchTerm
|
||||
let recentlySeen: Store<GeocodeResult[]> = state.userRelatedState.recentlyVisitedSearch.value
|
||||
|
||||
let allowOtherThemes = state.featureSwitches.featureSwitchBackToThemeOverview
|
||||
let allowFilters = state.featureSwitches.featureSwitchFilter
|
||||
|
@ -47,7 +55,38 @@
|
|||
{#if $allowFilters}
|
||||
<FilterResults {state} />
|
||||
{/if}
|
||||
<GeocodeResults {state} />
|
||||
<GeocodeResults {state}>
|
||||
<svelte:fragment slot="if-no-results">
|
||||
|
||||
{#if $recentlySeen?.length > 0}
|
||||
<SidebarUnit>
|
||||
<div class="flex justify-between">
|
||||
<h3 class="m-2">
|
||||
<Tr t={Translations.t.general.search.recents} />
|
||||
</h3>
|
||||
<DotMenu>
|
||||
<button
|
||||
on:click={() => {
|
||||
state.userRelatedState.recentlyVisitedSearch.clear()
|
||||
}}
|
||||
>
|
||||
<TrashIcon />
|
||||
<Tr t={Translations.t.general.search.deleteSearchHistory} />
|
||||
</button>
|
||||
<button on:click={() => state.guistate.openUsersettings("sync-visited-locations")}>
|
||||
<CogIcon />
|
||||
<Tr t={Translations.t.general.search.editSearchSyncSettings} />
|
||||
</button>
|
||||
</DotMenu>
|
||||
</div>
|
||||
{#each $recentlySeen as entry (entry)}
|
||||
<GeocodeResultSvelte {entry} {state} on:select />
|
||||
{/each}
|
||||
</SidebarUnit>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
|
||||
</GeocodeResults>
|
||||
|
||||
{#if $allowOtherThemes}
|
||||
<ThemeResults {state} />
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue