forked from MapComplete/MapComplete
		
	UX: map in 'add new point' now takes the full screen
This commit is contained in:
		
							parent
							
								
									5c692fb11a
								
							
						
					
					
						commit
						4219b23af1
					
				
					 8 changed files with 281 additions and 266 deletions
				
			
		|  | @ -21,3 +21,5 @@ The participant has extensive OpenStreetMap-knowledge but only used MapComplete | ||||||
| - [x] This user had an expression with two tags in an AND. There was some confusion if the taginfo-count gave the totals for the tags individually or for the entire expression. | - [x] This user had an expression with two tags in an AND. There was some confusion if the taginfo-count gave the totals for the tags individually or for the entire expression. | ||||||
|         Fix: play with padding and wording |         Fix: play with padding and wording | ||||||
| - [x] BUG: having a complex expression for tags (e.g. with `and: [key=value, key0=value0]`) fails as the JSON would be stringified | - [x] BUG: having a complex expression for tags (e.g. with `and: [key=value, key0=value0]`) fails as the JSON would be stringified | ||||||
|  | - [x] In MapComplete (not in studio): creating a new point: the buttons might dissapear under scroll if zoomed in a lot | ||||||
|  | - [x] If a layer does not have a title and a tagRenderings, it is not interpreted as 'standalone' theme | ||||||
|  |  | ||||||
|  | @ -156,6 +156,7 @@ | ||||||
|   "tagRenderings": [ |   "tagRenderings": [ | ||||||
|     { |     { | ||||||
|       "id": "add_new", |       "id": "add_new", | ||||||
|  |       "classes": "h-full flex", | ||||||
|       "condition": "has_presets=yes", |       "condition": "has_presets=yes", | ||||||
|       "render": { |       "render": { | ||||||
|         "*": "{add_new_point()}" |         "*": "{add_new_point()}" | ||||||
|  |  | ||||||
|  | @ -483,6 +483,9 @@ export class AddQuestionBox extends DesugaringStep<LayerConfigJson> { | ||||||
|         ) { |         ) { | ||||||
|             return json |             return json | ||||||
|         } |         } | ||||||
|  |         if (json.source === "special") { | ||||||
|  |             return json | ||||||
|  |         } | ||||||
|         json = { ...json } |         json = { ...json } | ||||||
|         json.tagRenderings = [...json.tagRenderings] |         json.tagRenderings = [...json.tagRenderings] | ||||||
|         const allSpecials: Exclude<RenderingSpecification, string>[] = <any>( |         const allSpecials: Exclude<RenderingSpecification, string>[] = <any>( | ||||||
|  |  | ||||||
|  | @ -28,10 +28,11 @@ | ||||||
|     <Tr t={Translations.t.general.returnToTheMap} /> |     <Tr t={Translations.t.general.returnToTheMap} /> | ||||||
|   </button> |   </button> | ||||||
| {:else} | {:else} | ||||||
|   <div class="flex flex-col gap-y-2 overflow-y-auto p-1 px-2"> |   <div class="flex flex-col gap-y-2 overflow-y-auto p-1 px-2 h-full"> | ||||||
|     {#each layer.tagRenderings as config (config.id)} |     {#each layer.tagRenderings as config (config.id)} | ||||||
|       {#if (config.condition?.matchesProperties($tags) ?? true) && config.metacondition?.matchesProperties({ ...$tags, ..._metatags } ?? true)} |       {#if (config.condition?.matchesProperties($tags) ?? true) && config.metacondition?.matchesProperties({ ...$tags, ..._metatags } ?? true)} | ||||||
|         {#if config.IsKnown($tags)} |         {#if config.IsKnown($tags)} | ||||||
|  |           {config.id} | ||||||
|           <TagRenderingEditable |           <TagRenderingEditable | ||||||
|             {tags} |             {tags} | ||||||
|             {config} |             {config} | ||||||
|  |  | ||||||
|  | @ -3,109 +3,109 @@ | ||||||
|    * This component ties together all the steps that are needed to create a new point. |    * This component ties together all the steps that are needed to create a new point. | ||||||
|    * There are many subcomponents which help with that |    * There are many subcomponents which help with that | ||||||
|    */ |    */ | ||||||
|   import type { SpecialVisualizationState } from "../../SpecialVisualization" |   import type { SpecialVisualizationState } from "../../SpecialVisualization"; | ||||||
|   import PresetList from "./PresetList.svelte" |   import PresetList from "./PresetList.svelte"; | ||||||
|   import type PresetConfig from "../../../Models/ThemeConfig/PresetConfig" |   import type PresetConfig from "../../../Models/ThemeConfig/PresetConfig"; | ||||||
|   import LayerConfig from "../../../Models/ThemeConfig/LayerConfig" |   import LayerConfig from "../../../Models/ThemeConfig/LayerConfig"; | ||||||
|   import Tr from "../../Base/Tr.svelte" |   import Tr from "../../Base/Tr.svelte"; | ||||||
|   import SubtleButton from "../../Base/SubtleButton.svelte" |   import SubtleButton from "../../Base/SubtleButton.svelte"; | ||||||
|   import FromHtml from "../../Base/FromHtml.svelte" |   import FromHtml from "../../Base/FromHtml.svelte"; | ||||||
|   import Translations from "../../i18n/Translations.js" |   import Translations from "../../i18n/Translations.js"; | ||||||
|   import TagHint from "../TagHint.svelte" |   import TagHint from "../TagHint.svelte"; | ||||||
|   import { And } from "../../../Logic/Tags/And.js" |   import { And } from "../../../Logic/Tags/And.js"; | ||||||
|   import LoginToggle from "../../Base/LoginToggle.svelte" |   import LoginToggle from "../../Base/LoginToggle.svelte"; | ||||||
|   import Constants from "../../../Models/Constants.js" |   import Constants from "../../../Models/Constants.js"; | ||||||
|   import FilteredLayer from "../../../Models/FilteredLayer" |   import FilteredLayer from "../../../Models/FilteredLayer"; | ||||||
|   import { Store, UIEventSource } from "../../../Logic/UIEventSource" |   import { Store, UIEventSource } from "../../../Logic/UIEventSource"; | ||||||
|   import { EyeIcon, EyeOffIcon } from "@rgossiaux/svelte-heroicons/solid" |   import { EyeIcon, EyeOffIcon } from "@rgossiaux/svelte-heroicons/solid"; | ||||||
|   import LoginButton from "../../Base/LoginButton.svelte" |   import LoginButton from "../../Base/LoginButton.svelte"; | ||||||
|   import NewPointLocationInput from "../../BigComponents/NewPointLocationInput.svelte" |   import NewPointLocationInput from "../../BigComponents/NewPointLocationInput.svelte"; | ||||||
|   import CreateNewNodeAction from "../../../Logic/Osm/Actions/CreateNewNodeAction" |   import CreateNewNodeAction from "../../../Logic/Osm/Actions/CreateNewNodeAction"; | ||||||
|   import { OsmWay } from "../../../Logic/Osm/OsmObject" |   import { OsmWay } from "../../../Logic/Osm/OsmObject"; | ||||||
|   import { Tag } from "../../../Logic/Tags/Tag" |   import { Tag } from "../../../Logic/Tags/Tag"; | ||||||
|   import type { WayId } from "../../../Models/OsmFeature" |   import type { WayId } from "../../../Models/OsmFeature"; | ||||||
|   import Loading from "../../Base/Loading.svelte" |   import Loading from "../../Base/Loading.svelte"; | ||||||
|   import type { GlobalFilter } from "../../../Models/GlobalFilter" |   import type { GlobalFilter } from "../../../Models/GlobalFilter"; | ||||||
|   import { onDestroy } from "svelte" |   import { onDestroy } from "svelte"; | ||||||
|   import NextButton from "../../Base/NextButton.svelte" |   import NextButton from "../../Base/NextButton.svelte"; | ||||||
|   import BackButton from "../../Base/BackButton.svelte" |   import BackButton from "../../Base/BackButton.svelte"; | ||||||
|   import ToSvelte from "../../Base/ToSvelte.svelte" |   import ToSvelte from "../../Base/ToSvelte.svelte"; | ||||||
|   import Svg from "../../../Svg" |   import Svg from "../../../Svg"; | ||||||
|   import OpenBackgroundSelectorButton from "../../BigComponents/OpenBackgroundSelectorButton.svelte" |   import OpenBackgroundSelectorButton from "../../BigComponents/OpenBackgroundSelectorButton.svelte"; | ||||||
|   import { twJoin } from "tailwind-merge" |   import { twJoin } from "tailwind-merge"; | ||||||
| 
 | 
 | ||||||
|   export let coordinate: { lon: number; lat: number } |   export let coordinate: { lon: number; lat: number }; | ||||||
|   export let state: SpecialVisualizationState |   export let state: SpecialVisualizationState; | ||||||
| 
 | 
 | ||||||
|   let selectedPreset: { |   let selectedPreset: { | ||||||
|     preset: PresetConfig |     preset: PresetConfig | ||||||
|     layer: LayerConfig |     layer: LayerConfig | ||||||
|     icon: string |     icon: string | ||||||
|     tags: Record<string, string> |     tags: Record<string, string> | ||||||
|   } = undefined |   } = undefined; | ||||||
|   let checkedOfGlobalFilters: number = 0 |   let checkedOfGlobalFilters: number = 0; | ||||||
|   let confirmedCategory = false |   let confirmedCategory = false; | ||||||
|   $: if (selectedPreset === undefined) { |   $: if (selectedPreset === undefined) { | ||||||
|     confirmedCategory = false |     confirmedCategory = false; | ||||||
|     creating = false |     creating = false; | ||||||
|     checkedOfGlobalFilters = 0 |     checkedOfGlobalFilters = 0; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   let flayer: FilteredLayer = undefined |   let flayer: FilteredLayer = undefined; | ||||||
|   let layerIsDisplayed: UIEventSource<boolean> | undefined = undefined |   let layerIsDisplayed: UIEventSource<boolean> | undefined = undefined; | ||||||
|   let layerHasFilters: Store<boolean> | undefined = undefined |   let layerHasFilters: Store<boolean> | undefined = undefined; | ||||||
|   let globalFilter: UIEventSource<GlobalFilter[]> = state.layerState.globalFilters |   let globalFilter: UIEventSource<GlobalFilter[]> = state.layerState.globalFilters; | ||||||
|   let _globalFilter: GlobalFilter[] = [] |   let _globalFilter: GlobalFilter[] = []; | ||||||
|   onDestroy( |   onDestroy( | ||||||
|     globalFilter.addCallbackAndRun((globalFilter) => { |     globalFilter.addCallbackAndRun((globalFilter) => { | ||||||
|       console.log("Global filters are", globalFilter) |       console.log("Global filters are", globalFilter); | ||||||
|       _globalFilter = globalFilter ?? [] |       _globalFilter = globalFilter ?? []; | ||||||
|     }) |     }) | ||||||
|   ) |   ); | ||||||
|   $: { |   $: { | ||||||
|     flayer = state.layerState.filteredLayers.get(selectedPreset?.layer?.id) |     flayer = state.layerState.filteredLayers.get(selectedPreset?.layer?.id); | ||||||
|     layerIsDisplayed = flayer?.isDisplayed |     layerIsDisplayed = flayer?.isDisplayed; | ||||||
|     layerHasFilters = flayer?.hasFilter |     layerHasFilters = flayer?.hasFilter; | ||||||
|   } |   } | ||||||
|   const t = Translations.t.general.add |   const t = Translations.t.general.add; | ||||||
| 
 | 
 | ||||||
|   const zoom = state.mapProperties.zoom |   const zoom = state.mapProperties.zoom; | ||||||
| 
 | 
 | ||||||
|   const isLoading = state.dataIsLoading |   const isLoading = state.dataIsLoading; | ||||||
|   let preciseCoordinate: UIEventSource<{ lon: number; lat: number }> = new UIEventSource(undefined) |   let preciseCoordinate: UIEventSource<{ lon: number; lat: number }> = new UIEventSource(undefined); | ||||||
|   let snappedToObject: UIEventSource<string> = new UIEventSource<string>(undefined) |   let snappedToObject: UIEventSource<string> = new UIEventSource<string>(undefined); | ||||||
| 
 | 
 | ||||||
|   // Small helper variable: if the map is tapped, we should let the 'Next'-button grab some attention as users have to click _that_ to continue, not the map |   // Small helper variable: if the map is tapped, we should let the 'Next'-button grab some attention as users have to click _that_ to continue, not the map | ||||||
|   let preciseInputIsTapped = false |   let preciseInputIsTapped = false; | ||||||
| 
 | 
 | ||||||
|   let creating = false |   let creating = false; | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|    * Call when the user should restart the flow by clicking on the map, e.g. because they disabled filters. |    * Call when the user should restart the flow by clicking on the map, e.g. because they disabled filters. | ||||||
|    * Will delete the lastclick-location |    * Will delete the lastclick-location | ||||||
|    */ |    */ | ||||||
|   function abort() { |   function abort() { | ||||||
|     state.selectedElement.setData(undefined) |     state.selectedElement.setData(undefined); | ||||||
|     // When aborted, we force the contributors to place the pin _again_ |     // When aborted, we force the contributors to place the pin _again_ | ||||||
|     // This is because there might be a nearby object that was disabled; this forces them to re-evaluate the map |     // This is because there might be a nearby object that was disabled; this forces them to re-evaluate the map | ||||||
|     state.lastClickObject.features.setData([]) |     state.lastClickObject.features.setData([]); | ||||||
|     preciseInputIsTapped = false |     preciseInputIsTapped = false; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async function confirm() { |   async function confirm() { | ||||||
|     creating = true |     creating = true; | ||||||
|     const location: { lon: number; lat: number } = preciseCoordinate.data |     const location: { lon: number; lat: number } = preciseCoordinate.data; | ||||||
|     const snapTo: WayId | undefined = <WayId>snappedToObject.data |     const snapTo: WayId | undefined = <WayId>snappedToObject.data; | ||||||
|     const tags: Tag[] = selectedPreset.preset.tags.concat( |     const tags: Tag[] = selectedPreset.preset.tags.concat( | ||||||
|       ..._globalFilter.map((f) => f?.onNewPoint?.tags ?? []) |       ..._globalFilter.map((f) => f?.onNewPoint?.tags ?? []) | ||||||
|     ) |     ); | ||||||
|     console.log("Creating new point at", location, "snapped to", snapTo, "with tags", tags) |     console.log("Creating new point at", location, "snapped to", snapTo, "with tags", tags); | ||||||
| 
 | 
 | ||||||
|     let snapToWay: undefined | OsmWay = undefined |     let snapToWay: undefined | OsmWay = undefined; | ||||||
|     if (snapTo !== undefined && snapTo !== null) { |     if (snapTo !== undefined && snapTo !== null) { | ||||||
|       const downloaded = await state.osmObjectDownloader.DownloadObjectAsync(snapTo, 0) |       const downloaded = await state.osmObjectDownloader.DownloadObjectAsync(snapTo, 0); | ||||||
|       if (downloaded !== "deleted") { |       if (downloaded !== "deleted") { | ||||||
|         snapToWay = downloaded |         snapToWay = downloaded; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -113,44 +113,44 @@ | ||||||
|       theme: state.layout?.id ?? "unkown", |       theme: state.layout?.id ?? "unkown", | ||||||
|       changeType: "create", |       changeType: "create", | ||||||
|       snapOnto: snapToWay, |       snapOnto: snapToWay, | ||||||
|       reusePointWithinMeters: 1, |       reusePointWithinMeters: 1 | ||||||
|     }) |     }); | ||||||
|     await state.changes.applyAction(newElementAction) |     await state.changes.applyAction(newElementAction); | ||||||
|     state.newFeatures.features.ping() |     state.newFeatures.features.ping(); | ||||||
|     // The 'changes' should have created a new point, which added this into the 'featureProperties' |     // The 'changes' should have created a new point, which added this into the 'featureProperties' | ||||||
|     const newId = newElementAction.newElementId |     const newId = newElementAction.newElementId; | ||||||
|     console.log("Applied pending changes, fetching store for", newId) |     console.log("Applied pending changes, fetching store for", newId); | ||||||
|     const tagsStore = state.featureProperties.getStore(newId) |     const tagsStore = state.featureProperties.getStore(newId); | ||||||
|     if (!tagsStore) { |     if (!tagsStore) { | ||||||
|       console.error("Bug: no tagsStore found for", newId) |       console.error("Bug: no tagsStore found for", newId); | ||||||
|     } |     } | ||||||
|     { |     { | ||||||
|       // Set some metainfo |       // Set some metainfo | ||||||
|       const properties = tagsStore.data |       const properties = tagsStore.data; | ||||||
|       if (snapTo) { |       if (snapTo) { | ||||||
|         // metatags (starting with underscore) are not uploaded, so we can safely mark this |         // metatags (starting with underscore) are not uploaded, so we can safely mark this | ||||||
|         delete properties["_referencing_ways"] |         delete properties["_referencing_ways"]; | ||||||
|         properties["_referencing_ways"] = `["${snapTo}"]` |         properties["_referencing_ways"] = `["${snapTo}"]`; | ||||||
|       } |       } | ||||||
|       properties["_backend"] = state.osmConnection.Backend() |       properties["_backend"] = state.osmConnection.Backend(); | ||||||
|       properties["_last_edit:timestamp"] = new Date().toISOString() |       properties["_last_edit:timestamp"] = new Date().toISOString(); | ||||||
|       const userdetails = state.osmConnection.userDetails.data |       const userdetails = state.osmConnection.userDetails.data; | ||||||
|       properties["_last_edit:contributor"] = userdetails.name |       properties["_last_edit:contributor"] = userdetails.name; | ||||||
|       properties["_last_edit:uid"] = "" + userdetails.uid |       properties["_last_edit:uid"] = "" + userdetails.uid; | ||||||
|       tagsStore.ping() |       tagsStore.ping(); | ||||||
|     } |     } | ||||||
|     const feature = state.indexedFeatures.featuresById.data.get(newId) |     const feature = state.indexedFeatures.featuresById.data.get(newId); | ||||||
|     console.log("Selecting feature", feature, "and opening their popup") |     console.log("Selecting feature", feature, "and opening their popup"); | ||||||
|     abort() |     abort(); | ||||||
|     state.selectedLayer.setData(selectedPreset.layer) |     state.selectedLayer.setData(selectedPreset.layer); | ||||||
|     state.selectedElement.setData(feature) |     state.selectedElement.setData(feature); | ||||||
|     tagsStore.ping() |     tagsStore.ping(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function confirmSync() { |   function confirmSync() { | ||||||
|     confirm() |     confirm() | ||||||
|       .then((_) => console.debug("New point successfully handled")) |       .then((_) => console.debug("New point successfully handled")) | ||||||
|       .catch((e) => console.error("Handling the new point went wrong due to", e)) |       .catch((e) => console.error("Handling the new point went wrong due to", e)); | ||||||
|   } |   } | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
|  | @ -162,206 +162,212 @@ | ||||||
|   <LoginButton osmConnection={state.osmConnection} slot="not-logged-in"> |   <LoginButton osmConnection={state.osmConnection} slot="not-logged-in"> | ||||||
|     <Tr slot="message" t={Translations.t.general.add.pleaseLogin} /> |     <Tr slot="message" t={Translations.t.general.add.pleaseLogin} /> | ||||||
|   </LoginButton> |   </LoginButton> | ||||||
|   {#if $zoom < Constants.minZoomLevelToAddNewPoint} |   <div class="h-full w-full"> | ||||||
|     <div class="alert"> | 
 | ||||||
|       <Tr t={Translations.t.general.add.zoomInFurther} /> |     {#if $zoom < Constants.minZoomLevelToAddNewPoint} | ||||||
|     </div> |       <div class="alert"> | ||||||
|   {:else if $isLoading} |         <Tr t={Translations.t.general.add.zoomInFurther} /> | ||||||
|     <div class="alert"> |       </div> | ||||||
|       <Loading> |     {:else if $isLoading} | ||||||
|         <Tr t={Translations.t.general.add.stillLoading} /> |       <div class="alert"> | ||||||
|       </Loading> |         <Loading> | ||||||
|     </div> |           <Tr t={Translations.t.general.add.stillLoading} /> | ||||||
|   {:else if selectedPreset === undefined} |         </Loading> | ||||||
|     <!-- First, select the correct preset --> |       </div> | ||||||
|     <PresetList |     {:else if selectedPreset === undefined} | ||||||
|       {state} |       <!-- First, select the correct preset --> | ||||||
|       on:select={(event) => { |       <PresetList | ||||||
|  |         {state} | ||||||
|  |         on:select={(event) => { | ||||||
|         selectedPreset = event.detail |         selectedPreset = event.detail | ||||||
|       }} |       }} | ||||||
|     /> |  | ||||||
|   {:else if !$layerIsDisplayed} |  | ||||||
|     <!-- Check that the layer is enabled, so that we don't add a duplicate --> |  | ||||||
|     <div class="alert flex items-center justify-center"> |  | ||||||
|       <EyeOffIcon class="w-8" /> |  | ||||||
|       <Tr |  | ||||||
|         t={Translations.t.general.add.layerNotEnabled.Subs({ layer: selectedPreset.layer.name })} |  | ||||||
|       /> |       /> | ||||||
|     </div> |     {:else if !$layerIsDisplayed} | ||||||
|  |       <!-- Check that the layer is enabled, so that we don't add a duplicate --> | ||||||
|  |       <div class="alert flex items-center justify-center"> | ||||||
|  |         <EyeOffIcon class="w-8" /> | ||||||
|  |         <Tr | ||||||
|  |           t={Translations.t.general.add.layerNotEnabled.Subs({ layer: selectedPreset.layer.name })} | ||||||
|  |         /> | ||||||
|  |       </div> | ||||||
| 
 | 
 | ||||||
|     <div class="flex flex-wrap-reverse md:flex-nowrap"> |       <div class="flex flex-wrap-reverse md:flex-nowrap"> | ||||||
|       <button |         <button | ||||||
|         class="flex w-full gap-x-1" |           class="flex w-full gap-x-1" | ||||||
|         on:click={() => { |           on:click={() => { | ||||||
|           abort() |           abort() | ||||||
|           state.guistate.openFilterView(selectedPreset.layer) |           state.guistate.openFilterView(selectedPreset.layer) | ||||||
|         }} |         }} | ||||||
|       > |         > | ||||||
|         <ToSvelte construct={Svg.layers_svg().SetClass("w-12")} /> |           <ToSvelte construct={Svg.layers_svg().SetClass("w-12")} /> | ||||||
|         <Tr t={Translations.t.general.add.openLayerControl} /> |           <Tr t={Translations.t.general.add.openLayerControl} /> | ||||||
|       </button> |         </button> | ||||||
| 
 | 
 | ||||||
|       <button |         <button | ||||||
|         class="primary flex w-full gap-x-1" |           class="primary flex w-full gap-x-1" | ||||||
|         on:click={() => { |           on:click={() => { | ||||||
|           layerIsDisplayed.setData(true) |           layerIsDisplayed.setData(true) | ||||||
|           abort() |           abort() | ||||||
|         }} |         }} | ||||||
|       > |         > | ||||||
|         <EyeIcon class="w-12" /> |           <EyeIcon class="w-12" /> | ||||||
|         <Tr t={Translations.t.general.add.enableLayer.Subs({ name: selectedPreset.layer.name })} /> |           <Tr t={Translations.t.general.add.enableLayer.Subs({ name: selectedPreset.layer.name })} /> | ||||||
|       </button> |         </button> | ||||||
|     </div> |       </div> | ||||||
|   {:else if $layerHasFilters} |     {:else if $layerHasFilters} | ||||||
|     <!-- Some filters are enabled. The feature to add might already be mapped, but hidden --> |       <!-- Some filters are enabled. The feature to add might already be mapped, but hidden --> | ||||||
|     <div class="alert flex items-center justify-center"> |       <div class="alert flex items-center justify-center"> | ||||||
|       <EyeOffIcon class="w-8" /> |         <EyeOffIcon class="w-8" /> | ||||||
|       <Tr t={Translations.t.general.add.disableFiltersExplanation} /> |         <Tr t={Translations.t.general.add.disableFiltersExplanation} /> | ||||||
|     </div> |       </div> | ||||||
|     <div class="flex flex-wrap-reverse md:flex-nowrap"> |       <div class="flex flex-wrap-reverse md:flex-nowrap"> | ||||||
|       <button |         <button | ||||||
|         class="primary flex w-full gap-x-1" |           class="primary flex w-full gap-x-1" | ||||||
|         on:click={() => { |           on:click={() => { | ||||||
|           abort() |           abort() | ||||||
|           state.layerState.filteredLayers.get(selectedPreset.layer.id).disableAllFilters() |           state.layerState.filteredLayers.get(selectedPreset.layer.id).disableAllFilters() | ||||||
|         }} |         }} | ||||||
|       > |         > | ||||||
|         <EyeOffIcon class="w-12" /> |           <EyeOffIcon class="w-12" /> | ||||||
|         <Tr t={Translations.t.general.add.disableFilters} /> |           <Tr t={Translations.t.general.add.disableFilters} /> | ||||||
|       </button> |         </button> | ||||||
|       <button |         <button | ||||||
|         class="flex w-full gap-x-1" |           class="flex w-full gap-x-1" | ||||||
|         on:click={() => { |           on:click={() => { | ||||||
|           abort() |           abort() | ||||||
|           state.guistate.openFilterView(selectedPreset.layer) |           state.guistate.openFilterView(selectedPreset.layer) | ||||||
|         }} |         }} | ||||||
|       > |         > | ||||||
|         <ToSvelte construct={Svg.layers_svg().SetClass("w-12")} /> |           <ToSvelte construct={Svg.layers_svg().SetClass("w-12")} /> | ||||||
|         <Tr t={Translations.t.general.add.openLayerControl} /> |           <Tr t={Translations.t.general.add.openLayerControl} /> | ||||||
|       </button> |         </button> | ||||||
|     </div> |       </div> | ||||||
|   {:else if !confirmedCategory} |     {:else if !confirmedCategory} | ||||||
|     <!-- Second, confirm the category --> |       <!-- Second, confirm the category --> | ||||||
|     <h2 class="mr-12"> |       <h2 class="mr-12"> | ||||||
|       <Tr |         <Tr | ||||||
|         t={Translations.t.general.add.confirmTitle.Subs({ title: selectedPreset.preset.title })} |           t={Translations.t.general.add.confirmTitle.Subs({ title: selectedPreset.preset.title })} | ||||||
|       /> |         /> | ||||||
|     </h2> |       </h2> | ||||||
| 
 | 
 | ||||||
|     <Tr t={Translations.t.general.add.confirmIntro} /> |       <Tr t={Translations.t.general.add.confirmIntro} /> | ||||||
| 
 | 
 | ||||||
|     {#if selectedPreset.preset.description} |       {#if selectedPreset.preset.description} | ||||||
|       <Tr t={selectedPreset.preset.description} /> |         <Tr t={selectedPreset.preset.description} /> | ||||||
|     {/if} |       {/if} | ||||||
| 
 | 
 | ||||||
|     {#if selectedPreset.preset.exampleImages} |       {#if selectedPreset.preset.exampleImages} | ||||||
|       <h3> |         <h3> | ||||||
|         {#if selectedPreset.preset.exampleImages.length === 1} |           {#if selectedPreset.preset.exampleImages.length === 1} | ||||||
|           <Tr t={Translations.t.general.example} /> |             <Tr t={Translations.t.general.example} /> | ||||||
|         {:else} |           {:else} | ||||||
|           <Tr t={Translations.t.general.examples} /> |             <Tr t={Translations.t.general.examples} /> | ||||||
|         {/if} |           {/if} | ||||||
|       </h3> |         </h3> | ||||||
|       <span class="flex flex-wrap items-stretch"> |         <span class="flex flex-wrap items-stretch"> | ||||||
|         {#each selectedPreset.preset.exampleImages as src} |         {#each selectedPreset.preset.exampleImages as src} | ||||||
|           <img {src} class="m-1 h-64 w-auto rounded-lg" /> |           <img {src} class="m-1 h-64 w-auto rounded-lg" /> | ||||||
|         {/each} |         {/each} | ||||||
|       </span> |       </span> | ||||||
|     {/if} |       {/if} | ||||||
|     <TagHint |       <TagHint | ||||||
|       embedIn={(tags) => t.presetInfo.Subs({ tags })} |         embedIn={(tags) => t.presetInfo.Subs({ tags })} | ||||||
|       {state} |         {state} | ||||||
|       tags={new And(selectedPreset.preset.tags)} |         tags={new And(selectedPreset.preset.tags)} | ||||||
|     /> |  | ||||||
| 
 |  | ||||||
|     <div class="flex w-full flex-wrap-reverse md:flex-nowrap"> |  | ||||||
|       <BackButton on:click={() => (selectedPreset = undefined)} clss="w-full"> |  | ||||||
|         <Tr t={t.backToSelect} /> |  | ||||||
|       </BackButton> |  | ||||||
| 
 |  | ||||||
|       <NextButton on:click={() => (confirmedCategory = true)} clss="primary w-full"> |  | ||||||
|         <div slot="image" class="relative"> |  | ||||||
|           <FromHtml src={selectedPreset.icon} /> |  | ||||||
|           <img class="absolute bottom-0 right-0 h-4 w-4" src="./assets/svg/confirm.svg" /> |  | ||||||
|         </div> |  | ||||||
|         <div class="w-full"> |  | ||||||
|           <Tr t={selectedPreset.text} /> |  | ||||||
|         </div> |  | ||||||
|       </NextButton> |  | ||||||
|     </div> |  | ||||||
|   {:else if _globalFilter?.length > 0 && _globalFilter?.length > checkedOfGlobalFilters} |  | ||||||
|     <Tr t={_globalFilter[checkedOfGlobalFilters].onNewPoint?.safetyCheck} cls="mx-12" /> |  | ||||||
|     <SubtleButton |  | ||||||
|       on:click={() => { |  | ||||||
|         checkedOfGlobalFilters = checkedOfGlobalFilters + 1 |  | ||||||
|       }} |  | ||||||
|     > |  | ||||||
|       <img |  | ||||||
|         slot="image" |  | ||||||
|         src={_globalFilter[checkedOfGlobalFilters].onNewPoint?.icon ?? "./assets/svg/confirm.svg"} |  | ||||||
|         class="h-12 w-12" |  | ||||||
|       /> |       /> | ||||||
|       <Tr |  | ||||||
|         slot="message" |  | ||||||
|         t={_globalFilter[checkedOfGlobalFilters].onNewPoint?.confirmAddNew.Subs({ |  | ||||||
|           preset: selectedPreset.preset, |  | ||||||
|         })} |  | ||||||
|       /> |  | ||||||
|     </SubtleButton> |  | ||||||
|     <SubtleButton |  | ||||||
|       on:click={() => { |  | ||||||
|         globalFilter.setData([]) |  | ||||||
|         abort() |  | ||||||
|       }} |  | ||||||
|     > |  | ||||||
|       <img slot="image" src="./assets/svg/close.svg" class="h-8 w-8" /> |  | ||||||
|       <Tr slot="message" t={Translations.t.general.cancel} /> |  | ||||||
|     </SubtleButton> |  | ||||||
|   {:else if !creating} |  | ||||||
|     <div class="relative w-full p-1"> |  | ||||||
|       <div class="h-96 max-h-screen w-full overflow-hidden rounded-xl"> |  | ||||||
|         <NewPointLocationInput |  | ||||||
|           on:click={() => { |  | ||||||
|             preciseInputIsTapped = true |  | ||||||
|           }} |  | ||||||
|           value={preciseCoordinate} |  | ||||||
|           snappedTo={snappedToObject} |  | ||||||
|           {state} |  | ||||||
|           {coordinate} |  | ||||||
|           targetLayer={selectedPreset.layer} |  | ||||||
|           snapToLayers={selectedPreset.preset.preciseInput.snapToLayers} |  | ||||||
|         /> |  | ||||||
|       </div> |  | ||||||
| 
 | 
 | ||||||
|       <div |       <div class="flex w-full flex-wrap-reverse md:flex-nowrap"> | ||||||
|         class={twJoin( |         <BackButton on:click={() => (selectedPreset = undefined)} clss="w-full"> | ||||||
|           !preciseInputIsTapped && "hidden", |           <Tr t={t.backToSelect} /> | ||||||
|           "absolute top-0 flex w-full justify-center p-12" |         </BackButton> | ||||||
|         )} | 
 | ||||||
|       > |         <NextButton on:click={() => (confirmedCategory = true)} clss="primary w-full"> | ||||||
|         <NextButton on:click={confirmSync} clss="primary w-fit"> |           <div slot="image" class="relative"> | ||||||
|           <div class="flex w-full justify-end gap-x-2"> |             <FromHtml src={selectedPreset.icon} /> | ||||||
|             <Tr t={Translations.t.general.add.confirmLocation} /> |             <img class="absolute bottom-0 right-0 h-4 w-4" src="./assets/svg/confirm.svg" /> | ||||||
|  |           </div> | ||||||
|  |           <div class="w-full"> | ||||||
|  |             <Tr t={selectedPreset.text} /> | ||||||
|           </div> |           </div> | ||||||
|         </NextButton> |         </NextButton> | ||||||
|       </div> |       </div> | ||||||
|  |     {:else if _globalFilter?.length > 0 && _globalFilter?.length > checkedOfGlobalFilters} | ||||||
|  |       <Tr t={_globalFilter[checkedOfGlobalFilters].onNewPoint?.safetyCheck} cls="mx-12" /> | ||||||
|  |       <SubtleButton | ||||||
|  |         on:click={() => { | ||||||
|  |         checkedOfGlobalFilters = checkedOfGlobalFilters + 1 | ||||||
|  |       }} | ||||||
|  |       > | ||||||
|  |         <img | ||||||
|  |           slot="image" | ||||||
|  |           src={_globalFilter[checkedOfGlobalFilters].onNewPoint?.icon ?? "./assets/svg/confirm.svg"} | ||||||
|  |           class="h-12 w-12" | ||||||
|  |         /> | ||||||
|  |         <Tr | ||||||
|  |           slot="message" | ||||||
|  |           t={_globalFilter[checkedOfGlobalFilters].onNewPoint?.confirmAddNew.Subs({ | ||||||
|  |           preset: selectedPreset.preset, | ||||||
|  |         })} | ||||||
|  |         /> | ||||||
|  |       </SubtleButton> | ||||||
|  |       <SubtleButton | ||||||
|  |         on:click={() => { | ||||||
|  |         globalFilter.setData([]) | ||||||
|  |         abort() | ||||||
|  |       }} | ||||||
|  |       > | ||||||
|  |         <img slot="image" src="./assets/svg/close.svg" class="h-8 w-8" /> | ||||||
|  |         <Tr slot="message" t={Translations.t.general.cancel} /> | ||||||
|  |       </SubtleButton> | ||||||
|  |     {:else if !creating} | ||||||
|  |       <div class="flex flex-col h-full"> | ||||||
|  |         <div class="relative min-h-20 h-full w-full p-1 "> | ||||||
|  |           <div class="h-full w-full overflow-hidden rounded-xl"> | ||||||
|  |             <NewPointLocationInput | ||||||
|  |               on:click={() => { | ||||||
|  |             preciseInputIsTapped = true | ||||||
|  |           }} | ||||||
|  |               value={preciseCoordinate} | ||||||
|  |               snappedTo={snappedToObject} | ||||||
|  |               {state} | ||||||
|  |               {coordinate} | ||||||
|  |               targetLayer={selectedPreset.layer} | ||||||
|  |               snapToLayers={selectedPreset.preset.preciseInput.snapToLayers} | ||||||
|  |             /> | ||||||
|  |           </div> | ||||||
| 
 | 
 | ||||||
|       <div class="absolute bottom-0 left-0 p-4"> |           <div | ||||||
|         <OpenBackgroundSelectorButton {state} /> |             class={twJoin( | ||||||
|       </div> |           !preciseInputIsTapped && "hidden", | ||||||
|     </div> |           "absolute top-0 flex w-full justify-center p-12" | ||||||
|     <div class="flex flex-wrap-reverse md:flex-nowrap"> |         )} | ||||||
|       <BackButton on:click={() => (selectedPreset = undefined)} clss="w-full"> |           > | ||||||
|         <Tr t={t.backToSelect} /> |             <!-- This is an _extra_ button that appears when the map is tapped - see usertest 2023-01-07 --> | ||||||
|       </BackButton> |             <NextButton on:click={confirmSync} clss="primary w-fit"> | ||||||
|  |               <div class="flex w-full justify-end gap-x-2"> | ||||||
|  |                 <Tr t={Translations.t.general.add.confirmLocation} /> | ||||||
|  |               </div> | ||||||
|  |             </NextButton> | ||||||
|  |           </div> | ||||||
| 
 | 
 | ||||||
|       <NextButton on:click={confirm} clss={"primary w-full"}> |           <div class="absolute bottom-0 left-0 p-4"> | ||||||
|         <div class="flex w-full justify-end gap-x-2"> |             <OpenBackgroundSelectorButton {state} /> | ||||||
|           <Tr t={Translations.t.general.add.confirmLocation} /> |           </div> | ||||||
|         </div> |         </div> | ||||||
|       </NextButton> |         <div class="flex flex-wrap-reverse md:flex-nowrap"> | ||||||
|     </div> |           <BackButton on:click={() => (selectedPreset = undefined)} clss="w-full"> | ||||||
|   {:else} |             <Tr t={t.backToSelect} /> | ||||||
|     <Loading>Creating point...</Loading> |           </BackButton> | ||||||
|   {/if} | 
 | ||||||
|  |           <NextButton on:click={confirm} clss={"primary w-full"}> | ||||||
|  |             <div class="flex w-full justify-end gap-x-2"> | ||||||
|  |               <Tr t={Translations.t.general.add.confirmLocation} /> | ||||||
|  |             </div> | ||||||
|  |           </NextButton> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     {:else} | ||||||
|  |       <Loading>Creating point...</Loading> | ||||||
|  |     {/if} | ||||||
|  |   </div> | ||||||
| </LoginToggle> | </LoginToggle> | ||||||
|  |  | ||||||
|  | @ -95,7 +95,7 @@ | ||||||
|   } |   } | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <div bind:this={questionboxElem}> | <div bind:this={questionboxElem} class="marker-questionbox-root" class:hidden={_questionsToAsk.length === 0 && skipped === 0 && answered === 0}> | ||||||
|   {#if _questionsToAsk.length === 0} |   {#if _questionsToAsk.length === 0} | ||||||
|     {#if skipped + answered > 0} |     {#if skipped + answered > 0} | ||||||
|       <div class="thanks"> |       <div class="thanks"> | ||||||
|  |  | ||||||
|  | @ -20,6 +20,8 @@ | ||||||
| 
 | 
 | ||||||
|   export let editingEnabled: Store<boolean> | undefined = state?.featureSwitchUserbadge; |   export let editingEnabled: Store<boolean> | undefined = state?.featureSwitchUserbadge; | ||||||
|    |    | ||||||
|  |   export let clss = config.classes.join(" ") | ||||||
|  |    | ||||||
|   export let highlightedRendering: UIEventSource<string> = undefined; |   export let highlightedRendering: UIEventSource<string> = undefined; | ||||||
|   export let showQuestionIfUnknown: boolean = false; |   export let showQuestionIfUnknown: boolean = false; | ||||||
|   /** |   /** | ||||||
|  | @ -71,7 +73,7 @@ | ||||||
|   } |   } | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <div bind:this={htmlElem} class=""> | <div bind:this={htmlElem} class={clss}> | ||||||
|   {#if config.question && (!editingEnabled || $editingEnabled)} |   {#if config.question && (!editingEnabled || $editingEnabled)} | ||||||
|     {#if editMode} |     {#if editMode} | ||||||
|       <TagRenderingQuestion {config} {tags} {selectedElement} {state} {layer}> |       <TagRenderingQuestion {config} {tags} {selectedElement} {state} {layer}> | ||||||
|  | @ -106,7 +108,7 @@ | ||||||
|       </div> |       </div> | ||||||
|     {/if} |     {/if} | ||||||
|   {:else} |   {:else} | ||||||
|     <div class="overflow-hidden p-2"> |     <div class="overflow-hidden p-2 w-full"> | ||||||
|       <TagRenderingAnswer {config} {tags} {selectedElement} {state} {layer} /> |       <TagRenderingAnswer {config} {tags} {selectedElement} {state} {layer} /> | ||||||
|     </div> |     </div> | ||||||
|   {/if} |   {/if} | ||||||
|  |  | ||||||
							
								
								
									
										0
									
								
								src/UI/Studio/ShowConversionMessage.svelte
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/UI/Studio/ShowConversionMessage.svelte
									
										
									
									
									
										Normal file
									
								
							
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue