Merge branch 'develop' into feature/nsi

This commit is contained in:
Robin van der Linde 2024-05-07 11:08:44 +02:00
commit 22c2f5166d
Signed by untrusted user: Robin-van-der-Linde
GPG key ID: 53956B3252478F0D
116 changed files with 5653 additions and 1538 deletions

View file

@ -0,0 +1,55 @@
<script lang="ts">
import ExtraLinkConfig from "../../Models/ThemeConfig/ExtraLinkConfig"
import Locale from "../i18n/Locale"
import { Utils } from "../../Utils"
import Translations from "../i18n/Translations"
import type { SpecialVisualizationState } from "../SpecialVisualization"
import Pop_out from "../../assets/svg/Pop_out.svelte"
import Tr from "../Base/Tr.svelte"
import Icon from "../Map/Icon.svelte"
export let state: SpecialVisualizationState
let theme = state.layout?.id ?? ""
let config: ExtraLinkConfig = state.layout.extraLink
const isIframe = window !== window.top
let basepath = window.location.host
let showWelcomeMessageSwitch = state.featureSwitches.featureSwitchWelcomeMessage
const t = Translations.t.general
const href = state.mapProperties.location.map(
(loc) => {
const subs = {
...loc,
theme: theme,
basepath,
language: Locale.language.data
}
return Utils.SubstituteKeys(config.href, subs)
},
[state.mapProperties.zoom]
)
</script>
{#if config !== undefined &&
!(config.requirements.has("iframe") && !isIframe) &&
!(config.requirements.has("no-iframe") && isIframe) &&
!(config.requirements.has("welcome-message") && !$showWelcomeMessageSwitch) &&
!(config.requirements.has("no-welcome-message") && $showWelcomeMessageSwitch)}
<div class="links-as-button">
<a href={$href} target={config.newTab ? "_blank" : ""} rel="noopener"
class="flex pointer-events-auto rounded-full border-black">
<Icon icon={config.icon} clss="w-6 h-6 m-2"/>
{#if config.text}
<Tr t={config.text} />
{:else}
<Tr t={t.screenToSmall.Subs({theme: state.layout.title})} />
{/if}
</a>
</div>
{/if}

View file

@ -1,101 +0,0 @@
import { UIElement } from "../UIElement"
import BaseUIElement from "../BaseUIElement"
import { Store } from "../../Logic/UIEventSource"
import ExtraLinkConfig from "../../Models/ThemeConfig/ExtraLinkConfig"
import Img from "../Base/Img"
import { SubtleButton } from "../Base/SubtleButton"
import Toggle from "../Input/Toggle"
import Locale from "../i18n/Locale"
import { Utils } from "../../Utils"
import Svg from "../../Svg"
import Translations from "../i18n/Translations"
import { Translation } from "../i18n/Translation"
interface ExtraLinkButtonState {
layout: { id: string; title: Translation }
featureSwitches: { featureSwitchWelcomeMessage: Store<boolean> }
mapProperties: {
location: Store<{ lon: number; lat: number }>
zoom: Store<number>
}
}
export default class ExtraLinkButton extends UIElement {
private readonly _config: ExtraLinkConfig
private readonly state: ExtraLinkButtonState
constructor(state: ExtraLinkButtonState, config: ExtraLinkConfig) {
super()
this.state = state
this._config = config
}
protected InnerRender(): BaseUIElement {
if (this._config === undefined) {
return undefined
}
const c = this._config
const isIframe = window !== window.top
if (c.requirements?.has("iframe") && !isIframe) {
return undefined
}
if (c.requirements?.has("no-iframe") && isIframe) {
return undefined
}
let link: BaseUIElement
const theme = this.state.layout?.id ?? ""
const basepath = window.location.host
const href = this.state.mapProperties.location.map(
(loc) => {
const subs = {
...loc,
theme: theme,
basepath,
language: Locale.language.data,
}
return Utils.SubstituteKeys(c.href, subs)
},
[this.state.mapProperties.zoom]
)
let img: BaseUIElement = Svg.pop_out_svg()
if (c.icon !== undefined) {
img = new Img(c.icon).SetClass("h-6")
}
let text: Translation
if (c.text === undefined) {
text = Translations.t.general.screenToSmall.Subs({
theme: this.state.layout.title,
})
} else {
text = c.text.Clone()
}
link = new SubtleButton(img, text, {
url: href,
newTab: c.newTab,
})
if (c.requirements?.has("no-welcome-message")) {
link = new Toggle(
undefined,
link,
this.state.featureSwitches.featureSwitchWelcomeMessage
)
}
if (c.requirements?.has("welcome-message")) {
link = new Toggle(
link,
undefined,
this.state.featureSwitches.featureSwitchWelcomeMessage
)
}
return link
}
}

View file

@ -91,11 +91,6 @@
return
}
if (unit !== undefined && isNaN(Number(v))) {
value.setData(undefined)
return
}
feedback?.setData(undefined)
if (selectedUnit.data) {
value.setData(unit.toOsm(v, selectedUnit.data))

View file

@ -34,6 +34,7 @@
import { LinkIcon } from "@babeard/svelte-heroicons/mini"
import Square_rounded from "../../assets/svg/Square_rounded.svelte"
import Bug from "../../assets/svg/Bug.svelte"
import Pop_out from "../../assets/svg/Pop_out.svelte"
/**
* Renders a single icon.
@ -123,6 +124,9 @@
<AddSmall {color} class={clss} />
{:else if icon === "link"}
<LinkIcon style="--svg-color: {color}" class={twMerge(clss, "apply-fill")} />
{:else if icon === "popout"}
<LinkIcon style="--svg-color: {color}" />
{:else}
<img class={clss ?? "h-full w-full"} src={icon} aria-hidden="true" alt="" />
{/if}

View file

@ -188,7 +188,7 @@ export default abstract class ImportFlow<ArgT extends ImportFlowArguments> {
return { error: new Translation({ "*": e }) }
}
if (state.mapProperties.zoom.data < 18) {
if (state.mapProperties.zoom.data < 16) {
return { error: t.zoomInMore }
}

View file

@ -79,7 +79,7 @@
console.log("Applying questions to ask")
const qta = questionsToAsk.data
firstQuestion.setData(undefined)
allQuestionsToAsk.setData([])
//allQuestionsToAsk.setData([])
await Utils.awaitAnimationFrame()
firstQuestion.setData(qta[0])
allQuestionsToAsk.setData(qta)

View file

@ -36,6 +36,7 @@
export let config: TagRenderingConfig
export let tags: UIEventSource<Record<string, string>>
export let selectedElement: Feature
export let state: SpecialVisualizationState
export let layer: LayerConfig | undefined
@ -71,6 +72,8 @@
/**
* Prepares and fills the checkedMappings
*/
console.log("Initing ", config.id)
function initialize(tgs: Record<string, string>, confg: TagRenderingConfig): void {
mappings = confg.mappings?.filter((m) => {
if (typeof m.hideInAnswer === "boolean") {
@ -139,11 +142,33 @@
feedback.setData(undefined)
}
$: {
// Even though 'config' is not declared as a store, Svelte uses it as one to update the component
// We want to (re)-initialize whenever the 'tags' or 'config' change - but not when 'checkedConfig' changes
initialize($tags, config)
}
let usedKeys: string[] = config.usedTags().flatMap((t) => t.usedKeys())
/**
* The 'minimalTags' is a subset of the tags of the feature, only containing the values relevant for this object.
* The main goal is to be stable and only 'ping' when an actual change is relevant
*/
let minimalTags = new UIEventSource<Record<string, string>>(undefined)
tags.addCallbackAndRunD((tags) => {
const previousMinimal = minimalTags.data
const newMinimal: Record<string, string> = {}
let somethingChanged = previousMinimal === undefined
for (const key of usedKeys) {
const newValue = tags[key]
somethingChanged ||= previousMinimal?.[key] !== newValue
if (newValue !== undefined && newValue !== null) {
newMinimal[key] = newValue
}
}
if (somethingChanged) {
console.log("Updating minimal tags to", newMinimal, "of", config.id)
minimalTags.setData(newMinimal)
}
})
minimalTags.addCallbackAndRunD((tgs) => {
initialize(tgs, config)
})
onDestroy(
freeformInput.subscribe((freeformValue) => {
if (!mappings || mappings?.length == 0 || config.freeform?.key === undefined) {
@ -180,6 +205,19 @@
checkedMappings,
tags.data
)
if (state.featureSwitches.featureSwitchIsDebugging.data) {
console.log(
"Constructing change spec from",
{
freeform: $freeformInput,
selectedMapping,
checkedMappings,
currentTags: tags.data,
},
" --> ",
selectedTags
)
}
} catch (e) {
console.error("Could not calculate changeSpecification:", e)
selectedTags = undefined
@ -210,7 +248,7 @@
if (layer === undefined || (layer?.source === null && layer.id !== "favourite")) {
/**
* This is a special, priviliged layer.
* This is a special, privileged layer.
* We simply apply the tags onto the records
*/
const kv = selectedTags.asChange(tags.data)

View file

@ -64,10 +64,14 @@
)
</script>
{#if unit.inverted}
<div class="bold px-2">/</div>
{/if}
<select bind:value={$selectedUnit}>
{#each unit.denominations as denom (denom.canonical)}
<option value={denom.canonical}>
{#if $isSingle}
{#if $isSingle || unit.inverted}
<Tr t={denom.humanSingular} />
{:else}
<Tr t={denom.human.Subs({ quantity: "" })} />

View file

@ -11,7 +11,7 @@
export let configs: ConfigMeta[]
export let title: string | undefined = undefined
export let path: (string | number)[] = []
export let path: readonly (string | number)[] = []
let expertMode = state.expertMode
let configsNoHidden = configs.filter((schema) => schema.hints?.group !== "hidden")
@ -21,9 +21,9 @@
</script>
{#if configs === undefined}
Bug: 'Region' received 'undefined'
Bug: 'Region' received 'undefined' at {path.join(".")}
{:else if configs.length === 0}
Bug: Region received empty list as configuration
Bug: Region received empty list as configuration at {path.join(".")}
{:else if title}
<div class="flex w-full flex-col">
<h3>{title}</h3>

View file

@ -7,7 +7,7 @@
import type { ConfigMeta } from "./configMeta"
import type {
MappingConfigJson,
QuestionableTagRenderingConfigJson,
QuestionableTagRenderingConfigJson
} from "../../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson"
import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig"
import TagRenderingEditable from "../Popup/TagRendering/TagRenderingEditable.svelte"
@ -59,8 +59,8 @@
labelMapping = {
if: "value=" + label,
then: {
en: "Builtin collection <b>" + label + "</b>:",
},
en: "Builtin collection <b>" + label + "</b>:"
}
}
perLabel[label] = labelMapping
mappingsBuiltin.push(labelMapping)
@ -72,14 +72,14 @@
mappingsBuiltin.push({
if: "value=" + tr["id"],
then: {
en: "Builtin <b>" + tr["id"] + "</b> <div class='subtle'>" + description + "</div>",
},
en: "Builtin <b>" + tr["id"] + "</b> <div class='subtle'>" + description + "</div>"
}
})
}
const configBuiltin = new TagRenderingConfig(<QuestionableTagRenderingConfigJson>{
question: "Which builtin element should be shown?",
mappings: mappingsBuiltin,
mappings: mappingsBuiltin
})
const tags = new UIEventSource({ value })
@ -112,7 +112,7 @@
"condition",
"metacondition",
"mappings",
"icon",
"icon"
])
const ignored = new Set(["labels", "description", "classes"])
@ -196,7 +196,10 @@
<h3>Text field and input element configuration</h3>
<div class="border-l border-dashed border-gray-800 pl-2">
<SchemaBasedField {state} path={[...path, "render"]} schema={topLevelItems["render"]} />
<Region {state} {path} configs={freeformSchema} />
{#if freeformSchema?.length > 0}
<!-- In read-only cases, (e.g. popup title) there will be no freeform-schema to set and thus freeformSchema will be undefined -->
<Region {state} {path} configs={freeformSchema} />
{/if}
<SchemaBasedField {state} path={[...path, "icon"]} schema={topLevelItems["icon"]} />
</div>

View file

@ -34,7 +34,6 @@
import { Utils } from "../Utils"
import Hotkeys from "./Base/Hotkeys"
import LevelSelector from "./BigComponents/LevelSelector.svelte"
import ExtraLinkButton from "./BigComponents/ExtraLinkButton"
import SelectedElementTitle from "./BigComponents/SelectedElementTitle.svelte"
import ThemeIntroPanel from "./BigComponents/ThemeIntroPanel.svelte"
import type { RasterLayerPolygon } from "../Models/RasterLayers"
@ -73,6 +72,7 @@
import PrivacyPolicy from "./BigComponents/PrivacyPolicy.svelte"
import { BBox } from "../Logic/BBox"
import ReviewsOverview from "./Reviews/ReviewsOverview.svelte"
import ExtraLinkButton from "./BigComponents/ExtraLinkButton.svelte"
export let state: ThemeViewState
let layout = state.layout
@ -260,9 +260,7 @@
/>
</MapControlButton>
{/if}
<ToSvelte
construct={() => new ExtraLinkButton(state, layout.extraLink).SetClass("pointer-events-auto")}
/>
<ExtraLinkButton {state} />
<UploadingImageCounter featureId="*" showThankYou={false} {state} />
<PendingChangesIndicator {state} />
<If condition={state.featureSwitchIsTesting}>