Search results: add menu, update searchers
This commit is contained in:
parent
9e0ae3321f
commit
ee2b3ce329
10 changed files with 88 additions and 41 deletions
|
@ -78,9 +78,6 @@ export class SummaryTileSource extends DynamicTileSource {
|
||||||
isActive?: Store<boolean>
|
isActive?: Store<boolean>
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
if(layers.length === 0){
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const layersSummed = layers.join("+")
|
const layersSummed = layers.join("+")
|
||||||
const zDiff = 2
|
const zDiff = 2
|
||||||
super(
|
super(
|
||||||
|
|
|
@ -61,6 +61,7 @@ export class RecentSearch {
|
||||||
const [lon, lat] = GeoOperations.centerpointCoordinates(selected)
|
const [lon, lat] = GeoOperations.centerpointCoordinates(selected)
|
||||||
const entry = <GeocodeResult>{
|
const entry = <GeocodeResult>{
|
||||||
feature: selected,
|
feature: selected,
|
||||||
|
display_name: selected.properties.name ?? selected.properties.alt_name ?? selected.properties.local_name,
|
||||||
osm_id, osm_type,
|
osm_id, osm_type,
|
||||||
lon, lat,
|
lon, lat,
|
||||||
}
|
}
|
||||||
|
@ -70,9 +71,9 @@ export class RecentSearch {
|
||||||
}
|
}
|
||||||
|
|
||||||
addSelected(entry: GeocodeResult) {
|
addSelected(entry: GeocodeResult) {
|
||||||
const id = entry.osm_type+entry.osm_id
|
const id = entry.osm_type + entry.osm_id
|
||||||
const arr = [...(this.seenThisSession.data.reverse() ?? []).slice(0, 5)]
|
const arr = [...(this.seenThisSession.data.reverse() ?? []).slice(0, 5)]
|
||||||
.filter(e => e.osm_type+e.osm_id !== id)
|
.filter(e => e.osm_type + e.osm_id !== id)
|
||||||
|
|
||||||
this.seenThisSession.set([entry, ...arr])
|
this.seenThisSession.set([entry, ...arr])
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,20 +138,24 @@ export default class SearchState {
|
||||||
if (query === "") {
|
if (query === "") {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const geolocationState = this.state.geolocation.geolocationState
|
const geolocationState = this.state.geolocation.geolocationState
|
||||||
const searcher = this.state.searchState.geosearch
|
|
||||||
const bounds = this.state.mapProperties.bounds
|
const bounds = this.state.mapProperties.bounds
|
||||||
const bbox = this.state.mapProperties.bounds.data
|
const bbox = this.state.mapProperties.bounds.data
|
||||||
try {
|
try {
|
||||||
this.isSearching.set(true)
|
this.isSearching.set(true)
|
||||||
geolocationState?.allowMoving.setData(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
|
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 })
|
let poi: SearchResult
|
||||||
if (result.length == 0) {
|
if(this.suggestions.data){
|
||||||
this.feedback.set(Translations.t.general.search.nothing)
|
poi = this.suggestions.data[0]
|
||||||
return false
|
}else{
|
||||||
|
const results = GeocodingUtils.mergeSimilarResults([].concat(...await Promise.all(this.locationSearchers.map(ls => ls.search(query, { bbox: bounds.data })))))
|
||||||
|
poi = results[0]
|
||||||
}
|
}
|
||||||
const poi = result[0]
|
|
||||||
if (poi.category === "theme") {
|
if (poi.category === "theme") {
|
||||||
const theme = <MinimalLayoutInformation>poi.payload
|
const theme = <MinimalLayoutInformation>poi.payload
|
||||||
const url = MoreScreen.createUrlFor(theme)
|
const url = MoreScreen.createUrlFor(theme)
|
||||||
|
|
|
@ -26,7 +26,6 @@ export default class Constants {
|
||||||
"last_click",
|
"last_click",
|
||||||
"favourite",
|
"favourite",
|
||||||
"summary",
|
"summary",
|
||||||
"search"
|
|
||||||
] as const
|
] as const
|
||||||
/**
|
/**
|
||||||
* Special layers which are not included in a theme by default
|
* Special layers which are not included in a theme by default
|
||||||
|
@ -39,7 +38,8 @@ export default class Constants {
|
||||||
"import_candidate",
|
"import_candidate",
|
||||||
"usersettings",
|
"usersettings",
|
||||||
"icons",
|
"icons",
|
||||||
"filters"
|
"filters",
|
||||||
|
"search"
|
||||||
] as const
|
] as const
|
||||||
/**
|
/**
|
||||||
* Layer IDs of layers which have special properties through built-in hooks
|
* Layer IDs of layers which have special properties through built-in hooks
|
||||||
|
|
|
@ -554,6 +554,10 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
this.previewedImage.setData(undefined)
|
this.previewedImage.setData(undefined)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if(this.selectedElement.data){
|
||||||
|
this.selectedElement.setData(undefined)
|
||||||
|
return
|
||||||
|
}
|
||||||
if (this.searchState.showSearchDrawer.data){
|
if (this.searchState.showSearchDrawer.data){
|
||||||
this.searchState.showSearchDrawer.set(false)
|
this.searchState.showSearchDrawer.set(false)
|
||||||
return
|
return
|
||||||
|
@ -561,7 +565,6 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
if (this.guistate.closeAll()){
|
if (this.guistate.closeAll()){
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.selectedElement.setData(undefined)
|
|
||||||
Zoomcontrol.resetzoom()
|
Zoomcontrol.resetzoom()
|
||||||
this.focusOnMap()
|
this.focusOnMap()
|
||||||
})
|
})
|
||||||
|
|
27
src/UI/Base/DotMenu.svelte
Normal file
27
src/UI/Base/DotMenu.svelte
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import DotsCircleHorizontal from "@rgossiaux/svelte-heroicons/solid/DotsCircleHorizontal"
|
||||||
|
import { Dropdown } from "flowbite-svelte"
|
||||||
|
import { TrashIcon } from "@babeard/svelte-heroicons/mini"
|
||||||
|
import SidebarUnit from "./SidebarUnit.svelte"
|
||||||
|
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A menu, opened by a dot
|
||||||
|
*/
|
||||||
|
export let dotColor = "var(--background-interactive)"
|
||||||
|
export let placement: "left" | "right" | "top" | "bottom" = "left"
|
||||||
|
|
||||||
|
export let isOpen : UIEventSource<boolean> = new UIEventSource<boolean>(false)
|
||||||
|
let _isOpen = isOpen.data
|
||||||
|
$: {
|
||||||
|
console.log("is open?", _isOpen)
|
||||||
|
isOpen.set(_isOpen)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<DotsCircleHorizontal class="w-6 h-6 dots-menu-themes transition-colors" color={$isOpen ? "black": "var(--interactive-background)"} />
|
||||||
|
<Dropdown placement="left" bind:open={_isOpen} triggeredBy=".dots-menu-themes" containerClass="p-1 border border-2 border-gray button-unstyled">
|
||||||
|
<SidebarUnit>
|
||||||
|
<slot />
|
||||||
|
</SidebarUnit>
|
||||||
|
</Dropdown>
|
|
@ -18,7 +18,7 @@
|
||||||
padding: 0.25rem;
|
padding: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.sidebar-button svg, .sidebar-button img) {
|
:global(.sidebar-button svg, .sidebar-button img, .sidebar-unit > button img, .sidebar-unit > button svg) {
|
||||||
width: 1.5rem;
|
width: 1.5rem;
|
||||||
height: 1.5rem;
|
height: 1.5rem;
|
||||||
margin-right: 0.5rem;
|
margin-right: 0.5rem;
|
||||||
|
@ -32,7 +32,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
:global(.sidebar-button, .sidebar-unit > a) {
|
:global(.sidebar-button, .sidebar-unit > a, .sidebar-unit > button) {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-radius: 0.25rem !important;
|
border-radius: 0.25rem !important;
|
||||||
|
@ -42,12 +42,12 @@
|
||||||
text-align: start;
|
text-align: start;
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.sidebar-button > svg , .sidebar-button > img, .sidebar-unit > a img, .sidebar-unit > a svg) {
|
:global(.sidebar-button > svg , .sidebar-button > img, .sidebar-unit > a img, .sidebar-unit > a svg, .sidebar-unit > button svg, .sidebar-unit > button img) {
|
||||||
margin-right: 0.5rem;
|
margin-right: 0.5rem;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(.sidebar-button:hover, .sidebar-unit > a:hover) {
|
:global(.sidebar-button:hover, .sidebar-unit > a:hover, .sidebar-unit > button:hover) {
|
||||||
background: var(--low-interaction-background) !important;
|
background: var(--low-interaction-background) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -158,11 +158,11 @@
|
||||||
|
|
||||||
<Page {onlyLink} shown={pg.about_theme}>
|
<Page {onlyLink} shown={pg.about_theme}>
|
||||||
<svelte:fragment slot="link">
|
<svelte:fragment slot="link">
|
||||||
<Marker icons={layout.icon} />
|
<Marker size="h-6 w-6 mr-2" icons={layout.icon} />
|
||||||
<Tr t={t.showIntroduction} />
|
<Tr t={t.showIntroduction} />
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
<svelte:fragment slot="header">
|
<svelte:fragment slot="header">
|
||||||
<Marker size="h-6 w-6 mr-2" icons={layout.icon} />
|
<Marker size="h-8 w-8 mr-3" icons={layout.icon} />
|
||||||
<Tr t={layout.title} />
|
<Tr t={layout.title} />
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
<ThemeIntroPanel {state} />
|
<ThemeIntroPanel {state} />
|
||||||
|
|
|
@ -15,6 +15,10 @@
|
||||||
import ThemeResult from "./ThemeResult.svelte"
|
import ThemeResult from "./ThemeResult.svelte"
|
||||||
import SidebarUnit from "../Base/SidebarUnit.svelte"
|
import SidebarUnit from "../Base/SidebarUnit.svelte"
|
||||||
import { TrashIcon } from "@babeard/svelte-heroicons/mini"
|
import { TrashIcon } from "@babeard/svelte-heroicons/mini"
|
||||||
|
import { Dropdown, DropdownItem } from "flowbite-svelte"
|
||||||
|
import DotsCircleHorizontal from "@rgossiaux/svelte-heroicons/solid/DotsCircleHorizontal"
|
||||||
|
import DotMenu from "../Base/DotMenu.svelte"
|
||||||
|
import { CogIcon } from "@rgossiaux/svelte-heroicons/solid"
|
||||||
|
|
||||||
export let state: ThemeViewState
|
export let state: ThemeViewState
|
||||||
let activeFilters: Store<ActiveFilter[]> = state.layerState.activeFilters.map(fs => fs.filter(f => Constants.priviliged_layers.indexOf(<any>f.layer.id) < 0))
|
let activeFilters: Store<ActiveFilter[]> = state.layerState.activeFilters.map(fs => fs.filter(f => Constants.priviliged_layers.indexOf(<any>f.layer.id) < 0))
|
||||||
|
@ -90,11 +94,11 @@
|
||||||
<h3 class="m-2">
|
<h3 class="m-2">
|
||||||
<Tr t={Translations.t.general.search.recents} />
|
<Tr t={Translations.t.general.search.recents} />
|
||||||
</h3>
|
</h3>
|
||||||
{#each $recentlySeen as entry}
|
{#each $recentlySeen as entry (entry)}
|
||||||
<SearchResultSvelte {entry} {state} on:select />
|
<SearchResultSvelte {entry} {state} on:select />
|
||||||
{/each}
|
{/each}
|
||||||
<button class="as-link flex self-end" on:click={() => {recentlySeen.set([])}}>
|
<button class="as-link flex self-end" on:click={() => {recentlySeen.set([])}}>
|
||||||
<TrashIcon class="w-4 h-4"/>
|
<TrashIcon class="w-4 h-4" />
|
||||||
Delete history
|
Delete history
|
||||||
</button>
|
</button>
|
||||||
</SidebarUnit>
|
</SidebarUnit>
|
||||||
|
@ -102,19 +106,29 @@
|
||||||
|
|
||||||
{#if $searchTerm.length === 0 && $recentThemes?.length > 0 && $allowOtherThemes}
|
{#if $searchTerm.length === 0 && $recentThemes?.length > 0 && $allowOtherThemes}
|
||||||
<SidebarUnit>
|
<SidebarUnit>
|
||||||
|
<div class="flex w-full justify-between">
|
||||||
|
|
||||||
<h3 class="m-2">
|
<h3 class="m-2">
|
||||||
<Tr t={Translations.t.general.search.recentThemes} />
|
<Tr t={Translations.t.general.search.recentThemes} />
|
||||||
</h3>
|
</h3>
|
||||||
|
<DotMenu>
|
||||||
|
<button on:click={() => {state.userRelatedState.recentlyVisitedThemes.set([])}}>
|
||||||
|
<TrashIcon />
|
||||||
|
Delete earlier visited themes
|
||||||
|
</button>
|
||||||
|
<button>
|
||||||
|
<CogIcon/>
|
||||||
|
Edit sync settings
|
||||||
|
</button>
|
||||||
|
</DotMenu>
|
||||||
|
</div>
|
||||||
{#each $recentThemes as themeId (themeId)}
|
{#each $recentThemes as themeId (themeId)}
|
||||||
<SearchResultSvelte
|
<SearchResultSvelte
|
||||||
entry={{payload: MoreScreen.officialThemesById.get(themeId), osm_id: themeId, category: "theme"}}
|
entry={{payload: MoreScreen.officialThemesById.get(themeId), osm_id: themeId, category: "theme"}}
|
||||||
{state}
|
{state}
|
||||||
on:select />
|
on:select />
|
||||||
{/each}
|
{/each}
|
||||||
<button class="as-link flex self-end" on:click={() => {state.userRelatedState.recentlyVisitedThemes.set([])}}>
|
|
||||||
<TrashIcon class="w-4 h-4"/>
|
|
||||||
Delete history
|
|
||||||
</button>
|
|
||||||
</SidebarUnit>
|
</SidebarUnit>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
export let entry: MinimalLayoutInformation
|
export let entry: MinimalLayoutInformation
|
||||||
let otherTheme = entry
|
let otherTheme = entry
|
||||||
</script>
|
</script>
|
||||||
|
{#if entry}
|
||||||
<a href={MoreScreen.createUrlFor(otherTheme, false)}
|
<a href={MoreScreen.createUrlFor(otherTheme)}
|
||||||
class="flex items-center p-2 w-full gap-y-2 rounded-xl searchresult">
|
class="flex items-center p-2 w-full gap-y-2 rounded-xl searchresult">
|
||||||
|
|
||||||
<Icon icon={otherTheme.icon} clss="w-6 h-6 m-1" />
|
<Icon icon={otherTheme.icon} clss="w-6 h-6 m-1" />
|
||||||
|
@ -19,4 +19,5 @@
|
||||||
</b>
|
</b>
|
||||||
<!--<Tr t={new Translation(otherTheme.shortDescription)} /> -->
|
<!--<Tr t={new Translation(otherTheme.shortDescription)} /> -->
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
{/if}
|
||||||
|
|
Loading…
Reference in a new issue