forked from MapComplete/MapComplete
		
	UI: fix behaviour of hotkey "escape" when closing previews and nearby images popups
This commit is contained in:
		
							parent
							
								
									ae84207555
								
							
						
					
					
						commit
						e22929bb35
					
				
					 6 changed files with 73 additions and 49 deletions
				
			
		|  | @ -4,6 +4,7 @@ import UserRelatedState from "../Logic/State/UserRelatedState" | |||
| import { Utils } from "../Utils" | ||||
| import Zoomcontrol from "../UI/Zoomcontrol" | ||||
| import { LocalStorageSource } from "../Logic/Web/LocalStorageSource" | ||||
| import { ProvidedImage } from "../Logic/ImageProviders/ImageProvider" | ||||
| 
 | ||||
| export type PageType = (typeof MenuState.pageNames)[number] | ||||
| 
 | ||||
|  | @ -27,7 +28,7 @@ export class MenuState { | |||
|         "favourites", | ||||
|         "usersettings", | ||||
|         "share", | ||||
|         "menu", | ||||
|         "menu" | ||||
|     ] as const | ||||
| 
 | ||||
|     /** | ||||
|  | @ -38,6 +39,9 @@ export class MenuState { | |||
|         undefined | ||||
|     ) | ||||
| 
 | ||||
|     public static readonly nearbyImagesFeature: UIEventSource<object> = new UIEventSource<object>( | ||||
|         undefined | ||||
|     ) | ||||
|     public readonly pageStates: Record<PageType, UIEventSource<boolean>> | ||||
| 
 | ||||
|     public readonly highlightedLayerInFilters: UIEventSource<string> = new UIEventSource<string>( | ||||
|  | @ -45,6 +49,7 @@ export class MenuState { | |||
|     ) | ||||
|     public highlightedUserSetting: UIEventSource<string> = new UIEventSource<string>(undefined) | ||||
|     private readonly _selectedElement: UIEventSource<any> | undefined | ||||
|     private isClosingAll = false | ||||
| 
 | ||||
|     constructor(selectedElement: UIEventSource<any> | undefined) { | ||||
|         this._selectedElement = selectedElement | ||||
|  | @ -129,29 +134,49 @@ export class MenuState { | |||
|      * Returns 'true' if at least one menu was opened | ||||
|      */ | ||||
|     public closeAll(): boolean { | ||||
|         console.log("Closing all") | ||||
|         if (this.isClosingAll) { | ||||
|             return true | ||||
|         } | ||||
|         this.isClosingAll = true | ||||
|         const ps = this.pageStates | ||||
|         if (ps.menu.data) { | ||||
|             ps.menu.set(false) | ||||
|             return true | ||||
|         } | ||||
|         try { | ||||
| 
 | ||||
|         if (MenuState.previewedImage.data !== undefined) { | ||||
|             MenuState.previewedImage.setData(undefined) | ||||
|             return true | ||||
|         } | ||||
| 
 | ||||
|         for (const key in ps) { | ||||
|             const toggle = ps[key] | ||||
|             const wasOpen = toggle.data | ||||
|             toggle.setData(false) | ||||
|             if (wasOpen) { | ||||
|             if (ps.menu.data) { | ||||
|                 ps.menu.set(false) | ||||
|                 return true | ||||
|             } | ||||
|         } | ||||
|         if (this._selectedElement.data) { | ||||
|             this._selectedElement.setData(undefined) | ||||
|             return true | ||||
| 
 | ||||
|             if (MenuState.previewedImage.data !== undefined) { | ||||
|                 MenuState.previewedImage.setData(undefined) | ||||
|                 return true | ||||
|             } | ||||
| 
 | ||||
|             if (MenuState.nearbyImagesFeature.data !== undefined) { | ||||
|                 MenuState.nearbyImagesFeature.setData(undefined) | ||||
|                 return true | ||||
|             } | ||||
|             for (const key in ps) { | ||||
|                 const toggle = ps[key] | ||||
|                 const wasOpen = toggle.data | ||||
|                 toggle.setData(false) | ||||
|                 if (wasOpen) { | ||||
|                     return true | ||||
|                 } | ||||
|             } | ||||
|             if (this._selectedElement.data) { | ||||
|                 this._selectedElement.setData(undefined) | ||||
|                 return true | ||||
|             } | ||||
|         } finally { | ||||
|             this.isClosingAll = false | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public setPreviewedImage(img?: Partial<ProvidedImage>) { | ||||
|         if (img === undefined && !this.isClosingAll) { | ||||
|             return | ||||
|         } | ||||
|         MenuState.previewedImage.setData(img) | ||||
| 
 | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -14,6 +14,8 @@ export default class Hotkeys { | |||
|         }[] | ||||
|     > = new UIEventSource([]) | ||||
| 
 | ||||
|     private static readonly seenKeys: Set<string> = new Set() | ||||
| 
 | ||||
|     /** | ||||
|      * Register a hotkey | ||||
|      * @param key | ||||
|  | @ -51,6 +53,9 @@ export default class Hotkeys { | |||
|             } | ||||
|         } | ||||
| 
 | ||||
|         const keyString = JSON.stringify(key) | ||||
|         this.seenKeys.add(keyString) | ||||
| 
 | ||||
|         this._docs.data.push({ key, documentation, alsoTriggeredBy }) | ||||
|         this._docs.ping() | ||||
|         if (Utils.runningFromConsole) { | ||||
|  |  | |||
|  | @ -56,6 +56,7 @@ | |||
|         <slot name="header" /> | ||||
|       </h1> | ||||
|     {/if} | ||||
|     <slot name="closebutton" /> | ||||
|   </svelte:fragment> | ||||
|   <slot /> | ||||
|   {#if $$slots.footer} | ||||
|  |  | |||
|  | @ -11,7 +11,6 @@ | |||
|   import ImageOperations from "./ImageOperations.svelte" | ||||
|   import Popup from "../Base/Popup.svelte" | ||||
|   import { onDestroy } from "svelte" | ||||
|   import type { SpecialVisualizationState } from "../SpecialVisualization" | ||||
|   import type { Feature, Point } from "geojson" | ||||
|   import Loading from "../Base/Loading.svelte" | ||||
|   import Translations from "../i18n/Translations" | ||||
|  | @ -19,8 +18,9 @@ | |||
|   import DotMenu from "../Base/DotMenu.svelte" | ||||
|   import LoadingPlaceholder from "../Base/LoadingPlaceholder.svelte" | ||||
|   import { MenuState } from "../../Models/MenuState" | ||||
|   import ThemeViewState from "../../Models/ThemeViewState" | ||||
| 
 | ||||
|   export let image: Partial<ProvidedImage> | ||||
|   export let image: Partial<ProvidedImage> & { id: string; url: string } | ||||
|   let fallbackImage: string = undefined | ||||
|   if (image.provider === Mapillary.singleton) { | ||||
|     fallbackImage = "./assets/svg/blocked.svg" | ||||
|  | @ -28,7 +28,7 @@ | |||
| 
 | ||||
|   let imgEl: HTMLImageElement | ||||
|   export let imgClass: string = undefined | ||||
|   export let state: SpecialVisualizationState = undefined | ||||
|   export let state: ThemeViewState = undefined | ||||
|   export let attributionFormat: "minimal" | "medium" | "large" = "medium" | ||||
|   let previewedImage: UIEventSource<Partial<ProvidedImage>> = MenuState.previewedImage | ||||
|   export let canZoom = previewedImage !== undefined | ||||
|  | @ -36,9 +36,7 @@ | |||
|   let showBigPreview = new UIEventSource(false) | ||||
|   onDestroy( | ||||
|     showBigPreview.addCallbackAndRun((shown) => { | ||||
|       if (!shown) { | ||||
|         previewedImage?.set(undefined) | ||||
|       } | ||||
|       state.guistate.setPreviewedImage(shown ? image : undefined) | ||||
|     }) | ||||
|   ) | ||||
|   if (previewedImage) { | ||||
|  |  | |||
|  | @ -89,17 +89,6 @@ | |||
|     imgClass="max-h-64 w-auto sm:h-32 md:h-64" | ||||
|     attributionFormat="minimal" | ||||
|   > | ||||
|     <!-- | ||||
|     <div slot="preview-action" class="self-center" > | ||||
|     <LoginToggle {state} silentFail={true}> | ||||
|       {#if linkable} | ||||
|         <label class="normal-background p-2 rounded-full pointer-events-auto"> | ||||
|           <input bind:checked={$isLinked} type="checkbox" /> | ||||
|           <SpecialTranslation t={t.link} {tags} {state} {layer} {feature} /> | ||||
|         </label> | ||||
|       {/if} | ||||
|     </LoginToggle> | ||||
|     </div>--> | ||||
|   </AttributedImage> | ||||
|   <LoginToggle {state} silentFail={true}> | ||||
|     {#if linkable} | ||||
|  |  | |||
|  | @ -1,22 +1,19 @@ | |||
| <script lang="ts"> | ||||
|   import { UIEventSource } from "../../Logic/UIEventSource" | ||||
|   import type { OsmTags } from "../../Models/OsmFeature" | ||||
|   import type { SpecialVisualizationState } from "../SpecialVisualization" | ||||
|   import type { Feature } from "geojson" | ||||
|   import LayerConfig from "../../Models/ThemeConfig/LayerConfig" | ||||
|   import Translations from "../i18n/Translations" | ||||
|   import Tr from "../Base/Tr.svelte" | ||||
|   import NearbyImages from "./NearbyImages.svelte" | ||||
|   import { XCircleIcon } from "@babeard/svelte-heroicons/solid" | ||||
|   import Camera_plus from "../../assets/svg/Camera_plus.svelte" | ||||
|   import LoginToggle from "../Base/LoginToggle.svelte" | ||||
|   import { ariaLabel } from "../../Utils/ariaLabel" | ||||
|   import { Accordion, AccordionItem, Modal } from "flowbite-svelte" | ||||
|   import AccordionSingle from "../Flowbite/AccordionSingle.svelte" | ||||
|   import Popup from "../Base/Popup.svelte" | ||||
|   import ThemeViewState from "../../Models/ThemeViewState" | ||||
|   import { onDestroy } from "svelte" | ||||
|   import { MenuState } from "../../Models/MenuState" | ||||
|   import { CloseButton } from "flowbite-svelte" | ||||
| 
 | ||||
|   export let tags: UIEventSource<OsmTags> | ||||
|   export let state: SpecialVisualizationState | ||||
|   export let state: ThemeViewState | ||||
|   export let lon: number | ||||
|   export let lat: number | ||||
|   export let feature: Feature | ||||
|  | @ -27,6 +24,16 @@ | |||
| 
 | ||||
|   let enableLogin = state.featureSwitches.featureSwitchEnableLogin | ||||
|   export let shown = new UIEventSource(false) | ||||
|   onDestroy(MenuState.nearbyImagesFeature.addCallback(something => { | ||||
|     if (something !== feature) { | ||||
|       shown.set(false) | ||||
|     } | ||||
|   })) | ||||
|   onDestroy(shown.addCallbackAndRun(isShown => { | ||||
|     if (isShown) { | ||||
|       MenuState.nearbyImagesFeature.set(feature) | ||||
|     } | ||||
|   })) | ||||
| </script> | ||||
| 
 | ||||
| {#if enableLogin.data} | ||||
|  | @ -37,10 +44,9 @@ | |||
|   > | ||||
|     <Tr t={t.seeNearby} /> | ||||
|   </button> | ||||
|   <Popup {shown} bodyPadding="p-4"> | ||||
|     <span slot="header"> | ||||
|       <Tr t={t.seeNearby} /> | ||||
|     </span> | ||||
|   <Popup {shown} bodyPadding="p-4" dismissable={false}> | ||||
|     <Tr slot="header" t={t.seeNearby} /> | ||||
|     <CloseButton slot="closebutton" on:click={() => shown?.set(false)} /> | ||||
|     <NearbyImages {tags} {state} {lon} {lat} {feature} {linkable} {layer} /> | ||||
|   </Popup> | ||||
| {/if} | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue