forked from MapComplete/MapComplete
		
	Fix: hide some elements of the UI if they are disabled by a featureSwitch
This commit is contained in:
		
							parent
							
								
									02da68a62e
								
							
						
					
					
						commit
						17503d5bfb
					
				
					 6 changed files with 402 additions and 366 deletions
				
			
		|  | @ -12,57 +12,57 @@ import { OsmTags } from "../../../Models/OsmFeature"; | |||
|  * Based on a lon/lat UIEVentSource, will generate the corresponding feature with the correct properties | ||||
|  */ | ||||
| export class LastClickFeatureSource implements WritableFeatureSource { | ||||
|     public readonly features: UIEventSource<Feature[]> = new UIEventSource<Feature[]>([]) | ||||
|     private i: number = 0 | ||||
|     private readonly hasNoteLayer: string | ||||
|     private readonly renderings: string[]; | ||||
|     private readonly hasPresets: string; | ||||
|     public readonly features: UIEventSource<Feature[]> = new UIEventSource<Feature[]>([]); | ||||
|     public readonly hasNoteLayer: boolean; | ||||
|     public readonly renderings: string[]; | ||||
|     public readonly hasPresets: boolean; | ||||
|     private i: number = 0; | ||||
| 
 | ||||
|     constructor(location: Store<{ lon: number; lat: number }>, layout: LayoutConfig) { | ||||
|         this.hasNoteLayer = layout.layers.some((l) => l.id === "note") ? "yes" : "no" | ||||
|         this.hasPresets=  layout.layers.some((l) => l.presets?.length > 0) ? "yes" : "no" | ||||
|         const allPresets: BaseUIElement[] = [] | ||||
|         this.hasNoteLayer = layout.layers.some((l) => l.id === "note"); | ||||
|         this.hasPresets = layout.layers.some((l) => l.presets?.length > 0); | ||||
|         const allPresets: BaseUIElement[] = []; | ||||
|         for (const layer of layout.layers) | ||||
|             for (let i = 0; i < (layer.presets ?? []).length; i++) { | ||||
|                 const preset = layer.presets[i] | ||||
|                 const tags = new ImmutableStore(TagUtils.KVtoProperties(preset.tags)) | ||||
|                 const preset = layer.presets[i]; | ||||
|                 const tags = new ImmutableStore(TagUtils.KVtoProperties(preset.tags)); | ||||
|                 const { html } = layer.mapRendering[0].RenderIcon(tags, false, { | ||||
|                     noSize: true, | ||||
|                     includeBadges: false, | ||||
|                 }) | ||||
|                 allPresets.push(html) | ||||
|                     includeBadges: false | ||||
|                 }); | ||||
|                 allPresets.push(html); | ||||
|             } | ||||
| 
 | ||||
|         this.renderings = Utils.Dedup( | ||||
|             allPresets.map((uiElem) => | ||||
|                 Utils.runningFromConsole ? "" : uiElem.ConstructElement().innerHTML | ||||
|             ) | ||||
|         ) | ||||
|         ); | ||||
| 
 | ||||
|         location.addCallbackAndRunD(({ lon, lat }) => { | ||||
|             this.features.setData([this.createFeature(lon, lat)]) | ||||
|         }) | ||||
|             this.features.setData([this.createFeature(lon, lat)]); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     public createFeature(lon: number, lat: number): Feature<Point, OsmTags> { | ||||
|         const properties: OsmTags = { | ||||
|             lastclick: "yes", | ||||
|             id: "last_click_" + this.i, | ||||
|             has_note_layer: this.hasNoteLayer , | ||||
|             has_presets:this.hasPresets , | ||||
|             has_note_layer: this.hasNoteLayer ? "yes" : "no", | ||||
|             has_presets: this.hasPresets ? "yes" : "no", | ||||
|             renderings: this.renderings.join(""), | ||||
|             number_of_presets: "" +this. renderings.length, | ||||
|             first_preset: this.renderings[0], | ||||
|         } | ||||
|        this. i++ | ||||
|             number_of_presets: "" + this.renderings.length, | ||||
|             first_preset: this.renderings[0] | ||||
|         }; | ||||
|         this.i++; | ||||
| 
 | ||||
|         return <Feature<Point, OsmTags>>{ | ||||
|             type: "Feature", | ||||
|             properties, | ||||
|             geometry: { | ||||
|                 type: "Point", | ||||
|                 coordinates: [lon, lat], | ||||
|             }, | ||||
|         } | ||||
|                 coordinates: [lon, lat] | ||||
|             } | ||||
|         }; | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -99,7 +99,7 @@ export default class FeatureSwitchState extends OsmConnectionFeatureSwitches { | |||
|         ) | ||||
|         this.featureSwitchCommunityIndex = FeatureSwitchUtils.initSwitch( | ||||
|             "fs-community-index", | ||||
|             true, | ||||
|             this.featureSwitchEnableLogin.data, | ||||
|             "Disables/enables the button to get in touch with the community" | ||||
|         ) | ||||
|         this.featureSwitchExtraLinkEnabled = FeatureSwitchUtils.initSwitch( | ||||
|  |  | |||
|  | @ -338,7 +338,6 @@ export default class ThemeViewState implements SpecialVisualizationState { | |||
|     ); | ||||
| 
 | ||||
|     this.initActors(); | ||||
|    // TODO remove this.addLastClick(lastClick);
 | ||||
|     this.drawSpecialLayers(); | ||||
|     this.initHotkeys(); | ||||
|     this.miscSetup(); | ||||
|  | @ -417,52 +416,61 @@ export default class ThemeViewState implements SpecialVisualizationState { | |||
|       } | ||||
|     ); | ||||
| 
 | ||||
