diff --git a/Customizations/HelpText.ts b/Customizations/HelpText.ts index e0d3ddc..814a10d 100644 --- a/Customizations/HelpText.ts +++ b/Customizations/HelpText.ts @@ -23,6 +23,7 @@ export default class HelpText extends UIElement { ) )) .ListenTo(currentSetting) + .SetClass("small-button") .onClick(() => currentSetting.setData(undefined)); diff --git a/Customizations/JSON/FromJSON.ts b/Customizations/JSON/FromJSON.ts index 2e9c2f0..ef17b80 100644 --- a/Customizations/JSON/FromJSON.ts +++ b/Customizations/JSON/FromJSON.ts @@ -29,7 +29,6 @@ export class FromJSON { FromJSON.Layer(drinkingWater), FromJSON.Layer(ghostbikes), FromJSON.Layer(viewpoint), - ]; for (const layer of sharedLayersList) { @@ -44,7 +43,6 @@ export class FromJSON { } public static LayoutFromJSON(json: LayoutConfigJson): Layout { - console.log("Parsing ", json.id) const tr = FromJSON.Translation; const layers = json.layers.map(FromJSON.Layer); @@ -99,7 +97,7 @@ export class FromJSON { public static TagRenderingWithDefault(json: TagRenderingConfigJson | string, propertyName, defaultValue: string): TagDependantUIElementConstructor { if (json === undefined) { if(defaultValue !== undefined){ - console.warn(`Using default value ${defaultValue} for ${propertyName}`) + console.log(`Using default value ${defaultValue} for ${propertyName}`) return FromJSON.TagRendering(defaultValue); } throw `Tagrendering ${propertyName} is undefined...` @@ -138,7 +136,7 @@ export class FromJSON { let template = FromJSON.Translation(json.render); let freeform = undefined; - if (json.freeform?.key) { + if (json.freeform?.key && json.freeform.key !== "") { // Setup the freeform if (template === undefined) { console.error("Freeform.key is defined, but render is not. This is not allowed.", json) @@ -171,6 +169,7 @@ export class FromJSON { ); if(template === undefined && (mappings === undefined || mappings.length === 0)){ + console.error("Empty tagrendering detected: no mappings nor template given", json) throw "Empty tagrendering detected: no mappings nor template given" } @@ -182,7 +181,6 @@ export class FromJSON { }); if (json.condition) { - console.log("Applying confition ", json.condition) return rendering.OnlyShowIf(FromJSON.Tag(json.condition)); } @@ -205,7 +203,6 @@ export class FromJSON { if (split[1] === "*") { split[1] = ".*" } - console.log(split) return new RegexTag( split[0], new RegExp("^" + split[1] + "$"), @@ -244,16 +241,6 @@ export class FromJSON { } } - private static Title(json: string | Map | TagRenderingConfigJson): TagDependantUIElementConstructor { - if ((json as TagRenderingConfigJson).render !== undefined) { - return FromJSON.TagRendering((json as TagRenderingConfigJson)); - } else if (typeof (json) === "string") { - return new FixedText(Translations.WT(json)); - } else { - return new FixedText(FromJSON.Translation(json as Map)); - } - } - public static Layer(json: LayerConfigJson | string): LayerDefinition { if (typeof (json) === "string") { @@ -265,8 +252,7 @@ export class FromJSON { throw "Layer not yet loaded..." } - - console.log("Parsing ", json.name); + console.log("Parsing layer", json) const tr = FromJSON.Translation; const overpassTags = FromJSON.Tag(json.overpassTags); const icon = FromJSON.TagRenderingWithDefault(json.icon, "layericon", "./assets/bug.svg"); @@ -328,7 +314,7 @@ export class FromJSON { icon: icon.GetContent(renderTags).txt, overpassFilter: overpassTags, - title: FromJSON.Title(json.title), + title: FromJSON.TagRendering(json.title), minzoom: json.minzoom, presets: presets, elementsToShow: json.tagRenderings?.map(FromJSON.TagRendering) ?? [], diff --git a/Customizations/JSON/LayerConfigJson.ts b/Customizations/JSON/LayerConfigJson.ts index 566f3ac..b8f488b 100644 --- a/Customizations/JSON/LayerConfigJson.ts +++ b/Customizations/JSON/LayerConfigJson.ts @@ -39,7 +39,7 @@ export interface LayerConfigJson { /** * The title shown in a popup for elements of this layer */ - title: string | any | TagRenderingConfigJson; + title: string | TagRenderingConfigJson; /** * The icon for an element. diff --git a/Customizations/TagRendering.ts b/Customizations/TagRendering.ts index 57b4b58..8a204c1 100644 --- a/Customizations/TagRendering.ts +++ b/Customizations/TagRendering.ts @@ -348,6 +348,7 @@ TagRendering extends UIElement implements TagDependantUIElement { return false; } if (this._question === undefined || + this._question === "" || (this._freeform?.template === undefined && (this._mapping?.length ?? 0) == 0)) { // We don't ask this question in the first place return false; @@ -395,7 +396,6 @@ TagRendering extends UIElement implements TagDependantUIElement { } } - InnerRender(): string { if (this.IsQuestioning() @@ -408,7 +408,7 @@ TagRendering extends UIElement implements TagDependantUIElement { new Combine([ question.Render(), "
", - this._questionElement.Render(), + this._questionElement, "", @@ -434,28 +434,29 @@ TagRendering extends UIElement implements TagDependantUIElement { } if (this.IsKnown()) { - const html = this.RenderAnswer().Render(); - if (html === "") { + + const answer = this.RenderAnswer(); + if(answer.IsEmpty()){ return ""; } - - - let editButton = ""; + let editButton; if (State.state === undefined || // state undefined -> we are custom testing State.state?.osmConnection?.userDetails?.data?.loggedIn && this._question !== undefined) { - editButton = this._editButton.Render(); + editButton = this._editButton; } - return "" + - "" + html + "" + - editButton + - ""; + return new Combine([ + "", + "", + answer, + "", + editButton ?? "", + ""]).Render(); } console.log("No rendering for",this) return ""; - } diff --git a/UI/Base/PageSplit.ts b/UI/Base/PageSplit.ts index 96791c4..36e46b4 100644 --- a/UI/Base/PageSplit.ts +++ b/UI/Base/PageSplit.ts @@ -14,7 +14,7 @@ export default class PageSplit extends UIElement{ } InnerRender(): string { - return `${this._left.Render()}${this._right.Render()}`; + return `${this._left.Render()}${this._right.Render()}`; } } \ No newline at end of file diff --git a/UI/CustomGenerator/AllLayersPanel.ts b/UI/CustomGenerator/AllLayersPanel.ts index 89f6337..042405a 100644 --- a/UI/CustomGenerator/AllLayersPanel.ts +++ b/UI/CustomGenerator/AllLayersPanel.ts @@ -3,18 +3,9 @@ import {TabbedComponent} from "../Base/TabbedComponent"; import {SubtleButton} from "../Base/SubtleButton"; import {UIEventSource} from "../../Logic/UIEventSource"; import {LayoutConfigJson} from "../../Customizations/JSON/LayoutConfigJson"; -import LayerPanel from "./LayerPanel"; -import SingleSetting from "./SingleSetting"; import Combine from "../Base/Combine"; import {GenerateEmpty} from "./GenerateEmpty"; -import PageSplit from "../Base/PageSplit"; -import {VariableUiElement} from "../Base/VariableUIElement"; -import HelpText from "../../Customizations/HelpText"; -import {MultiTagInput} from "../Input/MultiTagInput"; -import {FromJSON} from "../../Customizations/JSON/FromJSON"; -import {TagRenderingConfigJson} from "../../Customizations/JSON/TagRenderingConfigJson"; -import {FixedUiElement} from "../Base/FixedUiElement"; -import TagRenderingPanel from "./TagRenderingPanel"; +import LayerPanelWithPreview from "./LayerPanelWithPreview"; export default class AllLayersPanel extends UIElement { @@ -42,72 +33,13 @@ export default class AllLayersPanel extends UIElement { const layers = this._config.data.layers; for (let i = 0; i < layers.length; i++) { - const currentlySelected = new UIEventSource<(SingleSetting)>(undefined); - const layer = new LayerPanel(this._config, this.languages, i, currentlySelected); - const helpText = new HelpText(currentlySelected); - - const previewTagInput = new MultiTagInput(); - previewTagInput.GetValue().setData(["id=123456"]); - const previewTagValue = previewTagInput.GetValue().map(tags => { - const properties = {}; - for (const str of tags) { - const tag = FromJSON.SimpleTag(str); - if (tag !== undefined) { - properties[tag.key] = tag.value; - } - } - return properties; - }); - - const preview = new VariableUiElement(layer.selectedTagRendering.map( - (tagRenderingPanel: TagRenderingPanel) => { - if (tagRenderingPanel === undefined) { - return "No tag rendering selected at the moment"; - } - - let es = tagRenderingPanel.GetValue(); - let tagRenderingConfig: TagRenderingConfigJson = es.data; - - let rendering: UIElement; - try { - rendering = FromJSON.TagRendering(tagRenderingConfig) - .construct({tags: previewTagValue}) - } catch (e) { - console.error("User defined tag rendering incorrect:", e); - rendering = new FixedUiElement(e).SetClass("alert"); - } - - return new Combine([ - "

", - tagRenderingPanel.options.title ?? "Extra tag rendering", - "

", - tagRenderingPanel.options.description ?? "This tag rendering will appear in the popup", - "
", - rendering]).Render(); - - }, - [this._config] - )).ListenTo(layer.selectedTagRendering); - + tabs.push({ header: "", - content: - new PageSplit( - layer.SetClass("scrollable"), - new Combine([ - helpText, - "
", - "

Testing tags

", - previewTagInput, - "

Tag Rendering preview

", - preview - - ]), 60 - ) - }); + content: new LayerPanelWithPreview(this._config, this.languages, i)}); } tabs.push({ - header: "", + header: "", content: new Combine([ "

Layer editor

", "In this tab page, you can add and edit the layers of the theme. Click the layers above or add a new layer to get started.", diff --git a/UI/CustomGenerator/GenerateEmpty.ts b/UI/CustomGenerator/GenerateEmpty.ts index 5a9c67c..d835be8 100644 --- a/UI/CustomGenerator/GenerateEmpty.ts +++ b/UI/CustomGenerator/GenerateEmpty.ts @@ -11,6 +11,7 @@ export class GenerateEmpty { overpassTags: {and: [""]}, title: undefined, description: {}, + tagRenderings: [] } } @@ -47,10 +48,10 @@ export class GenerateEmpty { socialImage: "", layers: [{ id: "testlayer", - name: "Testing layer", + name: {en:"Testing layer"}, minzoom: 15, overpassTags: {and: ["highway=residential"]}, - title: "Some Title", + title: {}, description: {"en": "Some Description"}, icon: {render: {en: "./assets/pencil.svg"}}, width: {render: {en: "5"}}, diff --git a/UI/CustomGenerator/LayerPanel.ts b/UI/CustomGenerator/LayerPanel.ts index fe2817e..d2a68d8 100644 --- a/UI/CustomGenerator/LayerPanel.ts +++ b/UI/CustomGenerator/LayerPanel.ts @@ -11,11 +11,9 @@ import MultiLingualTextFields from "../Input/MultiLingualTextFields"; import {CheckBox} from "../Input/CheckBox"; import {AndOrTagInput} from "../Input/AndOrTagInput"; import TagRenderingPanel from "./TagRenderingPanel"; -import {GenerateEmpty} from "./GenerateEmpty"; import {DropDown} from "../Input/DropDown"; import {TagRenderingConfigJson} from "../../Customizations/JSON/TagRenderingConfigJson"; import {MultiInput} from "../Input/MultiInput"; -import {Tag} from "../../Logic/Tags"; import {LayerConfigJson} from "../../Customizations/JSON/LayerConfigJson"; /** @@ -25,10 +23,12 @@ export default class LayerPanel extends UIElement { private readonly _config: UIEventSource; private readonly settingsTable: UIElement; - private readonly renderingOptions: UIElement; + private readonly mapRendering: UIElement; private readonly deleteButton: UIElement; + public readonly titleRendering: UIElement; + public readonly selectedTagRendering: UIEventSource = new UIEventSource(undefined); private tagRenderings: UIElement; @@ -39,7 +39,7 @@ export default class LayerPanel extends UIElement { currentlySelected: UIEventSource>) { super(); this._config = config; - this.renderingOptions = this.setupRenderOptions(config, languages, index, currentlySelected); + this.mapRendering = this.setupRenderOptions(config, languages, index, currentlySelected); const actualDeleteButton = new SubtleButton( "./assets/delete.svg", @@ -81,7 +81,7 @@ export default class LayerPanel extends UIElement { this.settingsTable = new SettingsTable([ setting(TextField.StringInput(), "id", "Id", "An identifier for this layer
This should be a simple, lowercase, human readable string that is used to identify the layer."), - setting(new MultiLingualTextFields(languages), "title", "Title", "The human-readable name of this layer
Used in the layer control panel and the 'Personal theme'"), + setting(new MultiLingualTextFields(languages), "name", "Name", "The human-readable name of this layer
Used in the layer control panel and the 'Personal theme'"), setting(new MultiLingualTextFields(languages, true), "description", "Description", "A description for this layer.
Shown in the layer selections and in the personal theme"), setting(TextField.NumberInput("nat", n => n < 23), "minzoom", "Minimal zoom", "The minimum zoomlevel needed to load and show this layer."), @@ -98,6 +98,16 @@ export default class LayerPanel extends UIElement { currentlySelected); const self = this; + const popupTitleRendering = new TagRenderingPanel(languages, currentlySelected, { + title: "Popup title", + description: "This is the rendering shown as title in the popup for this element", + disableQuestions: true + }); + + new SingleSetting(config, popupTitleRendering, ["layers", index, "title"], "Popup title", "This is the rendering shown as title in the popup"); + this.titleRendering = popupTitleRendering; + this.registerTagRendering(popupTitleRendering); + const tagRenderings = new MultiInput("Add a tag rendering/question", () => ({}), () => { @@ -192,10 +202,11 @@ export default class LayerPanel extends UIElement { return new Combine([ "

General layer settings

", this.settingsTable, - "

Map rendering options

", - this.renderingOptions, - "

Tag rendering and questions

", + "

Popup contents

", + this.titleRendering, this.tagRenderings, + "

Map rendering options

", + this.mapRendering, "

Layer delete

", this.deleteButton ]).Render(); diff --git a/UI/CustomGenerator/LayerPanelWithPreview.ts b/UI/CustomGenerator/LayerPanelWithPreview.ts new file mode 100644 index 0000000..7d1df5a --- /dev/null +++ b/UI/CustomGenerator/LayerPanelWithPreview.ts @@ -0,0 +1,62 @@ +import {UIElement} from "../UIElement"; +import {UIEventSource} from "../../Logic/UIEventSource"; +import SingleSetting from "./SingleSetting"; +import LayerPanel from "./LayerPanel"; +import HelpText from "../../Customizations/HelpText"; +import {MultiTagInput} from "../Input/MultiTagInput"; +import {FromJSON} from "../../Customizations/JSON/FromJSON"; +import {VariableUiElement} from "../Base/VariableUIElement"; +import TagRenderingPanel from "./TagRenderingPanel"; +import {TagRenderingConfigJson} from "../../Customizations/JSON/TagRenderingConfigJson"; +import {FixedUiElement} from "../Base/FixedUiElement"; +import Combine from "../Base/Combine"; +import PageSplit from "../Base/PageSplit"; +import TagRenderingPreview from "./TagRenderingPreview"; + + +export default class LayerPanelWithPreview extends UIElement{ + private panel: UIElement; + + constructor(config: UIEventSource, languages: UIEventSource, index: number) { + super(); + + const currentlySelected = new UIEventSource<(SingleSetting)>(undefined); + const layer = new LayerPanel(config, languages, index, currentlySelected); + const helpText = new HelpText(currentlySelected); + + const previewTagInput = new MultiTagInput(); + previewTagInput.GetValue().setData(["id=123456"]); + + const previewTagValue = previewTagInput.GetValue().map(tags => { + const properties = {}; + for (const str of tags) { + const tag = FromJSON.SimpleTag(str); + if (tag !== undefined) { + properties[tag.key] = tag.value; + } + } + return properties; + }); + + const preview = new TagRenderingPreview(layer.selectedTagRendering, previewTagValue); + + this.panel = new PageSplit( + layer.SetClass("scrollable"), + new Combine([ + helpText, + "
", + "

Testing tags

", + previewTagInput, + "

Tag Rendering preview

", + preview + + ]), 60 + ); + + } + + InnerRender(): string { + return this.panel.Render(); + } + +} \ No newline at end of file diff --git a/UI/CustomGenerator/TagRenderingPanel.ts b/UI/CustomGenerator/TagRenderingPanel.ts index 2f2b9bb..6937a95 100644 --- a/UI/CustomGenerator/TagRenderingPanel.ts +++ b/UI/CustomGenerator/TagRenderingPanel.ts @@ -56,7 +56,7 @@ export default class TagRenderingPanel extends InputElementNote that the Overpass-tags are already always included in this object"), "

Freeform key

", - setting(TextField.KeyInput(), ["freeform", "key"], "Freeform key
", + setting(TextField.KeyInput(true), ["freeform", "key"], "Freeform key
", "If specified, the rendering will search if this key is present." + "If it is, the rendering above will be used to display the element.
" + "The rendering will go into question mode if
  • this key is not present
  • No single mapping matches
  • A question is given
  • "), diff --git a/UI/CustomGenerator/TagRenderingPreview.ts b/UI/CustomGenerator/TagRenderingPreview.ts index 61c7163..8be7b24 100644 --- a/UI/CustomGenerator/TagRenderingPreview.ts +++ b/UI/CustomGenerator/TagRenderingPreview.ts @@ -1,15 +1,67 @@ import {UIElement} from "../UIElement"; import {UIEventSource} from "../../Logic/UIEventSource"; import TagRenderingPanel from "./TagRenderingPanel"; +import {VariableUiElement} from "../Base/VariableUIElement"; +import {TagRenderingConfigJson} from "../../Customizations/JSON/TagRenderingConfigJson"; +import {FromJSON} from "../../Customizations/JSON/FromJSON"; +import {FixedUiElement} from "../Base/FixedUiElement"; +import Combine from "../Base/Combine"; -export default class TagRenderingPreview extends UIElement{ - - constructor(selectedTagRendering: UIEventSource) { +export default class TagRenderingPreview extends UIElement { + + private readonly previewTagValue: UIEventSource; + private selectedTagRendering: UIEventSource; + private panel: UIElement; + + constructor(selectedTagRendering: UIEventSource, + previewTagValue: UIEventSource) { super(selectedTagRendering); + this.selectedTagRendering = selectedTagRendering; + this.previewTagValue = previewTagValue; + this.panel = this.GetPanel(undefined); + const self = this; + this.selectedTagRendering.addCallback(trp => { + self.panel = self.GetPanel(trp); + self.Update(); + }) + } - + + private GetPanel(tagRenderingPanel: TagRenderingPanel): UIElement { + if (tagRenderingPanel === undefined) { + return new FixedUiElement("No tag rendering selected at the moment. Hover over a tag rendering to see what it looks like"); + } + + let es = tagRenderingPanel.GetValue(); + let tagRenderingConfig: TagRenderingConfigJson = es.data; + + let rendering: UIElement; + try { + rendering = + new VariableUiElement(es.map(tagRenderingConfig => { + const tr = FromJSON.TagRendering(tagRenderingConfig) + .construct({tags: this.previewTagValue}); + return tr.Render(); + } + )); + + } catch (e) { + console.error("User defined tag rendering incorrect:", e); + rendering = new FixedUiElement(e).SetClass("alert"); + } + + return new Combine([ + "

    ", + tagRenderingPanel.options.title ?? "Extra tag rendering", + "

    ", + tagRenderingPanel.options.description ?? "This tag rendering will appear in the popup", + "

    ", + rendering]); + + } + InnerRender(): string { - return ""; + return this.panel.Render(); } - + } \ No newline at end of file diff --git a/UI/Input/InputElementWrapper.ts b/UI/Input/InputElementWrapper.ts index 7128a96..b01d2fa 100644 --- a/UI/Input/InputElementWrapper.ts +++ b/UI/Input/InputElementWrapper.ts @@ -1,6 +1,5 @@ import {InputElement} from "./InputElement"; import {UIElement} from "../UIElement"; -import {FixedUiElement} from "../Base/FixedUiElement"; import Translations from "../i18n/Translations"; import {UIEventSource} from "../../Logic/UIEventSource"; @@ -9,6 +8,9 @@ export class InputElementWrapper extends InputElement{ private input: InputElement; private post: UIElement ; + IsSelected: UIEventSource + + constructor( pre: UIElement | string, input: InputElement, @@ -21,6 +23,7 @@ export class InputElementWrapper extends InputElement{ this.input = input; // this.post =typeof(post) === 'string' ? new FixedUiElement(post) : post this.post = Translations.W(post) + this.IsSelected = input.IsSelected; } diff --git a/UI/Input/MultiTagInput.ts b/UI/Input/MultiTagInput.ts index 659534b..cae2f1d 100644 --- a/UI/Input/MultiTagInput.ts +++ b/UI/Input/MultiTagInput.ts @@ -3,7 +3,7 @@ import {UIEventSource} from "../../Logic/UIEventSource"; import {UIElement} from "../UIElement"; import Combine from "../Base/Combine"; import {SubtleButton} from "../Base/SubtleButton"; -import TagInput from "./TagInput"; +import TagInput from "./SingleTagInput"; import {FixedUiElement} from "../Base/FixedUiElement"; import {MultiInput} from "./MultiInput"; diff --git a/UI/Input/RadioButton.ts b/UI/Input/RadioButton.ts index 5d23dc3..196efed 100644 --- a/UI/Input/RadioButton.ts +++ b/UI/Input/RadioButton.ts @@ -1,5 +1,6 @@ import {InputElement} from "./InputElement"; import {UIEventSource} from "../../Logic/UIEventSource"; +import {Utils} from "../../Utils"; export class RadioButton extends InputElement { IsSelected: UIEventSource = new UIEventSource(false); @@ -15,7 +16,7 @@ export class RadioButton extends InputElement { constructor(elements: InputElement[], selectFirstAsDefault = true) { super(undefined); - this._elements = elements; + this._elements = Utils.NoNull(elements); this._selectFirstAsDefault = selectFirstAsDefault; const self = this; diff --git a/UI/Input/TagInput.ts b/UI/Input/SingleTagInput.ts similarity index 98% rename from UI/Input/TagInput.ts rename to UI/Input/SingleTagInput.ts index 8e1a127..d48860d 100644 --- a/UI/Input/TagInput.ts +++ b/UI/Input/SingleTagInput.ts @@ -23,7 +23,7 @@ export default class SingleTagInput extends InputElement { this.value = new TextField({ placeholder: "value - if blank, matches if key is NOT present", fromString: str => str, - toString: str => str + toString: str => str, } ); this.operator = new DropDown("", [ diff --git a/UI/Input/TextField.ts b/UI/Input/TextField.ts index 63a9383..dd50a0f 100644 --- a/UI/Input/TextField.ts +++ b/UI/Input/TextField.ts @@ -65,13 +65,17 @@ export class TextField extends InputElement { }); } - public static KeyInput(): TextField{ + public static KeyInput(allowEmpty : boolean = false): TextField{ return new TextField({ placeholder: "key", fromString: str => { if (str?.match(/^[a-zA-Z][a-zA-Z0-9:_-]*$/)) { return str; } + if(str === "" && allowEmpty){ + return ""; + } + return undefined }, toString: str => str diff --git a/assets/layers.svg b/assets/layers.svg index 8af7fc7..6eb851c 100644 --- a/assets/layers.svg +++ b/assets/layers.svg @@ -1,5 +1,66 @@ - - - - - \ No newline at end of file + + + + + + image/svg+xml + + + + + + + + + + diff --git a/assets/layers/drinking_water/drinking_water.json b/assets/layers/drinking_water/drinking_water.json index 2221d72..660ccb7 100644 --- a/assets/layers/drinking_water/drinking_water.json +++ b/assets/layers/drinking_water/drinking_water.json @@ -6,12 +6,12 @@ "fr": "Eau potable", "gl": "Auga potábel" }, - "title": { + "title":{"render": { "en": "Drinking water", "nl": "Drinkbaar water", "fr": "Eau potable", "gl": "Auga potábel" - }, + }}, "icon": "./assets/layers/drinking_water/drinking_water.svg", "iconSize": "40,40,bottom", "overpassTags": "amenity=drinking_water", diff --git a/assets/layers/viewpoint/viewpoint.json b/assets/layers/viewpoint/viewpoint.json index fd41dac..befeeeb 100644 --- a/assets/layers/viewpoint/viewpoint.json +++ b/assets/layers/viewpoint/viewpoint.json @@ -27,8 +27,10 @@ } ], "title": { - "en": "Viewpoint", - "nl": "Uitzicht" + "render": { + "en": "Viewpoint", + "nl": "Uitzicht" + } }, "tagRenderings": [ "images", diff --git a/assets/layersAdd.svg b/assets/layersAdd.svg new file mode 100644 index 0000000..927e6c8 --- /dev/null +++ b/assets/layersAdd.svg @@ -0,0 +1,300 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/themes/cyclestreets/F111.svg b/assets/themes/cyclestreets/F111.svg index 23d0369..0217385 100644 --- a/assets/themes/cyclestreets/F111.svg +++ b/assets/themes/cyclestreets/F111.svg @@ -1,2149 +1,668 @@ - - image/svg+xml + style="fill:#000000;fill-opacity:0.24709999;fill-rule:nonzero;stroke:none" + d="M 27,1171 H 718 V -2555 H 27 Z" /> + id="path5255" /> + stroke-miterlimit="3.863" + d="m -553.89264,417.08191 h 111.79767 c 9.3186,0 16.89994,-7.61127 16.89994,-17.02872 V 214.47252 c 0,-9.35087 -7.58134,-16.83543 -16.89994,-16.83543 h -111.92541 c -9.38034,0 -16.96382,7.61342 -16.96382,16.96645 l 0.066,185.44965 c 0,9.41745 7.64522,17.02872 17.02556,17.02872 z" + id="path5257" /> + d="m -430.65802,214.27924 c 0,-6.12724 -4.94352,-11.09261 -10.92173,-11.09261 h -112.95372 c -6.03995,0 -10.92174,4.96751 -10.92174,11.09261 v 186.22497 c 0,6.06282 4.88179,11.09476 10.92174,11.09476 35.40302,0 77.48682,0 112.95372,0 5.97821,0 10.92173,-4.96752 10.92173,-11.15704 z" + id="path5263" /> - - + + + stroke-miterlimit="3.863" + d="m -436.05715,214.21696 c 0,-3.09476 -2.56756,-5.54738 -5.5886,-5.54738 h -112.95371 c -3.01891,0 -5.46087,2.45262 -5.46087,5.54738 v 186.35167 c 0,3.03248 2.43982,5.54738 5.46087,5.54738 32.57571,0 80.50786,0 113.08358,0 3.01891,0 5.45873,-2.45047 5.45873,-5.54738 z" + id="path5269" /> @@ -2188,84 +707,69 @@