Merge branch 'develop' into develop

This commit is contained in:
Pieter Vander Vennet 2025-08-17 11:53:06 +00:00
commit 38c0287ff5
13 changed files with 194 additions and 27 deletions

View file

@ -12,10 +12,17 @@
"hidden" "hidden"
], ],
"render": { "render": {
"special": {
"type": "show_icons",
"labels": "diets_content",
"class": "inline-flex float-right"
},
"before": {
"en": "Dietary options", "en": "Dietary options",
"cs": "Dietní možnosti", "cs": "Dietní možnosti",
"nl": "Dieetopties" "nl": "Dieetopties"
} }
}
}, },
{ {
"id": "diets_group", "id": "diets_group",

View file

@ -131,7 +131,8 @@
}, },
"tags": [ "tags": [
"historic=locomotive" "historic=locomotive"
] ],
"snapToLayer": ["railway"]
}, },
{ {
"title": { "title": {
@ -144,7 +145,9 @@
}, },
"tags": [ "tags": [
"historic=railway_car" "historic=railway_car"
] ],
"snapToLayer": ["railway"]
}, },
{ {
"title": { "title": {
@ -157,7 +160,9 @@
}, },
"tags": [ "tags": [
"historic=minecart" "historic=minecart"
] ],
"snapToLayer": ["railway"]
} }
], ],
"tagRenderings": [ "tagRenderings": [

View file

@ -0,0 +1,66 @@
{
"id": "railway",
"name": {
"en": "Railway"
},
"description": {
"en": "Railways and disused railways"
},
"source": {
"osmTags": {
"or": [
"railway=rail",
"railway=tram",
"railway=subway",
"railway=light_rail",
"railway=disused",
"disused:railway=rail",
"disused:railway=tram",
"disused:railway=subway",
"disused:railway=light_rail",
"abandoned:railway=rail",
"abandoned:railway=tram",
"abandoned:railway=subway",
"abandoned:railway=light_rail"
]
}
},
"minzoom": 14,
"title": {
"render": {
"en": "Railway"
},
"icon": "./assets/svg/train.svg"
},
"pointRendering": [
{
"location": [
"point"
],
"marker": [
{
"icon": "circle"
}
]
}
],
"lineRendering": [
{
"width": 1,
"color": "black"
}
],
"tagRenderings": [
"images"
],
"allowMove": false,
"#": "In first instance to snap historic rolling stock",
"snapName": {
"en": "railway track"
},
"credits": "mnalis ALTernative",
"credits:uid": 172435
}

View file

@ -18,6 +18,14 @@
}, },
"icon": "./assets/layers/historic_rolling_stock/steam_locomotive.svg", "icon": "./assets/layers/historic_rolling_stock/steam_locomotive.svg",
"layers": [ "layers": [
"historic_rolling_stock" "historic_rolling_stock",
{
"builtin": "railway",
"override": {
"name": null,
"presets": null,
"shownByDefault": false
}
}
] ]
} }

View file