|     Hotkeys.RegisterHotkey( | ||||
|       { | ||||
|         nomod: "b" | ||||
|       }, | ||||
|       Translations.t.hotkeyDocumentation.openLayersPanel, | ||||
|       () => { | ||||
|         if (this.featureSwitches.featureSwitchFilter.data) { | ||||
|           this.guistate.openFilterView(); | ||||
|     this.featureSwitches.featureSwitchBackgroundSelection.addCallbackAndRun(enable => { | ||||
|         if(!enable){ | ||||
|             return | ||||
|         } | ||||
|       } | ||||
|     ); | ||||
|         Hotkeys.RegisterHotkey( | ||||
|             { | ||||
|                 nomod: "b" | ||||
|             }, | ||||
|             Translations.t.hotkeyDocumentation.openLayersPanel, | ||||
|             () => { | ||||
|                 if (this.featureSwitches.featureSwitchFilter.data) { | ||||
|                     this.guistate.openFilterView(); | ||||
|                 } | ||||
|             } | ||||
|         ); | ||||
|         Hotkeys.RegisterHotkey( | ||||
|             { shift: "O" }, | ||||
|             Translations.t.hotkeyDocumentation.selectMapnik, | ||||
|             () => { | ||||
|                 this.mapProperties.rasterLayer.setData(AvailableRasterLayers.osmCarto); | ||||
|             } | ||||
|         ); | ||||
|         const setLayerCategory = (category: EliCategory) => { | ||||
|             const available = this.availableLayers.data; | ||||
|             const current = this.mapProperties.rasterLayer; | ||||
|             const best = RasterLayerUtils.SelectBestLayerAccordingTo( | ||||
|                 available, | ||||
|                 category, | ||||
|                 current.data | ||||
|             ); | ||||
|             console.log("Best layer for category", category, "is", best.properties.id); | ||||
|             current.setData(best); | ||||
|         }; | ||||
| 
 | ||||
|         Hotkeys.RegisterHotkey( | ||||
|             { nomod: "O" }, | ||||
|             Translations.t.hotkeyDocumentation.selectOsmbasedmap, | ||||
|             () => setLayerCategory("osmbasedmap") | ||||
|         ); | ||||
| 
 | ||||
|         Hotkeys.RegisterHotkey({ nomod: "M" }, Translations.t.hotkeyDocumentation.selectMap, () => | ||||
|             setLayerCategory("map") | ||||
|         ); | ||||
| 
 | ||||
|         Hotkeys.RegisterHotkey( | ||||
|             { nomod: "P" }, | ||||
|             Translations.t.hotkeyDocumentation.selectAerial, | ||||
|             () => setLayerCategory("photo") | ||||
|         ); | ||||
|         return true | ||||
|     }) | ||||
| 
 | ||||
|     Hotkeys.RegisterHotkey( | ||||
|       { shift: "O" }, | ||||
|       Translations.t.hotkeyDocumentation.selectMapnik, | ||||
|       () => { | ||||
|         this.mapProperties.rasterLayer.setData(AvailableRasterLayers.osmCarto); | ||||
|       } | ||||
|     ); | ||||
|     const setLayerCategory = (category: EliCategory) => { | ||||
|       const available = this.availableLayers.data; | ||||
|       const current = this.mapProperties.rasterLayer; | ||||
|       const best = RasterLayerUtils.SelectBestLayerAccordingTo( | ||||
|         available, | ||||
|         category, | ||||
|         current.data | ||||
|       ); | ||||
|       console.log("Best layer for category", category, "is", best.properties.id); | ||||
|       current.setData(best); | ||||
|     }; | ||||
| 
 | ||||
|     Hotkeys.RegisterHotkey( | ||||
|       { nomod: "O" }, | ||||
|       Translations.t.hotkeyDocumentation.selectOsmbasedmap, | ||||
|       () => setLayerCategory("osmbasedmap") | ||||
|     ); | ||||
| 
 | ||||
|     Hotkeys.RegisterHotkey({ nomod: "M" }, Translations.t.hotkeyDocumentation.selectMap, () => | ||||
|       setLayerCategory("map") | ||||
|     ); | ||||
| 
 | ||||
|     Hotkeys.RegisterHotkey( | ||||
|       { nomod: "P" }, | ||||
|       Translations.t.hotkeyDocumentation.selectAerial, | ||||
|       () => setLayerCategory("photo") | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   private addLastClick(last_click: LastClickFeatureSource) { | ||||
|  |  | |||
|  | @ -1,20 +1,32 @@ | |||
| <script lang="ts"> | ||||
|   /** | ||||
|    * Thin wrapper around 'TabGroup' which binds the state | ||||
|    */ | ||||
|     /** | ||||
|      * Thin wrapper around 'TabGroup' which binds the state | ||||
|      */ | ||||
| 
 | ||||
|   import { Tab, TabGroup, TabList, TabPanel, TabPanels } from "@rgossiaux/svelte-headlessui" | ||||
|   import { UIEventSource } from "../../Logic/UIEventSource" | ||||
|   import { twJoin } from "tailwind-merge" | ||||
|     import { Tab, TabGroup, TabList, TabPanel, TabPanels } from "@rgossiaux/svelte-headlessui"; | ||||
|     import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource"; | ||||
|     import { twJoin } from "tailwind-merge"; | ||||
| 
 | ||||
|   export let tab: UIEventSource<number> | ||||
|   let tabElements: HTMLElement[] = [] | ||||
|   $: tabElements[$tab]?.click() | ||||
|   $: { | ||||
|     if (tabElements[tab.data]) { | ||||
|       window.setTimeout(() => tabElements[tab.data].click(), 50) | ||||
|     /** | ||||
|      * If a condition is given for a certain tab, it will only be shown if this condition is true. | ||||
|      * E.g. | ||||
|      * condition3 = new ImmutableStore(false) will always hide tab3 (the fourth tab) | ||||
|      */ | ||||
|     let tr = new ImmutableStore(true) | ||||
|     export let condition0: Store<boolean> = tr | ||||
|     export let condition1: Store<boolean> = tr | ||||
|     export let condition2: Store<boolean> = tr | ||||
|     export let condition3: Store<boolean> = tr | ||||
|     export let condition4: Store<boolean> = tr | ||||
|      | ||||
|     export let tab: UIEventSource<number>; | ||||
|     let tabElements: HTMLElement[] = []; | ||||
|     $: tabElements[$tab]?.click(); | ||||
|     $: { | ||||
|         if (tabElements[tab.data]) { | ||||
|             window.setTimeout(() => tabElements[tab.data].click(), 50); | ||||
|         } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
| 
 | ||||
| <div class="tabbedgroup flex h-full w-full"> | ||||
|  | @ -29,41 +41,31 @@ | |||
|   > | ||||
|     <div class="interactive sticky top-0 flex items-center justify-between"> | ||||
|       <TabList class="flex flex-wrap"> | ||||
|         {#if $$slots.title1} | ||||
|           <Tab class={({ selected }) => twJoin("tab", selected && "primary")}> | ||||
|             <div bind:this={tabElements[0]} class="flex"> | ||||
|               <slot name="title0">Tab 0</slot> | ||||
|             </div> | ||||
|           </Tab> | ||||
|         {/if} | ||||
|         {#if $$slots.title1} | ||||
|           <Tab class={({ selected }) => twJoin("tab", selected && "primary")}> | ||||
|             <div bind:this={tabElements[1]} class="flex"> | ||||
|               <slot name="title1" /> | ||||
|             </div> | ||||
|           </Tab> | ||||
|         {/if} | ||||
|         {#if $$slots.title2} | ||||
|           <Tab class={({ selected }) => twJoin("tab", selected && "primary")}> | ||||
|             <div bind:this={tabElements[2]} class="flex"> | ||||
|               <slot name="title2" /> | ||||
|             </div> | ||||
|           </Tab> | ||||
|         {/if} | ||||
|         {#if $$slots.title3} | ||||
|           <Tab class={({ selected }) => twJoin("tab", selected && "primary")}> | ||||
|             <div bind:this={tabElements[3]} class="flex"> | ||||
|               <slot name="title3" /> | ||||
|             </div> | ||||
|           </Tab> | ||||
|         {/if} | ||||
|         {#if $$slots.title4} | ||||
|           <Tab class={({ selected }) => twJoin("tab", selected && "primary")}> | ||||
|             <div bind:this={tabElements[4]} class="flex"> | ||||
|               <slot name="title4" /> | ||||
|             </div> | ||||
|           </Tab> | ||||
|         {/if} | ||||
|         <Tab class={({ selected }) => twJoin("tab", selected && "primary", !$condition0 && "hidden")}> | ||||
|           <div bind:this={tabElements[0]} class="flex"> | ||||
|             <slot name="title0">Tab 0</slot> | ||||
|           </div> | ||||
|         </Tab> | ||||
|         <Tab class={({ selected }) => twJoin("tab", selected && "primary", !$condition1 && "hidden")}> | ||||
|           <div bind:this={tabElements[1]} class="flex"> | ||||
|             <slot name="title1" /> | ||||
|           </div> | ||||
|         </Tab> | ||||
|         <Tab class={({ selected }) => twJoin("tab", selected && "primary", !$condition2 && "hidden")}> | ||||
|           <div bind:this={tabElements[2]} class="flex"> | ||||
|             <slot name="title2" /> | ||||
|           </div> | ||||
|         </Tab> | ||||
|         <Tab class={({ selected }) => twJoin("tab", selected && "primary", !$condition3 && "hidden")}> | ||||
|           <div bind:this={tabElements[3]} class="flex"> | ||||
|             <slot name="title3" /> | ||||
|           </div> | ||||
|         </Tab> | ||||
|         <Tab class={({ selected }) => twJoin("tab", selected && "primary", !$condition4 && "hidden")}> | ||||
|           <div bind:this={tabElements[4]} class="flex"> | ||||
|             <slot name="title4" /> | ||||
|           </div> | ||||
|         </Tab> | ||||
|       </TabList> | ||||
|       <slot name="post-tablist" /> | ||||
|     </div> | ||||
|  | @ -75,16 +77,24 @@ | |||
|           </slot> | ||||
|         </TabPanel> | ||||
|         <TabPanel class="tabpanel"> | ||||
|           <slot name="content1" /> | ||||
|           <slot name="content1"> | ||||
|             <div /> | ||||
|           </slot> | ||||
|         </TabPanel> | ||||
|         <TabPanel class="tabpanel"> | ||||
|           <slot name="content2" /> | ||||
|           <slot name="content2"> | ||||
|             <div /> | ||||
|           </slot> | ||||
|         </TabPanel> | ||||
|         <TabPanel class="tabpanel"> | ||||
|           <slot name="content3" /> | ||||
|           <slot name="content3"> | ||||
|             <div /> | ||||
|           </slot> | ||||
|         </TabPanel> | ||||
|         <TabPanel class="tabpanel"> | ||||
|           <slot name="content4" /> | ||||
|           <slot name="content4"> | ||||
|             <div /> | ||||
|           </slot> | ||||
|         </TabPanel> | ||||
|       </TabPanels> | ||||
|     </div> | ||||
|  | @ -92,44 +102,44 @@ | |||
| </div> | ||||
| 
 | ||||
| <style> | ||||
|   .tabbedgroup { | ||||
|     max-height: 100vh; | ||||
|     height: 100%; | ||||
|   } | ||||
|     .tabbedgroup { | ||||
|         max-height: 100vh; | ||||
|         height: 100%; | ||||
|     } | ||||
| 
 | ||||
|   :global(.tabpanel) { | ||||
|     height: 100%; | ||||
|   } | ||||
|     :global(.tabpanel) { | ||||
|         height: 100%; | ||||
|     } | ||||
| 
 | ||||
|   :global(.tabpanels) { | ||||
|     height: calc(100% - 2rem); | ||||
|   } | ||||
|     :global(.tabpanels) { | ||||
|         height: calc(100% - 2rem); | ||||
|     } | ||||
| 
 | ||||
|   :global(.tab) { | ||||
|     margin: 0.25rem; | ||||
|     padding: 0.25rem; | ||||
|     padding-left: 0.75rem; | ||||
|     padding-right: 0.75rem; | ||||
|     border-radius: 1rem; | ||||
|   } | ||||
|     :global(.tab) { | ||||
|         margin: 0.25rem; | ||||
|         padding: 0.25rem; | ||||
|         padding-left: 0.75rem; | ||||
|         padding-right: 0.75rem; | ||||
|         border-radius: 1rem; | ||||
|     } | ||||
| 
 | ||||
|   :global(.tab .flex) { | ||||
|     align-items: center; | ||||
|     gap: 0.25rem; | ||||
|   } | ||||
|     :global(.tab .flex) { | ||||
|         align-items: center; | ||||
|         gap: 0.25rem; | ||||
|     } | ||||
| 
 | ||||
|   :global(.tab span|div) { | ||||
|     align-items: center; | ||||
|     gap: 0.25rem; | ||||
|     display: flex; | ||||
|   } | ||||
|     :global(.tab span|div) { | ||||
|         align-items: center; | ||||
|         gap: 0.25rem; | ||||
|         display: flex; | ||||
|     } | ||||
| 
 | ||||
|   :global(.tab-selected svg) { | ||||
|     fill: var(--catch-detail-color-contrast); | ||||
|   } | ||||
|     :global(.tab-selected svg) { | ||||
|         fill: var(--catch-detail-color-contrast); | ||||
|     } | ||||
| 
 | ||||
|   :global(.tab-unselected) { | ||||
|     background-color: var(--background-color) !important; | ||||
|     color: var(--foreground-color) !important; | ||||
|   } | ||||
|     :global(.tab-unselected) { | ||||
|         background-color: var(--background-color) !important; | ||||
|         color: var(--foreground-color) !important; | ||||
|     } | ||||
| </style> | ||||
|  |  | |||
|  | @ -1,47 +1,48 @@ | |||
| <script lang="ts"> | ||||
|   import Translations from "../i18n/Translations" | ||||
|   import Svg from "../../Svg" | ||||
|   import Tr from "../Base/Tr.svelte" | ||||
|   import NextButton from "../Base/NextButton.svelte" | ||||
|   import Geosearch from "./Geosearch.svelte" | ||||
|   import ToSvelte from "../Base/ToSvelte.svelte" | ||||
|   import ThemeViewState from "../../Models/ThemeViewState" | ||||
|   import { Store, UIEventSource } from "../../Logic/UIEventSource" | ||||
|   import { SearchIcon } from "@rgossiaux/svelte-heroicons/solid" | ||||
|   import { twJoin } from "tailwind-merge" | ||||
|   import { Utils } from "../../Utils" | ||||
|   import type { GeolocationPermissionState } from "../../Logic/State/GeoLocationState" | ||||
|     import Translations from "../i18n/Translations"; | ||||
|     import Svg from "../../Svg"; | ||||
|     import Tr from "../Base/Tr.svelte"; | ||||
|     import NextButton from "../Base/NextButton.svelte"; | ||||
|     import Geosearch from "./Geosearch.svelte"; | ||||
|     import ToSvelte from "../Base/ToSvelte.svelte"; | ||||
|     import ThemeViewState from "../../Models/ThemeViewState"; | ||||
|     import { Store, UIEventSource } from "../../Logic/UIEventSource"; | ||||
|     import { SearchIcon } from "@rgossiaux/svelte-heroicons/solid"; | ||||
|     import { twJoin } from "tailwind-merge"; | ||||
|     import { Utils } from "../../Utils"; | ||||
|     import type { GeolocationPermissionState } from "../../Logic/State/GeoLocationState"; | ||||
|     import If from "../Base/If.svelte"; | ||||
| 
 | ||||
|   /** | ||||
|    * The theme introduction panel | ||||
|    */ | ||||
|   export let state: ThemeViewState | ||||
|   let layout = state.layout | ||||
|   let selectedElement = state.selectedElement | ||||
|   let selectedLayer = state.selectedLayer | ||||
|     /** | ||||
|      * The theme introduction panel | ||||
|      */ | ||||
|     export let state: ThemeViewState; | ||||
|     let layout = state.layout; | ||||
|     let selectedElement = state.selectedElement; | ||||
|     let selectedLayer = state.selectedLayer; | ||||
| 
 | ||||
|   let triggerSearch: UIEventSource<any> = new UIEventSource<any>(undefined) | ||||
|   let searchEnabled = false | ||||
|     let triggerSearch: UIEventSource<any> = new UIEventSource<any>(undefined); | ||||
|     let searchEnabled = false; | ||||
| 
 | ||||
|   let geopermission: Store<GeolocationPermissionState> = | ||||
|     state.geolocation.geolocationState.permission | ||||
|   let currentGPSLocation = state.geolocation.geolocationState.currentGPSLocation | ||||
|     let geopermission: Store<GeolocationPermissionState> = | ||||
|         state.geolocation.geolocationState.permission; | ||||
|     let currentGPSLocation = state.geolocation.geolocationState.currentGPSLocation; | ||||
| 
 | ||||
|   geopermission.addCallback((perm) => console.log(">>>> Permission", perm)) | ||||
|     geopermission.addCallback((perm) => console.log(">>>> Permission", perm)); | ||||
| 
 | ||||
|   function jumpToCurrentLocation() { | ||||
|     const glstate = state.geolocation.geolocationState | ||||
|     if (glstate.currentGPSLocation.data !== undefined) { | ||||
|       const c: GeolocationCoordinates = glstate.currentGPSLocation.data | ||||
|       state.guistate.themeIsOpened.setData(false) | ||||
|       const coor = { lon: c.longitude, lat: c.latitude } | ||||
|       state.mapProperties.location.setData(coor) | ||||
|     function jumpToCurrentLocation() { | ||||
|         const glstate = state.geolocation.geolocationState; | ||||
|         if (glstate.currentGPSLocation.data !== undefined) { | ||||
|             const c: GeolocationCoordinates = glstate.currentGPSLocation.data; | ||||
|             state.guistate.themeIsOpened.setData(false); | ||||
|             const coor = { lon: c.longitude, lat: c.latitude }; | ||||
|             state.mapProperties.location.setData(coor); | ||||
|         } | ||||
|         if (glstate.permission.data !== "granted") { | ||||
|             glstate.requestPermission(); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|     if (glstate.permission.data !== "granted") { | ||||
|       glstate.requestPermission() | ||||
|       return | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
| 
 | ||||
| <div class="flex h-full flex-col justify-between"> | ||||
|  | @ -62,61 +63,67 @@ | |||
|       </div> | ||||
|     </NextButton> | ||||
| 
 | ||||
|     <div class="flex w-full flex-wrap sm:flex-nowrap"> | ||||
|       {#if $currentGPSLocation !== undefined || $geopermission === "prompt"} | ||||
|         <button class="flex w-full items-center gap-x-2" on:click={jumpToCurrentLocation}> | ||||
|           <ToSvelte construct={Svg.crosshair_svg().SetClass("w-8 h-8")} /> | ||||
|           <Tr t={Translations.t.general.openTheMapAtGeolocation} /> | ||||
|         </button> | ||||
|         <!-- No geolocation granted - we don't show the button --> | ||||
|       {:else if $geopermission === "requested"} | ||||
|         <button class="disabled flex w-full items-center gap-x-2" on:click={jumpToCurrentLocation}> | ||||
|           <!-- Even though disabled, when clicking we request the location again in case the contributor dismissed the location popup --> | ||||
|           <ToSvelte | ||||
|             construct={Svg.crosshair_svg() | ||||
|               .SetClass("w-8 h-8") | ||||
|               .SetStyle("animation: 3s linear 0s infinite normal none running spin;")} | ||||
|           /> | ||||
|           <Tr t={Translations.t.general.waitingForGeopermission} /> | ||||
|         </button> | ||||
|       {:else if $geopermission === "denied"} | ||||
|         <button class="disabled flex w-full items-center gap-x-2"> | ||||
|           <ToSvelte construct={Svg.location_refused_svg().SetClass("w-8 h-8")} /> | ||||
|           <Tr t={Translations.t.general.geopermissionDenied} /> | ||||
|         </button> | ||||
|       {:else} | ||||
|         <button class="disabled flex w-full items-center gap-x-2"> | ||||
|           <ToSvelte | ||||
|             construct={Svg.crosshair_svg() | ||||
|               .SetClass("w-8 h-8") | ||||
|               .SetStyle("animation: 3s linear 0s infinite normal none running spin;")} | ||||
|           /> | ||||
|           <Tr t={Translations.t.general.waitingForLocation} /> | ||||
|         </button> | ||||
|       {/if} | ||||
| 
 | ||||
|       <div class=".button low-interaction m-1 flex w-full items-center gap-x-2 rounded border p-2"> | ||||
|         <div class="w-full"> | ||||
|           <Geosearch | ||||
|             bounds={state.mapProperties.bounds} | ||||
|             on:searchCompleted={() => state.guistate.themeIsOpened.setData(false)} | ||||
|             on:searchIsValid={(isValid) => { | ||||
|     <div class="flex w-full flex-wrap sm:flex-nowrap"> | ||||
|       <If condition={state.featureSwitches.featureSwitchGeolocation}> | ||||
|         {#if $currentGPSLocation !== undefined || $geopermission === "prompt"} | ||||
|           <button class="flex w-full items-center gap-x-2" on:click={jumpToCurrentLocation}> | ||||
|             <ToSvelte construct={Svg.crosshair_svg().SetClass("w-8 h-8")} /> | ||||
|             <Tr t={Translations.t.general.openTheMapAtGeolocation} /> | ||||
|           </button> | ||||
|           <!-- No geolocation granted - we don't show the button --> | ||||
|         {:else if $geopermission === "requested"} | ||||
|           <button class="disabled flex w-full items-center gap-x-2" on:click={jumpToCurrentLocation}> | ||||
|             <!-- Even though disabled, when clicking we request the location again in case the contributor dismissed the location popup --> | ||||
|             <ToSvelte | ||||
|               construct={Svg.crosshair_svg() | ||||
|               .SetClass("w-8 h-8") | ||||
|               .SetStyle("animation: 3s linear 0s infinite normal none running spin;")} | ||||
|             /> | ||||
|             <Tr t={Translations.t.general.waitingForGeopermission} /> | ||||
|           </button> | ||||
|         {:else if $geopermission === "denied"} | ||||
|           <button class="disabled flex w-full items-center gap-x-2"> | ||||
|             <ToSvelte construct={Svg.location_refused_svg().SetClass("w-8 h-8")} /> | ||||
|             <Tr t={Translations.t.general.geopermissionDenied} /> | ||||
|           </button> | ||||
|         {:else} | ||||
|           <button class="disabled flex w-full items-center gap-x-2"> | ||||
|             <ToSvelte | ||||
|               construct={Svg.crosshair_svg() | ||||
|               .SetClass("w-8 h-8") | ||||
|               .SetStyle("animation: 3s linear 0s infinite normal none running spin;")} | ||||
|             /> | ||||
|             <Tr t={Translations.t.general.waitingForLocation} /> | ||||
|           </button> | ||||
|         {/if} | ||||
|       </If> | ||||
| 
 | ||||
| 
 | ||||
|       <If condition={state.featureSwitches.featureSwitchSearch}> | ||||
|         <div class=".button low-interaction m-1 flex w-full items-center gap-x-2 rounded border p-2"> | ||||
|           <div class="w-full"> | ||||
|             <Geosearch | ||||
|               bounds={state.mapProperties.bounds} | ||||
|               on:searchCompleted={() => state.guistate.themeIsOpened.setData(false)} | ||||
|               on:searchIsValid={(isValid) => { | ||||
|               searchEnabled = isValid | ||||
|             }} | ||||
|             perLayer={state.perLayer} | ||||
|             {selectedElement} | ||||
|             {selectedLayer} | ||||
|             {triggerSearch} | ||||
|           /> | ||||
|               perLayer={state.perLayer} | ||||
|               {selectedElement} | ||||
|               {selectedLayer} | ||||
|               {triggerSearch} | ||||
|             /> | ||||
|           </div> | ||||
|           <button | ||||
|             class={twJoin("flex items-center justify-between gap-x-2", !searchEnabled && "disabled")} | ||||
|             on:click={() => triggerSearch.ping()} | ||||
|           > | ||||
|             <Tr t={Translations.t.general.search.searchShort} /> | ||||
|             <SearchIcon class="h-6 w-6" /> | ||||
|           </button> | ||||
|         </div> | ||||
|         <button | ||||
|           class={twJoin("flex items-center justify-between gap-x-2", !searchEnabled && "disabled")} | ||||
|           on:click={() => triggerSearch.ping()} | ||||
|         > | ||||
|           <Tr t={Translations.t.general.search.searchShort} /> | ||||
|           <SearchIcon class="h-6 w-6" /> | ||||
|         </button> | ||||
|       </div> | ||||
|       </If> | ||||
|     </div> | ||||
|   </div> | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,114 +1,114 @@ | |||
| <script lang="ts"> | ||||
|   import { Store, UIEventSource } from "../Logic/UIEventSource"; | ||||
|   import { Map as MlMap } from "maplibre-gl"; | ||||
|   import MaplibreMap from "./Map/MaplibreMap.svelte"; | ||||
|   import FeatureSwitchState from "../Logic/State/FeatureSwitchState"; | ||||
|   import MapControlButton from "./Base/MapControlButton.svelte"; | ||||
|   import ToSvelte from "./Base/ToSvelte.svelte"; | ||||
|   import If from "./Base/If.svelte"; | ||||
|   import { GeolocationControl } from "./BigComponents/GeolocationControl"; | ||||
|   import type { Feature } from "geojson"; | ||||
|   import SelectedElementView from "./BigComponents/SelectedElementView.svelte"; | ||||
|   import LayerConfig from "../Models/ThemeConfig/LayerConfig"; | ||||
|   import Filterview from "./BigComponents/Filterview.svelte"; | ||||
|   import ThemeViewState from "../Models/ThemeViewState"; | ||||
|   import type { MapProperties } from "../Models/MapProperties"; | ||||
|   import Geosearch from "./BigComponents/Geosearch.svelte"; | ||||
|   import Translations from "./i18n/Translations"; | ||||
|   import { CogIcon, EyeIcon, MenuIcon, XCircleIcon } from "@rgossiaux/svelte-heroicons/solid"; | ||||
|     import { Store, UIEventSource } from "../Logic/UIEventSource"; | ||||
|     import { Map as MlMap } from "maplibre-gl"; | ||||
|     import MaplibreMap from "./Map/MaplibreMap.svelte"; | ||||
|     import FeatureSwitchState from "../Logic/State/FeatureSwitchState"; | ||||
|     import MapControlButton from "./Base/MapControlButton.svelte"; | ||||
|     import ToSvelte from "./Base/ToSvelte.svelte"; | ||||
|     import If from "./Base/If.svelte"; | ||||
|     import { GeolocationControl } from "./BigComponents/GeolocationControl"; | ||||
|     import type { Feature } from "geojson"; | ||||
|     import SelectedElementView from "./BigComponents/SelectedElementView.svelte"; | ||||
|     import LayerConfig from "../Models/ThemeConfig/LayerConfig"; | ||||
|     import Filterview from "./BigComponents/Filterview.svelte"; | ||||
|     import ThemeViewState from "../Models/ThemeViewState"; | ||||
|     import type { MapProperties } from "../Models/MapProperties"; | ||||
|     import Geosearch from "./BigComponents/Geosearch.svelte"; | ||||
|     import Translations from "./i18n/Translations"; | ||||
|     import { CogIcon, EyeIcon, MenuIcon, XCircleIcon } from "@rgossiaux/svelte-heroicons/solid"; | ||||
| 
 | ||||
|   import Tr from "./Base/Tr.svelte"; | ||||
|   import CommunityIndexView from "./BigComponents/CommunityIndexView.svelte"; | ||||
|   import FloatOver from "./Base/FloatOver.svelte"; | ||||
|   import PrivacyPolicy from "./BigComponents/PrivacyPolicy"; | ||||
|   import Constants from "../Models/Constants"; | ||||
|   import TabbedGroup from "./Base/TabbedGroup.svelte"; | ||||
|   import UserRelatedState from "../Logic/State/UserRelatedState"; | ||||
|   import LoginToggle from "./Base/LoginToggle.svelte"; | ||||
|   import LoginButton from "./Base/LoginButton.svelte"; | ||||
|   import CopyrightPanel from "./BigComponents/CopyrightPanel"; | ||||
|   import DownloadPanel from "./DownloadFlow/DownloadPanel.svelte"; | ||||
|   import ModalRight from "./Base/ModalRight.svelte"; | ||||
|   import { Utils } from "../Utils"; | ||||
|   import Hotkeys from "./Base/Hotkeys"; | ||||
|   import { VariableUiElement } from "./Base/VariableUIElement"; | ||||
|   import SvelteUIElement from "./Base/SvelteUIElement"; | ||||
|   import OverlayToggle from "./BigComponents/OverlayToggle.svelte"; | ||||
|   import LevelSelector from "./BigComponents/LevelSelector.svelte"; | ||||
|   import ExtraLinkButton from "./BigComponents/ExtraLinkButton"; | ||||
|   import SelectedElementTitle from "./BigComponents/SelectedElementTitle.svelte"; | ||||
|   import Svg from "../Svg"; | ||||
|   import ThemeIntroPanel from "./BigComponents/ThemeIntroPanel.svelte"; | ||||
|   import type { RasterLayerPolygon } from "../Models/RasterLayers"; | ||||
|   import { AvailableRasterLayers } from "../Models/RasterLayers"; | ||||
|   import RasterLayerOverview from "./Map/RasterLayerOverview.svelte"; | ||||
|   import IfHidden from "./Base/IfHidden.svelte"; | ||||
|   import { onDestroy } from "svelte"; | ||||
|   import { OpenJosm } from "./BigComponents/OpenJosm"; | ||||
|   import MapillaryLink from "./BigComponents/MapillaryLink.svelte"; | ||||
|   import OpenIdEditor from "./BigComponents/OpenIdEditor.svelte"; | ||||
|   import OpenBackgroundSelectorButton from "./BigComponents/OpenBackgroundSelectorButton.svelte"; | ||||
|   import StateIndicator from "./BigComponents/StateIndicator.svelte"; | ||||
|   import LanguagePicker from "./LanguagePicker"; | ||||
|   import Locale from "./i18n/Locale"; | ||||
|   import ShareScreen from "./BigComponents/ShareScreen.svelte"; | ||||
|     import Tr from "./Base/Tr.svelte"; | ||||
|     import CommunityIndexView from "./BigComponents/CommunityIndexView.svelte"; | ||||
|     import FloatOver from "./Base/FloatOver.svelte"; | ||||
|     import PrivacyPolicy from "./BigComponents/PrivacyPolicy"; | ||||
|     import Constants from "../Models/Constants"; | ||||
|     import TabbedGroup from "./Base/TabbedGroup.svelte"; | ||||
|     import UserRelatedState from "../Logic/State/UserRelatedState"; | ||||
|     import LoginToggle from "./Base/LoginToggle.svelte"; | ||||
|     import LoginButton from "./Base/LoginButton.svelte"; | ||||
|     import CopyrightPanel from "./BigComponents/CopyrightPanel"; | ||||
|     import DownloadPanel from "./DownloadFlow/DownloadPanel.svelte"; | ||||
|     import ModalRight from "./Base/ModalRight.svelte"; | ||||
|     import { Utils } from "../Utils"; | ||||
|     import Hotkeys from "./Base/Hotkeys"; | ||||
|     import { VariableUiElement } from "./Base/VariableUIElement"; | ||||
|     import SvelteUIElement from "./Base/SvelteUIElement"; | ||||
|     import OverlayToggle from "./BigComponents/OverlayToggle.svelte"; | ||||
|     import LevelSelector from "./BigComponents/LevelSelector.svelte"; | ||||
|     import ExtraLinkButton from "./BigComponents/ExtraLinkButton"; | ||||
|     import SelectedElementTitle from "./BigComponents/SelectedElementTitle.svelte"; | ||||
|     import Svg from "../Svg"; | ||||
|     import ThemeIntroPanel from "./BigComponents/ThemeIntroPanel.svelte"; | ||||
|     import type { RasterLayerPolygon } from "../Models/RasterLayers"; | ||||
|     import { AvailableRasterLayers } from "../Models/RasterLayers"; | ||||
|     import RasterLayerOverview from "./Map/RasterLayerOverview.svelte"; | ||||
|     import IfHidden from "./Base/IfHidden.svelte"; | ||||
|     import { onDestroy } from "svelte"; | ||||
|     import { OpenJosm } from "./BigComponents/OpenJosm"; | ||||
|     import MapillaryLink from "./BigComponents/MapillaryLink.svelte"; | ||||
|     import OpenIdEditor from "./BigComponents/OpenIdEditor.svelte"; | ||||
|     import OpenBackgroundSelectorButton from "./BigComponents/OpenBackgroundSelectorButton.svelte"; | ||||
|     import StateIndicator from "./BigComponents/StateIndicator.svelte"; | ||||
|     import LanguagePicker from "./LanguagePicker"; | ||||
|     import Locale from "./i18n/Locale"; | ||||
|     import ShareScreen from "./BigComponents/ShareScreen.svelte"; | ||||
| 
 | ||||
|   export let state: ThemeViewState; | ||||
|   let layout = state.layout; | ||||
|     export let state: ThemeViewState; | ||||
|     let layout = state.layout; | ||||
| 
 | ||||
|   let maplibremap: UIEventSource<MlMap> = state.map; | ||||
|   let selectedElement: UIEventSource<Feature> = state.selectedElement; | ||||
|   let selectedLayer: UIEventSource<LayerConfig> = state.selectedLayer; | ||||
|     let maplibremap: UIEventSource<MlMap> = state.map; | ||||
|     let selectedElement: UIEventSource<Feature> = state.selectedElement; | ||||
|     let selectedLayer: UIEventSource<LayerConfig> = state.selectedLayer; | ||||
| 
 | ||||
|   const selectedElementView = selectedElement.map( | ||||
|     (selectedElement) => { | ||||
|       // Svelte doesn't properly reload some of the legacy UI-elements | ||||
|       // As such, we _reconstruct_ the selectedElementView every time a new feature is selected | ||||
|       // This is a bit wasteful, but until everything is a svelte-component, this should do the trick | ||||
|       const layer = selectedLayer.data; | ||||
|       if (selectedElement === undefined || layer === undefined) { | ||||
|         return undefined; | ||||
|       } | ||||
|     const selectedElementView = selectedElement.map( | ||||
|         (selectedElement) => { | ||||
|             // Svelte doesn't properly reload some of the legacy UI-elements | ||||
|             // As such, we _reconstruct_ the selectedElementView every time a new feature is selected | ||||
|             // This is a bit wasteful, but until everything is a svelte-component, this should do the trick | ||||
|             const layer = selectedLayer.data; | ||||
|             if (selectedElement === undefined || layer === undefined) { | ||||
|                 return undefined; | ||||
|             } | ||||
| 
 | ||||
|       if (!(layer.tagRenderings?.length > 0) || layer.title === undefined) { | ||||
|         return undefined; | ||||
|       } | ||||
|             if (!(layer.tagRenderings?.length > 0) || layer.title === undefined) { | ||||
|                 return undefined; | ||||
|             } | ||||
| 
 | ||||
|       const tags = state.featureProperties.getStore(selectedElement.properties.id); | ||||
|       return new SvelteUIElement(SelectedElementView, { state, layer, selectedElement, tags }); | ||||
|     }, | ||||
|     [selectedLayer] | ||||
|   ); | ||||
|             const tags = state.featureProperties.getStore(selectedElement.properties.id); | ||||
|             return new SvelteUIElement(SelectedElementView, { state, layer, selectedElement, tags }); | ||||
|         }, | ||||
|         [selectedLayer] | ||||
|     ); | ||||
| 
 | ||||
|   const selectedElementTitle = selectedElement.map( | ||||
|     (selectedElement) => { | ||||
|       // Svelte doesn't properly reload some of the legacy UI-elements | ||||
|       // As such, we _reconstruct_ the selectedElementView every time a new feature is selected | ||||
|       // This is a bit wasteful, but until everything is a svelte-component, this should do the trick | ||||
|       const layer = selectedLayer.data; | ||||
|       if (selectedElement === undefined || layer === undefined) { | ||||
|         return undefined; | ||||
|       } | ||||
|     const selectedElementTitle = selectedElement.map( | ||||
|         (selectedElement) => { | ||||
|             // Svelte doesn't properly reload some of the legacy UI-elements | ||||
|             // As such, we _reconstruct_ the selectedElementView every time a new feature is selected | ||||
|             // This is a bit wasteful, but until everything is a svelte-component, this should do the trick | ||||
|             const layer = selectedLayer.data; | ||||
|             if (selectedElement === undefined || layer === undefined) { | ||||
|                 return undefined; | ||||
|             } | ||||
| 
 | ||||
|       const tags = state.featureProperties.getStore(selectedElement.properties.id); | ||||
|       return new SvelteUIElement(SelectedElementTitle, { state, layer, selectedElement, tags }); | ||||
|     }, | ||||
|     [selectedLayer] | ||||
|   ); | ||||
|             const tags = state.featureProperties.getStore(selectedElement.properties.id); | ||||
|             return new SvelteUIElement(SelectedElementTitle, { state, layer, selectedElement, tags }); | ||||
|         }, | ||||
|         [selectedLayer] | ||||
|     ); | ||||
| 
 | ||||
|   let mapproperties: MapProperties = state.mapProperties; | ||||
|   let featureSwitches: FeatureSwitchState = state.featureSwitches; | ||||
|   let availableLayers = state.availableLayers; | ||||
|   let userdetails = state.osmConnection.userDetails; | ||||
|   let currentViewLayer = layout.layers.find((l) => l.id === "current_view"); | ||||
|   let rasterLayer: Store<RasterLayerPolygon> = state.mapProperties.rasterLayer; | ||||
|   let rasterLayerName = | ||||
|     rasterLayer.data?.properties?.name ?? AvailableRasterLayers.maptilerDefaultLayer.properties.name; | ||||
|   onDestroy( | ||||
|     rasterLayer.addCallbackAndRunD((l) => { | ||||
|       rasterLayerName = l.properties.name; | ||||
|     }) | ||||
|   ); | ||||
|     let mapproperties: MapProperties = state.mapProperties; | ||||
|     let featureSwitches: FeatureSwitchState = state.featureSwitches; | ||||
|     let availableLayers = state.availableLayers; | ||||
|     let userdetails = state.osmConnection.userDetails; | ||||
|     let currentViewLayer = layout.layers.find((l) => l.id === "current_view"); | ||||
|     let rasterLayer: Store<RasterLayerPolygon> = state.mapProperties.rasterLayer; | ||||
|     let rasterLayerName = | ||||
|         rasterLayer.data?.properties?.name ?? AvailableRasterLayers.maptilerDefaultLayer.properties.name; | ||||
|     onDestroy( | ||||
|         rasterLayer.addCallbackAndRunD((l) => { | ||||
|             rasterLayerName = l.properties.name; | ||||
|         }) | ||||
|     ); | ||||
| </script> | ||||
| 
 | ||||
| <div class="absolute top-0 left-0 h-screen w-screen overflow-hidden"> | ||||
|  | @ -169,19 +169,28 @@ | |||
|   <!-- bottom controls --> | ||||
|   <div class="flex w-full items-end justify-between px-4"> | ||||
|     <div class="flex flex-col"> | ||||
|       <span> | ||||
|       <button class="w-fit pointer-events-auto" on:click={() => {state.openNewDialog()}}> | ||||
|         <Tr t={Translations.t.general.add.title}/> | ||||
|       </button> | ||||
|       </span> | ||||
|        | ||||
|       <If condition={featureSwitches.featureSwitchEnableLogin}> | ||||
|         {#if state.lastClickObject.hasPresets || state.lastClickObject.hasNoteLayer} | ||||
|           <button class="w-fit pointer-events-auto" on:click={() => {state.openNewDialog()}}> | ||||
|             {#if state.lastClickObject.hasPresets} | ||||
|               <Tr t={Translations.t.general.add.title} /> | ||||
|             {:else} | ||||
|               <Tr t={Translations.t.notes.addAComment} /> | ||||
|             {/if} | ||||
|           </button> | ||||
|         {/if} | ||||
|       </If> | ||||
| 
 | ||||
|       <div class="flex"> | ||||
|         <!-- bottom left elements --> | ||||
|         <MapControlButton on:click={() => state.guistate.openFilterView()}> | ||||
|           <ToSvelte construct={Svg.filter_svg().SetClass("h-6 w-6")} /> | ||||
|         </MapControlButton> | ||||
| 
 | ||||
|         <OpenBackgroundSelectorButton hideTooltip={true} {state} /> | ||||
|         <If condition={state.featureSwitches.featureSwitchFilter}> | ||||
|           <MapControlButton on:click={() => state.guistate.openFilterView()}> | ||||
|             <ToSvelte construct={Svg.filter_svg().SetClass("h-6 w-6")} /> | ||||
|           </MapControlButton> | ||||
|         </If> | ||||
|         <If condition={state.featureSwitches.featureSwitchBackgroundSelection}> | ||||
|           <OpenBackgroundSelectorButton hideTooltip={true} {state} /> | ||||
|         </If> | ||||
|         <a | ||||
|           class="bg-black-transparent pointer-events-auto h-fit max-h-12 cursor-pointer self-end overflow-hidden rounded-2xl pl-1 pr-2 text-white opacity-50 hover:opacity-100" | ||||
|           on:click={() => { | ||||
|  | @ -267,9 +276,9 @@ | |||
| 
 | ||||
| <If condition={state.guistate.themeIsOpened}> | ||||
|   <!-- Theme menu --> | ||||
|   <FloatOver   on:close={() => state.guistate.themeIsOpened.setData(false)}> | ||||
|   <FloatOver on:close={() => state.guistate.themeIsOpened.setData(false)}> | ||||
|     <span slot="close-button"><!-- Disable the close button --></span> | ||||
|     <TabbedGroup tab={state.guistate.themeViewTabIndex}> | ||||
|     <TabbedGroup condition1={state.featureSwitches.featureSwitchFilter} tab={state.guistate.themeViewTabIndex}> | ||||
|       <div slot="post-tablist"> | ||||
|         <XCircleIcon | ||||
|           class="mr-2 h-8 w-8" | ||||
|  | @ -287,10 +296,8 @@ | |||
|       </div> | ||||
| 
 | ||||
|       <div class="flex" slot="title1"> | ||||
|         <If condition={state.featureSwitches.featureSwitchFilter}> | ||||
|           <ToSvelte construct={Svg.filter_svg().SetClass("w-4 h-4")} /> | ||||
|           <Tr t={Translations.t.general.menu.filter} /> | ||||
|         </If> | ||||
|         <ToSvelte construct={Svg.filter_svg().SetClass("w-4 h-4")} /> | ||||
|         <Tr t={Translations.t.general.menu.filter} /> | ||||
|       </div> | ||||
| 
 | ||||
|       <div class="m-2 flex flex-col" slot="content1"> | ||||
|  | @ -310,6 +317,7 @@ | |||
|           /> | ||||
|         {/each} | ||||
|       </div> | ||||
| 
 | ||||
|       <div class="flex" slot="title2"> | ||||
|         <If condition={state.featureSwitches.featureSwitchEnableExport}> | ||||
|           <ToSvelte construct={Svg.download_svg().SetClass("w-4 h-4")} /> | ||||
|  | @ -356,7 +364,8 @@ | |||
|   <!-- Menu page --> | ||||
|   <FloatOver on:close={() =>      state.guistate.menuIsOpened.setData(false)    }> | ||||
|     <span slot="close-button"><!-- Hide the default close button --></span> | ||||
|     <TabbedGroup tab={state.guistate.menuViewTabIndex}> | ||||
|     <TabbedGroup condition1={featureSwitches.featureSwitchEnableLogin} condition2={state.featureSwitches. featureSwitchCommunityIndex} | ||||
|                  tab={state.guistate.menuViewTabIndex}> | ||||
|       <div slot="post-tablist"> | ||||
|         <XCircleIcon | ||||
|           class="mr-2 h-8 w-8" | ||||
|  | @ -431,7 +440,6 @@ | |||
|       <div class="m-2" slot="content2"> | ||||
|         <CommunityIndexView location={state.mapProperties.location} /> | ||||
|       </div> | ||||
| 
 | ||||
|       <div class="flex" slot="title3"> | ||||
|         <EyeIcon class="w-6" /> | ||||
|         <Tr t={Translations.t.privacy.title} /> | ||||
|  | @ -442,12 +450,15 @@ | |||
| 
 | ||||
|       <Tr slot="title4" t={Translations.t.advanced.title} /> | ||||
|       <div class="m-2 flex flex-col" slot="content4"> | ||||
|         <OpenIdEditor mapProperties={state.mapProperties} /> | ||||
|         <ToSvelte | ||||
|           construct={() => | ||||
|         <If condition={featureSwitches.featureSwitchEnableLogin}> | ||||
|           <OpenIdEditor mapProperties={state.mapProperties} /> | ||||
|           <ToSvelte | ||||
|             construct={() => | ||||
|             new OpenJosm(state.osmConnection, state.mapProperties.bounds).SetClass("w-full")} | ||||
|         /> | ||||
|         <MapillaryLink mapProperties={state.mapProperties} /> | ||||
|           /> | ||||
|           <MapillaryLink mapProperties={state.mapProperties} /> | ||||
|         </If> | ||||
| 
 | ||||
|         <ToSvelte construct={Hotkeys.generateDocumentationDynamic} /> | ||||
|       </div> | ||||
|     </TabbedGroup> | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue