From 335906b48176ebff68bbee98a75a2021600efef9 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Thu, 2 Jan 2025 03:56:42 +0100 Subject: [PATCH] Refactoring: move 'GetDefaultIcon' into its own Svelte-class --- scripts/generateLayerOverview.ts | 2 +- src/Models/ThemeConfig/LayerConfig.ts | 102 ++++++++---------- .../ThemeConfig/PointRenderingConfig.ts | 9 -- src/UI/BigComponents/Filterview.svelte | 3 +- src/UI/History/History.svelte | 3 +- src/UI/Map/DefaultIcon.svelte | 27 +++++ src/UI/Map/DynamicMarker.svelte | 2 +- src/UI/Popup/DisabledQuestionsLayer.svelte | 3 +- .../TagRendering/TagRenderingMapping.svelte | 8 +- src/UI/Search/ActiveFilters.svelte | 5 +- src/UI/Search/FilterResult.svelte | 3 +- src/UI/Search/GeocodeResult.svelte | 5 +- src/UI/ThemeViewGUI.svelte | 5 +- 13 files changed, 97 insertions(+), 80 deletions(-) create mode 100644 src/UI/Map/DefaultIcon.svelte diff --git a/scripts/generateLayerOverview.ts b/scripts/generateLayerOverview.ts index b62a5e533..64c35df4c 100644 --- a/scripts/generateLayerOverview.ts +++ b/scripts/generateLayerOverview.ts @@ -119,7 +119,7 @@ class AddIconSummary extends DesugaringStep<{ raw: LayerConfigJson; parsed: Laye const pointRendering: PointRenderingConfig = layerConfig.mapRendering.find((pr) => pr.location.has("point") ) - const defaultTags = layerConfig.GetBaseTags() + const defaultTags = layerConfig.baseTags fixed["_layerIcon"] = Utils.NoNull( (pointRendering?.marker ?? []).map((i) => { const icon = i.icon?.GetRenderValue(defaultTags)?.txt diff --git a/src/Models/ThemeConfig/LayerConfig.ts b/src/Models/ThemeConfig/LayerConfig.ts index 60652478f..c5fea4525 100644 --- a/src/Models/ThemeConfig/LayerConfig.ts +++ b/src/Models/ThemeConfig/LayerConfig.ts @@ -24,6 +24,9 @@ import { QuestionableTagRenderingConfigJson } from "./Json/QuestionableTagRender import MarkdownUtils from "../../Utils/MarkdownUtils" import { And } from "../../Logic/Tags/And" import Combine from "../../UI/Base/Combine" +import SvelteUIElement from "../../UI/Base/SvelteUIElement" +import DynamicMarker from "../../UI/Map/DynamicMarker.svelte" +import { ImmutableStore } from "../../Logic/UIEventSource" export default class LayerConfig extends WithContextLoader { public static readonly syncSelectionAllowed = ["no", "local", "theme-only", "global"] as const @@ -67,6 +70,8 @@ export default class LayerConfig extends WithContextLoader { public readonly popupInFloatover: boolean | string public readonly enableMorePrivacy: boolean + public readonly baseTags: Readonly> + /** * If this layer is based on another layer, this might be indicated here * @private @@ -104,7 +109,7 @@ export default class LayerConfig extends WithContextLoader { mercatorCrs: json.source["mercatorCrs"], idKey: json.source["idKey"], }, - json.id + json.id, ) } @@ -124,7 +129,7 @@ export default class LayerConfig extends WithContextLoader { if (json.calculatedTags !== undefined) { if (!official) { console.warn( - `Unofficial theme ${this.id} with custom javascript! This is a security risk` + `Unofficial theme ${this.id} with custom javascript! This is a security risk`, ) } this.calculatedTags = [] @@ -194,7 +199,7 @@ export default class LayerConfig extends WithContextLoader { tags: pr.tags.map((t) => TagUtils.SimpleTag(t)), description: Translations.T( pr.description, - `${translationContext}.presets.${i}.description` + `${translationContext}.presets.${i}.description`, ), preciseInput: preciseInput, exampleImages: pr.exampleImages, @@ -208,7 +213,7 @@ export default class LayerConfig extends WithContextLoader { if (json.lineRendering) { this.lineRendering = Utils.NoNull(json.lineRendering).map( - (r, i) => new LineRenderingConfig(r, `${context}[${i}]`) + (r, i) => new LineRenderingConfig(r, `${context}[${i}]`), ) } else { this.lineRendering = [] @@ -216,7 +221,7 @@ export default class LayerConfig extends WithContextLoader { if (json.pointRendering) { this.mapRendering = Utils.NoNull(json.pointRendering).map( - (r, i) => new PointRenderingConfig(r, `${context}[${i}](${this.id})`) + (r, i) => new PointRenderingConfig(r, `${context}[${i}](${this.id})`), ) } else { this.mapRendering = [] @@ -228,7 +233,7 @@ export default class LayerConfig extends WithContextLoader { r.location.has("centroid") || r.location.has("projected_centerpoint") || r.location.has("start") || - r.location.has("end") + r.location.has("end"), ) if ( @@ -250,7 +255,7 @@ export default class LayerConfig extends WithContextLoader { Constants.priviliged_layers.indexOf(this.id) < 0 && this.source !== null /*library layer*/ && !this.source?.geojsonSource?.startsWith( - "https://api.openstreetmap.org/api/0.6/notes.json" + "https://api.openstreetmap.org/api/0.6/notes.json", ) ) { throw ( @@ -269,7 +274,7 @@ export default class LayerConfig extends WithContextLoader { typeof tr !== "string" && tr["builtin"] === undefined && tr["id"] === undefined && - tr["rewrite"] === undefined + tr["rewrite"] === undefined, ) ?? [] if (missingIds?.length > 0 && official) { console.error("Some tagRenderings of", this.id, "are missing an id:", missingIds) @@ -280,8 +285,8 @@ export default class LayerConfig extends WithContextLoader { (tr, i) => new TagRenderingConfig( tr, - this.id + ".tagRenderings[" + i + "]" - ) + this.id + ".tagRenderings[" + i + "]", + ), ) if (json.units !== undefined && !Array.isArray(json.units)) { throw ( @@ -291,7 +296,7 @@ export default class LayerConfig extends WithContextLoader { ) } this.units = (json.units ?? []).flatMap((unitJson, i) => - Unit.fromJson(unitJson, this.tagRenderings, `${context}.unit[${i}]`) + Unit.fromJson(unitJson, this.tagRenderings, `${context}.unit[${i}]`), ) if ( @@ -352,31 +357,18 @@ export default class LayerConfig extends WithContextLoader { ) } this.popupInFloatover = json.popupInFloatover ?? false - } - - public defaultIcon(properties?: Record): BaseUIElement | undefined { - if (this.mapRendering === undefined || this.mapRendering === null) { - return undefined - } - const mapRenderings = this.mapRendering.filter((r) => r.location.has("point")) - if (mapRenderings.length === 0) { - return undefined - } - return new Combine( - mapRenderings.map((mr) => - mr - .GetBaseIcon(properties ?? this.GetBaseTags()) - .SetClass("absolute left-0 top-0 w-full h-full") - ) - ).SetClass("relative block w-full h-full") - } - - public GetBaseTags(): Record { - return TagUtils.changeAsProperties( - this.source?.osmTags?.asChange({ id: "node/-1" }) ?? [{ k: "id", v: "node/-1" }] + this.baseTags = TagUtils.changeAsProperties( + this.source?.osmTags?.asChange({ id: "node/-1" }) ?? [{ k: "id", v: "node/-1" }], ) } + + public hasDefaultIcon() { + if (this.mapRendering === undefined || this.mapRendering === null) { + return false + } + return this.mapRendering.some((r) => r.location.has("point")) + } public GenerateDocumentation( usedInThemes: string[], layerIsNeededBy?: Map, @@ -386,7 +378,7 @@ export default class LayerConfig extends WithContextLoader { neededLayer: string }[] = [], addedByDefault = false, - canBeIncluded = true + canBeIncluded = true, ): string { const extraProps: string[] = [] extraProps.push("This layer is shown at zoomlevel **" + this.minzoom + "** and higher") @@ -394,32 +386,32 @@ export default class LayerConfig extends WithContextLoader { if (canBeIncluded) { if (addedByDefault) { extraProps.push( - "**This layer is included automatically in every theme. This layer might contain no points**" + "**This layer is included automatically in every theme. This layer might contain no points**", ) } if (this.shownByDefault === false) { extraProps.push( - "This layer is not visible by default and must be enabled in the filter by the user. " + "This layer is not visible by default and must be enabled in the filter by the user. ", ) } if (this.title === undefined) { extraProps.push( - "Elements don't have a title set and cannot be toggled nor will they show up in the dashboard. If you import this layer in your theme, override `title` to make this toggleable." + "Elements don't have a title set and cannot be toggled nor will they show up in the dashboard. If you import this layer in your theme, override `title` to make this toggleable.", ) } if (this.name === undefined && this.shownByDefault === false) { extraProps.push( - "This layer is not visible by default and the visibility cannot be toggled, effectively resulting in a fully hidden layer. This can be useful, e.g. to calculate some metatags. If you want to render this layer (e.g. for debugging), enable it by setting the URL-parameter layer-=true" + "This layer is not visible by default and the visibility cannot be toggled, effectively resulting in a fully hidden layer. This can be useful, e.g. to calculate some metatags. If you want to render this layer (e.g. for debugging), enable it by setting the URL-parameter layer-=true", ) } if (this.name === undefined) { extraProps.push( - "Not visible in the layer selection by default. If you want to make this layer toggable, override `name`" + "Not visible in the layer selection by default. If you want to make this layer toggable, override `name`", ) } if (this.mapRendering.length === 0) { extraProps.push( - "Not rendered on the map by default. If you want to rendering this on the map, override `mapRenderings`" + "Not rendered on the map by default. If you want to rendering this on the map, override `mapRenderings`", ) } @@ -429,12 +421,12 @@ export default class LayerConfig extends WithContextLoader { "", "This layer is loaded from an external source, namely ", "`" + this.source.geojsonSource + "`", - ].join("\n\n") + ].join("\n\n"), ) } } else { extraProps.push( - "This layer can **not** be included in a theme. It is solely used by [special renderings](SpecialRenderings.md) showing a minimap with custom data." + "This layer can **not** be included in a theme. It is solely used by [special renderings](SpecialRenderings.md) showing a minimap with custom data.", ) } @@ -444,7 +436,7 @@ export default class LayerConfig extends WithContextLoader { usingLayer = [ "## Themes using this layer", MarkdownUtils.list( - (usedInThemes ?? []).map((id) => `[${id}](https://mapcomplete.org/${id})`) + (usedInThemes ?? []).map((id) => `[${id}](https://mapcomplete.org/${id})`), ), ] } else if (this.source !== null) { @@ -460,7 +452,7 @@ export default class LayerConfig extends WithContextLoader { " into the layout as it depends on it: ", dep.reason, "(" + dep.context + ")", - ].join(" ") + ].join(" "), ) } @@ -487,7 +479,7 @@ export default class LayerConfig extends WithContextLoader { new And(preset.tags).asHumanString(true) + snaps ) - }) + }), ), ] } @@ -495,8 +487,8 @@ export default class LayerConfig extends WithContextLoader { for (const revDep of Utils.Dedup(layerIsNeededBy?.get(this.id) ?? [])) { extraProps.push( ["This layer is needed as dependency for layer", `[${revDep}](#${revDep})`].join( - " " - ) + " ", + ), ) } @@ -507,10 +499,10 @@ export default class LayerConfig extends WithContextLoader { .filter((values) => values.key !== "id") .map((values) => { const embedded: string[] = values.values?.map((v) => - Link.OsmWiki(values.key, v, true).SetClass("mr-2").AsMarkdown() + Link.OsmWiki(values.key, v, true).SetClass("mr-2").AsMarkdown(), ) ?? ["_no preset options defined, or no values in them_"] const statistics = `https://taghistory.raifer.tech/?#***/${encodeURIComponent( - values.key + values.key, )}/` const tagInfo = `https://taginfo.openstreetmap.org/keys/${values.key}#values` return [ @@ -525,7 +517,7 @@ export default class LayerConfig extends WithContextLoader { : `[${values.type}](../SpecialInputElements.md#${values.type})`, embedded.join(" "), ] - }) + }), ) let quickOverview: string[] = [] @@ -535,7 +527,7 @@ export default class LayerConfig extends WithContextLoader { "this quick overview is incomplete", MarkdownUtils.table( ["attribute", "type", "values which are supported by this layer"], - tableRows + tableRows, ), ] } @@ -569,19 +561,19 @@ export default class LayerConfig extends WithContextLoader { const parts = neededTags["and"] tagsDescription.push( "Elements must match **all** of the following expressions:", - parts.map((p, i) => i + ". " + p.asHumanString(true, false, {})).join("\n") + parts.map((p, i) => i + ". " + p.asHumanString(true, false, {})).join("\n"), ) } else if (neededTags["or"]) { const parts = neededTags["or"] tagsDescription.push( "Elements must match **any** of the following expressions:", - parts.map((p) => " - " + p.asHumanString(true, false, {})).join("\n") + parts.map((p) => " - " + p.asHumanString(true, false, {})).join("\n"), ) } else { tagsDescription.push( "Elements must match the expression **" + - neededTags.asHumanString(true, false, {}) + - "**" + neededTags.asHumanString(true, false, {}) + + "**", ) } diff --git a/src/Models/ThemeConfig/PointRenderingConfig.ts b/src/Models/ThemeConfig/PointRenderingConfig.ts index 8bae5f296..4c74a4843 100644 --- a/src/Models/ThemeConfig/PointRenderingConfig.ts +++ b/src/Models/ThemeConfig/PointRenderingConfig.ts @@ -143,15 +143,6 @@ export default class PointRenderingConfig extends WithContextLoader { "w-full h-full block absolute top-0 left-0" ) } - - public GetBaseIcon(tags?: Record): BaseUIElement { - return new SvelteUIElement(DynamicMarker, { - marker: this.marker, - rotation: this.rotation, - tags: new ImmutableStore(tags), - }) - } - public RenderIcon( tags: Store>, options?: { diff --git a/src/UI/BigComponents/Filterview.svelte b/src/UI/BigComponents/Filterview.svelte index a59962d5f..aa3bdec8b 100644 --- a/src/UI/BigComponents/Filterview.svelte +++ b/src/UI/BigComponents/Filterview.svelte @@ -14,6 +14,7 @@ import Translations from "../i18n/Translations" import type { SpecialVisualizationState } from "../SpecialVisualization" import Constants from "../../Models/Constants" + import DefaultIcon from "../Map/DefaultIcon.svelte" export let state: SpecialVisualizationState export let filteredLayer: FilteredLayer @@ -58,7 +59,7 @@ {#if showLayerTitle}
- layer.defaultIcon()} /> +
diff --git a/src/UI/History/History.svelte b/src/UI/History/History.svelte index 66792cefc..065822d08 100644 --- a/src/UI/History/History.svelte +++ b/src/UI/History/History.svelte @@ -10,6 +10,7 @@ import ToSvelte from "../Base/ToSvelte.svelte" import Tr from "../Base/Tr.svelte" import Translations from "../i18n/Translations" + import DefaultIcon from "../Map/DefaultIcon.svelte" export let onlyShowChangesBy: string[] export let id: OsmId @@ -58,7 +59,7 @@

- +
+ + + import LayerConfig from "../../Models/ThemeConfig/LayerConfig" + import DynamicIcon from "./DynamicIcon.svelte" + import DynamicMarker from "./DynamicMarker.svelte" + import Marker from "./Marker.svelte" + import { ImmutableStore } from "../../Logic/UIEventSource" + + /** + * The 'DefaultIcon' is the icon that a layer shows by default + * Used e.g. in the filterview + */ + export let layer: LayerConfig + export let properties: Readonly> = layer.baseTags + export let clss= "" + let tags = new ImmutableStore(properties) + let mapRenderings = layer.mapRendering?.filter((r) => r.location.has("point")) + + +{#if mapRenderings?.length > 0} +
+ {#each mapRenderings as mr} + + {/each} +
+{/if} diff --git a/src/UI/Map/DynamicMarker.svelte b/src/UI/Map/DynamicMarker.svelte index 2f6b1cb90..bc88a2291 100644 --- a/src/UI/Map/DynamicMarker.svelte +++ b/src/UI/Map/DynamicMarker.svelte @@ -24,7 +24,7 @@ } -{#if marker && marker} +{#if marker}
{#each marker as icon}
diff --git a/src/UI/Popup/DisabledQuestionsLayer.svelte b/src/UI/Popup/DisabledQuestionsLayer.svelte index 6460f2fac..8396e5843 100644 --- a/src/UI/Popup/DisabledQuestionsLayer.svelte +++ b/src/UI/Popup/DisabledQuestionsLayer.svelte @@ -8,6 +8,7 @@ import { Translation } from "../i18n/Translation" import { XMarkIcon } from "@babeard/svelte-heroicons/mini" import ToSvelte from "../Base/ToSvelte.svelte" + import DefaultIcon from "../Map/DefaultIcon.svelte" export let layer: LayerConfig export let state: ThemeViewState @@ -28,7 +29,7 @@

- layer.defaultIcon()} /> +

diff --git a/src/UI/Popup/TagRendering/TagRenderingMapping.svelte b/src/UI/Popup/TagRendering/TagRenderingMapping.svelte index 73413b0e9..f28b8633b 100644 --- a/src/UI/Popup/TagRendering/TagRenderingMapping.svelte +++ b/src/UI/Popup/TagRendering/TagRenderingMapping.svelte @@ -15,6 +15,7 @@ import SvelteUIElement from "../../Base/SvelteUIElement" import Icon from "../../Map/Icon.svelte" import { TagsFilter } from "../../../Logic/Tags/TagsFilter" + import DefaultIcon from "../../Map/DefaultIcon.svelte" export let selectedElement: Feature export let tags: UIEventSource> @@ -27,6 +28,7 @@ */ export let clss: string = "ml-2" export let mapping: { + readonly if?: TagsFilter readonly then: Translation readonly searchTerms?: Record readonly icon?: string @@ -46,13 +48,13 @@ large: "5rem", } - function getAutoIcon(mapping: { if?: TagsFilter }): BaseUIElement { + function getAutoIcon(mapping: { readonly if?: TagsFilter }): Readonly> { for (const preset of layer.presets) { if (!new And(preset.tags).shadows(mapping.if)) { continue } - return layer.defaultIcon(TagUtils.asProperties(preset.tags)) + return TagUtils.asProperties(preset.tags) } return undefined } @@ -62,7 +64,7 @@
{#if mapping.icon === "auto"}
- getAutoIcon(mapping)} /> +
{:else} enableAllLayers()}>
- +
@@ -82,7 +83,7 @@ {#each $nonactiveLayers as nonActive (nonActive.layerDef.id)} nonActive.isDisplayed.set(true)}>
- +
diff --git a/src/UI/Search/FilterResult.svelte b/src/UI/Search/FilterResult.svelte index e19a21339..0ea0e07d6 100644 --- a/src/UI/Search/FilterResult.svelte +++ b/src/UI/Search/FilterResult.svelte @@ -6,6 +6,7 @@ import type { FilterSearchResult } from "../../Logic/Search/FilterSearch" import LayerConfig from "../../Models/ThemeConfig/LayerConfig" import Loading from "../Base/Loading.svelte" + import DefaultIcon from "../Map/DefaultIcon.svelte" export let entry: FilterSearchResult[] | LayerConfig let asFilter: FilterSearchResult[] @@ -41,7 +42,7 @@
{#if asLayer}
- +
diff --git a/src/UI/Search/GeocodeResult.svelte b/src/UI/Search/GeocodeResult.svelte index 2f3f6fc6f..3562ab02a 100644 --- a/src/UI/Search/GeocodeResult.svelte +++ b/src/UI/Search/GeocodeResult.svelte @@ -12,6 +12,7 @@ import Icon from "../Map/Icon.svelte" import TagRenderingAnswer from "../Popup/TagRendering/TagRenderingAnswer.svelte" import ArrowUp from "@babeard/svelte-heroicons/mini/ArrowUp" + import DefaultIcon from "../Map/DefaultIcon.svelte" export let entry: GeocodeResult export let state: SpecialVisualizationState @@ -62,9 +63,7 @@
{#if layer}
- layer.defaultIcon(entry.feature.properties)?.SetClass("w-6 h-6")} - /> +
{:else if entry.category} - {#if currentViewLayer?.tagRenderings && currentViewLayer.defaultIcon()} + {#if currentViewLayer?.tagRenderings && currentViewLayer.hasDefaultIcon()} { state.selectCurrentView() @@ -403,7 +404,7 @@ on:keydown={forwardEventToMap} >
- currentViewLayer.defaultIcon()} /> +
{/if}