@ -4751,7 +4751,9 @@
"diets": { "diets": {
"tagRenderings": { "tagRenderings": {
"diets_title": { "diets_title": {
"render": "Dietní možnosti" "render": {
"before": "Dietní možnosti"
}
}, },
"gluten_free": { "gluten_free": {
"mappings": { "mappings": {

View file

@ -4768,7 +4768,9 @@
"diets": { "diets": {
"tagRenderings": { "tagRenderings": {
"diets_title": { "diets_title": {
"render": "Dietary options" "render": {
"before": "Dietary options"
}
}, },
"gluten_free": { "gluten_free": {
"mappings": { "mappings": {
@ -10092,6 +10094,14 @@
} }
} }
}, },
"railway": {
"description": "Railways and disused railways",
"name": "Railway",
"snapName": "railway track",
"title": {
"render": "Railway"
}
},
"railway_platforms": { "railway_platforms": {
"description": "Find every platform in the station, and the train routes that use them.", "description": "Find every platform in the station, and the train routes that use them.",
"name": "Railway Platforms", "name": "Railway Platforms",

View file

@ -4561,7 +4561,9 @@
"diets": { "diets": {
"tagRenderings": { "tagRenderings": {
"diets_title": { "diets_title": {
"render": "Dieetopties" "render": {
"before": "Dieetopties"
}
}, },
"gluten_free": { "gluten_free": {
"mappings": { "mappings": {

View file

@ -646,6 +646,13 @@
"grb-reference": { "grb-reference": {
"render": "Has been imported from GRB, reference number is {source:geometry:ref}" "render": "Has been imported from GRB, reference number is {source:geometry:ref}"
} }
},
"title": {
"mappings": {
"0": {
"then": "Building part"
}
}
} }
}, },
"1": { "1": {

View file

@ -37,15 +37,8 @@ import { Translatable } from "../src/Models/ThemeConfig/Json/Translatable"
import { ValidateThemeAndLayers } from "../src/Models/ThemeConfig/Conversion/ValidateThemeAndLayers" import { ValidateThemeAndLayers } from "../src/Models/ThemeConfig/Conversion/ValidateThemeAndLayers"
import { ExtractImages } from "../src/Models/ThemeConfig/Conversion/FixImages" import { ExtractImages } from "../src/Models/ThemeConfig/Conversion/FixImages"
import { TagRenderingConfigJson } from "../src/Models/ThemeConfig/Json/TagRenderingConfigJson" import { TagRenderingConfigJson } from "../src/Models/ThemeConfig/Json/TagRenderingConfigJson"
import {
LayerConfigDependencyGraph,
LevelInfo,
} from "../src/Models/ThemeConfig/LayerConfigDependencyGraph"
import { Lists } from "../src/Utils/Lists" import { Lists } from "../src/Utils/Lists"
import { import { LayerConfigDependencyGraph, LevelInfo } from "../src/Models/ThemeConfig/LayerConfigDependencyGraph"
LayerConfigDependencyGraph,
LevelInfo,
} from "../src/Models/ThemeConfig/LayerConfigDependencyGraph"
import { AddContextToTranslations } from "../src/Models/ThemeConfig/Conversion/AddContextToTranslations" import { AddContextToTranslations } from "../src/Models/ThemeConfig/Conversion/AddContextToTranslations"
// This scripts scans 'src/assets/layers/*.json' for layer definition files and 'src/assets/themes/*.json' for theme definition files. // This scripts scans 'src/assets/layers/*.json' for layer definition files and 'src/assets/themes/*.json' for theme definition files.
@ -121,7 +114,7 @@ class AddIconSummary extends DesugaringStep<{ raw: LayerConfigJson; parsed: Laye
static singleton = new AddIconSummary() static singleton = new AddIconSummary()
constructor() { constructor() {
super("AddIconSummary", "Adds an icon summary for quick reference") super("AddIconSummary", "Adds an icon summary ('_layerIcon') for quick reference. This previews how the layer should be shown in e.g. the filter menu")
} }
convert(json: { raw: LayerConfigJson; parsed: LayerConfig }) { convert(json: { raw: LayerConfigJson; parsed: LayerConfig }) {
@ -706,8 +699,8 @@ class LayerOverviewUtils extends Script {
) )
const path = "assets/layers/questions/questions.json" const path = "assets/layers/questions/questions.json"
const sharedQuestionsRaw = this.parseLayer(doesImageExist, prepareLayer, path).raw const sharedQuestionsRaw: LayerConfigJson = this.parseLayer(doesImageExist, prepareLayer, path).raw
const sharedQuestions = new AddContextToTranslations("").convertStrict( const sharedQuestions: LayerConfigJson = new AddContextToTranslations<LayerConfigJson>("").convertStrict(
sharedQuestionsRaw, sharedQuestionsRaw,
ConversionContext.construct(["layers:questions"], []) ConversionContext.construct(["layers:questions"], [])
) )

View file

@ -299,7 +299,7 @@ export interface LayerConfigJson {
/** /**
* Advanced option - might be set by the theme compiler * Advanced option - might be set by the theme compiler
* *
* If true, this data will _always_ be loaded, even if the theme is disabled by a filter or hidden. * If true, this data will _always_ be loaded, even if the layer is disabled by a filter or hidden.
* The opposite of `doNotDownload` * The opposite of `doNotDownload`
* *
* question: Should this layer be forcibly loaded? * question: Should this layer be forcibly loaded?

View file

@ -523,7 +523,9 @@ export default class TagRenderingConfig {
/** /**
* Gets all the render values. Will return multiple render values if 'multianswer' is enabled. * Gets all the render values. Will return multiple render values if 'multianswer' is enabled.
* The result will equal [GetRenderValue] if not 'multiAnswer' * The result will equal [GetRenderValue] if not 'multiAnswer'.
*
* If an iconsource is given, will return an icon too (but not necessarly an iconSize)
* @param tags * @param tags
* @constructor * @constructor
*/ */

View file

@ -1,4 +1,9 @@
import { SpecialVisualisationParams, SpecialVisualization, SpecialVisualizationSvelte } from "../SpecialVisualization" import {
SpecialVisualisationArg,
SpecialVisualisationParams,
SpecialVisualization,
SpecialVisualizationSvelte,
} from "../SpecialVisualization"
import { HistogramViz } from "./HistogramViz" import { HistogramViz } from "./HistogramViz"
import { Store } from "../../Logic/UIEventSource" import { Store } from "../../Logic/UIEventSource"
import BaseUIElement from "../BaseUIElement" import BaseUIElement from "../BaseUIElement"
@ -22,6 +27,9 @@ import TagRenderingEditable from "./TagRendering/TagRenderingEditable.svelte"
import AllTagsPanel from "./AllTagsPanel/AllTagsPanel.svelte" import AllTagsPanel from "./AllTagsPanel/AllTagsPanel.svelte"
import CollectionTimes from "../CollectionTimes/CollectionTimes.svelte" import CollectionTimes from "../CollectionTimes/CollectionTimes.svelte"
import Tr from "../Base/Tr.svelte" import Tr from "../Base/Tr.svelte"
import Combine from "../Base/Combine"
import Marker from "../Map/Marker.svelte"
import { twJoin } from "tailwind-merge"
class DirectionIndicatorVis extends SpecialVisualizationSvelte { class DirectionIndicatorVis extends SpecialVisualizationSvelte {
funcName = "direction_indicator" funcName = "direction_indicator"
@ -209,6 +217,7 @@ class PresetDescription extends SpecialVisualizationSvelte {
docs = docs =
"Shows the extra description from the presets of the layer, if one matches. It will pick the most specific one (e.g. if preset `A` implies `B`, but `B` does not imply `A`, it'll pick B) or the first one if no ordering can be made. Might be empty" "Shows the extra description from the presets of the layer, if one matches. It will pick the most specific one (e.g. if preset `A` implies `B`, but `B` does not imply `A`, it'll pick B) or the first one if no ordering can be made. Might be empty"
args = [] args = []
group = "UI"
constr({ state, tags }: SpecialVisualisationParams): SvelteUIElement { constr({ state, tags }: SpecialVisualisationParams): SvelteUIElement {
const translation = tags.map((tags) => { const translation = tags.map((tags) => {
@ -223,6 +232,7 @@ class PresetTypeSelect extends SpecialVisualizationSvelte {
funcName = "preset_type_select" funcName = "preset_type_select"
docs = "An editable tag rendering which allows to change the type" docs = "An editable tag rendering which allows to change the type"
args = [] args = []
group = "ui"
constr({ state, tags, feature, layer }: SpecialVisualisationParams,): SvelteUIElement { constr({ state, tags, feature, layer }: SpecialVisualisationParams,): SvelteUIElement {
const t = Translations.t.preset_type const t = Translations.t.preset_type
@ -294,6 +304,60 @@ class PointsInTimeVis extends SpecialVisualization {
} }
} }
class KnownIcons extends SpecialVisualization {
docs = "Displays all icons from the specified tagRenderings (if they are known and have an icon) together, e.g. to give a summary of the dietary options"
needsUrls = []
group = "UI"
funcName = "show_icons"
args: SpecialVisualisationArg[] = [{
name: "labels",
doc: "A ';'-separated list of labels and/or ids of tagRenderings",
type: "key",
required: true,
}, {
name: "class",
doc: "CSS-classes of the container, space-separated",
type: "css",
required: false,
defaultValue: "inline-flex mx-4",
}]
private static readonly emojiHeights = {
small: "2rem",
medium: "3rem",
large: "5rem",
}
constr(options: SpecialVisualisationParams): BaseUIElement {
const labels = new Set(options.args[0].split(";").map(s => s.trim()))
const matchingTrs = options.layer.tagRenderings.filter(
tr => labels.has(tr.id) || tr.labels.some(l => labels.has(l)),
)
return new VariableUiElement(options.tags.map(tags =>
new Combine(matchingTrs.map(tr => {
const mapping = tr.GetRenderValueWithImage(tags)
if (!mapping?.icon) {
return undefined
}
return new SvelteUIElement(Marker, {
emojiHeight: KnownIcons.emojiHeights[mapping.iconClass] ?? "2rem",
clss: `mapping-icon-${mapping.iconClass ?? "small"}`,
icons: mapping.icon,
size: twJoin(
"shrink-0",
`mapping-icon-${mapping.iconClass ?? "small"}-height mapping-icon-${
mapping.iconClass ?? "small"
}-width`),
})
})
).SetClass(options.args[1] ?? "inline-flex mx-4")
))
}
}
export class DataVisualisations { export class DataVisualisations {
public static initList(): SpecialVisualization[] { public static initList(): SpecialVisualization[] {
return [ return [
@ -309,6 +373,7 @@ export class DataVisualisations {
new PresetDescription(), new PresetDescription(),
new PresetTypeSelect(), new PresetTypeSelect(),
new AllTagsVis(), new AllTagsVis(),
new KnownIcons(),
] ]
} }
} }

View file

@ -213,7 +213,7 @@ class OpenInId extends SpecialVisualizationSvelte {
funcName = "open_in_iD" funcName = "open_in_iD"
docs = "Opens the current view in the iD-editor" docs = "Opens the current view in the iD-editor"
args = [] args = []
group = "tagrendering_manipulation" group = "web_and_communication"
constr({state, feature}: SpecialVisualisationParams): SvelteUIElement { constr({state, feature}: SpecialVisualisationParams): SvelteUIElement {
return new SvelteUIElement(OpenIdEditor, { return new SvelteUIElement(OpenIdEditor, {
@ -225,7 +225,7 @@ class OpenInId extends SpecialVisualizationSvelte {
class OpenInJosm extends SpecialVisualizationSvelte { class OpenInJosm extends SpecialVisualizationSvelte {
funcName = "open_in_josm" funcName = "open_in_josm"
group = "tagrendering_manipulation" group = "web_and_communication"
docs = "Opens the current view in the JOSM-editor" docs = "Opens the current view in the JOSM-editor"
args = [] args = []
needsUrls = [ needsUrls = [