UX: map in 'add new point' now takes the full screen

This commit is contained in:
Pieter Vander Vennet 2023-11-03 01:05:17 +01:00
parent 5c692fb11a
commit 4219b23af1
8 changed files with 281 additions and 266 deletions

View file

@ -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

View file

@ -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()}"

View file

@ -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>(

View file

@ -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}

View file

@ -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>

View file

@ -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">

View file

@ -19,7 +19,9 @@
export let layer: LayerConfig = undefined; export let layer: LayerConfig = undefined;
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}