forked from MapComplete/MapComplete
		
	Merge develop
This commit is contained in:
		
						commit
						bcd53405c8
					
				
					 197 changed files with 5675 additions and 5188 deletions
				
			
		|  | @ -27,6 +27,7 @@ | |||
|   import Github from "../assets/svg/Github.svelte" | ||||
|   import { Utils } from "../Utils" | ||||
|   import { ArrowTrendingUp } from "@babeard/svelte-heroicons/solid/ArrowTrendingUp" | ||||
|   import Searchbar from "./Base/Searchbar.svelte" | ||||
| 
 | ||||
|   const featureSwitches = new OsmConnectionFeatureSwitches() | ||||
|   const osmConnection = new OsmConnection({ | ||||
|  | @ -42,7 +43,7 @@ | |||
|   const tr = Translations.t.general.morescreen | ||||
| 
 | ||||
|   let userLanguages = osmConnection.userDetails.map((ud) => ud.languages) | ||||
|   let themeSearchText: UIEventSource<string | undefined> = new UIEventSource<string>(undefined) | ||||
|   let themeSearchText: UIEventSource<string | undefined> = new UIEventSource<string>("") | ||||
| 
 | ||||
|   document.addEventListener("keydown", function(event) { | ||||
|     if (event.ctrlKey && event.code === "KeyF") { | ||||
|  | @ -91,24 +92,7 @@ | |||
|       </div> | ||||
|     </div> | ||||
| 
 | ||||
|     <form | ||||
|       class="flex justify-center" | ||||
|       on:submit|preventDefault={() => MoreScreen.applySearch(themeSearchText.data)} | ||||
|     > | ||||
|       <label | ||||
|         class="neutral-label my-2 flex w-full items-center rounded-full border-2 border-black sm:w-1/2" | ||||
|       > | ||||
|         <SearchIcon aria-hidden="true" class="h-8 w-8" /> | ||||
|         <input | ||||
|           autofocus | ||||
|           bind:value={$themeSearchText} | ||||
|           class="mr-4 w-full outline-none" | ||||
|           id="theme-search" | ||||
|           type="search" | ||||
|           use:placeholder={tr.searchForATheme} | ||||
|         /> | ||||
|       </label> | ||||
|     </form> | ||||
|     <Searchbar value={themeSearchText} placeholder={tr.searchForATheme} on:search={() => MoreScreen.applySearch(themeSearchText.data)}/> | ||||
| 
 | ||||
|     <ThemesList search={themeSearchText} {state} themes={MoreScreen.officialThemes} /> | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ | |||
|   import { ariaLabel } from "../../Utils/ariaLabel" | ||||
|   import Translations from "../i18n/Translations" | ||||
|   import { XCircleIcon } from "@babeard/svelte-heroicons/solid" | ||||
|   import { CloseButton } from "flowbite-svelte" | ||||
| 
 | ||||
|   /** | ||||
|    * The slotted element will be shown on top, with a lower-opacity border | ||||
|  | @ -29,7 +30,7 @@ | |||
|   }} | ||||
| > | ||||
|   <div | ||||
|     class="content normal-background pointer-events-auto h-full" | ||||
|     class="content relative normal-background pointer-events-auto h-full" | ||||
|     on:click|stopPropagation={() => {}} | ||||
|   > | ||||
|     <div class="h-full rounded-xl"> | ||||
|  | @ -37,22 +38,21 @@ | |||
|     </div> | ||||
|     <slot name="close-button"> | ||||
|       <!-- The close button is placed _after_ the default slot in order to always paint it on top --> | ||||
|       <div | ||||
|         class="absolute right-10 top-10 m-0 cursor-pointer rounded-full border-0 border-none bg-white p-0" | ||||
|         style="margin: -0.25rem" | ||||
|         on:click={() => dispatch("close")} | ||||
|         use:ariaLabel={Translations.t.general.backToMap} | ||||
|       > | ||||
|         <XCircleIcon class="h-8 w-8" /> | ||||
|       <div class="absolute top-0 right-0"> | ||||
| 
 | ||||
|         <CloseButton class="normal-background mt-2 mr-2" | ||||
|                      on:click={() => dispatch("close")} | ||||
|         /> | ||||
|       </div> | ||||
| 
 | ||||
|     </slot> | ||||
|   </div> | ||||
| </div> | ||||
| 
 | ||||
| <style> | ||||
|   .content { | ||||
|     border-radius: 0.5rem; | ||||
|     overflow-x: hidden; | ||||
|     box-shadow: 0 0 1rem #00000088; | ||||
|   } | ||||
|     .content { | ||||
|         border-radius: 0.5rem; | ||||
|         overflow-x: hidden; | ||||
|         box-shadow: 0 0 1rem #00000088; | ||||
|     } | ||||
| </style> | ||||
|  |  | |||
|  | @ -29,7 +29,7 @@ | |||
|          size="xl" | ||||
|          {defaultClass} {bodyClass} {dialogClass} {headerClass} | ||||
|          color="none"> | ||||
|     <h1 slot="header" class="w-full"> | ||||
|     <h1 slot="header" class="page-header w-full"> | ||||
|       <slot name="header" /> | ||||
|     </h1> | ||||
|     <slot /> | ||||
|  | @ -44,3 +44,16 @@ | |||
|     </slot> | ||||
|   </button> | ||||
| {/if} | ||||
| 
 | ||||
| <style> | ||||
|     :global(.page-header) { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|     } | ||||
| 
 | ||||
|   :global(.page-header svg) { | ||||
|       width: 2rem; | ||||
|       height: 2rem; | ||||
|       margin-right: 0.75rem; | ||||
|   } | ||||
| </style> | ||||
|  |  | |||
							
								
								
									
										43
									
								
								src/UI/Base/Searchbar.svelte
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								src/UI/Base/Searchbar.svelte
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,43 @@ | |||
| <script lang="ts"> | ||||
|   import { UIEventSource } from "../../Logic/UIEventSource" | ||||
|   import Translations from "../i18n/Translations" | ||||
|   import { createEventDispatcher } from "svelte" | ||||
|   import { placeholder as set_placeholder } from "../../Utils/placeholder" | ||||
|   import { SearchIcon } from "@rgossiaux/svelte-heroicons/solid" | ||||
|   import { ariaLabel } from "../../Utils/ariaLabel" | ||||
|   import { Translation } from "../i18n/Translation" | ||||
| 
 | ||||
|   export let value: UIEventSource<string> | ||||
|   let _value = value.data ?? "" | ||||
|   value.addCallbackD(v => { | ||||
|     _value = v | ||||
|   }) | ||||
|   $: value.set(_value) | ||||
| 
 | ||||
|   const dispatch = createEventDispatcher<{ search }>() | ||||
|   export let placeholder: Translation =  Translations.t.general.search.search | ||||
| </script> | ||||
| 
 | ||||
| 
 | ||||
| <form | ||||
|   class="flex justify-center" | ||||
|   on:submit|preventDefault={() => dispatch("search")} | ||||
| > | ||||
|   <label | ||||
|     class="neutral-label my-2 flex w-full items-center rounded-full border-2 border-black sm:w-1/2  box-shadow" | ||||
|   > | ||||
|     <input | ||||
|       type="search" | ||||
|       style=" --tw-ring-color: rgb(0 0 0 / 0) !important;" | ||||
|       class="ml-4 pl-1 w-full outline-none border-none" | ||||
|       on:keypress={(keypr) => { | ||||
|           return keypr.key === "Enter" ? dispatch("search") : undefined | ||||
|         }} | ||||
|       bind:value={_value} | ||||
|       use:set_placeholder={placeholder} | ||||
|       use:ariaLabel={Translations.t.general.search.search} | ||||
|     /> | ||||
|     <SearchIcon aria-hidden="true" class="h-8 w-8 mx-2" /> | ||||
| 
 | ||||
|   </label> | ||||
| </form> | ||||
|  | @ -11,7 +11,7 @@ | |||
|   import CommunityIndexView from "./CommunityIndexView.svelte" | ||||
|   import Community from "../../assets/svg/Community.svelte" | ||||
|   import LoginToggle from "../Base/LoginToggle.svelte" | ||||
|   import { Sidebar } from "flowbite-svelte" | ||||
|   import { CloseButton, Sidebar } from "flowbite-svelte" | ||||
|   import HotkeyTable from "./HotkeyTable.svelte" | ||||
|   import { Utils } from "../../Utils" | ||||
|   import Constants from "../../Models/Constants" | ||||
|  | @ -47,6 +47,8 @@ | |||
|   import LogoutButton from "../Base/LogoutButton.svelte" | ||||
|   import { BoltIcon } from "@babeard/svelte-heroicons/mini" | ||||
|   import Copyright from "../../assets/svg/Copyright.svelte" | ||||
|   import Pencil from "../../assets/svg/Pencil.svelte" | ||||
|   import Squares2x2 from "@babeard/svelte-heroicons/mini/Squares2x2" | ||||
| 
 | ||||
|   export let state: ThemeViewState | ||||
|   let userdetails = state.osmConnection.userDetails | ||||
|  | @ -62,6 +64,23 @@ | |||
| </script> | ||||
| 
 | ||||
| <div class="flex flex-col p-2 sm:p-3 low-interaction gap-y-2 sm:gap-y-3 h-screen overflow-y-auto"> | ||||
|   <div class="flex justify-between"> | ||||
|     <h2> | ||||
|       <Tr t={t.title}/> | ||||
|     </h2> | ||||
|     <CloseButton on:click={() => {pg.menu.set(false)}} /> | ||||
|   </div> | ||||
|   {#if $showHome} | ||||
|     <a class="flex button primary" href={Utils.HomepageLink()}> | ||||
|       <Squares2x2 class="h-10 w-10" /> | ||||
|       {#if Utils.isIframe} | ||||
|         <Tr t={Translations.t.general.seeIndex} /> | ||||
|       {:else} | ||||
|         <Tr t={Translations.t.general.backToIndex} /> | ||||
|       {/if} | ||||
|     </a> | ||||
|   {/if} | ||||
| 
 | ||||
| 
 | ||||
|   <!-- User related: avatar, settings, favourits, logout --> | ||||
|   <div class="sidebar-unit"> | ||||
|  | @ -77,10 +96,10 @@ | |||
| 
 | ||||
| 
 | ||||
|     <Page {onlyLink} shown={pg.usersettings}> | ||||
|       <div class="flex" slot="header"> | ||||
|         <CogIcon class="h-6 w-6" /> | ||||
|       <svelte:fragment slot="header"> | ||||
|         <CogIcon/> | ||||
|         <Tr t={UserRelatedState.usersettingsConfig.title.GetRenderValue({})} /> | ||||
|       </div> | ||||
|       </svelte:fragment> | ||||
| 
 | ||||
|       <!-- All shown components are set by 'usersettings.json', which happily uses some special visualisations created specifically for it --> | ||||
|       <LoginToggle {state}> | ||||
|  | @ -109,10 +128,12 @@ | |||
|     <LoginToggle {state}> | ||||
|       <Page {onlyLink} shown={pg.favourites}> | ||||
| 
 | ||||
|         <div class="flex" slot="header"> | ||||
|           <HeartIcon class="h-6 w-6" /> | ||||
|         <svelte:fragment slot="header"> | ||||
|           <HeartIcon /> | ||||
|           <Tr t={Translations.t.favouritePoi.tab} /> | ||||
|         </div> | ||||
|         </svelte:fragment> | ||||
| 
 | ||||
| 
 | ||||
|         <h3> | ||||
| 
 | ||||
|           <Tr t={Translations.t.favouritePoi.title} /> | ||||
|  | @ -146,10 +167,10 @@ | |||
|         <Marker icons={layout.icon} size="h-6 w-6 mr-2" /> | ||||
|         <Tr t={t.showIntroduction} /> | ||||
|       </div> | ||||
|       <div class="flex" slot="header"> | ||||
|         <Marker icons={layout.icon} size="h-8 w-8 mr-4" /> | ||||
|       <svelte:fragment  slot="header"> | ||||
|         <Marker icons={layout.icon} /> | ||||
|         <Tr t={layout.title} /> | ||||
|       </div> | ||||
|       </svelte:fragment> | ||||
|       <ThemeIntroPanel {state} /> | ||||
|     </Page> | ||||
| 
 | ||||
|  | @ -158,20 +179,20 @@ | |||
|     <RasterLayerOverview {onlyLink} {state} /> | ||||
| 
 | ||||
|     <Page {onlyLink} shown={pg.share}> | ||||
|       <div class="flex" slot="header"> | ||||
|         <Share class="h-4 w-4" /> | ||||
|       <svelte:fragment slot="header"> | ||||
|         <Share/> | ||||
|         <Tr t={Translations.t.general.sharescreen.title} /> | ||||
|       </div> | ||||
|       </svelte:fragment> | ||||
|       <ShareScreen {state} /> | ||||
|     </Page> | ||||
| 
 | ||||
| 
 | ||||
|     {#if state.featureSwitches.featureSwitchEnableExport} | ||||
|       <Page {onlyLink} shown={pg.download}> | ||||
|         <div slot="header" class="flex"> | ||||
|           <ArrowDownTray class="h-4 w-4" /> | ||||
|         <svelte:fragment slot="header"> | ||||
|           <ArrowDownTray  /> | ||||
|           <Tr t={Translations.t.general.download.title} /> | ||||
|         </div> | ||||
|         </svelte:fragment> | ||||
|         <DownloadPanel {state} /> | ||||
|       </Page> | ||||
|     {/if} | ||||
|  | @ -206,22 +227,13 @@ | |||
|     <h3> | ||||
|       <Tr t={t.moreUtilsTitle} /> | ||||
|     </h3> | ||||
|     {#if $showHome} | ||||
|       <a class="flex" href={Utils.HomepageLink()}> | ||||
|         <Add class="h-6 w-6" /> | ||||
|         {#if Utils.isIframe} | ||||
|           <Tr t={Translations.t.general.seeIndex} /> | ||||
|         {:else} | ||||
|           <Tr t={Translations.t.general.backToIndex} /> | ||||
|         {/if} | ||||
|       </a> | ||||
|     {/if} | ||||
| 
 | ||||
| 
 | ||||
|     <Page {onlyLink} shown={pg.community_index}> | ||||
|       <div class="flex" slot="header"> | ||||
|         <Community class="h-6 w-6" /> | ||||
|       <svelte:fragment slot="header"> | ||||
|         <Community/> | ||||
|         <Tr t={Translations.t.communityIndex.title} /> | ||||
|       </div> | ||||
|       </svelte:fragment> | ||||
|       <CommunityIndexView location={state.mapProperties.location} /> | ||||
|     </Page> | ||||
| 
 | ||||
|  | @ -242,13 +254,20 @@ | |||
|       <Tr t={Translations.t.general.menu.aboutMapComplete} /> | ||||
|     </h3> | ||||
| 
 | ||||
|     <div class="hidden-on-mobile"> | ||||
|     <a | ||||
|       class="flex" | ||||
|       href={window.location.protocol + "//" + window.location.host + "/studio.html"} | ||||
|     > | ||||
|       <Pencil class="mr-2 h-6 w-6" /> | ||||
|       <Tr t={Translations.t.general.morescreen.createYourOwnTheme} /> | ||||
|     </a> | ||||
| 
 | ||||
|     <div class="hidden-on-mobile w-full"> | ||||
|       <Page {onlyLink} shown={pg.hotkeys}> | ||||
|         <div class="flex" slot="header"> | ||||
|           <BoltIcon class="w-6 h-6" /> | ||||
|         <svelte:fragment  slot="header"> | ||||
|           <BoltIcon /> | ||||
|           <Tr t={ Translations.t.hotkeyDocumentation.title} /> | ||||
|         </div> | ||||
|         </svelte:fragment> | ||||
|         <HotkeyTable /> | ||||
|       </Page> | ||||
|     </div> | ||||
|  | @ -276,29 +295,29 @@ | |||
| 
 | ||||
| 
 | ||||
|     <Page {onlyLink} shown={pg.copyright}> | ||||
|       <div slot="header" class="flex"> | ||||
|         <Copyright class="w-8 h-8" /> | ||||
|       <svelte:fragment slot="header"> | ||||
|         <Copyright /> | ||||
|         <Tr t={Translations.t.general.attribution.attributionTitle} /> | ||||
|       </div> | ||||
|       </svelte:fragment> | ||||
|       <CopyrightPanel {state} /> | ||||
|     </Page> | ||||
| 
 | ||||
| 
 | ||||
|     <Page {onlyLink} shown={pg.copyright_icons}> | ||||
|       <div slot="header" class="flex"> | ||||
|         <Copyright class="w-8 h-8" /> | ||||
|       <svelte:fragment slot="header" > | ||||
|         <Copyright/> | ||||
|         <Tr t={ Translations.t.general.attribution.iconAttribution.title} /> | ||||
|       </div> | ||||
|       </svelte:fragment> | ||||
|       <CopyrightAllIcons {state} /> | ||||
| 
 | ||||
|     </Page> | ||||
| 
 | ||||
| 
 | ||||
|     <Page {onlyLink} shown={pg.privacy}> | ||||
|       <div class="flex" slot="header"> | ||||
|         <EyeIcon class="w-8 h-8" /> | ||||
|       <svelte:fragment slot="header"> | ||||
|         <EyeIcon /> | ||||
|         <Tr t={Translations.t.privacy.title} /> | ||||
|       </div> | ||||
|       </svelte:fragment> | ||||
|       <PrivacyPolicy {state} /> | ||||
|     </Page> | ||||
| 
 | ||||
|  | @ -340,12 +359,14 @@ | |||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     :global(.sidebar-button, .sidebar-button, .sidebar-unit > a) { | ||||
|     :global(.sidebar-button, .sidebar-unit > a) { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|         border-radius: 0.25rem !important; | ||||
|         padding: 0.4rem 0.75rem !important; | ||||
|         text-decoration: none !important; | ||||
|         width: 100%; | ||||
|         text-align: start; | ||||
|     } | ||||
| 
 | ||||
|     :global(.sidebar-button > svg , .sidebar-button > img, .sidebar-unit a > img, .sidebar-unit > a svg) { | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ | |||
|   import Tr from "../Base/Tr.svelte" | ||||
|   import { XCircleIcon } from "@rgossiaux/svelte-heroicons/solid" | ||||
|   import { ariaLabel } from "../../Utils/ariaLabel" | ||||
|   import { CloseButton } from "flowbite-svelte" | ||||
| 
 | ||||
|   export let state: SpecialVisualizationState | ||||
|   export let layer: LayerConfig | ||||
|  | @ -72,14 +73,10 @@ | |||
|     {/if} | ||||
|   </div> | ||||
|   <slot name="close-button"> | ||||
|     <button | ||||
|       class="mt-2 h-fit shrink-0 cursor-pointer self-center rounded-full border-none p-0" | ||||
|       on:click={() => state.selectedElement.setData(undefined)} | ||||
|       style="border: 0 !important; padding: 0 !important;" | ||||
|       use:ariaLabel={Translations.t.general.backToMap} | ||||
|     > | ||||
|       <XCircleIcon aria-hidden={true} class="h-8 w-8" /> | ||||
|     </button> | ||||
|     <div class="mt-4"> | ||||
|     <CloseButton  on:click={() => state.selectedElement.setData(undefined)}/> | ||||
|     </div> | ||||
| 
 | ||||
|   </slot> | ||||
| </div> | ||||
| 
 | ||||
|  |  | |||
|  | @ -35,6 +35,8 @@ | |||
|   let enableBackground = true | ||||
|   let enableGeolocation = true | ||||
| 
 | ||||
|   let location = state.mapProperties.location | ||||
| 
 | ||||
|   function calculateLinkToShare( | ||||
|     showWelcomeMessage: boolean, | ||||
|     enableLogin: boolean, | ||||
|  | @ -116,10 +118,12 @@ | |||
|   ) | ||||
| </script> | ||||
| 
 | ||||
| <div class="flex flex-col"> | ||||
| <div class="flex flex-col link-underline"> | ||||
| 
 | ||||
|   <a href="geo:{$location.lat},{$location.lon}">Open the current location in other applications</a> | ||||
| 
 | ||||
|   <div class="flex flex-col"> | ||||
|     <Tr t={tr.intro} /> | ||||
| 
 | ||||
|     <Copyable {state} text={linkToShare} /> | ||||
|   </div> | ||||
|   <div class="flex justify-center"> | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ | |||
|     state.mapProperties.location.setData({ lon, lat }) | ||||
|     const z = state.mapProperties.zoom.data | ||||
|     state.mapProperties.zoom.setData(Math.min(17, Math.max(12, z))) | ||||
|     state.guistate.menuIsOpened.setData(false) | ||||
|     state.guistate.pageStates.menu.setData(false) | ||||
|   } | ||||
| 
 | ||||
|   function select() { | ||||
|  |  | |||
|  | @ -41,7 +41,7 @@ | |||
|     /> | ||||
| 
 | ||||
|     {#if canZoom && loaded} | ||||
|       <div class="absolute right-0 top-0 bg-black-transparent rounded-bl-full"> | ||||
|       <div class="absolute right-0 top-0 bg-black-transparent rounded-bl-full" on:click={() => previewedImage.set(image)}> | ||||
|       <MagnifyingGlassPlusIcon class="w-8 h-8 pl-3 pb-3 cursor-zoom-in" color="white" /> | ||||
|       </div> | ||||
|     {/if} | ||||
|  |  | |||
|  | @ -11,6 +11,8 @@ | |||
|   import { twMerge } from "tailwind-merge" | ||||
|   import { UIEventSource } from "../../Logic/UIEventSource" | ||||
|   import Loading from "../Base/Loading.svelte" | ||||
|   import Tr from "../Base/Tr.svelte" | ||||
|   import Translations from "../i18n/Translations" | ||||
| 
 | ||||
|   export let image: ProvidedImage | ||||
|   export let clss: string = undefined | ||||
|  | @ -48,7 +50,7 @@ | |||
|       on:click={() => download()} | ||||
|     > | ||||
|       <DownloadIcon class="h-6 w-6 px-2 opacity-100" /> | ||||
|       Download | ||||
|       <Tr t={Translations.t.general.download.downloadImage}/> | ||||
|     </button> | ||||
|   </div> | ||||
| </div> | ||||
|  |  | |||
|  | @ -1996,6 +1996,9 @@ export default class SpecialVisualizations { | |||
|                 ): BaseUIElement { | ||||
|                     const translation = tagSource.map((tags) => { | ||||
|                         const presets = state.layout.getMatchingLayer(tags)?.presets | ||||
|                         if(!presets){ | ||||
|                             return undefined | ||||
|                         } | ||||
|                         const matchingPresets = presets | ||||
|                             .filter((pr) => pr.description !== undefined) | ||||
|                             .filter((pr) => new And(pr.tags).matchesProperties(tags)) | ||||
|  |  | |||
|  | @ -46,10 +46,12 @@ | |||
|   import DrawerRight from "./Base/DrawerRight.svelte" | ||||
|   import SearchResults from "./Search/SearchResults.svelte" | ||||
|   import { CloseButton } from "flowbite-svelte" | ||||
|   import Hash from "../Logic/Web/Hash" | ||||
| 
 | ||||
|   export let state: ThemeViewState | ||||
|   let layout = state.layout | ||||
|   let maplibremap: UIEventSource<MlMap> = state.map | ||||
|   let state_selectedElement = state.selectedElement | ||||
|   let selectedElement: UIEventSource<Feature> = new UIEventSource<Feature>(undefined) | ||||
|   let compass = Orientation.singleton.alpha | ||||
|   let compassLoaded = Orientation.singleton.gotMeasurement | ||||
|  | @ -71,6 +73,7 @@ | |||
|     }) | ||||
|   }) | ||||
| 
 | ||||
| 
 | ||||
|   let selectedLayer: Store<LayerConfig> = state.selectedElement.mapD((element) => { | ||||
|     if (element.properties.id.startsWith("current_view")) { | ||||
|       return currentViewLayer | ||||
|  | @ -85,11 +88,11 @@ | |||
|   state.mapProperties.installCustomKeyboardHandler(viewport) | ||||
|   let canZoomIn = mapproperties.maxzoom.map( | ||||
|     (mz) => mapproperties.zoom.data < mz, | ||||
|     [mapproperties.zoom] | ||||
|     [mapproperties.zoom], | ||||
|   ) | ||||
|   let canZoomOut = mapproperties.minzoom.map( | ||||
|     (mz) => mapproperties.zoom.data > mz, | ||||
|     [mapproperties.zoom] | ||||
|     [mapproperties.zoom], | ||||
|   ) | ||||
| 
 | ||||
|   function updateViewport() { | ||||
|  | @ -105,7 +108,7 @@ | |||
|     const bottomRight = mlmap.unproject([rect.right, rect.bottom]) | ||||
|     const bbox = new BBox([ | ||||
|       [topLeft.lng, topLeft.lat], | ||||
|       [bottomRight.lng, bottomRight.lat] | ||||
|       [bottomRight.lng, bottomRight.lat], | ||||
|     ]) | ||||
|     state.visualFeedbackViewportBounds.setData(bbox) | ||||
|   } | ||||
|  | @ -125,7 +128,7 @@ | |||
|   onDestroy( | ||||
|     rasterLayer.addCallbackAndRunD((l) => { | ||||
|       rasterLayerName = l.properties.name | ||||
|     }) | ||||
|     }), | ||||
|   ) | ||||
|   let previewedImage = state.previewedImage | ||||
|   let addNewFeatureMode = state.userRelatedState.addNewFeatureMode | ||||
|  | @ -154,6 +157,7 @@ | |||
|     animation?.cameraAnimation(mlmap) | ||||
|   } | ||||
| 
 | ||||
|   let hash = Hash.hash | ||||
| </script> | ||||
| 
 | ||||
| <main> | ||||
|  | @ -172,6 +176,110 @@ | |||
|       /> | ||||
|     </div> | ||||
|   {/if} | ||||
| 
 | ||||
|   <div class="pointer-events-none absolute top-0 left-0 w-full"> | ||||
|     <!-- Top components --> | ||||
| 
 | ||||
|     <div | ||||
|       class="flex bg-black-light-transparent pointer-events-auto items-center justify-between px-4 py-1 flex-wrap-reverse"> | ||||
|       <!-- Top bar with tools --> | ||||
|       <div class="flex items-center"> | ||||
| 
 | ||||
|         <MapControlButton | ||||
|           cls="m-0.5 p-0.5 sm:p-1" | ||||
|           arialabel={Translations.t.general.labels.menu} | ||||
|           on:click={() => {console.log("Opening...."); state.guistate.pageStates.menu.setData(true)}} | ||||
|           on:keydown={forwardEventToMap} | ||||
|         > | ||||
|           <MenuIcon class="h-6 w-6 cursor-pointer" /> | ||||
|         </MapControlButton> | ||||
| 
 | ||||
|         <MapControlButton | ||||
|           on:click={() => state.guistate.pageStates.about_theme.set(true)} | ||||
|           on:keydown={forwardEventToMap} | ||||
|         > | ||||
|           <div | ||||
|             class="m-0.5 mx-1 flex cursor-pointer items-center max-[480px]:w-full sm:mx-1 mr-2" | ||||
|           > | ||||
|             <Marker icons={layout.icon} size="h-6 w-6 shrink-0 mr-0.5 sm:mr-1 md:mr-2" /> | ||||
|             <b class="mr-1"> | ||||
|               <Tr t={layout.title} /> | ||||
|             </b> | ||||
|           </div> | ||||
|         </MapControlButton> | ||||
|       </div> | ||||
| 
 | ||||
|       {#if $debug && $hash} | ||||
|         <div class="alert"> | ||||
|           {$hash} | ||||
|         </div> | ||||
|       {/if} | ||||
| 
 | ||||
|       <If condition={state.featureSwitches.featureSwitchSearch}> | ||||
|         <div class="w-full sm:w-64 my-2 sm:mt-0"> | ||||
| 
 | ||||
|           <Geosearch | ||||
|             bounds={state.mapProperties.bounds} | ||||
|             on:searchCompleted={() => { | ||||
|             state.map?.data?.getCanvas()?.focus() | ||||
|           }} | ||||
|             perLayer={state.perLayer} | ||||
|             selectedElement={state.selectedElement} | ||||
|             geolocationState={state.geolocation.geolocationState} | ||||
|           /> | ||||
|         </div> | ||||
|       </If> | ||||
| 
 | ||||
|     </div> | ||||
| 
 | ||||
|     <div class="pointer-events-auto float-right mt-1 flex flex-col px-1 max-[480px]:w-full sm:m-2"> | ||||
|       <If condition={state.visualFeedback}> | ||||
|         {#if $selectedElement === undefined} | ||||
|           <div class="w-fit"> | ||||
|             <VisualFeedbackPanel {state} /> | ||||
|           </div> | ||||
|         {/if} | ||||
|       </If> | ||||
| 
 | ||||
|     </div> | ||||
|     <div class="float-left m-1 flex flex-col sm:mt-2"> | ||||
|       <If condition={state.featureSwitches.featureSwitchWelcomeMessage}> | ||||
| 
 | ||||
| 
 | ||||
|       </If> | ||||
|       {#if currentViewLayer?.tagRenderings && currentViewLayer.defaultIcon()} | ||||
|         <MapControlButton | ||||
|           on:click={() => { | ||||
|             state.selectCurrentView() | ||||
|           }} | ||||
|           on:keydown={forwardEventToMap} | ||||
|         > | ||||
|           <div class="h-8 w-8 cursor-pointer"> | ||||
|             <ToSvelte construct={() => currentViewLayer.defaultIcon()} /> | ||||
|           </div> | ||||
|         </MapControlButton> | ||||
|       {/if} | ||||
|       <ExtraLinkButton {state} /> | ||||
|       <UploadingImageCounter featureId="*" showThankYou={false} {state} /> | ||||
|       <PendingChangesIndicator {state} /> | ||||
|       <If condition={state.featureSwitchIsTesting}> | ||||
|         <div class="alert w-fit">Testmode</div> | ||||
|       </If> | ||||
|       {#if state.osmConnection.Backend().startsWith("https://master.apis.dev.openstreetmap.org")} | ||||
|         <div class="thanks">Testserver</div> | ||||
|       {/if} | ||||
|       <If condition={state.featureSwitches.featureSwitchFakeUser}> | ||||
|         <div class="alert w-fit">Faking a user (Testmode)</div> | ||||
|       </If> | ||||
|     </div> | ||||
|     <div class="flex w-full flex-col items-center justify-center"> | ||||
|       <!-- Flex and w-full are needed for the positioning --> | ||||
|       <!-- Centermessage --> | ||||
|       <StateIndicator {state} /> | ||||
|       <ReverseGeocoding {state} /> | ||||
|     </div> | ||||
|   </div> | ||||
| 
 | ||||
|   <div class="pointer-events-none absolute bottom-0 left-0 mb-4 w-screen"> | ||||
|     <!-- bottom controls --> | ||||
|     <div class="flex w-full items-end justify-between px-4"> | ||||
|  | @ -395,7 +503,7 @@ | |||
|     <svelte:fragment slot="error" /> | ||||
|   </LoginToggle> | ||||
| 
 | ||||
|   <DrawerLeft shown={state.guistate.menuIsOpened}> | ||||
|   <DrawerLeft shown={state.guistate.pageStates.menu}> | ||||
|     <div class="h-screen overflow-y-auto"> | ||||
|       <MenuDrawer onlyLink={true} {state} /> | ||||
|     </div> | ||||
|  | @ -406,11 +514,11 @@ | |||
|     <!-- right modal with the selected element view --> | ||||
|     <ModalRight | ||||
|       on:close={() => { | ||||
|         selectedElement.setData(undefined) | ||||
|         state.selectedElement.setData(undefined) | ||||
|       }} | ||||
|     > | ||||
|       <div slot="close-button" /> | ||||
|       <SelectedElementPanel {state} selected={$selectedElement} /> | ||||
|       <SelectedElementPanel {state} selected={$state_selectedElement} /> | ||||
|     </ModalRight> | ||||
|   {/if} | ||||
| 
 | ||||
|  | @ -424,7 +532,7 @@ | |||
|         }} | ||||
|       > | ||||
|         <span slot="close-button" /> | ||||
|         <SelectedElementPanel absolute={false} {state} selected={$selectedElement} /> | ||||
|         <SelectedElementPanel absolute={false} {state} selected={$state_selectedElement} /> | ||||
|       </FloatOver> | ||||
|     {:else} | ||||
|       <FloatOver | ||||
|  | @ -432,7 +540,7 @@ | |||
|           state.selectedElement.setData(undefined) | ||||
|         }} | ||||
|       > | ||||
|         <SelectedElementView {state} layer={$selectedLayer} selectedElement={$selectedElement} /> | ||||
|         <SelectedElementView {state} layer={$selectedLayer} selectedElement={$state_selectedElement} /> | ||||
|       </FloatOver> | ||||
|     {/if} | ||||
|   {/if} | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue