More work on the custom theme generator, kindof works now

This commit is contained in:
Pieter Vander Vennet 2020-09-03 00:00:37 +02:00
parent 1fa6a8edfb
commit ee9c9e201f
24 changed files with 1192 additions and 2265 deletions

View file

@ -23,6 +23,7 @@ export default class HelpText extends UIElement {
)
))
.ListenTo(currentSetting)
.SetClass("small-button")
.onClick(() => currentSetting.setData(undefined));

View file

@ -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<string, string> | 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<string, string>));
}
}
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) ?? [],

View file

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

View file

@ -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(),
"<br/>",
this._questionElement.Render(),
this._questionElement,
"<span class='login-button-friendly'>",
this._friendlyLogin,
"</span>",
@ -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 "<span class='answer'>" +
"<span class='answer-text'>" + html + "</span>" +
editButton +
"</span>";
return new Combine([
"<span class='answer'>",
"<span class='answer-text'>",
answer,
"</span>",
editButton ?? "",
"</span>"]).Render();
}
console.log("No rendering for",this)
return "";
}

View file

@ -14,7 +14,7 @@ export default class PageSplit extends UIElement{
}
InnerRender(): string {
return `<span class="page-split" style="height: min-content"><span style="width:${this._leftPercentage}%">${this._left.Render()}</span><span style="width:${100-this._leftPercentage}">${this._right.Render()}</span></span>`;
return `<span class="page-split" style="height: min-content"><span style="flex:0 0 ${this._leftPercentage}%">${this._left.Render()}</span><span style="flex: 0 0 ${100-this._leftPercentage}%">${this._right.Render()}</span></span>`;
}
}

View file

@ -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<any>)>(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([
"<h3>",
tagRenderingPanel.options.title ?? "Extra tag rendering",
"</h3>",
tagRenderingPanel.options.description ?? "This tag rendering will appear in the popup",
"<br/>",
rendering]).Render();
},
[this._config]
)).ListenTo(layer.selectedTagRendering);
tabs.push({
header: "<img src='./assets/bug.svg'>",
content:
new PageSplit(
layer.SetClass("scrollable"),
new Combine([
helpText,
"</br>",
"<h2>Testing tags</h2>",
previewTagInput,
"<h2>Tag Rendering preview</h2>",
preview
]), 60
)
});
content: new LayerPanelWithPreview(this._config, this.languages, i)});
}
tabs.push({
header: "<img src='./assets/add.svg'>",
header: "<img src='./assets/layersAdd.svg'>",
content: new Combine([
"<h2>Layer editor</h2>",
"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.",

View file

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

View file

@ -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<LayoutConfigJson>;
private readonly settingsTable: UIElement;
private readonly renderingOptions: UIElement;
private readonly mapRendering: UIElement;
private readonly deleteButton: UIElement;
public readonly titleRendering: UIElement;
public readonly selectedTagRendering: UIEventSource<TagRenderingPanel>
= new UIEventSource<TagRenderingPanel>(undefined);
private tagRenderings: UIElement;
@ -39,7 +39,7 @@ export default class LayerPanel extends UIElement {
currentlySelected: UIEventSource<SingleSetting<any>>) {
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<br/>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<br/>Used in the layer control panel and the 'Personal theme'"),
setting(new MultiLingualTextFields(languages), "name", "Name", "The human-readable name of this layer<br/>Used in the layer control panel and the 'Personal theme'"),
setting(new MultiLingualTextFields(languages, true), "description", "Description", "A description for this layer.<br/>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<TagRenderingConfigJson>("Add a tag rendering/question",
() => ({}),
() => {
@ -192,10 +202,11 @@ export default class LayerPanel extends UIElement {
return new Combine([
"<h2>General layer settings</h2>",
this.settingsTable,
"<h2>Map rendering options</h2>",
this.renderingOptions,
"<h2>Tag rendering and questions</h2>",
"<h2>Popup contents</h2>",
this.titleRendering,
this.tagRenderings,
"<h2>Map rendering options</h2>",
this.mapRendering,
"<h2>Layer delete</h2>",
this.deleteButton
]).Render();

View file

@ -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<any>, languages: UIEventSource<string[]>, index: number) {
super();
const currentlySelected = new UIEventSource<(SingleSetting<any>)>(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,
"</br>",
"<h2>Testing tags</h2>",
previewTagInput,
"<h2>Tag Rendering preview</h2>",
preview
]), 60
);
}
InnerRender(): string {
return this.panel.Render();
}
}

View file

@ -56,7 +56,7 @@ export default class TagRenderingPanel extends InputElement<TagRenderingConfigJs
"Only show this tag rendering if these tags matches. Optional field.<br/>Note that the Overpass-tags are already always included in this object"),
"<h3>Freeform key</h3>",
setting(TextField.KeyInput(), ["freeform", "key"], "Freeform key<br/>",
setting(TextField.KeyInput(true), ["freeform", "key"], "Freeform key<br/>",
"If specified, the rendering will search if this key is present." +
"If it is, the rendering above will be used to display the element.<br/>" +
"The rendering will go into question mode if <ul><li>this key is not present</li><li>No single mapping matches</li><li>A question is given</li>"),

View file

@ -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<TagRenderingPanel>) {
export default class TagRenderingPreview extends UIElement {
private readonly previewTagValue: UIEventSource<any>;
private selectedTagRendering: UIEventSource<TagRenderingPanel>;
private panel: UIElement;
constructor(selectedTagRendering: UIEventSource<TagRenderingPanel>,
previewTagValue: UIEventSource<any>) {
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([
"<h3>",
tagRenderingPanel.options.title ?? "Extra tag rendering",
"</h3>",
tagRenderingPanel.options.description ?? "This tag rendering will appear in the popup",
"<br/><br/>",
rendering]);
}
InnerRender(): string {
return "";
return this.panel.Render();
}
}

View file

@ -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<T> extends InputElement<T>{
private input: InputElement<T>;
private post: UIElement ;
IsSelected: UIEventSource<boolean>
constructor(
pre: UIElement | string,
input: InputElement<T>,
@ -21,6 +23,7 @@ export class InputElementWrapper<T> extends InputElement<T>{
this.input = input;
// this.post =typeof(post) === 'string' ? new FixedUiElement(post) : post
this.post = Translations.W(post)
this.IsSelected = input.IsSelected;
}

View file

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

View file

@ -1,5 +1,6 @@
import {InputElement} from "./InputElement";
import {UIEventSource} from "../../Logic/UIEventSource";
import {Utils} from "../../Utils";
export class RadioButton<T> extends InputElement<T> {
IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false);
@ -15,7 +16,7 @@ export class RadioButton<T> extends InputElement<T> {
constructor(elements: InputElement<T>[],
selectFirstAsDefault = true) {
super(undefined);
this._elements = elements;
this._elements = Utils.NoNull(elements);
this._selectFirstAsDefault = selectFirstAsDefault;
const self = this;

View file

@ -23,7 +23,7 @@ export default class SingleTagInput extends InputElement<string> {
this.value = new TextField<string>({
placeholder: "value - if blank, matches if key is NOT present",
fromString: str => str,
toString: str => str
toString: str => str,
}
);
this.operator = new DropDown<string>("", [

View file

@ -65,13 +65,17 @@ export class TextField<T> extends InputElement<T> {
});
}
public static KeyInput(): TextField<string>{
public static KeyInput(allowEmpty : boolean = false): TextField<string>{
return new TextField<string>({
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

View file

@ -1,5 +1,66 @@
<svg width="27" height="27" viewBox="0 0 27 27" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M26.5353 8.13481C26.4422 8.35428 26.2683 8.47598 26.0632 8.58537C21.9977 10.7452 17.935 12.9085 13.8758 15.0799C13.6475 15.2016 13.4831 15.1962 13.2568 15.0751C9.19822 12.903 5.13484 10.7404 1.07215 8.5758C0.490599 8.26608 0.448478 7.52562 0.991303 7.13796C1.0803 7.07438 1.17813 7.0231 1.2746 6.97045C5.15862 4.86462 9.04536 2.7629 12.9246 0.648187C13.3805 0.399316 13.7779 0.406837 14.2311 0.65434C18.0954 2.76153 21.9658 4.85779 25.8383 6.94926C26.1569 7.12155 26.411 7.32872 26.5353 7.67604C26.5353 7.82919 26.5353 7.98166 26.5353 8.13481Z" fill="#003B8B"/>
<path d="M13.318 26.535C12.1576 25.9046 10.9972 25.2736 9.83614 24.6439C6.96644 23.0877 4.09674 21.533 1.22704 19.9762C0.694401 19.6876 0.466129 19.2343 0.669943 18.7722C0.759621 18.5691 0.931505 18.3653 1.11969 18.2512C1.66659 17.9182 2.23727 17.6228 2.80863 17.3329C2.89423 17.2892 3.04981 17.3206 3.14493 17.3712C6.40799 19.1031 9.66969 20.837 12.9239 22.5845C13.3703 22.8238 13.7609 22.83 14.208 22.59C17.4554 20.8472 20.7117 19.1202 23.9605 17.3801C24.1493 17.2789 24.2838 17.283 24.4632 17.3876C24.8926 17.6386 25.3301 17.8772 25.7751 18.1001C26.11 18.2683 26.3838 18.4857 26.5346 18.8385C26.5346 18.9916 26.5346 19.1441 26.5346 19.2972C26.4049 19.6528 26.1399 19.8613 25.8152 20.0363C22.9964 21.5549 20.1831 23.0829 17.3684 24.609C16.1863 25.2496 15.0055 25.893 13.8248 26.535C13.6556 26.535 13.4865 26.535 13.318 26.535Z" fill="#003B8B"/>
<path d="M26.3988 13.7412C26.2956 13.9661 26.1026 14.081 25.8927 14.1924C21.8198 16.3577 17.749 18.5258 13.6815 20.7013C13.492 20.8025 13.3602 20.7902 13.1795 20.6938C9.09638 18.5114 5.01059 16.3359 0.924798 14.1582C0.399637 13.8786 0.307921 13.2646 0.735251 12.838C0.829005 12.7443 0.947217 12.6705 1.06407 12.6055C1.56545 12.3279 2.07635 12.0654 2.57297 11.7789C2.74214 11.6812 2.86579 11.6921 3.03291 11.7817C6.27492 13.5155 9.52303 15.2378 12.761 16.9792C13.2352 17.2343 13.6394 17.2322 14.1129 16.9772C17.3509 15.2358 20.5996 13.5142 23.8416 11.7796C24.0095 11.69 24.1338 11.6818 24.3016 11.7789C24.7384 12.0339 25.1821 12.2794 25.6352 12.5037C25.9701 12.6691 26.2426 12.8831 26.3995 13.2304C26.3988 13.4014 26.3988 13.5716 26.3988 13.7412Z" fill="#003B8B"/>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="27"
height="27"
viewBox="0 0 27 27"
fill="none"
version="1.1"
id="svg8"
sodipodi:docname="layers.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata14">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs12" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1680"
inkscape:window-height="1013"
id="namedview10"
showgrid="false"
inkscape:zoom="12.361274"
inkscape:cx="13.100126"
inkscape:cy="2.3570853"
inkscape:window-x="1560"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" />
<path
d="M26.5353 8.13481C26.4422 8.35428 26.2683 8.47598 26.0632 8.58537C21.9977 10.7452 17.935 12.9085 13.8758 15.0799C13.6475 15.2016 13.4831 15.1962 13.2568 15.0751C9.19822 12.903 5.13484 10.7404 1.07215 8.5758C0.490599 8.26608 0.448478 7.52562 0.991303 7.13796C1.0803 7.07438 1.17813 7.0231 1.2746 6.97045C5.15862 4.86462 9.04536 2.7629 12.9246 0.648187C13.3805 0.399316 13.7779 0.406837 14.2311 0.65434C18.0954 2.76153 21.9658 4.85779 25.8383 6.94926C26.1569 7.12155 26.411 7.32872 26.5353 7.67604C26.5353 7.82919 26.5353 7.98166 26.5353 8.13481Z"
fill="#003B8B"
id="path2"
style="fill:#030000;fill-opacity:1" />
<path
d="M13.318 26.535C12.1576 25.9046 10.9972 25.2736 9.83614 24.6439C6.96644 23.0877 4.09674 21.533 1.22704 19.9762C0.694401 19.6876 0.466129 19.2343 0.669943 18.7722C0.759621 18.5691 0.931505 18.3653 1.11969 18.2512C1.66659 17.9182 2.23727 17.6228 2.80863 17.3329C2.89423 17.2892 3.04981 17.3206 3.14493 17.3712C6.40799 19.1031 9.66969 20.837 12.9239 22.5845C13.3703 22.8238 13.7609 22.83 14.208 22.59C17.4554 20.8472 20.7117 19.1202 23.9605 17.3801C24.1493 17.2789 24.2838 17.283 24.4632 17.3876C24.8926 17.6386 25.3301 17.8772 25.7751 18.1001C26.11 18.2683 26.3838 18.4857 26.5346 18.8385C26.5346 18.9916 26.5346 19.1441 26.5346 19.2972C26.4049 19.6528 26.1399 19.8613 25.8152 20.0363C22.9964 21.5549 20.1831 23.0829 17.3684 24.609C16.1863 25.2496 15.0055 25.893 13.8248 26.535C13.6556 26.535 13.4865 26.535 13.318 26.535Z"
fill="#003B8B"
id="path4"
style="fill:#030000;fill-opacity:1" />
<path
d="M26.3988 13.7412C26.2956 13.9661 26.1026 14.081 25.8927 14.1924C21.8198 16.3577 17.749 18.5258 13.6815 20.7013C13.492 20.8025 13.3602 20.7902 13.1795 20.6938C9.09638 18.5114 5.01059 16.3359 0.924798 14.1582C0.399637 13.8786 0.307921 13.2646 0.735251 12.838C0.829005 12.7443 0.947217 12.6705 1.06407 12.6055C1.56545 12.3279 2.07635 12.0654 2.57297 11.7789C2.74214 11.6812 2.86579 11.6921 3.03291 11.7817C6.27492 13.5155 9.52303 15.2378 12.761 16.9792C13.2352 17.2343 13.6394 17.2322 14.1129 16.9772C17.3509 15.2358 20.5996 13.5142 23.8416 11.7796C24.0095 11.69 24.1338 11.6818 24.3016 11.7789C24.7384 12.0339 25.1821 12.2794 25.6352 12.5037C25.9701 12.6691 26.2426 12.8831 26.3995 13.2304C26.3988 13.4014 26.3988 13.5716 26.3988 13.7412Z"
fill="#003B8B"
id="path6"
style="fill:#030000;fill-opacity:1" />
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

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

View file

@ -27,8 +27,10 @@
}
],
"title": {
"en": "Viewpoint",
"nl": "Uitzicht"
"render": {
"en": "Viewpoint",
"nl": "Uitzicht"
}
},
"tagRenderings": [
"images",

300
assets/layersAdd.svg Normal file
View file

@ -0,0 +1,300 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="27"
height="27"
viewBox="0 0 27 27"
fill="none"
version="1.1"
id="svg8"
sodipodi:docname="layersAdd.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata14">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs12">
<filter
style="color-interpolation-filters:sRGB"
filterUnits="userSpaceOnUse"
height="17.436001"
width="25.4126"
y="52.703999"
x="58.84"
id="filter0_d">
<feFlood
id="feFlood52"
result="BackgroundImageFix"
flood-opacity="0" />
<feColorMatrix
id="feColorMatrix54"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
type="matrix"
in="SourceAlpha" />
<feOffset
id="feOffset56"
dy="4" />
<feGaussianBlur
id="feGaussianBlur58"
stdDeviation="2" />
<feColorMatrix
id="feColorMatrix60"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"
type="matrix" />
<feBlend
id="feBlend62"
result="effect1_dropShadow"
in2="BackgroundImageFix"
mode="normal" />
<feBlend
id="feBlend64"
result="shape"
in2="effect1_dropShadow"
in="SourceGraphic"
mode="normal" />
</filter>
<filter
style="color-interpolation-filters:sRGB"
filterUnits="userSpaceOnUse"
height="38"
width="38.000099"
y="15"
x="14"
id="filter1_d">
<feFlood
id="feFlood67"
result="BackgroundImageFix"
flood-opacity="0" />
<feColorMatrix
id="feColorMatrix69"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
type="matrix"
in="SourceAlpha" />
<feOffset
id="feOffset71"
dy="4" />
<feGaussianBlur
id="feGaussianBlur73"
stdDeviation="2" />
<feColorMatrix
id="feColorMatrix75"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"
type="matrix" />
<feBlend
id="feBlend77"
result="effect1_dropShadow"
in2="BackgroundImageFix"
mode="normal" />
<feBlend
id="feBlend79"
result="shape"
in2="effect1_dropShadow"
in="SourceGraphic"
mode="normal" />
</filter>
<filter
style="color-interpolation-filters:sRGB"
filterUnits="userSpaceOnUse"
height="53"
width="53"
y="7"
x="39.5"
id="filter2_d">
<feFlood
id="feFlood82"
result="BackgroundImageFix"
flood-opacity="0" />
<feColorMatrix
id="feColorMatrix84"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
type="matrix"
in="SourceAlpha" />
<feOffset
id="feOffset86"
dy="4" />
<feGaussianBlur
id="feGaussianBlur88"
stdDeviation="2" />
<feColorMatrix
id="feColorMatrix90"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"
type="matrix" />
<feBlend
id="feBlend92"
result="effect1_dropShadow"
in2="BackgroundImageFix"
mode="normal" />
<feBlend
id="feBlend94"
result="shape"
in2="effect1_dropShadow"
in="SourceGraphic"
mode="normal" />
</filter>
<filter
style="color-interpolation-filters:sRGB"
filterUnits="userSpaceOnUse"
height="38.142899"
width="54.766701"
y="54"
x="11"
id="filter3_d">
<feFlood
id="feFlood97"
result="BackgroundImageFix"
flood-opacity="0" />
<feColorMatrix
id="feColorMatrix99"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
type="matrix"
in="SourceAlpha" />
<feOffset
id="feOffset101"
dy="4" />
<feGaussianBlur
id="feGaussianBlur103"
stdDeviation="2" />
<feColorMatrix
id="feColorMatrix105"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"
type="matrix" />
<feBlend
id="feBlend107"
result="effect1_dropShadow"
in2="BackgroundImageFix"
mode="normal" />
<feBlend
id="feBlend109"
result="shape"
in2="effect1_dropShadow"
in="SourceGraphic"
mode="normal" />
</filter>
<filter
style="color-interpolation-filters:sRGB"
filterUnits="userSpaceOnUse"
height="29"
width="28"
y="64"
x="41"
id="filter4_d">
<feFlood
id="feFlood112"
result="BackgroundImageFix"
flood-opacity="0" />
<feColorMatrix
id="feColorMatrix114"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
type="matrix"
in="SourceAlpha" />
<feOffset
id="feOffset116"
dy="4" />
<feGaussianBlur
id="feGaussianBlur118"
stdDeviation="2" />
<feColorMatrix
id="feColorMatrix120"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"
type="matrix" />
<feBlend
id="feBlend122"
result="effect1_dropShadow"
in2="BackgroundImageFix"
mode="normal" />
<feBlend
id="feBlend124"
result="shape"
in2="effect1_dropShadow"
in="SourceGraphic"
mode="normal" />
</filter>
<clipPath
id="clip0">
<rect
style="fill:#ffffff"
y="0"
x="0"
id="rect127"
transform="rotate(-45,57.35965,-37.759145)"
height="31.819799"
width="31.819799" />
</clipPath>
</defs>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1680"
inkscape:window-height="1013"
id="namedview10"
showgrid="false"
inkscape:zoom="12.361274"
inkscape:cx="10.353576"
inkscape:cy="3.3905227"
inkscape:window-x="1560"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" />
<path
d="M26.5353 8.13481C26.4422 8.35428 26.2683 8.47598 26.0632 8.58537C21.9977 10.7452 17.935 12.9085 13.8758 15.0799C13.6475 15.2016 13.4831 15.1962 13.2568 15.0751C9.19822 12.903 5.13484 10.7404 1.07215 8.5758C0.490599 8.26608 0.448478 7.52562 0.991303 7.13796C1.0803 7.07438 1.17813 7.0231 1.2746 6.97045C5.15862 4.86462 9.04536 2.7629 12.9246 0.648187C13.3805 0.399316 13.7779 0.406837 14.2311 0.65434C18.0954 2.76153 21.9658 4.85779 25.8383 6.94926C26.1569 7.12155 26.411 7.32872 26.5353 7.67604C26.5353 7.82919 26.5353 7.98166 26.5353 8.13481Z"
fill="#003B8B"
id="path2"
style="fill:#030000;fill-opacity:1" />
<path
d="M13.318 26.535C12.1576 25.9046 10.9972 25.2736 9.83614 24.6439C6.96644 23.0877 4.09674 21.533 1.22704 19.9762C0.694401 19.6876 0.466129 19.2343 0.669943 18.7722C0.759621 18.5691 0.931505 18.3653 1.11969 18.2512C1.66659 17.9182 2.23727 17.6228 2.80863 17.3329C2.89423 17.2892 3.04981 17.3206 3.14493 17.3712C6.40799 19.1031 9.66969 20.837 12.9239 22.5845C13.3703 22.8238 13.7609 22.83 14.208 22.59C17.4554 20.8472 20.7117 19.1202 23.9605 17.3801C24.1493 17.2789 24.2838 17.283 24.4632 17.3876C24.8926 17.6386 25.3301 17.8772 25.7751 18.1001C26.11 18.2683 26.3838 18.4857 26.5346 18.8385C26.5346 18.9916 26.5346 19.1441 26.5346 19.2972C26.4049 19.6528 26.1399 19.8613 25.8152 20.0363C22.9964 21.5549 20.1831 23.0829 17.3684 24.609C16.1863 25.2496 15.0055 25.893 13.8248 26.535C13.6556 26.535 13.4865 26.535 13.318 26.535Z"
fill="#003B8B"
id="path4"
style="fill:#030000;fill-opacity:1" />
<path
d="M26.3988 13.7412C26.2956 13.9661 26.1026 14.081 25.8927 14.1924C21.8198 16.3577 17.749 18.5258 13.6815 20.7013C13.492 20.8025 13.3602 20.7902 13.1795 20.6938C9.09638 18.5114 5.01059 16.3359 0.924798 14.1582C0.399637 13.8786 0.307921 13.2646 0.735251 12.838C0.829005 12.7443 0.947217 12.6705 1.06407 12.6055C1.56545 12.3279 2.07635 12.0654 2.57297 11.7789C2.74214 11.6812 2.86579 11.6921 3.03291 11.7817C6.27492 13.5155 9.52303 15.2378 12.761 16.9792C13.2352 17.2343 13.6394 17.2322 14.1129 16.9772C17.3509 15.2358 20.5996 13.5142 23.8416 11.7796C24.0095 11.69 24.1338 11.6818 24.3016 11.7789C24.7384 12.0339 25.1821 12.2794 25.6352 12.5037C25.9701 12.6691 26.2426 12.8831 26.3995 13.2304C26.3988 13.4014 26.3988 13.5716 26.3988 13.7412Z"
fill="#003B8B"
id="path6"
style="fill:#030000;fill-opacity:1" />
<g
style="fill:none"
id="g937"
transform="matrix(0.10434568,0,0,0.10434568,16.419348,16.024978)">
<circle
style="fill:#70c549"
id="circle4"
r="49"
cy="49.02142"
cx="48.999996" />
<g
inkscape:label="Layer 1"
id="layer1"
transform="matrix(1.5647038,-1.5647038,1.5647038,1.5647038,-416.27812,-373.23804)">
<path
style="fill:none;stroke:#ffffff;stroke-width:7.51411438;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 22.100902,291.35894 5.785709,275.04375 v 0"
id="path815"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#ffffff;stroke-width:7.51411438;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 22.125504,274.96508 5.8103071,291.28027 v 0"
id="path815-3"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because it is too large Load diff

Before

Width:  |  Height:  |  Size: 122 KiB

After

Width:  |  Height:  |  Size: 60 KiB

View file

@ -3,9 +3,6 @@ import {UIElement} from "./UI/UIElement";
UIElement.runningFromConsole = true;
import {TagRendering} from "./Customizations/TagRendering";
TagRendering.injectFunction();
import {AllKnownLayouts} from "./Customizations/AllKnownLayouts";
import {Layout} from "./Customizations/Layout";
import {readFileSync, writeFile, writeFileSync} from "fs";
@ -13,7 +10,8 @@ import Locale from "./UI/i18n/Locale";
import svg2img from 'promise-svg2img';
import Translation from "./UI/i18n/Translation";
import Translations from "./UI/i18n/Translations";
import {TagRenderingOptions} from "./Customizations/TagRenderingOptions";
TagRendering.injectFunction();
console.log("Building the layouts")
@ -24,7 +22,7 @@ function enc(str: string): string {
}
function validate(layout: Layout) {
console.log("Validationg ", layout.name)
console.log("Validationg ", layout.id)
const translations: Translation[] = [];
const queue: any[] = [layout]
@ -61,7 +59,7 @@ function validate(layout: Layout) {
}
}
console.log("Translation completenes for", layout.name);
console.log("Translation completenes for", layout.id);
for (const ln of layout.supportedLanguages) {
const amiss = missing[ln];
const ok = present[ln];
@ -109,7 +107,7 @@ function createIcon(iconPath: string, size: number) {
}
function createManifest(layout: Layout, relativePath: string) {
const name = layout.name;
const name = layout.id;
const icons = [];
@ -133,7 +131,7 @@ function createManifest(layout: Layout, relativePath: string) {
})
} else {
throw "Icon is not an svg for " + layout.name
throw "Icon is not an svg for " + layout.id
}
const ogTitle = Translations.W(layout.title).InnerRender();
const ogDescr = Translations.W(layout.description ?? "").InnerRender();
@ -141,7 +139,7 @@ function createManifest(layout: Layout, relativePath: string) {
const manif = {
name: name,
short_name: ogTitle,
start_url: `${relativePath}/${layout.name.toLowerCase()}.html`,
start_url: `${relativePath}/${layout.id.toLowerCase()}.html`,
display: "standalone",
background_color: "#fff",
description: ogDescr,
@ -156,17 +154,17 @@ function createLandingPage(layout: Layout) {
Locale.language.setData(layout.supportedLanguages[0]);
const ogTitle = Translations.W(layout.title).InnerRender();
const ogDescr = Translations.W(layout.description ?? "").InnerRender();
const ogTitle = Translations.W(layout.title)?.InnerRender();
const ogDescr = Translations.W(layout.description ?? "Easily add and edit geodata with OpenStreetMap")?.InnerRender();
const ogImage = layout.socialImage;
const og = `
<meta property="og:image" content="${ogImage}">
<meta property="og:image" content="${ogImage ?? './assets/add.svg'}">
<meta property="og:title" content="${ogTitle}">
<meta property="og:description" content="${ogDescr}">`
let output = template
.replace(`./manifest.manifest`, `./${enc(layout.name)}.webmanifest`)
.replace(`./manifest.manifest`, `./${enc(layout.id)}.webmanifest`)
.replace("<!-- $$$OG-META -->", og)
.replace(`<link rel="icon" href="assets/add.svg" sizes="any" type="image/svg+xml">`,
`<link rel="icon" href="${layout.icon}" sizes="any" type="image/svg+xml">`);
@ -199,12 +197,12 @@ for (const layoutName in all) {
console.log("Generating manifest")
const manif = JSON.stringify(createManifest(layout, "/MapComplete"));
const manifestLocation = encodeURIComponent(layout.name.toLowerCase()) + ".webmanifest";
const manifestLocation = encodeURIComponent(layout.id.toLowerCase()) + ".webmanifest";
writeFile(manifestLocation, manif, err);
const landing = createLandingPage(layout);
console.log("Generating html-file for ", layout.name)
writeFile(enc(layout.name) + ".html", landing, err)
console.log("Generating html-file for ", layout.id)
writeFile(enc(layout.id) + ".html", landing, err)
console.log("done")
}

View file

@ -10,9 +10,15 @@ import {GenerateEmpty} from "./UI/CustomGenerator/GenerateEmpty";
import PageSplit from "./UI/Base/PageSplit";
import HelpText from "./Customizations/HelpText";
import {TagRendering} from "./Customizations/TagRendering";
import {FromJSON} from "./Customizations/JSON/FromJSON";
import {LayoutConfigJson} from "./Customizations/JSON/LayoutConfigJson";
const es = new UIEventSource(GenerateEmpty.createTestLayout());
let layout = GenerateEmpty.createTestLayout();
if(window.location.hash.length > 10){
layout = JSON.parse(atob(window.location.hash.substr(1))) as LayoutConfigJson;
}
const es = new UIEventSource(layout);
const encoded = es.map(config => btoa(JSON.stringify(config)));
const liveUrl = encoded.map(encoded => `./index.html?userlayout=${es.data.id}#${encoded}`)
const iframe = liveUrl.map(url => `<iframe src='${url}' width='100%' height='99%' style="box-sizing: border-box" title='Theme Preview'></iframe>`);

View file

@ -1233,6 +1233,8 @@
background-color: white;
position: relative;
padding: 1em;
display: inline-block;
width: 100%;
}
.tab-single-header {