forked from MapComplete/MapComplete
		
	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, | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  | @ -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,7 +94,7 @@ | ||||||
|       <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([])}}> | ||||||
|  | @ -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" /> | ||||||
|  | @ -20,3 +20,4 @@ | ||||||
|       <!--<Tr t={new Translation(otherTheme.shortDescription)} /> --> |       <!--<Tr t={new Translation(otherTheme.shortDescription)} /> --> | ||||||
|     </div> |     </div> | ||||||
|   </a> |   </a> | ||||||
|  | {/if} | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue