Merge latest master

This commit is contained in:
Pieter Vander Vennet 2020-12-14 00:56:07 +01:00
commit c693faea95
249 changed files with 8610 additions and 2657 deletions

View file

@ -44,7 +44,7 @@ export default class AllTranslationAssets {
zoomInFurther: new Translation( {"en":"Zoom in further to add a point.","ca":"Apropa per afegir un punt.","es":"Acerca para añadir un punto.","nl":"Gelieve verder in te zoomen om een punt toe te voegen.","fr":"Rapprochez vous pour ajouter un point.","gl":"Achégate para engadir un punto.","de":"Weiter einzoomen, um einen Punkt hinzuzufügen."} ),
stillLoading: new Translation( {"en":"The data is still loading. Please wait a bit before you add a new point.","ca":"Les dades es segueixen carregant. Espera una mica abans d'afegir cap punt.","es":"Los datos se siguen cargando. Espera un poco antes de añadir ningún punto.","nl":"De data wordt nog geladen. Nog even geduld en dan kan je een punt toevoegen.","fr":"Chargement des donnés. Patientez un instant avant d'ajouter un nouveau point.","gl":"Os datos seguen a cargarse. Agarda un intre antes de engadir ningún punto.","de":"Die Daten werden noch geladen. Bitte warten Sie etwas, bevor Sie einen neuen Punkt hinzufügen."} ),
confirmIntro: new Translation( {"en":"<h3>Add a {title} here?</h3>The point you create here will be <b>visible for everyone</b>. Please, only add things on to the map if they truly exist. A lot of applications use this data.","ca":"<h3>Afegir {title} aquí?</h3>El punt que estàs creant <b>el veurà tothom</b>. Només afegeix coses que realment existeixin. Moltes aplicacions fan servir aquestes dades.","es":"<h3>Añadir {title} aquí?</h3>El punto que estás creando <b>lo verá todo el mundo</b>. Sólo añade cosas que realmente existan. Muchas aplicaciones usan estos datos.","nl":"<h3>Voeg hier een {title} toe?</h3>Het punt dat je hier toevoegt, is <b>zichtbaar voor iedereen</b>. Veel applicaties gebruiken deze data, voeg dus enkel punten toe die echt bestaan.","fr":"<h3>Ajouter un/une {title} ici?</h3>Le point que vous ajouter sera visible par tout le monde. Merci d'etre sûr que ce point existe réellement. Beaucoup d'autres applications reposent sur ces données.","gl":"<h3>Engadir {title} aquí?</h3>O punto que estás a crear <b>será ollado por todo o mundo</b>. Só engade cousas que realmente existan. Moitas aplicacións empregan estes datos.","de":"<h3>Hier einen {title} hinzufügen?</h3>Der Punkt, den Sie hier anlegen, wird <b>für alle sichtbar sein</b>. Bitte fügen Sie der Karte nur dann Dinge hinzu, wenn sie wirklich existieren. Viele Anwendungen verwenden diese Daten."} ),
confirmButton: new Translation( {"en":"Add a {category} here","ca":"Afegir {category} aquí","es":"Añadir {category} aquí","nl":"Voeg hier een {category} toe","fr":"Ajouter un/une {category} ici","gl":"Engadir {category} aquí","de":"Hier eine {category} hinzufügen"} ),
confirmButton: new Translation( {"en":"Add a {category} here.<br/><div class='alert'>Your addition is visble for everyone</div>","ca":"Afegir {category} aquí","es":"Añadir {category} aquí","nl":"Voeg hier een {category} toe<br/><div class='alert'>Je toevoeging is voor iedereen zichtbaar</div>","fr":"Ajouter un/une {category} ici","gl":"Engadir {category} aquí","de":"Hier eine {category} hinzufügen"} ),
openLayerControl: new Translation( {"en":"Open the layer control box","ca":"Obrir el control de capes","es":"Abrir el control de capas","nl":"Open de laag-instellingen","de":"Das Ebenen-Kontrollkästchen öffnen"} ),
layerNotEnabled: new Translation( {"en":"The layer {layer} is not enabled. Enable this layer to add a point","ca":"La capa {layer} no està habilitada. Fes-ho per poder afegir un punt a aquesta capa","es":"La capa {layer} no está habilitada. Hazlo para poder añadir un punto en esta capa","nl":"De laag {layer} is gedeactiveerd. Activeer deze om een punt toe te voegn","de":"Die Ebene {layer} ist nicht aktiviert. Aktivieren Sie diese Ebene, um einen Punkt hinzuzufügen"} ),
},
@ -110,7 +110,8 @@ export default class AllTranslationAssets {
saturday: new Translation( {"en":"Saturday","ca":"Dissabte","es":"Sábado","nl":"Zaterdag","fr":"Samedi"} ),
sunday: new Translation( {"en":"Sunday","ca":"Diumenge","es":"Domingo","nl":"Zondag","fr":"Dimance"} ),
},
opening_hours: { open_during_ph: new Translation( {"nl":"Op een feestdag is deze zaak","ca":"Durant festes aquest servei és","es":"Durante fiestas este servicio está","en":"During a public holiday, this amenity is"} ),
opening_hours: { error_loading: new Translation( {"en":"Error: could not visualize these opening hours.","nl":"Sorry, deze openingsuren kunnen niet getoond worden"} ),
open_during_ph: new Translation( {"nl":"Op een feestdag is deze zaak","ca":"Durant festes aquest servei és","es":"Durante fiestas este servicio está","en":"During a public holiday, this amenity is"} ),
opensAt: new Translation( {"en":"from","ca":"des de","es":"desde","nl":"vanaf"} ),
openTill: new Translation( {"en":"till","ca":"fins","es":" hasta","nl":"tot"} ),
not_all_rules_parsed: new Translation( {"en":"The opening hours of this shop are complicated. The following rules are ignored in the input element:","ca":"L'horari d'aquesta botiga és complicat. Les normes següents seran ignorades en l'entrada:","es":"El horario de esta tienda es complejo. Las normas siguientes serán ignoradas en la entrada:"} ),
@ -124,5 +125,19 @@ export default class AllTranslationAssets {
favourite: { panelIntro: new Translation( {"en":"<h3>Your personal theme</h3>Activate your favourite layers from all the official themes","ca":"<h3>La teva interfície personal</h3>Activa les teves capes favorites de totes les interfícies oficials","es":"<h3>Tu interficie personal</h3>Activa tus capas favoritas de todas las interficies oficiales","gl":"<h3>O teu tema personalizado</h3>Activa as túas capas favoritas de todos os temas oficiais","de":"<h3>Ihr persönliches Thema</h3>Aktivieren Sie Ihre Lieblingsebenen aus allen offiziellen Themen"} ),
loginNeeded: new Translation( {"en":"<h3>Log in</h3>A personal layout is only available for OpenStreetMap users","es":"<h3>Entrar</h3>El diseño personalizado sólo está disponible para los usuarios de OpenstreetMap","ca":"<h3>Entrar</h3>El disseny personalizat només està disponible pels usuaris d' OpenstreetMap","gl":"<h3>Iniciar a sesión</h3>O deseño personalizado só está dispoñíbel para os usuarios do OpenstreetMap","de":"<h3>Anmelden</h3>Ein persönliches Layout ist nur für OpenStreetMap-Benutzer verfügbar"} ),
reload: new Translation( {"en":"Reload the data","es":"Recargar datos","ca":"Recarregar dades","gl":"Recargar os datos","de":"Daten neu laden"} ),
},
reviews: { title: new Translation( {"en":"{count} reviews","nl":"{count} beoordelingen"} ),
name_required: new Translation( {"en":"A name is required in order to display and create reviews","nl":"De naam van dit object moet gekend zijn om een review te kunnen maken"} ),
no_reviews_yet: new Translation( {"en":"There are no reviews yet. Be the first to write one and help open data and the business!","nl":"Er zijn nog geen beoordelingen. Wees de eerste om een beoordeling te schrijven en help open data en het bedrijf"} ),
write_a_comment: new Translation( {"en":"Leave a review...","nl":"Schrijf een beoordeling..."} ),
no_rating: new Translation( {"en":"No rating given","nl":"Geen score bekend"} ),
posting_as: new Translation( {"en":"Posting as","nl":"Ingelogd als"} ),
i_am_affiliated: new Translation( {"en":"<div'><span>I am affiliated with this object</span><br/><span class='subtle'>Check if you are an owner, creator, employee, ...</span></div>","nl":"<div style='display:inline-block;max-width: 40%;'><span>I am affiliated with this object</span><br/><span class='subtle'>Vink aan indien je de oprichter, maker, werknemer, ... of dergelijke bent</span></div>"} ),
affiliated_reviewer_warning: new Translation( {"en":"(Affiliated review)","nl":"(Review door betrokkene)"} ),
saving_review: new Translation( {"en":"Saving...","nl":"Opslaan..."} ),
saved: new Translation( {"en":"<span class='thanks'>Review saved. Thanks for sharing!</span>","nl":"<span class='thanks'>Bedankt om je beoordeling te delen!</span>"} ),
tos: new Translation( {"en":"If you create a review, you agree to <a href='https://mangrove.reviews/terms' target='_blank'>the TOS and privacy policy of Mangrove.reviews</a>","nl":"Als je je review publiceert, ga je akkoord met de <a href='https://mangrove.reviews/terms' target='_blank'>de gebruiksvoorwaarden en privacy policy van Mangrove.reviews</a>"} ),
attribution: new Translation( {"en":"Reviews are powered by <a href='https://mangrove.reviews/' target='_blank'>Mangrove Reviews</a> and are available under <a href='https://mangrove.reviews/terms#8-licensing-of-content' target='_blank'>CC-BY 4.0</a>.","nl":"De beoordelingen worden voorzien door <a href='https://mangrove.reviews/' target='_blank'>Mangrove Reviews</a> en zijn beschikbaar onder de<a href='https://mangrove.reviews/terms#8-licensing-of-content' target='_blank'>CC-BY 4.0-licentie</a>. "} ),
plz_login: new Translation( {"en":"Login to leave a review","nl":"Meld je aan om een beoordeling te geven"} ),
},
}}

View file

@ -12,6 +12,9 @@ import {SubstitutedTranslation} from "../../UI/SpecialVisualizations";
import {Utils} from "../../Utils";
import Combine from "../../UI/Base/Combine";
import {VariableUiElement} from "../../UI/Base/VariableUIElement";
import {UIEventSource} from "../../Logic/UIEventSource";
import {FixedUiElement} from "../../UI/Base/FixedUiElement";
import {UIElement} from "../../UI/UIElement";
export default class LayerConfig {
@ -33,6 +36,7 @@ export default class LayerConfig {
titleIcons: TagRenderingConfig[];
icon: TagRenderingConfig;
iconOverlays: { if: TagsFilter, then: TagRenderingConfig, badge: boolean }[]
iconSize: TagRenderingConfig;
rotation: TagRenderingConfig;
color: TagRenderingConfig;
@ -89,6 +93,12 @@ export default class LayerConfig {
return tagRenderings.map(
(renderingJson, i) => {
if (typeof renderingJson === "string") {
if(renderingJson === "questions"){
return new TagRenderingConfig("questions")
}
const shared = SharedTagRenderings.SharedTagRendering[renderingJson];
if (shared !== undefined) {
return shared;
@ -100,8 +110,20 @@ export default class LayerConfig {
}
this.tagRenderings = trs(json.tagRenderings).concat(roamingRenderings);
this.titleIcons = trs(json.titleIcons ?? ["phonelink","wikipedialink","osmlink", "sharelink"]);
const titleIcons = [];
const defaultIcons = ["phonelink", "emaillink", "wikipedialink", "osmlink", "sharelink"];
for (const icon of (json.titleIcons ?? defaultIcons)) {
if (icon === "defaults") {
titleIcons.push(...defaultIcons);
} else {
titleIcons.push(icon);
}
}
this.titleIcons = trs(titleIcons);
function tr(key, deflt) {
const v = json[key];
@ -124,6 +146,18 @@ export default class LayerConfig {
this.title = tr("title", undefined);
this.icon = tr("icon", Img.AsData(Svg.bug));
this.iconOverlays = (json.iconOverlays ?? []).map(overlay => {
let tr = new TagRenderingConfig(overlay.then);
if (typeof overlay.then === "string" && SharedTagRenderings.SharedIcons[overlay.then] !== undefined) {
tr = SharedTagRenderings.SharedIcons[overlay.then];
}
return {
if: FromJSON.Tag(overlay.if),
then: tr,
badge: overlay.badge ?? false
}
});
const iconPath = this.icon.GetRenderValue({id: "node/-1"}).txt;
if (iconPath.startsWith(Utils.assets_path)) {
const iconKey = iconPath.substr(Utils.assets_path.length);
@ -141,7 +175,7 @@ export default class LayerConfig {
}
public GenerateLeafletStyle(tags: any, clickable: boolean):
public GenerateLeafletStyle(tags: UIEventSource<any>, clickable: boolean):
{
color: string;
icon: {
@ -149,8 +183,7 @@ export default class LayerConfig {
popupAnchor: [number, number];
iconAnchor: [number, number];
iconSize: [number, number];
html: string;
rotation: string;
html: UIElement;
className?: string;
};
weight: number; dashArray: number[]
@ -174,11 +207,10 @@ export default class LayerConfig {
}
function render(tr: TagRenderingConfig, deflt?: string) {
const str = (tr?.GetRenderValue(tags)?.txt ?? deflt);
return SubstitutedTranslation.SubstituteKeys(str, tags);
const str = (tr?.GetRenderValue(tags.data)?.txt ?? deflt);
return SubstitutedTranslation.SubstituteKeys(str, tags.data);
}
const iconUrl = render(this.icon);
const iconSize = render(this.iconSize, "40,40,center").split(",");
const dashArray = render(this.dashArray).split(" ").map(Number);
let color = render(this.color, "#00f");
@ -188,8 +220,6 @@ export default class LayerConfig {
}
const weight = rendernum(this.width, 5);
const rotation = render(this.rotation, "0deg");
const iconW = num(iconSize[0]);
const iconH = num(iconSize[1]);
@ -211,24 +241,84 @@ export default class LayerConfig {
anchorH = iconH;
}
let html = `<img src="${iconUrl}" style="width:100%;height:100%;rotate:${rotation};display:block;" />`;
if (iconUrl.startsWith(Utils.assets_path)) {
const key = iconUrl.substr(Utils.assets_path.length);
html = new Combine([
(Svg.All[key] as string).replace(/stop-color:#000000/g, 'stop-color:' + color)
]).SetStyle(`width:100%;height:100%;rotate:${rotation};display:block;`).Render();
}
const iconUrlStatic = render(this.icon);
const self = this;
var mappedHtml = tags.map(tgs => {
// What do you mean, 'tgs' is never read?
// It is read implicitly in the 'render' method
const iconUrl = render(self.icon);
const rotation = render(self.rotation, "0deg");
let htmlParts: UIElement[] = [];
let sourceParts = iconUrl.split(";");
function genHtmlFromString(sourcePart: string): UIElement {
const style = `width:100%;height:100%;rotate:${rotation};display:block;position: absolute; top: 0, left: 0`;
let html: UIElement = new FixedUiElement(`<img src="${sourcePart}" style="${style}" />`);
const match = sourcePart.match(/([a-zA-Z0-9_]*):#([0-9a-fA-F]{3,6})/)
if (match !== null && Svg.All[match[1] + ".svg"] !== undefined) {
html = new Combine([
(Svg.All[match[1] + ".svg"] as string)
.replace(/#000000/g, "#" + match[2])
]).SetStyle(style);
}
if (sourcePart.startsWith(Utils.assets_path)) {
const key = sourcePart.substr(Utils.assets_path.length);
html = new Combine([
(Svg.All[key] as string).replace(/stop-color:#000000/g, 'stop-color:' + color)
]).SetStyle(style);
}
return html;
}
for (const sourcePart of sourceParts) {
htmlParts.push(genHtmlFromString(sourcePart))
}
let badges = [];
for (const iconOverlay of self.iconOverlays) {
if (!iconOverlay.if.matchesProperties(tgs)) {
continue;
}
if (iconOverlay.badge) {
const badgeParts: UIElement[] = [];
const partDefs = iconOverlay.then.GetRenderValue(tgs).txt.split(";");
for (const badgePartStr of partDefs) {
badgeParts.push(genHtmlFromString(badgePartStr))
}
const badgeCompound = new Combine(badgeParts)
.SetStyle("display:flex;position:relative;width:100%;height:100%;");
badges.push(badgeCompound)
} else {
htmlParts.push(genHtmlFromString(
iconOverlay.then.GetRenderValue(tgs).txt));
}
}
if (badges.length > 0) {
const badgesComponent = new Combine(badges)
.SetStyle("display:flex;height:50%;width:100%;position:absolute;top:50%;left:50%;");
htmlParts.push(badgesComponent)
}
return new Combine(htmlParts).Render();
})
return {
icon:
{
html: html,
html: new VariableUiElement(mappedHtml),
iconSize: [iconW, iconH],
iconAnchor: [anchorW, anchorH],
popupAnchor: [0, 3 - anchorH],
rotation: rotation,
iconUrl: iconUrl,
iconUrl: iconUrlStatic,
className: clickable ? "leaflet-div-icon" : "leaflet-div-icon unclickable"
},
color: color,

View file

@ -57,9 +57,25 @@ export interface LayerConfigJson {
/**
* The icon for an element.
* Note that this also doubles as the icon for this layer (rendered with the overpass-tags) ánd the icon in the presets.
*
* The result of the icon is rendered as follows:
* the resulting string is interpreted as a _list_ of items, seperated by ";". The bottommost layer is the first layer.
* As a result, on could use a generic pin, then overlay it with a specific icon.
* To make things even more practical, one can use all svgs from the folder "assets/svg" and _substitute the color_ in it.
* E.g. to draw a red pin, use "pin:#f00", to have a green circle with your icon on top, use `circle:#0f0;<path to my icon.svg>`
*/
icon?: string | TagRenderingConfigJson;
/**
* IconsOverlays are a list of extra icons/badges to overlay over the icon.
* The 'badge'-toggle changes their behaviour.
* If badge is set, it will be added as a 25% height icon at the bottom right of the icon, with all the badges in a flex layout.
* If badges is false, it'll be a simple overlay
*
* Note: strings are interpreted as icons, so layering and substituting is supported
*/
iconOverlays?: {if: string | AndOrTagConfigJson, then: string | TagRenderingConfigJson, badge?: boolean}[]
/**
* A string containing "width,height" or "width,height,anchorpoint" where anchorpoint is any of 'center', 'top', 'bottom', 'left', 'right', 'bottomleft','topright', ...
* Default is '40,40,center'
@ -110,7 +126,17 @@ export interface LayerConfigJson {
passAllFeatures?:boolean
/**
* Presets for this layer
* Presets for this layer.
* A preset shows up when clicking the map on a without data (or when right-clicking/long-pressing);
* it will prompt the user to add a new point.
*
* The most important aspect are the tags, which define which tags the new point will have;
* The title is shown in the dialog, along with the first sentence of the description.
*
* Upon confirmation, the full description is shown beneath the buttons - perfect to add pictures and examples.
*
* Note: the icon of the preset is determined automatically based on the tags and the icon above. Don't worry about that!
* NB: if no presets are defined, the popup to add new points doesn't show up at all
*/
presets?: {
title: string | any,
@ -127,6 +153,10 @@ export interface LayerConfigJson {
* Note that we can also use a string here - where the string refers to a tagrenering defined in `assets/questions/questions.json`,
* where a few very general questions are defined e.g. website, phone number, ...
*
* A special value is 'questions', which indicates the location of the questions box. If not specified, it'll be appended to the bottom of the featureInfobox.
*
*/
tagRenderings?: (string | TagRenderingConfigJson) []
}

View file

@ -26,13 +26,20 @@ export default class TagRenderingConfig {
mappings?: {
if: TagsFilter,
then: Translation
hideInAnswer: boolean
hideInAnswer: boolean | TagsFilter
}[]
constructor(json: string | TagRenderingConfigJson, context?: string) {
if(json === undefined){
throw "Initing a TagRenderingConfig with undefined in "+context;
if (json === "questions") {
// Very special value
this.render = null;
this.question = null;
this.condition = null;
}
if (json === undefined) {
throw "Initing a TagRenderingConfig with undefined in " + context;
}
if (typeof json === "string") {
this.render = Translations.T(json);
@ -62,10 +69,16 @@ export default class TagRenderingConfig {
if (mapping.then === undefined) {
throw "Invalid mapping: if without body"
}
let hideInAnswer : boolean | TagsFilter = false;
if (typeof mapping.hideInAnswer === "boolean") {
hideInAnswer = mapping.hideInAnswer;
} else if (mapping.hideInAnswer !== undefined) {
hideInAnswer = FromJSON.Tag(mapping.hideInAnswer, `${context}.mapping[${i}].hideInAnswer`);
}
return {
if: FromJSON.Tag(mapping.if, `${context}.mapping[${i}]`),
if: FromJSON.Tag(mapping.if, `${context}.mapping[${i}].if`),
then: Translations.T(mapping.then),
hideInAnswer: mapping.hideInAnswer ?? false
hideInAnswer: hideInAnswer
};
});
}

View file

@ -16,7 +16,7 @@ import * as information_boards from "../assets/layers/information_board/informat
import * as direction from "../assets/layers/direction/direction.json"
import * as surveillance_camera from "../assets/layers/surveillance_cameras/surveillance_cameras.json"
import * as toilets from "../assets/layers/toilets/toilets.json"
import * as bookcases from "../assets/layers/public_bookcases/public_bookcases.json"
import LayerConfig from "./JSON/LayerConfig";
export default class SharedLayers {
@ -44,6 +44,7 @@ export default class SharedLayers {
new LayerConfig(direction,[], "shared_layers"),
new LayerConfig(information_boards,[], "shared_layers"),
new LayerConfig(toilets,[], "shared_layers"),
new LayerConfig(bookcases,[], "shared_layers"),
new LayerConfig(surveillance_camera,[], "shared_layers")
];

View file

@ -5,27 +5,28 @@ import * as icons from "../assets/tagRenderings/icons.json";
export default class SharedTagRenderings {
public static SharedTagRendering = SharedTagRenderings.generatedSharedFields();
public static SharedIcons = SharedTagRenderings.generatedSharedFields(true);
private static generatedSharedFields() {
private static generatedSharedFields(iconsOnly = false) {
const dict = {}
function add(key, store){
function add(key, store) {
try {
dict[key] = new TagRenderingConfig(store[key])
dict[key] = new TagRenderingConfig(store[key], key)
} catch (e) {
console.error("BUG: could not parse", key, " from questions.json or icons.json", e)
console.error("BUG: could not parse", key, " from questions.json or icons.json - this error happened during the build step of the SharedTagRenderings", e)
}
}
for (const key in questions) {
add(key, questions);
if (!iconsOnly) {
for (const key in questions) {
add(key, questions);
}
}
for (const key in icons) {
add(key, icons);
}
return dict;
}

View file

@ -85,11 +85,6 @@ export class InitUiElements {
throw "Incorrect layout"
}
const hashContent = QueryParameters.GetQueryParameter("hash_content", "", "A workaround for the share-api which doesn't share the hash...");
if((hashContent.data ?? "") !== ""){
window.location.hash = hashContent.data;
}
console.log("Using layout: ", layoutToUse.id, "LayoutFromBase64 is ", layoutFromBase64);
State.state = new State(layoutToUse);
@ -186,7 +181,7 @@ export class InitUiElements {
// This layer is the layer that gives the questions
const featureBox = new FeatureInfoBox(
State.state.allElements.getElement(data.id),
State.state.allElements.getEventSourceById(data.id),
layer
);

View file

@ -42,10 +42,14 @@ export class ElementStorage {
}
}
getElement(elementId): UIEventSource<any> {
getEventSourceById(elementId): UIEventSource<any> {
if (elementId in this._elements) {
return this._elements[elementId];
}
console.log("Can not find eventsource with id ", elementId);
console.error("Can not find eventsource with id ", elementId);
}
getEventSourceFor(feature): UIEventSource<any> {
return this.getEventSourceById(feature.properties.id);
}
}

View file

@ -7,6 +7,7 @@ import {UIElement} from "../UI/UIElement";
import State from "../State";
import LayerConfig from "../Customizations/JSON/LayerConfig";
import Hash from "./Web/Hash";
import LazyElement from "../UI/Base/LazyElement";
/***
* A filtered layer is a layer which offers a 'set-data' function
@ -78,7 +79,7 @@ export class FilteredLayer {
const tags = TagUtils.proprtiesToKV(feature.properties);
const matches = this.filters.matches(tags);
if (matches) {
selfFeatures.push(feature);
selfFeatures.push(feature);
}
if (!matches || this.layerDef.passAllFeatures) {
leftoverFeatures.push(feature);
@ -129,13 +130,16 @@ export class FilteredLayer {
let self = this;
this._geolayer = L.geoJSON(data, {
style: feature =>
self.layerDef.GenerateLeafletStyle(feature.properties, self._showOnPopup !== undefined),
style: feature => {
const tagsSource = State.state.allElements.getEventSourceFor(feature);
return self.layerDef.GenerateLeafletStyle(tagsSource, self._showOnPopup !== undefined);
},
pointToLayer: function (feature, latLng) {
// Point to layer converts the 'point' to a layer object - as the geojson layer natively cannot handle points
// Click handling is done in the next step
const tagSource = State.state.allElements.getEventSourceFor(feature);
const style = self.layerDef.GenerateLeafletStyle(feature.properties, self._showOnPopup !== undefined);
const style = self.layerDef.GenerateLeafletStyle(tagSource, self._showOnPopup !== undefined);
let marker;
if (style.icon === undefined) {
marker = L.circle(latLng, {
@ -148,8 +152,16 @@ export class FilteredLayer {
color: style.color
});
} else {
style.icon.html.ListenTo(self.isDisplayed)
marker = L.marker(latLng, {
icon: L.divIcon(style.icon)
icon: L.divIcon({
html: style.icon.html.Render(),
className: style.icon.className,
iconAnchor: style.icon.iconAnchor,
iconUrl: style.icon.iconUrl,
popupAnchor: style.icon.popupAnchor,
iconSize: style.icon.iconSize
})
});
}
return marker;
@ -165,10 +177,9 @@ export class FilteredLayer {
closeOnEscapeKey: true,
}, layer);
let uiElement: UIElement;
const eventSource = State.state.allElements.addOrGetElement(feature);
uiElement = self._showOnPopup(eventSource, feature);
const eventSource = State.state.allElements.getEventSourceFor(feature);
let uiElement: LazyElement = new LazyElement(() => self._showOnPopup(eventSource, feature));
popup.setContent(uiElement.Render());
layer.bindPopup(popup);
// We first render the UIelement (which'll still need an update later on...)
@ -177,11 +188,16 @@ export class FilteredLayer {
layer.on("click", (e) => {
// We set the element as selected...
uiElement.Activate();
State.state.selectedElement.setData(feature);
uiElement.Update();
});
if (feature.properties.id.replace(/\//g, "_") === Hash.Get().data) {
// This element is in the URL, so this is a share link
// We already open it
uiElement.Activate();
popup.setContent(uiElement.Render());
const center = GeoOperations.centerpoint(feature).geometry.coordinates;
popup.setLatLng({lat: center[1], lng: center[0]});
popup.openOn(State.state.bm.map);

View file

@ -103,18 +103,15 @@ export class GeoLocationHandler extends UIElement {
}
private StartGeolocating() {
private StartGeolocating(zoomlevel = 19) {
const self = this;
const map = State.state.bm.map;
if (self._permission.data === "denied") {
return "";
}
if (State.state.currentGPSLocation.data !== undefined) {
State.state.bm.map.flyTo(
State.state.currentGPSLocation.data.latlng, 16,
{
duration: 0.25,
}
State.state.bm.map.setView(
State.state.currentGPSLocation.data.latlng, zoomlevel
);
}
@ -148,8 +145,15 @@ export class GeoLocationHandler extends UIElement {
const self = this;
htmlElement.onclick = function () {
self.StartGeolocating();
self.StartGeolocating(19);
}
htmlElement.oncontextmenu = function (e) {
self.StartGeolocating(15);
e.preventDefault();
return false;
}
}
}

View file

@ -1,10 +1,9 @@
import {GeoOperations} from "./GeoOperations";
import CodeGrid from "./Web/CodeGrid";
import State from "../State";
import opening_hours from "opening_hours";
import {And, Or, Tag} from "./Tags";
import {Utils} from "../Utils";
import CountryCoder from "latlon2country"
class SimpleMetaTagger {
private _f: (feature: any, index: number) => void;
@ -61,62 +60,69 @@ export default class MetaTagging {
})
);
private static country = new SimpleMetaTagger(
["_country"], "The country code of the point",
((feature, index) => {
const centerPoint = GeoOperations.centerpoint(feature);
["_country"], "The country code of the property (with latlon2country)",
(feature, index) => {
const coder = new CountryCoder("https://pietervdvn.github.io/latlon2country/");
let centerPoint: any = GeoOperations.centerpoint(feature);
const lat = centerPoint.geometry.coordinates[1];
const lon = centerPoint.geometry.coordinates[0]
// But the codegrid SHOULD be a number!
CodeGrid.getCode(lat, lon, (error, code) => {
if (error === null) {
feature.properties["_country"] = code;
// There is a huge performance issue: if there are ~1000 features receiving a ping at the same time,
// The application hangs big time
// So we disable pinging all together
} else {
console.warn("Could not determine country for", feature.properties.id, error);
const lon = centerPoint.geometry.coordinates[0];
coder.GetCountryCodeFor(lon, lat, (countries) => {
try {
feature.properties["_country"] = countries[0].trim().toLowerCase();
const tagsSource = State.state.allElements.getEventSourceFor(feature);
tagsSource.ping();
} catch (e) {
console.error(e)
}
});
})
}
)
private static isOpen = new SimpleMetaTagger(
["_isOpen", "_isOpen:description"], "If 'opening_hours' is present, it will add the current state of the feature (being 'yes' or 'no')",
["_isOpen", "_isOpen:description"],
"If 'opening_hours' is present, it will add the current state of the feature (being 'yes' or 'no')",
(feature => {
const tagsSource = State.state.allElements.addOrGetElement(feature);
tagsSource.addCallback(tags => {
if (tags["opening_hours"] !== undefined && tags["_country"] !== undefined) {
if (tags._isOpen !== undefined) {
// Already defined
return;
const tagsSource = State.state.allElements.getEventSourceFor(feature);
tagsSource.addCallbackAndRun(tags => {
if (tags.opening_hours === undefined || tags._country === undefined) {
return;
}
try{
const oh = new opening_hours(tags["opening_hours"], {
lat: tags._lat,
lon: tags._lon,
address: {
country_code: tags._country.toLowerCase()
}
}, {tag_key: "opening_hours"});
// AUtomatically triggered on the next change
const updateTags = () => {
const oldValueIsOpen = tags["_isOpen"];
tags["_isOpen"] = oh.getState() ? "yes" : "no";
const comment = oh.getComment();
if (comment) {
tags["_isOpen:description"] = comment;
}
const oh = new opening_hours(tags["opening_hours"], {
lat: tags._lat,
lon: tags._lon,
address: {
country_code: tags._country
}
}, {tag_key: "opening_hours"});
const updateTags = () => {
tags["_isOpen"] = oh.getState() ? "yes" : "no";
const comment = oh.getComment();
if (comment) {
tags["_isOpen:description"] = comment;
}
const nextChange = oh.getNextChange() as Date;
if (nextChange !== undefined) {
window.setTimeout(
updateTags,
(nextChange.getTime() - (new Date()).getTime())
)
}
if (oldValueIsOpen !== tags._isOpen) {
tagsSource.ping();
}
updateTags();
const nextChange = oh.getNextChange();
if (nextChange !== undefined) {
window.setTimeout(
updateTags,
(nextChange.getTime() - (new Date()).getTime())
)
}
}
updateTags();
}catch(e){
console.error(e);
tags["_isOpen"] = "parse_error";
}
})

View file

@ -18,7 +18,7 @@ export class Changes {
if (changes.length == 0) {
return;
}
const eventSource = tags ?? State.state?.allElements.getElement(elementId);
const eventSource = tags ?? State.state?.allElements.getEventSourceById(elementId);
const elementTags = eventSource.data;
const pending : {elementId:string, key: string, value: string}[] = [];
for (const change of changes) {

View file

@ -181,7 +181,7 @@ export class ChangesetHandler {
continue;
}
console.log("Rewriting id: ", oldId, "-->", newId);
const element = allElements.getElement("node/" + oldId);
const element = allElements.getEventSourceById("node/" + oldId);
element.data.id = "node/" + newId;
allElements.addElementById("node/" + newId, element);
element.ping();

View file

@ -24,7 +24,7 @@ export class OsmConnection {
public auth;
public userDetails: UIEventSource<UserDetails>;
private _dryRun: boolean;
_dryRun: boolean;
public preferencesHandler: OsmPreferences;
public changesetHandler: ChangesetHandler;

View file

@ -96,17 +96,20 @@ export class UpdateFromOverpass {
const self = this;
self.retries.setData(0);
let newIds = 1;
for (const feature of geojson.features) {
if(feature.properties.id === undefined){
feature.properties.id = "ext/"+newIds;
if (feature.properties.id === undefined) {
feature.properties.id = "ext/" + newIds;
newIds++;
}
}
geojson.features.forEach(feature => {
State.state.allElements.addElement(feature);
})
MetaTagging.addMetatags(geojson.features);
function renderLayers(layers: FilteredLayer[]) {
if (layers.length === 0) {
self.runningQuery.setData(false);
@ -125,6 +128,7 @@ export class UpdateFromOverpass {
}, 50)
}
renderLayers(State.state.filteredLayers.data);
}

View file

@ -0,0 +1,192 @@
import * as mangrove from 'mangrove-reviews'
import {UIEventSource} from "../UIEventSource";
import {Review} from "./Review";
export class MangroveIdentity {
private readonly _mangroveIdentity: UIEventSource<string>;
public keypair: any = undefined;
public readonly kid: UIEventSource<string> = new UIEventSource<string>(undefined);
constructor(mangroveIdentity: UIEventSource<string>) {
const self = this;
this._mangroveIdentity = mangroveIdentity;
mangroveIdentity.addCallbackAndRun(str => {
if (str === undefined || str === "") {
return;
}
mangrove.jwkToKeypair(JSON.parse(str)).then(keypair => {
self.keypair = keypair;
mangrove.publicToPem(keypair.publicKey).then(pem => {
console.log("Identity loaded")
self.kid.setData(pem);
})
})
})
if ((mangroveIdentity.data ?? "") === "") {
this.CreateIdentity();
}
}
/**
* Creates an identity if none exists already.
* Is written into the UIEventsource, which was passed into the constructor
* @constructor
*/
private CreateIdentity() {
if ("" !== (this._mangroveIdentity.data ?? "")) {
throw "Identity already defined - not creating a new one"
}
const self = this;
mangrove.generateKeypair().then(
keypair => {
self.keypair = keypair;
mangrove.keypairToJwk(keypair).then(jwk => {
self._mangroveIdentity.setData(JSON.stringify(jwk));
})
});
}
}
export default class MangroveReviews {
private readonly _lon: number;
private readonly _lat: number;
private readonly _name: string;
private readonly _reviews: UIEventSource<Review[]> = new UIEventSource<Review[]>([]);
private _dryRun: boolean;
private _mangroveIdentity: MangroveIdentity;
private _lastUpdate : Date = undefined;
private static _reviewsCache = {};
public static Get(lon: number, lat: number, name: string,
identity: MangroveIdentity,
dryRun?: boolean){
const newReviews = new MangroveReviews(lon, lat, name, identity, dryRun);
const uri = newReviews.GetSubjectUri();
const cached = MangroveReviews._reviewsCache[uri];
if(cached !== undefined){
return cached;
}
MangroveReviews._reviewsCache[uri] = newReviews;
return newReviews;
}
private constructor(lon: number, lat: number, name: string,
identity: MangroveIdentity,
dryRun?: boolean) {
this._lon = lon;
this._lat = lat;
this._name = name;
this._mangroveIdentity = identity;
this._dryRun = dryRun;
}
/**
* Gets an URI which represents the item in a mangrove-compatible way
* @constructor
*/
public GetSubjectUri() {
let uri = `geo:${this._lat},${this._lon}?u=50`;
if (this._name !== undefined && this._name !== null) {
uri += "&q=" + this._name;
}
return uri;
}
/**
* Gives a UIEVentsource with all reviews.
* Note: rating is between 1 and 100
*/
public GetReviews(): UIEventSource<Review[]> {
if(this._lastUpdate !== undefined && this._reviews.data !== undefined &&
(new Date().getTime() - this._lastUpdate.getTime()) < 15000
){
// Last update was pretty recent
return this._reviews;
}
this._lastUpdate = new Date();
const self = this;
mangrove.getReviews({sub: this.GetSubjectUri()}).then(
(data) => {
const reviews = [];
const reviewsByUser = [];
for (const review of data.reviews) {
const r = review.payload;
console.log("PublicKey is ", self._mangroveIdentity.kid.data, "reviews.kid is", review.kid);
const byUser = self._mangroveIdentity.kid.map(data => data === review.signature);
const rev: Review = {
made_by_user: byUser,
date: new Date(r.iat * 1000),
comment: r.opinion,
author: r.metadata.nickname,
affiliated: r.metadata.is_affiliated,
rating: r.rating // percentage points
};
(rev.made_by_user ? reviewsByUser : reviews).push(rev);
}
self._reviews.setData(reviewsByUser.concat(reviews))
}
);
return this._reviews;
}
AddReview(r: Review, callback?: (() => void)) {
callback = callback ?? (() => {
return undefined;
});
const payload = {
sub: this.GetSubjectUri(),
rating: r.rating,
opinion: r.comment,
metadata: {
nickname: r.author,
}
};
if (r.affiliated) {
// @ts-ignore
payload.metadata.is_affiliated = true;
}
if (this._dryRun) {
console.warn("DRYRUNNING mangrove reviews: ", payload);
if (callback) {
if (callback) {
console.log("Calling callback")
callback();
}
this._reviews.data.push(r);
this._reviews.ping();
}
} else {
mangrove.signAndSubmitReview(this._mangroveIdentity.keypair, payload).then(() => {
if (callback) {
console.log("Calling callback")
callback();
}
this._reviews.data.push(r);
this._reviews.ping();
})
}
}
}

View file

@ -27,7 +27,6 @@ export class QueryParameters {
this.initialized = true;
if (window?.location?.search) {
console.log("Window.location.search is",window.location.search)
const params = window.location.search.substr(1).split("&");
for (const param of params) {
const kv = param.split("=");
@ -51,7 +50,12 @@ export class QueryParameters {
if (QueryParameters.knownSources[key].data === undefined) {
continue;
}
if (QueryParameters.knownSources[key].data === "undefined") {
continue;
}
if (QueryParameters.knownSources[key].data == QueryParameters.defaults[key]) {
continue;
}

13
Logic/Web/Review.ts Normal file
View file

@ -0,0 +1,13 @@
import {UIEventSource} from "../UIEventSource";
export interface Review {
comment?: string,
author: string,
date: Date,
rating: number,
affiliated: boolean,
/**
* True if the current logged in user is the creator of this comment
*/
made_by_user: UIEventSource<boolean>
}

View file

@ -262,4 +262,6 @@ https://commons.wikimedia.org/wiki/File:Shower_symbol.svg
Bench icons from StreetComplete: https://github.com/westnordost/StreetComplete/tree/v25.0-beta1/res/graphics/quest%20icons, GPLv3.0
Urinal icon: https://thenounproject.com/term/urinal/1307984/
Urinal icon: https://thenounproject.com/term/urinal/1307984/
24/7 icon: https://www.vecteezy.com/vector-art/1394992-24-7-service-and-support-icon-set

View file

@ -13,6 +13,7 @@ import {QueryParameters} from "./Logic/Web/QueryParameters";
import {BaseLayer} from "./Logic/BaseLayer";
import LayoutConfig from "./Customizations/JSON/LayoutConfig";
import Hash from "./Logic/Web/Hash";
import {MangroveIdentity} from "./Logic/Web/MangroveReviews";
/**
* Contains the global state: a bunch of UI-event sources
@ -23,7 +24,7 @@ export default class State {
// The singleton of the global state
public static state: State;
public static vNumber = "0.2.2a";
public static vNumber = "0.2.5b";
// The user journey states thresholds when a new feature gets unlocked
public static userJourney = {
@ -64,13 +65,15 @@ export default class State {
*/
public osmConnection: OsmConnection;
public mangroveIdentity: MangroveIdentity;
public favouriteLayers: UIEventSource<string[]>;
public layerUpdater: UpdateFromOverpass;
public filteredLayers: UIEventSource<FilteredLayer[]> = new UIEventSource<FilteredLayer[]>([])
/**
* The message that should be shown at the center of the screen
*/
@ -209,6 +212,10 @@ export default class State {
true
);
this.mangroveIdentity = new MangroveIdentity(
this.osmConnection.GetLongPreference("identity", "mangrove")
);
const h = Hash.Get();
this.selectedElement.addCallback(selected => {

59
Svg.ts

File diff suppressed because one or more lines are too long

30
UI/Base/LazyElement.ts Normal file
View file

@ -0,0 +1,30 @@
import {UIElement} from "../UIElement";
export default class LazyElement extends UIElement {
private _content: UIElement = undefined;
public Activate: () => void;
constructor(content: (() => UIElement)) {
super();
this.dumbMode = false;
const self = this;
this.Activate = () => {
if (this._content === undefined) {
self._content = content();
}
self.Update();
}
}
InnerRender(): string {
if (this._content === undefined) {
return "Rendering...";
}
return this._content.InnerRender();
}
}

View file

@ -13,7 +13,7 @@ export default class SettingsTable extends UIElement {
public selectedSetting: UIEventSource<SingleSetting<any>>;
constructor(elements: (SingleSetting<any> | string)[],
currentSelectedSetting: UIEventSource<SingleSetting<any>>) {
currentSelectedSetting?: UIEventSource<SingleSetting<any>>) {
super(undefined);
const self = this;
this.selectedSetting = currentSelectedSetting ?? new UIEventSource<SingleSetting<any>>(undefined);

View file

@ -42,7 +42,7 @@ export default class SharePanel extends UIElement {
"Copy the json configuration from the 'save-tab', paste it between the 'nowiki'-tags in the Wiki",
"Click 'save' to save the wiki page",
"Share the link with the url parameter <span class='literal-code'>userlayout=wiki:YOURWIKIPAGE</span>, e.g. " +
`<a href='./index.html?userlayout=${proposedNameEnc}' target='_blank'>https://kletterspots.de?userlayout=${proposedNameEnc}</a>`
`<a href='./index.html?userlayout=${proposedNameEnc}' target='_blank'>https://${window.location.host}?userlayout=${proposedNameEnc}</a>`
].map(li => `<li>${li}</li>`),
"</ol>",

View file

@ -12,7 +12,7 @@ export class TextField extends InputElement<string> {
private readonly _htmlType: string;
private readonly _textAreaRows: number;
private readonly _isValid: (string, country) => boolean;
private readonly _isValid: (string,country) => boolean;
private _label: UIElement;
constructor(options?: {
@ -22,7 +22,7 @@ export class TextField extends InputElement<string> {
htmlType?: string,
label?: UIElement,
textAreaRows?: number,
isValid?: ((s: string, country?: string) => boolean)
isValid?: ((s: string, country?: () => string) => boolean)
}) {
super(undefined);
const self = this;
@ -63,11 +63,11 @@ export class TextField extends InputElement<string> {
InnerRender(): string {
const placeholder = this._placeholder.InnerRender().replace("'", "&#39");
if (this._htmlType === "area") {
return `<span id="${this.id}"><textarea id="txt-${this.id}" class="form-text-field" rows="${this._textAreaRows}" cols="50" style="max-width: 100%; width: 100%; box-sizing: border-box"></textarea></span>`
return `<span id="${this.id}"><textarea id="txt-${this.id}" placeholder='${placeholder}' class="form-text-field" rows="${this._textAreaRows}" cols="50" style="max-width: 100%; width: 100%; box-sizing: border-box"></textarea></span>`
}
const placeholder = this._placeholder.InnerRender().replace("'", "&#39");
let label = "";
if (this._label != undefined) {
label = this._label.Render();

View file

@ -14,8 +14,8 @@ import DirectionInput from "./DirectionInput";
interface TextFieldDef {
name: string,
explanation: string,
isValid: ((s: string, country?: string) => boolean),
reformat?: ((s: string, country?: string) => string),
isValid: ((s: string, country?:() => string) => boolean),
reformat?: ((s: string, country?: () => string) => string),
inputHelper?: (value: UIEventSource<string>, options?: {
location: [number, number]
}) => InputElement<string>,
@ -26,8 +26,8 @@ export default class ValidatedTextField {
private static tp(name: string,
explanation: string,
isValid?: ((s: string, country?: string) => boolean),
reformat?: ((s: string, country?: string) => string),
isValid?: ((s: string, country?: () => string) => boolean),
reformat?: ((s: string, country?: () => string) => string),
inputHelper?: (value: UIEventSource<string>, options?:{
location: [number, number]
}) => InputElement<string>): TextFieldDef {
@ -154,13 +154,13 @@ export default class ValidatedTextField {
ValidatedTextField.tp(
"phone",
"A phone number",
(str, country: any) => {
(str, country: () => string) => {
if (str === undefined) {
return false;
}
return parsePhoneNumberFromString(str, country?.toUpperCase())?.isValid() ?? false
return parsePhoneNumberFromString(str, (country())?.toUpperCase() as any)?.isValid() ?? false
},
(str, country: any) => parsePhoneNumberFromString(str, country?.toUpperCase()).formatInternational()
(str, country: () => string) => parsePhoneNumberFromString(str, (country())?.toUpperCase() as any).formatInternational()
),
ValidatedTextField.tp(
"opening_hours",
@ -200,8 +200,8 @@ export default class ValidatedTextField {
value?: UIEventSource<string>,
textArea?: boolean,
textAreaRows?: number,
isValid?: ((s: string, country: string) => boolean),
country?: string,
isValid?: ((s: string, country: () => string) => boolean),
country?: () => string,
location?: [number /*lat*/, number /*lon*/]
}): InputElement<string> {
options = options ?? {};
@ -304,7 +304,7 @@ export default class ValidatedTextField {
textArea?: boolean,
textAreaRows?: number,
isValid?: ((string: string) => boolean),
country?: string
country?: () => string
}): InputElement<T> {
let textField: InputElement<string>;
if (options?.type) {

View file

@ -5,6 +5,7 @@ import State from "../State";
import Translations from "./i18n/Translations";
import {FixedUiElement} from "./Base/FixedUiElement";
import {VariableUiElement} from "./Base/VariableUIElement";
import {UIEventSource} from "../Logic/UIEventSource";
export class LayerSelection extends UIElement {
@ -15,15 +16,15 @@ export class LayerSelection extends UIElement {
this._checkboxes = [];
for (const layer of State.state.filteredLayers.data) {
let iconUrl = "./asets/checkbox.svg";
if (layer.layerDef.icon ) {
iconUrl = layer.layerDef.icon.GetRenderValue({id:"node/-1"}).txt;
}
const icon = new FixedUiElement(`<img style="height:2em;max-width: 2em;" src="${iconUrl}">`);
const leafletStyle = layer.layerDef.GenerateLeafletStyle(new UIEventSource<any>({id: "node/-1"}), true)
const leafletHtml = leafletStyle.icon.html;
const icon =
new FixedUiElement(leafletHtml.Render())
.SetClass("single-layer-selection-toggle")
let iconUnselected: UIElement = new FixedUiElement(leafletHtml.Render())
.SetClass("single-layer-selection-toggle")
.SetStyle("opacity:0.2;");
let iconUnselected: UIElement;
iconUnselected = new FixedUiElement(`<img style="height:2em;max-width: 2em; opacity:0.2;" src="${iconUrl}">`);
const name = Translations.WT(layer.layerDef.name).Clone()
.SetStyle("font-size:large;margin-left: 0.5em;");

View file

@ -5,6 +5,7 @@ import Combine from "./Base/Combine";
import Translations from "./i18n/Translations";
import {FixedUiElement} from "./Base/FixedUiElement";
import {OH} from "../Logic/OpeningHours";
import State from "../State";
export default class OpeningHoursVisualization extends UIElement {
private readonly _key: string;
@ -151,7 +152,7 @@ export default class OpeningHoursVisualization extends UIElement {
const tags = this._source.data;
if (tags._country === undefined) {
return "Loading...";
return "Loading country information...";
}
let oh = null;
@ -165,7 +166,12 @@ export default class OpeningHoursVisualization extends UIElement {
}, {tag_key: this._key});
} catch (e) {
console.log(e);
return "Error: could not visualize these opening hours"
const msg = new Combine([Translations.t.general.opening_hours.error_loading,
State.state?.osmConnection?.userDetails?.data?.csCount >= State.userJourney.tagsVisibleAndWikiLinked ?
`<span class='subtle'>${e}</span>`
: ""
]);
return msg.Render();
}
if (!oh.getState() && !oh.getUnknown()) {

View file

@ -6,6 +6,7 @@ import QuestionBox from "./QuestionBox";
import Combine from "../Base/Combine";
import TagRenderingAnswer from "./TagRenderingAnswer";
import State from "../../State";
import {FixedUiElement} from "../Base/FixedUiElement";
export class FeatureInfoBox extends UIElement {
private _tags: UIEventSource<any>;
@ -34,10 +35,25 @@ export class FeatureInfoBox extends UIElement {
this._titleIcons = new Combine(
layerConfig.titleIcons.map(icon => new TagRenderingAnswer(tags, icon)))
.SetClass("featureinfobox-icons");
this._renderings = layerConfig.tagRenderings.map(tr => new EditableTagRendering(tags, tr));
let questionBox : UIElement = undefined;
if (State.state.featureSwitchUserbadge.data) {
this._questionBox = new QuestionBox(tags, layerConfig.tagRenderings);
questionBox = new QuestionBox(tags, layerConfig.tagRenderings);
}
let questionBoxIsUsed = false;
this._renderings = layerConfig.tagRenderings.map(tr => {
if(tr.question === null){
questionBoxIsUsed = true;
// This is the question box!
return questionBox;
}
return new EditableTagRendering(tags, tr);
});
this._renderings[0]?.SetClass("first-rendering");
if(!questionBoxIsUsed){
this._renderings.push(questionBox);
}
}
InnerRender(): string {
@ -46,7 +62,8 @@ export class FeatureInfoBox extends UIElement {
.SetClass("featureinfobox-titlebar"),
new Combine([
...this._renderings,
this._questionBox
this._questionBox,
new FixedUiElement("").SetClass("featureinfobox-tail")
]
).SetClass("featureinfobox-content"),
]).SetClass("featureinfobox")

View file

@ -22,7 +22,9 @@ export default class QuestionBox extends UIElement {
this.ListenTo(this._skippedQuestions);
this._tags = tags;
const self = this;
this._tagRenderings = tagRenderings.filter(tr => tr.question !== undefined);
this._tagRenderings = tagRenderings
.filter(tr => tr.question !== undefined)
.filter(tr => tr.question !== null);
this._tagRenderingQuestions = this._tagRenderings
.map((tagRendering, i) => new TagRenderingQuestion(this._tags, tagRendering,
() => {

View file

@ -1,32 +1,33 @@
import {UIEventSource} from "../../Logic/UIEventSource";
import {UIElement} from "../UIElement";
import Translations from "../i18n/Translations";
import State from "../../State";
import {OsmConnection, UserDetails} from "../../Logic/Osm/OsmConnection";
export class SaveButton extends UIElement {
private _value: UIEventSource<any>;
private _friendlyLogin: UIElement;
private readonly _value: UIEventSource<any>;
private readonly _friendlyLogin: UIElement;
private readonly _userDetails: UIEventSource<UserDetails>;
constructor(value: UIEventSource<any>) {
constructor(value: UIEventSource<any>, osmConnection: OsmConnection) {
super(value);
this._userDetails = osmConnection?.userDetails;
if(value === undefined){
throw "No event source for savebutton, something is wrong"
}
this._value = value;
this._friendlyLogin = Translations.t.general.loginToStart.Clone()
.SetClass("login-button-friendly")
.onClick(() => State.state.osmConnection.AttemptLogin())
.onClick(() => osmConnection?.AttemptLogin())
}
InnerRender(): string {
let clss = "save";
if(State.state !== undefined && !State.state.osmConnection.userDetails.data.loggedIn){
if(this._userDetails != undefined && !this._userDetails.data.loggedIn){
return this._friendlyLogin.Render();
}
if ((this._value.data ?? "") === "") {
if (this._value.data === false || (this._value.data ?? "") === "") {
clss = "save-non-active";
}
return Translations.t.general.save.Clone().SetClass(clss).Render();

View file

@ -64,7 +64,7 @@ export default class TagRenderingQuestion extends UIElement {
}
this._saveButton = new SaveButton(this._inputElement.GetValue())
this._saveButton = new SaveButton(this._inputElement.GetValue(), State.state.osmConnection)
.onClick(save)
@ -198,9 +198,12 @@ export default class TagRenderingQuestion extends UIElement {
private GenerateMappingElement(mapping: {
if: TagsFilter,
then: Translation,
hideInAnswer: boolean
hideInAnswer: boolean | TagsFilter
}): InputElement<TagsFilter> {
if (mapping.hideInAnswer) {
if (mapping.hideInAnswer === true) {
return undefined;
}
if(typeof(mapping.hideInAnswer) !== "boolean" && mapping.hideInAnswer.matches(this._tags.data)){
return undefined;
}
return new FixedInputElement(
@ -251,7 +254,7 @@ export default class TagRenderingQuestion extends UIElement {
const textField = ValidatedTextField.InputForType(this._configuration.freeform.type, {
isValid: (str) => (str.length <= 255),
country: this._tags.data._country,
country: () => this._tags.data._country,
location: [this._tags.data._lat, this._tags.data._lon]
});

View file

@ -0,0 +1,59 @@
/**
* Shows the reviews and scoring base on mangrove.reviesw
*/
import {UIEventSource} from "../../Logic/UIEventSource";
import {Review} from "../../Logic/Web/Review";
import {UIElement} from "../UIElement";
import Combine from "../Base/Combine";
import Translations from "../i18n/Translations";
import SingleReview from "./SingleReview";
export default class ReviewElement extends UIElement {
private readonly _reviews: UIEventSource<Review[]>;
private readonly _subject: string;
private _middleElement: UIElement;
constructor(subject: string, reviews: UIEventSource<Review[]>, middleElement: UIElement) {
super(reviews);
this._middleElement = middleElement;
if (reviews === undefined) {
throw "No reviews UIEVentsource Given!"
}
this._reviews = reviews;
this._subject = subject;
}
InnerRender(): string {
const elements = [];
const revs = this._reviews.data;
revs.sort((a, b) => (b.date.getTime() - a.date.getTime())); // Sort with most recent first
const avg = (revs.map(review => review.rating).reduce((a, b) => a + b, 0) / revs.length);
elements.push(
new Combine([
SingleReview.GenStars(avg).SetClass("stars"),
`<a target="_blank" href='https://mangrove.reviews/search?sub=${encodeURIComponent(this._subject)}'>`,
Translations.t.reviews.title
.Subs({count: "" + revs.length}),
"</a>"
])
.SetClass("review-title"));
elements.push(this._middleElement);
elements.push(...revs.map(review => new SingleReview(review)));
elements.push(
new Combine([
Translations.t.reviews.attribution,
"<img src='./assets/mangrove_logo.png'>"
])
.SetClass("review-attribution"))
return new Combine(elements).SetClass("review").Render();
}
}

119
UI/Reviews/ReviewForm.ts Normal file
View file

@ -0,0 +1,119 @@
import {UIElement} from "../UIElement";
import {InputElement} from "../Input/InputElement";
import {Review} from "../../Logic/Web/Review";
import {UIEventSource} from "../../Logic/UIEventSource";
import {TextField} from "../Input/TextField";
import Translations from "../i18n/Translations";
import Combine from "../Base/Combine";
import Svg from "../../Svg";
import {VariableUiElement} from "../Base/VariableUIElement";
import {SaveButton} from "../Popup/SaveButton";
import CheckBoxes from "../Input/Checkboxes";
import {UserDetails} from "../../Logic/Osm/OsmConnection";
export default class ReviewForm extends InputElement<Review> {
private readonly _value: UIEventSource<Review>;
private readonly _comment: UIElement;
private readonly _stars: UIElement;
private _saveButton: UIElement;
private readonly _isAffiliated: UIElement;
private userDetails: UIEventSource<UserDetails>;
private readonly _postingAs: UIElement;
constructor(onSave: ((r: Review, doneSaving: (() => void)) => void), userDetails: UIEventSource<UserDetails>) {
super();
this.userDetails = userDetails;
const t = Translations.t.reviews;
this._value = new UIEventSource({
made_by_user: new UIEventSource<boolean>(true),
rating: undefined,
comment: undefined,
author: userDetails.data.name,
affiliated: false,
date: new Date()
});
const comment = new TextField({
placeholder: Translations.t.reviews.write_a_comment,
textArea: true,
value: this._value.map(r => r?.comment),
textAreaRows: 5
})
comment.GetValue().addCallback(comment => {
self._value.data.comment = comment;
self._value.ping();
})
const self = this;
this._postingAs =
new Combine([t.posting_as, new VariableUiElement(userDetails.map((ud: UserDetails) => ud.name)).SetClass("review-author")])
.SetStyle("display:flex;flex-direction: column;align-items: flex-end;margin-right: 0.5;")
this._saveButton =
new SaveButton(this._value.map(r => self.IsValid(r)), undefined)
.onClick(() => {
self._saveButton = Translations.t.reviews.saving_review;
onSave(this._value.data, () => {
self._saveButton = Translations.t.reviews.saved.SetClass("thanks");
});
})
this._isAffiliated = new CheckBoxes([t.i_am_affiliated]).SetStyle(" display:inline-block;")
this._comment = comment;
const stars = []
for (let i = 1; i <= 5; i++) {
stars.push(
new VariableUiElement(this._value.map(review => {
if (review.rating === undefined) {
return Svg.star_outline.replace(/#000000/g, "#ccc");
}
return review.rating < i * 20 ?
Svg.star_outline :
Svg.star
}
))
.onClick(() => {
self._value.data.rating = i * 20;
self._value.ping();
})
)
}
this._stars = new Combine(stars).SetClass("review-form-rating")
}
GetValue(): UIEventSource<Review> {
return this._value;
}
InnerRender(): string {
if(!this.userDetails.data.loggedIn){
return Translations.t.reviews.plz_login.Render();
}
return new Combine([
new Combine([this._stars, this._postingAs]).SetClass("review-form-top"),
this._comment,
new Combine([
this._isAffiliated,
this._saveButton
]).SetClass("review-form-bottom"),
"<br/>",
Translations.t.reviews.tos.SetClass("subtle")
])
.SetClass("review-form")
.Render();
}
IsSelected: UIEventSource<boolean> = new UIEventSource<boolean>(false);
IsValid(r: Review): boolean {
if (r === undefined) {
return false;
}
return (r.comment?.length ?? 0) <= 1000 && (r.author?.length ?? 0) <= 20 && r.rating >= 0 && r.rating <= 100;
}
}

View file

@ -0,0 +1,59 @@
import {UIElement} from "../UIElement";
import {Review} from "../../Logic/Web/Review";
import Combine from "../Base/Combine";
import {FixedUiElement} from "../Base/FixedUiElement";
import Translations from "../i18n/Translations";
import {Utils} from "../../Utils";
import ReviewElement from "./ReviewElement";
export default class SingleReview extends UIElement{
private _review: Review;
constructor(review: Review) {
super(review.made_by_user);
this._review = review;
}
public static GenStars(rating: number): UIElement {
if (rating === undefined) {
return Translations.t.reviews.no_rating;
}
if (rating < 10) {
rating = 10;
}
const scoreTen = Math.round(rating / 10);
return new Combine([
"<img src='./assets/svg/star.svg' />".repeat(Math.floor(scoreTen / 2)),
scoreTen % 2 == 1 ? "<img src='./assets/svg/star_half.svg' />" : ""
])
}
InnerRender(): string {
const d = this._review.date;
let review = this._review;
const el= new Combine(
[
new Combine([
SingleReview.GenStars(review.rating)
.SetClass("review-rating"),
new FixedUiElement(review.comment).SetClass("review-comment")
]).SetClass("review-stars-comment"),
new Combine([
new Combine([
new FixedUiElement(review.author).SetClass("review-author"),
review.affiliated ? Translations.t.reviews.affiliated_reviewer_warning : "",
]).SetStyle("margin-right: 0.5em"),
new FixedUiElement(`${d.getFullYear()}-${Utils.TwoDigits(d.getMonth() + 1)}-${Utils.TwoDigits(d.getDate())} ${Utils.TwoDigits(d.getHours())}:${Utils.TwoDigits(d.getMinutes())}`)
.SetClass("review-date")
]).SetClass("review-author-date")
]
);
el.SetClass("review-element");
if(review.made_by_user){
el.SetClass("review-by-current-user")
}
return el.Render();
}
}

View file

@ -12,9 +12,6 @@ export default class ShareButton extends UIElement{
super();
this._embedded = embedded;
this._shareData = shareData;
if(this._shareData.url.indexOf("#")> 0){
this._shareData.url = this._shareData.url.replace("#","&hash_content=");
}
}
InnerRender(): string {

View file

@ -146,14 +146,14 @@ export class ShareScreen extends UIElement {
this._options = new VerticalCombine(optionCheckboxes)
const url = (currentLocation ?? new UIEventSource(undefined)).map(() => {
let literalText = "https://kletterspots.de/" + layout.id.toLowerCase() + ".html"
const host = window.location.host;
let literalText = `https://${host}/${layout.id.toLowerCase()}.html`
const parts = Utils.NoEmpty(Utils.NoNull(optionParts.map((eventSource) => eventSource.data)));
let hash = "";
if (layoutDefinition !== undefined) {
literalText = "https://kletterspots.de/"
literalText = `https://${host}/index.html`
if (layout.id.startsWith("wiki:")) {
parts.push("userlayout=" + encodeURIComponent(layout.id))
} else {

View file

@ -9,6 +9,7 @@ import State from "../State";
import {UIEventSource} from "../Logic/UIEventSource";
import Svg from "../Svg";
import {FixedUiElement} from "./Base/FixedUiElement";
/**
* Asks to add a feature at the last clicked location, at least if zoom is sufficient
@ -21,12 +22,13 @@ export class SimpleAddUI extends UIElement {
private _confirmPreset: UIEventSource<{
description: string | UIElement,
name: string | UIElement,
icon: string,
icon: UIElement,
tags: Tag[],
layerToAddTo: FilteredLayer
}>
= new UIEventSource(undefined);
private confirmButton: UIElement = undefined;
private _confirmDescription: UIElement = undefined;
private openLayerControl: UIElement;
private cancelButton: UIElement;
private goToInboxButton: UIElement = new SubtleButton(Svg.envelope_ui(),
@ -52,8 +54,8 @@ export class SimpleAddUI extends UIElement {
const presets = layer.layerDef.presets;
for (const preset of presets) {
let icon: string = layer.layerDef.icon.GetRenderValue(
TagUtils.KVtoProperties(preset.tags ?? [])).txt
const tags = TagUtils.KVtoProperties(preset.tags ?? []);
let icon: UIElement = new FixedUiElement(layer.layerDef.GenerateLeafletStyle(new UIEventSource<any>(tags), false).icon.html.Render()).SetClass("simple-add-ui-icon");
const csCount = State.state.osmConnection.userDetails.data.csCount;
let tagInfo = "";
@ -68,7 +70,7 @@ export class SimpleAddUI extends UIElement {
"<b>",
preset.title,
"</b>",
preset.description !== undefined ? new Combine(["<br/>", preset.description]) : "",
preset.description !== undefined ? new Combine(["<br/>", preset.description.FirstSentence()]) : "",
tagInfo
])
).onClick(
@ -77,9 +79,9 @@ export class SimpleAddUI extends UIElement {
new Combine([
"<b>",
Translations.t.general.add.confirmButton.Subs({category: preset.title}),
"</b><br/>",
preset.description !== undefined ? preset.description : ""]));
"</b>"]));
self.confirmButton.onClick(self.CreatePoint(preset.tags, layer));
self._confirmDescription = preset.description;
self._confirmPreset.setData({
tags: preset.tags,
layerToAddTo: layer,
@ -147,6 +149,7 @@ export class SimpleAddUI extends UIElement {
userDetails.data.dryRun ? "<span class='alert'>TESTING - changes won't be saved</span>" : "",
this.confirmButton,
this.cancelButton,
this._confirmDescription,
tagInfo
]).Render();
@ -189,7 +192,7 @@ export class SimpleAddUI extends UIElement {
}
if (State.state.locationControl.data.zoom < State.userJourney.minZoomLevelToAddNewPoints) {
return new Combine([header, Translations.t.general.add.zoomInFurther]).Render()
return new Combine([header, Translations.t.general.add.zoomInFurther.SetClass("alert")]).Render()
}
if (State.state.layerUpdater.runningQuery.data) {

View file

@ -12,6 +12,10 @@ import {Translation} from "./i18n/Translation";
import State from "../State";
import ShareButton from "./ShareButton";
import Svg from "../Svg";
import ReviewElement from "./Reviews/ReviewElement";
import MangroveReviews from "../Logic/Web/MangroveReviews";
import Translations from "./i18n/Translations";
import ReviewForm from "./Reviews/ReviewForm";
export class SubstitutedTranslation extends UIElement {
private readonly tags: UIEventSource<any>;
@ -58,7 +62,7 @@ export class SubstitutedTranslation extends UIElement {
for (const knownSpecial of SpecialVisualizations.specialVisualizations) {
// NOte: the '.*?' in the regex reads as 'any character, but in a non-greedy way'
// Note: the '.*?' in the regex reads as 'any character, but in a non-greedy way'
const matched = template.match(`(.*){${knownSpecial.funcName}\\((.*?)\\)}(.*)`);
if (matched != null) {
@ -119,6 +123,7 @@ export default class SpecialVisualizations {
})).SetStyle("border: 1px solid black; border-radius: 1em;padding:1em;display:block;")
})
},
{
funcName: "image_carousel",
docs: "Creates an image carousel for the given sources. An attempt will be made to guess what source is used. Supported: Wikidata identifiers, Wikipedia pages, Wikimedia categories, IMGUR (with attribution, direct links)",
@ -149,6 +154,24 @@ export default class SpecialVisualizations {
return new ImageUploadFlow(tags, args[0])
}
},
{
funcName: "reviews",
docs: "Adds an overview of the mangrove-reviews of this object. IMPORTANT: the _name_ of the object should be defined for this to work!",
args: [],
constr: (tags, args) => {
const tgs = tags.data;
if (tgs.name === undefined || tgs.name === "") {
return Translations.t.reviews.name_required;
}
const mangrove = MangroveReviews.Get(Number(tgs._lon), Number(tgs._lat), tgs.name,
State.state.mangroveIdentity,
State.state.osmConnection._dryRun
);
const form = new ReviewForm((r, whenDone) => mangrove.AddReview(r, whenDone), State.state.osmConnection.userDetails);
return new ReviewElement(mangrove.GetSubjectUri(), mangrove.GetReviews(), form);
}
},
{
funcName: "opening_hours_table",
docs: "Creates an opening-hours table. Usage: {opening_hours_table(opening_hours)} to create a table of the tag 'opening_hours'.",
@ -200,16 +223,20 @@ export default class SpecialVisualizations {
if (window.navigator.share) {
const title = State.state.layoutToUse.data.title.txt;
let name = tagSource.data.name;
if(name){
if (name) {
name = `${name} (${title})`
}else{
} else {
name = title;
}
return new ShareButton(Svg.share_svg(), {
title: name,
url: args[0] ?? window.location.href,
text: State.state.layoutToUse.data.shortDescription.txt
})
let url = args[0] ?? ""
if (url === "") {
url = window.location.href
}
return new ShareButton(Svg.share_svg(), {
title: name,
url: url,
text: State.state.layoutToUse.data.shortDescription.txt
})
} else {
return new FixedUiElement("")
}

View file

@ -1,5 +1,4 @@
import {UIElement} from "./UIElement";
import * as L from "leaflet";
import {FixedUiElement} from "./Base/FixedUiElement";
import {VariableUiElement} from "./Base/VariableUIElement";
import Translations from "./i18n/Translations";
@ -9,7 +8,6 @@ import {UIEventSource} from "../Logic/UIEventSource";
import Combine from "./Base/Combine";
import Svg from "../Svg";
import Link from "./Base/Link";
import {Img} from "./Img";
import LanguagePicker from "./LanguagePicker";
/**
@ -61,7 +59,7 @@ export class UserBadge extends UIElement {
if (home === undefined) {
return;
}
State.state.bm.map.flyTo([home.lat, home.lon], 18);
State.state.bm.map.setView([home.lat, home.lon], 16);
});
}

View file

@ -169,5 +169,14 @@ export class Utils {
}
static MatchKeys(object: any, prototype: any, context?: string){
for (const objectKey in object) {
if(prototype[objectKey] === undefined){
console.error("Key ", objectKey, "might be not supported (in context",context,")")
}
}
}
}

View file

@ -146,6 +146,51 @@
}
]
},
{
"#": "Underground?",
"question": {
"en": "What is the relative location of this bicycle parking?",
"nl": "Wat is de relatieve locatie van deze parking??"
},
"mappings": [
{
"if": "location=underground",
"then": {
"en": "Underground parking",
"nl": "Ondergrondse parking"
}
},
{
"if": "location=underground",
"then": {
"en": "Underground parking",
"nl": "Ondergrondse parking"
}
},
{
"if": "location=surface",
"then": {
"en": "Surface level parking",
"nl": "Parking op de begane grond"
}
},
{
"if": "location=",
"then": {
"en": "Surface level parking",
"nl": "Parking op de begane grond"
},
"hideInAnwser": true
},
{
"if": "location=rooftop",
"then": {
"en": "Rooftop parking",
"nl": "Dakparking"
}
}
]
},
{
"#": "Is covered?",
"question": {
@ -154,7 +199,12 @@
"gl": "Este aparcadoiro está cuberto? Tamén escolle \"cuberto\" para aparcadoiros interiores.",
"de": "Ist dieser Parkplatz überdacht? Wählen Sie auch \"überdacht\" für Innenparkplätze."
},
"condition": "bicycle_parking!=shed",
"condition": {
"and": [
"bicycle_parking!=shed",
"location!=underground"
]
},
"mappings": [
{
"if": "covered=yes",
@ -200,7 +250,7 @@
{
"#": "Access",
"question": {
"en": "Who can use this bicycle?",
"en": "Who can use this bicycle parking?",
"nl": "Wie mag er deze fietsenstalling gebruiken?"
},
"render": {

View file

@ -0,0 +1,148 @@
<?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="98"
height="98"
viewBox="0 0 98 98"
version="1.1"
id="svg42"
sodipodi:docname="logo.svg"
style="fill:none"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata46">
<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 />
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1001"
id="namedview44"
showgrid="false"
inkscape:zoom="4"
inkscape:cx="-2.2900136"
inkscape:cy="62.988337"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer4" />
<defs
id="defs40">
<filter
id="filter0_d"
x="-3"
y="2"
width="102.479"
height="102.479"
filterUnits="userSpaceOnUse"
style="color-interpolation-filters:sRGB">
<feFlood
flood-opacity="0"
result="BackgroundImageFix"
id="feFlood22" />
<feColorMatrix
in="SourceAlpha"
type="matrix"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
id="feColorMatrix24" />
<feOffset
dy="4"
id="feOffset26" />
<feGaussianBlur
stdDeviation="2"
id="feGaussianBlur28" />
<feColorMatrix
type="matrix"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"
id="feColorMatrix30" />
<feBlend
mode="normal"
in2="BackgroundImageFix"
result="effect1_dropShadow"
id="feBlend32" />
<feBlend
mode="normal"
in="SourceGraphic"
in2="effect1_dropShadow"
result="shape"
id="feBlend34" />
</filter>
<clipPath
id="clip0">
<rect
width="66.806396"
height="66.806396"
transform="rotate(-45,59.937093,23.412543)"
id="rect37"
x="0"
y="0"
style="fill:#ffffff" />
</clipPath>
</defs>
<g
inkscape:groupmode="layer"
id="layer1"
inkscape:label="re"
style="display:inline"
transform="translate(-12.466103,-2.0847473)">
<rect
style="fill:#fffcff;fill-opacity:1;stroke:#ffffff;stroke-width:3.50900006;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect834"
width="23.963444"
height="3.9908068"
x="47.66375"
y="21.641689" />
<rect
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect839"
width="6.5160999"
height="8.9842997"
x="56.447304"
y="27.271845" />
<path
style="fill:none;stroke:#ffffff;stroke-width:7.93900013;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 47.842047,77.142657 23.821625,0.209511"
id="path842"
inkscape:connector-curvature="0" />
<rect
style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:2.87199998;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect863"
width="7.4682202"
height="36.044868"
x="55.90678"
y="37.580132" />
<path
style="display:inline;fill:none;stroke:#ffffff;stroke-width:2.5999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 64.040577,70.321209 c 0,0 6.250256,1.104191 6.250256,-4.19911 0,-5.303301 0,-31.201087 0,-31.201087 0,0 0.176777,-3.623922 4.154253,-3.623922 3.977475,0 4.065864,3.447145 4.065864,3.447145 l 0.08839,29.875262"
id="path868"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cscscc" />
<path
style="display:inline;fill:#fffeff;fill-opacity:1;stroke:#fffeff;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.97014926"
d="m 76.543734,62.21875 4.018766,-0.03125 0.125,4.640625 3,-0.0625 0.104018,4.221891 -3.783471,-0.02589 c -2.730516,-0.27045 -3.676466,-1.207877 -3.48639,-3.569907 z"
id="path871"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.1 KiB

View file

@ -71,6 +71,21 @@
"gl": "Bomba de ar estragada",
"de": "Kaputte Pumpe"
}
},{
"if": {
"and": [
"service:bicycle:pump=yes",
"service:bicycle:tools=no",
"name~*"
]
},
"then": {
"en": "Bicycle pump <i>{name}</i>",
"nl": "Fietspomp <i>{name}</i>",
"fr": "Pompe de vélo <i>{name}</i>",
"gl": "Bomba de ar <i>{name}</i>",
"de": "Fahrradpumpe <i>{name}</i>"
}
},
{
"if": {
@ -94,8 +109,7 @@
"render": "<a href='https://fietsambassade.gent.be/' target='_blank'><img src='./assets/themes/cyclofix/fietsambassade_gent_logo_small.svg'/></a>",
"condition": "operator=De Fietsambassade Gent"
},
"wikipedialink",
"osmlink"
"defaults"
],
"tagRenderings": [
"images",
@ -174,6 +188,34 @@
}
]
},
{
"question": {
"nl": "Wanneer is dit fietsherstelpunt open?",
"en": "When is this bicycle repair point opened?"
},
"render": "{opening_hours_table()}",
"freeform": {
"key": "opening_hours",
"type": "opening_hours"
},
"mappings": [
{
"if": "opening_hours=24/7",
"then": {
"nl": "Dag en nacht open",
"en": "Always opened"
}
},
{
"if": "opening_hours=",
"then": {
"nl": "Dag en nacht open",
"en": "Always opened"
},
"hideInAnswer": true
}
]
},
{
"question": {
"en": "Does this bike repair station have a special tool to repair your bike chain?",
@ -448,6 +490,13 @@
}
]
},
"iconOverlays": [
{
"if": "operator=De Fietsambassade Gent",
"then": "./assets/themes/cyclofix/fietsambassade_gent_logo_small.svg",
"badge": true
}
],
"iconSize": {
"render": {
"en": "50,50,bottom"
@ -477,7 +526,11 @@
"amenity=bicycle_repair_station",
"service:bicycle:tools=no",
"service:bicycle:pump=yes"
]
],
"description": {
"en": "A device to inflate your tires on a fixed location in the public space.<h3>Examples of bicycle pumps</h3><img src='./assets/layers/bike_repair_station/pump_example_manual.jpg' height='200'/><img src='./assets/layers/bike_repair_station/pump_example.png' height='200'/><img src='./assets/layers/bike_repair_station/pump_example_round.jpg' height='200'/>",
"nl": "Een apparaat waar je je fietsbanden kan oppompen, beschikbaar in de publieke ruimte. De fietspomp in je kelder telt dus niet.<h3>Voorbeelden</h3><img src='./assets/layers/bike_repair_station/pump_example_manual.jpg' height='200'/><img src='./assets/layers/bike_repair_station/pump_example.png' height='200'/><img src='./assets/layers/bike_repair_station/pump_example_round.jpg' height='200'/>"
}
},
{
"title": {
@ -491,7 +544,11 @@
"amenity=bicycle_repair_station",
"service:bicycle:tools=yes",
"service:bicycle:pump=yes"
]
],
"description": {
"en": "A device with tools to repair your bike combined with a pump at a fixed location. The tools are often secured with chains against theft.<h3>Example</h3><img src='./assets/layers/bike_repair_station/repair_station_example.jpg' height='200'/>",
"nl": "Een apparaat met zowel gereedschap om je fiets te herstellen, met een pomp. Deze zijn op een vastgemaakt op een plaats in de publieke ruimte, bv. aan een paal.<h3>Voorbeeld</h3><img src='./assets/layers/bike_repair_station/repair_station_example.jpg' height='200'/>"
}
},
{
"title": {

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 942 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 760 KiB

View file

@ -195,10 +195,7 @@
},
"render": "<img src='./assets/layers/bike_shop/bike_cleaning.svg'/>"
},
"phonelink",
"wikipedialink",
"osmlink",
"sharelink"
"defaults"
],
"description": {
"en": "A shop specifically selling bicycles or related items",
@ -580,6 +577,18 @@
}
]
},
"iconOverlays": [
{
"if": "opening_hours~*",
"then": "isOpen",
"badge": true
},
{
"if": "service:bicycle:pump=yes",
"then": "circle:#e2783d;./assets/layers/bike_repair_station/pump.svg",
"badge": true
}
],
"width": {
"render": "1"
},

View file

@ -17,15 +17,21 @@
}
},
"icon": {
"render": "./assets/layers/drinking_water/drinking_water.svg",
"mappings": [
{
"if": {"or": ["operational_status=broken", "operational_status=closed"]},
"then": "./assets/layers/drinking_water/drinking_water_broken.svg"
}
]
"render": "pin:#6BC4F7;./assets/layers/drinking_water/drips.svg"
},
"iconOverlays": [
{
"if": {
"or": [
"operational_status=broken",
"operational_status=closed"
]
},
"then": "close:#c33",
"badge": true
}
],
"iconSize": "40,40,bottom",
"overpassTags": {
"and": [

View file

@ -1,18 +0,0 @@
<svg width="98" height="124" viewBox="0 0 98 124" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M55.0445 114.094C53.2614 117.981 47.7386 117.981 45.9555 114.094L15.2124 47.085C13.6928 43.7729 16.1129 40 19.7569 40L81.2431 40C84.8871 40 87.3072 43.7729 85.7876 47.085L55.0445 114.094Z" fill="#6BC4F7"/>
<circle cx="49" cy="49" r="49" fill="#6BC4F7"/>
<g filter="url(#filter0_d)">
<path d="M79 41.8705C79 39.3976 77.4079 35.6726 74.1327 30.4823C71.8064 26.7956 69.5171 23.8005 69.4208 23.6747C69.0964 23.2513 68.5726 23 68.0144 23C67.4562 23 66.9322 23.2514 66.6078 23.6748C66.3787 23.9738 61.828 29.939 59.0942 35.3688C54.8849 28.8794 50.9494 23.7307 50.9067 23.6748C50.5821 23.2513 50.0582 23 49.5 23C48.9418 23 48.4179 23.2513 48.0934 23.6747C48.0468 23.7357 43.367 29.8581 38.753 37.1701C38.2587 37.9536 37.7856 38.7192 37.3295 39.4706C34.9483 35.6504 32.5162 32.4661 32.3922 32.3043C32.0677 31.8809 31.5438 31.6296 30.9856 31.6296C30.4274 31.6296 29.9036 31.8809 29.5791 32.3043C29.4828 32.43 27.1935 35.4252 24.8672 39.1119C21.5921 44.3021 20 48.0271 20 50.5C20 55.6193 24.0504 59.8732 29.3205 60.6234C30.1402 70.3329 38.8775 78 49.5 78C60.6619 78 69.7429 69.5347 69.7429 59.1295C69.7429 57.2539 69.2077 54.9089 68.1449 52.1097C74.1423 52.0443 79 47.4766 79 41.8705V41.8705ZM23.457 50.5C23.457 49.457 24.0257 46.8053 27.8344 40.7656C28.9755 38.9562 30.126 37.2947 30.9856 36.0929C32.1576 37.7318 33.8718 40.2278 35.3741 42.8008C31.9223 48.9002 29.9183 53.7824 29.3954 57.3607C26.0053 56.6784 23.457 53.8613 23.457 50.5V50.5ZM49.5 74.7773C40.2443 74.7773 32.7142 67.7578 32.7142 59.1295C32.7142 56.3792 34.2766 50.6239 41.7201 38.8241C44.7375 34.0407 47.784 29.7745 49.5 27.4354C51.213 29.7702 54.2519 34.0258 57.2673 38.8042C64.7212 50.6167 66.2857 56.3773 66.2857 59.1296C66.2858 67.7578 58.7557 74.7773 49.5 74.7773V74.7773ZM68.0144 48.8887C67.5836 48.8887 67.156 48.8549 66.7362 48.7879C65.3713 45.8533 63.5372 42.506 61.2717 38.8163C62.8077 35.0043 66.1199 30.1147 68.0149 27.4638C68.8707 28.6601 70.0148 30.3125 71.153 32.1162C74.9727 38.1694 75.543 40.8257 75.543 41.8705C75.543 45.7402 72.1656 48.8887 68.0144 48.8887V48.8887Z" fill="white"/>
</g>
<defs>
<filter id="filter0_d" x="16" y="23" width="67" height="63" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
<feOffset dy="4"/>
<feGaussianBlur stdDeviation="2"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
</filter>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -1,124 +0,0 @@
<?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="98"
height="124"
viewBox="0 0 98 124"
fill="none"
version="1.1"
id="svg27"
sodipodi:docname="drinking_water_broken.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata31">
<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>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1043"
id="namedview29"
showgrid="false"
inkscape:zoom="1.9032258"
inkscape:cx="49"
inkscape:cy="62"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg27" />
<path
d="M55.0445 114.094C53.2614 117.981 47.7386 117.981 45.9555 114.094L15.2124 47.085C13.6928 43.7729 16.1129 40 19.7569 40L81.2431 40C84.8871 40 87.3072 43.7729 85.7876 47.085L55.0445 114.094Z"
fill="#6BC4F7"
id="path2" />
<circle
cx="49"
cy="49"
r="49"
fill="#6BC4F7"
id="circle4" />
<g
filter="url(#filter0_d)"
id="g8">
<path
d="M79 41.8705C79 39.3976 77.4079 35.6726 74.1327 30.4823C71.8064 26.7956 69.5171 23.8005 69.4208 23.6747C69.0964 23.2513 68.5726 23 68.0144 23C67.4562 23 66.9322 23.2514 66.6078 23.6748C66.3787 23.9738 61.828 29.939 59.0942 35.3688C54.8849 28.8794 50.9494 23.7307 50.9067 23.6748C50.5821 23.2513 50.0582 23 49.5 23C48.9418 23 48.4179 23.2513 48.0934 23.6747C48.0468 23.7357 43.367 29.8581 38.753 37.1701C38.2587 37.9536 37.7856 38.7192 37.3295 39.4706C34.9483 35.6504 32.5162 32.4661 32.3922 32.3043C32.0677 31.8809 31.5438 31.6296 30.9856 31.6296C30.4274 31.6296 29.9036 31.8809 29.5791 32.3043C29.4828 32.43 27.1935 35.4252 24.8672 39.1119C21.5921 44.3021 20 48.0271 20 50.5C20 55.6193 24.0504 59.8732 29.3205 60.6234C30.1402 70.3329 38.8775 78 49.5 78C60.6619 78 69.7429 69.5347 69.7429 59.1295C69.7429 57.2539 69.2077 54.9089 68.1449 52.1097C74.1423 52.0443 79 47.4766 79 41.8705V41.8705ZM23.457 50.5C23.457 49.457 24.0257 46.8053 27.8344 40.7656C28.9755 38.9562 30.126 37.2947 30.9856 36.0929C32.1576 37.7318 33.8718 40.2278 35.3741 42.8008C31.9223 48.9002 29.9183 53.7824 29.3954 57.3607C26.0053 56.6784 23.457 53.8613 23.457 50.5V50.5ZM49.5 74.7773C40.2443 74.7773 32.7142 67.7578 32.7142 59.1295C32.7142 56.3792 34.2766 50.6239 41.7201 38.8241C44.7375 34.0407 47.784 29.7745 49.5 27.4354C51.213 29.7702 54.2519 34.0258 57.2673 38.8042C64.7212 50.6167 66.2857 56.3773 66.2857 59.1296C66.2858 67.7578 58.7557 74.7773 49.5 74.7773V74.7773ZM68.0144 48.8887C67.5836 48.8887 67.156 48.8549 66.7362 48.7879C65.3713 45.8533 63.5372 42.506 61.2717 38.8163C62.8077 35.0043 66.1199 30.1147 68.0149 27.4638C68.8707 28.6601 70.0148 30.3125 71.153 32.1162C74.9727 38.1694 75.543 40.8257 75.543 41.8705C75.543 45.7402 72.1656 48.8887 68.0144 48.8887V48.8887Z"
fill="white"
id="path6" />
</g>
<defs
id="defs25">
<filter
id="filter0_d"
x="16"
y="23"
width="67"
height="63"
filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB">
<feFlood
flood-opacity="0"
result="BackgroundImageFix"
id="feFlood10" />
<feColorMatrix
in="SourceAlpha"
type="matrix"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
id="feColorMatrix12" />
<feOffset
dy="4"
id="feOffset14" />
<feGaussianBlur
stdDeviation="2"
id="feGaussianBlur16" />
<feColorMatrix
type="matrix"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"
id="feColorMatrix18" />
<feBlend
mode="normal"
in2="BackgroundImageFix"
result="effect1_dropShadow"
id="feBlend20" />
<feBlend
mode="normal"
in="SourceGraphic"
in2="effect1_dropShadow"
result="shape"
id="feBlend22" />
</filter>
</defs>
<g
style="display:inline;fill:none"
id="g878"
transform="matrix(1.323177,0,0,1.323177,-54.427394,-2.8930963)">
<path
inkscape:connector-curvature="0"
id="path842-3"
d="M 80.687554,63.907833 97.680134,47.211548"
style="display:inline;fill:none;stroke:#ff002f;stroke-width:7.93900013;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path842-3-6"
d="m 80.747314,46.886624 16.696285,16.99258"
style="display:inline;fill:none;stroke:#ff002f;stroke-width:7.93900013;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.3 KiB

View file

@ -0,0 +1,101 @@
<?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="98"
height="124"
viewBox="0 0 98 124"
fill="none"
version="1.1"
id="svg27"
sodipodi:docname="drips.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata31">
<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>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="995"
id="namedview29"
showgrid="false"
inkscape:zoom="1.9032258"
inkscape:cx="-125.44068"
inkscape:cy="62"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg27" />
<g
id="g8"
transform="matrix(1.1921948,0,0,1.1921948,-9.5136428,-10.474617)"
style="filter:url(#filter0_d)">
<path
d="M 79,41.8705 C 79,39.3976 77.4079,35.6726 74.1327,30.4823 71.8064,26.7956 69.5171,23.8005 69.4208,23.6747 69.0964,23.2513 68.5726,23 68.0144,23 c -0.5582,0 -1.0822,0.2514 -1.4066,0.6748 -0.2291,0.299 -4.7798,6.2642 -7.5136,11.694 C 54.8849,28.8794 50.9494,23.7307 50.9067,23.6748 50.5821,23.2513 50.0582,23 49.5,23 c -0.5582,0 -1.0821,0.2513 -1.4066,0.6747 -0.0466,0.061 -4.7264,6.1834 -9.3404,13.4954 -0.4943,0.7835 -0.9674,1.5491 -1.4235,2.3005 -2.3812,-3.8202 -4.8133,-7.0045 -4.9373,-7.1663 -0.3245,-0.4234 -0.8484,-0.6747 -1.4066,-0.6747 -0.5582,0 -1.082,0.2513 -1.4065,0.6747 -0.0963,0.1257 -2.3856,3.1209 -4.7119,6.8076 C 21.5921,44.3021 20,48.0271 20,50.5 c 0,5.1193 4.0504,9.3732 9.3205,10.1234 C 30.1402,70.3329 38.8775,78 49.5,78 c 11.1619,0 20.2429,-8.4653 20.2429,-18.8705 0,-1.8756 -0.5352,-4.2206 -1.598,-7.0198 C 74.1423,52.0443 79,47.4766 79,41.8705 Z M 23.457,50.5 c 0,-1.043 0.5687,-3.6947 4.3774,-9.7344 1.1411,-1.8094 2.2916,-3.4709 3.1512,-4.6727 1.172,1.6389 2.8862,4.1349 4.3885,6.7079 -3.4518,6.0994 -5.4558,10.9816 -5.9787,14.5599 C 26.0053,56.6784 23.457,53.8613 23.457,50.5 Z M 49.5,74.7773 c -9.2557,0 -16.7858,-7.0195 -16.7858,-15.6478 0,-2.7503 1.5624,-8.5056 9.0059,-20.3054 3.0174,-4.7834 6.0639,-9.0496 7.7799,-11.3887 1.713,2.3348 4.7519,6.5904 7.7673,11.3688 7.4539,11.8125 9.0184,17.5731 9.0184,20.3254 10e-5,8.6282 -7.53,15.6477 -16.7857,15.6477 z M 68.0144,48.8887 c -0.4308,0 -0.8584,-0.0338 -1.2782,-0.1008 -1.3649,-2.9346 -3.199,-6.2819 -5.4645,-9.9716 1.536,-3.812 4.8482,-8.7016 6.7432,-11.3525 0.8558,1.1963 1.9999,2.8487 3.1381,4.6524 3.8197,6.0532 4.39,8.7095 4.39,9.7543 0,3.8697 -3.3774,7.0182 -7.5286,7.0182 z"
id="path6"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
</g>
<defs
id="defs25">
<filter
id="filter0_d"
x="16"
y="23"
width="67"
height="63"
filterUnits="userSpaceOnUse"
color-interpolation-filters="sRGB">
<feFlood
flood-opacity="0"
result="BackgroundImageFix"
id="feFlood10" />
<feColorMatrix
in="SourceAlpha"
type="matrix"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
id="feColorMatrix12" />
<feOffset
dy="4"
id="feOffset14" />
<feGaussianBlur
stdDeviation="2"
id="feGaussianBlur16" />
<feColorMatrix
type="matrix"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"
id="feColorMatrix18" />
<feBlend
mode="normal"
in2="BackgroundImageFix"
result="effect1_dropShadow"
id="feBlend20" />
<feBlend
mode="normal"
in="SourceGraphic"
in2="effect1_dropShadow"
result="shape"
id="feBlend22" />
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

View file

@ -341,7 +341,7 @@
}
],
"hideUnderlayingFeaturesMinPercentage": 10,
"wayHandling": 1,
"wayHandling": 2,
"icon": {
"render": "./assets/themes/buurtnatuur/nature_reserve.svg"
},

View file

@ -0,0 +1,349 @@
{
"id": "public_bookcases",
"name": {
"en": "Bookcases",
"nl": "Boekenruilkastjes",
"de": "Bücherschränke",
"fr": "Microbibliothèque"
},
"description": {
"en": "A streetside cabinet with books, accessible to anyone",
"nl": "Een straatkastje met boeken voor iedereen",
"de": "Ein Bücherschrank am Straßenrand mit Büchern, für jedermann zugänglich",
"fr": "Une armoire ou une boite contenant des livres en libre accès"
},
"overpassTags": "amenity=public_bookcase",
"minzoom": 12,
"wayHandling": 2,
"title": {
"render": {
"en": "Bookcase",
"nl": "Boekenruilkast",
"de": "Bücherschrank",
"fr": "Microbibliothèque"
},
"mappings": [
{
"if": "name~*",
"then": {
"en": "Public bookcase <i>{name}</i>",
"nl": "Boekenruilkast <i>{name}</i>",
"de": "Öffentlicher Bücherschrank <i>{name}</i>",
"fr": "Microbibliothèque <i>{name}</i>"
}
}
]
},
"icon": {
"render": "./assets/themes/bookcases/bookcase.svg"
},
"color": {
"render": "#0000ff"
},
"width": {
"render": "8"
},
"presets": [
{
"title": {
"en": "Bookcase",
"nl": "Boekenruilkast",
"de": "Bücherschrank",
"fr": "Microbibliothèque"
},
"tags": [
"amenity=public_bookcase"
]
}
],
"tagRenderings": [
"images",
{
"render": {
"en": "The name of this bookcase is {name}",
"nl": "De naam van dit boekenruilkastje is {name}",
"de": "Der Name dieses Bücherschrank lautet {name}",
"fr": "Le nom de cette microbibliothèque est {name}"
},
"question": {
"en": "What is the name of this public bookcase?",
"nl": "Wat is de naam van dit boekenuilkastje?",
"de": "Wie heißt dieser öffentliche Bücherschrank?",
"fr": "Quel est le nom de cette microbibliothèque ?"
},
"freeform": {
"key": "name"
},
"mappings": [
{
"if": {
"and": [
"noname=yes",
"name="
]
},
"then": {
"en": "This bookcase doesn't have a name",
"nl": "Dit boekenruilkastje heeft geen naam",
"de": "Dieser Bücherschrank hat keinen Namen",
"fr": "Cette microbibliothèque n'a pas de nom"
}
}
]
},
{
"render": {
"en": "{capacity} books fit in this bookcase",
"nl": "Er passen {capacity} boeken",
"de": "{capacity} Bücher passen in diesen Bücherschrank",
"fr": "{capacity} livres rentrent dans cette microbibliothèque"
},
"question": {
"en": "How many books fit into this public bookcase?",
"nl": "Hoeveel boeken passen er in dit boekenruilkastje?",
"de": "Wie viele Bücher passen in diesen öffentlichen Bücherschrank?",
"fr": "Combien de livre rentrent dans cette microbibliothèque ?"
},
"freeform": {
"key": "capacity",
"type": "nat"
}
},
{
"question": {
"en": "What kind of books can be found in this public bookcase?",
"nl": "Voor welke doelgroep zijn de meeste boeken in dit boekenruilkastje?",
"de": "Welche Art von Büchern sind in diesem öffentlichen Bücherschrank zu finden?",
"fr": "Quel type de livres peuvent être trouvés dans cette microbibliothèque ?"
},
"mappings": [
{
"if": "books=children",
"then": {
"en": "Mostly children books",
"nl": "Voornamelijk kinderboeken",
"de": "Vorwiegend Kinderbücher",
"fr": "Livres pour enfants"
}
},
{
"if": "books=adults",
"then": {
"en": "Mostly books for adults",
"nl": "Voornamelijk boeken voor volwassenen",
"de": "Vorwiegend Bücher für Erwachsene",
"fr": "Livres pour les adultes"
}
},
{
"if": "books=children;adults",
"then": {
"en": "Both books for kids and adults",
"nl": "Boeken voor zowel kinderen als volwassenen",
"de": "Sowohl Bücher für Kinder als auch für Erwachsene",
"fr": "Livres pour enfants et adultes également"
}
}
]
},
{
"question": {
"en": "Is this bookcase located outdoors?",
"nl": "Staat dit boekenruilkastje binnen of buiten?",
"de": "Befindet sich dieser Bücherschrank im Freien?",
"fr": "Cette microbiliothèque est-elle en extérieur ?"
},
"mappings": [
{
"then": {
"en": "This bookcase is located indoors",
"nl": "Dit boekenruilkastje staat binnen",
"de": "Dieser Bücherschrank befindet sich im Innenbereich",
"fr": "Cette microbibliothèque est en intérieur"
},
"if": "indoor=yes"
},
{
"then": {
"en": "This bookcase is located outdoors",
"nl": "Dit boekenruilkastje staat buiten",
"de": "Dieser Bücherschrank befindet sich im Freien",
"fr": "Cette microbibliothèque est en extérieur"
},
"if": "indoor=no"
},
{
"then": {
"en": "This bookcase is located outdoors",
"nl": "Dit boekenruilkastje staat buiten",
"de": "Dieser Bücherschrank befindet sich im Freien",
"fr": "Cette microbibliothèque est en extérieur"
},
"if": "indoor=",
"hideInAnswer": true
}
]
},
{
"question": {
"en": "Is this public bookcase freely accessible?",
"nl": "Is dit boekenruilkastje publiek toegankelijk?",
"de": "Ist dieser öffentliche Bücherschrank frei zugänglich?",
"fr": "Cette microbibliothèque est-elle librement accèssible ?"
},
"condition": "indoor=yes",
"mappings": [
{
"then": {
"en": "Publicly accessible",
"nl": "Publiek toegankelijk",
"de": "Öffentlich zugänglich",
"fr": "Accèssible au public"
},
"if": "access=yes"
},
{
"then": {
"en": "Only accessible to customers",
"nl": "Enkel toegankelijk voor klanten",
"de": "Nur für Kunden zugänglich",
"fr": "Accèssible aux clients"
},
"if": "access=customers"
}
]
},
{
"question": {
"en": "Who maintains this public bookcase?",
"nl": "Wie is verantwoordelijk voor dit boekenruilkastje?",
"de": "Wer unterhält diesen öffentlichen Bücherschrank?",
"fr": "Qui entretien cette microbibliothèque"
},
"render": {
"en": "Operated by {operator}",
"nl": "Onderhouden door {operator}",
"de": "Betrieben von {operator}",
"fr": "Entretenue par {operator}"
},
"freeform": {
"type": "string",
"key": "operator"
}
},
{
"question": {
"en": "Is this public bookcase part of a bigger network?",
"nl": "Is dit boekenruilkastje deel van een netwerk?",
"de": "Ist dieser öffentliche Bücherschrank Teil eines größeren Netzwerks?",
"fr": "Cette microbibliothèque fait-elle partie d'un réseau/groupe ?"
},
"render": {
"en": "This public bookcase is part of {brand}",
"nl": "Dit boekenruilkastje is deel van het netwerk {brand}",
"de": "Dieser Bücherschrank ist Teil von {brand}",
"fr": "Cette microbibliothèque fait partie du groupe {brand}"
},
"condition": "ref=",
"freeform": {
"key": "brand"
},
"mappings": [
{
"then": {
"en": "Part of the network 'Little Free Library'",
"nl": "Deel van het netwerk 'Little Free Library'",
"de": "Teil des Netzwerks 'Little Free Library'",
"fr": "Fait partie du réseau 'Little Free Library'"
},
"if": "brand=Little Free Library"
},
{
"if": {
"and": [
"nobrand=yes",
"brand="
]
},
"then": {
"en": "This public bookcase is not part of a bigger network",
"nl": "Dit boekenruilkastje maakt geen deel uit van een netwerk",
"de": "Dieser öffentliche Bücherschrank ist nicht Teil eines größeren Netzwerks",
"fr": "Cette microbibliothèque ne fait pas partie d'un réseau/groupe"
}
}
]
},
{
"render": {
"en": "The reference number of this public bookcase within {brand} is {ref}",
"nl": "Het referentienummer binnen {brand} is {ref}",
"de": "Die Referenznummer dieses öffentlichen Bücherschranks innerhalb {brand} lautet {ref}",
"fr": "Cette microbibliothèque du réseau {brand} possède le numéro {ref}"
},
"question": {
"en": "What is the reference number of this public bookcase?",
"nl": "Wat is het referentienummer van dit boekenruilkastje?",
"de": "Wie lautet die Referenznummer dieses öffentlichen Bücherschranks?",
"fr": "Quelle est le numéro de référence de cette microbibliothèque ?"
},
"condition": "brand~*",
"freeform": {
"key": "ref"
},
"mappings": [
{
"then": {
"en": "This bookcase is not part of a bigger network",
"nl": "Dit boekenruilkastje maakt geen deel uit van een netwerk",
"de": "Dieser Bücherschrank ist nicht Teil eines größeren Netzwerks",
"fr": "Cette microbibliothèque ne fait pas partie d'un réseau/groupe"
},
"if": {
"and": [
"nobrand=yes",
"brand=",
"ref="
]
}
}
]
},
{
"question": {
"en": "When was this public bookcase installed?",
"nl": "Op welke dag werd dit boekenruilkastje geinstalleerd?",
"de": "Wann wurde dieser öffentliche Bücherschrank installiert?",
"fr": "Quand a été installée cette microbibliothèque ?"
},
"render": {
"en": "Installed on {start_date}",
"nl": "Geplaatst op {start_date}",
"de": "Installiert am {start_date}",
"fr": "Installée le {start_date}"
},
"freeform": {
"key": "start_date",
"type": "date"
}
},
{
"render": {
"en": "More info on <a href='{website}' target='_blank'>the website</a>",
"nl": "Meer info op <a href='{website}' target='_blank'>de website</a>",
"de": "Weitere Informationen auf <a href='{website}' target='_blank'>der Webseite</a>",
"fr": "Plus d'info sur <a href='{website} target='_blank'>le site web</a>"
},
"question": {
"en": "Is there a website with more information about this public bookcase?",
"nl": "Is er een website over dit boekenruilkastje?",
"de": "Gibt es eine Webseite mit weiteren Informationen über diesen öffentlichen Bücherschrank?",
"fr": "Existe-t-il un site web avec plus d'information sur cette microbibliothèque ?"
},
"freeform": {
"key": "website",
"type": "url"
}
}
]
}

BIN
assets/mangrove_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

14
assets/svg/circle.svg Normal file
View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
style="fill:none"
version="1.1"
viewBox="0 0 100 100"
height="100"
width="100">
<circle
style="fill:#000000;fill-opacity:1"
id="circle4"
r="50"
cy="50"
cx="50" />
</svg>

After

Width:  |  Height:  |  Size: 272 B

36
assets/svg/clock.svg Normal file
View file

@ -0,0 +1,36 @@
<?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"
id="svg5"
style="fill:none"
version="1.1"
viewBox="0 0 100 100"
height="100"
width="100">
<metadata
id="metadata11">
<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="defs9" />
<path
style="fill:none;stroke:#000000;stroke-width:9;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 46,55.932203 H 66.550847"
id="path823" />
<path
style="fill:none;stroke:#000000;stroke-width:9;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 46,55.533898 v -27.805085 0"
id="path825" />
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<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="100"
height="100"
viewBox="0 0 26.458333 26.458334"
version="1.1"
id="svg8"
sodipodi:docname="cross_bottom_right.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.8284271"
inkscape:cx="-71.204807"
inkscape:cy="118.94409"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1920"
inkscape:window-height="995"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1">
<sodipodi:guide
position="13.229167,23.859748"
orientation="1,0"
id="guide815"
inkscape:locked="false" />
<sodipodi:guide
position="14.944824,13.229167"
orientation="0,1"
id="guide817"
inkscape:locked="false" />
</sodipodi:namedview>
<metadata
id="metadata5">
<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 />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-270.54165)">
<g
id="g836"
transform="matrix(0.82247743,0,0,0.82247743,9.1847058,57.199661)">
<path
inkscape:connector-curvature="0"
id="path815"
d="M 18.972892,289.3838 7.7469352,278.15784 v 0"
style="fill:none;stroke:#000000;stroke-width:3.4395833;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path815-3"
d="M 18.98982,278.10371 7.7638604,289.32967 v 0"
style="fill:none;stroke:#000000;stroke-width:3.4395833;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

102
assets/svg/pin.svg Normal file
View file

@ -0,0 +1,102 @@
<?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="98"
height="117.00925"
viewBox="0 0 98 117.00925"
version="1.1"
id="svg27"
sodipodi:docname="pin.svg"
style="fill:none"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata31">
<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>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="995"
id="namedview29"
showgrid="false"
inkscape:zoom="5.3831355"
inkscape:cx="61.971609"
inkscape:cy="57.776671"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg27" />
<path
d="m 55.0445,114.094 c -1.7831,3.887 -7.3059,3.887 -9.089,0 L 15.2124,47.085 C 13.6928,43.7729 16.1129,40 19.7569,40 h 61.4862 c 3.644,0 6.0641,3.7729 4.5445,7.085 z"
id="path2"
inkscape:connector-curvature="0"
style="fill:#000000;fill-opacity:1" />
<circle
cx="49"
cy="49"
r="49"
id="circle4"
style="fill:#000000;fill-opacity:1" />
<defs
id="defs25">
<filter
id="filter0_d"
x="16"
y="23"
width="67"
height="63"
filterUnits="userSpaceOnUse"
style="color-interpolation-filters:sRGB">
<feFlood
flood-opacity="0"
result="BackgroundImageFix"
id="feFlood10" />
<feColorMatrix
in="SourceAlpha"
type="matrix"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
id="feColorMatrix12" />
<feOffset
dy="4"
id="feOffset14" />
<feGaussianBlur
stdDeviation="2"
id="feGaussianBlur16" />
<feColorMatrix
type="matrix"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"
id="feColorMatrix18" />
<feBlend
mode="normal"
in2="BackgroundImageFix"
result="effect1_dropShadow"
id="feBlend20" />
<feBlend
mode="normal"
in="SourceGraphic"
in2="effect1_dropShadow"
result="shape"
id="feBlend22" />
</filter>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

34
assets/svg/ring.svg Normal file
View file

@ -0,0 +1,34 @@
<?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"
id="svg5"
style="fill:none"
version="1.1"
viewBox="0 0 100 100"
height="100"
width="100">
<metadata
id="metadata11">
<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="defs9" />
<circle
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:10;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="circle4"
r="45.0"
cy="50"
cx="50" />
</svg>

After

Width:  |  Height:  |  Size: 924 B

89
assets/svg/send_email.svg Normal file
View file

@ -0,0 +1,89 @@
<?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"
id="svg4"
version="1.1"
viewBox="0 0 114 114"
height="114"
width="114"
sodipodi:docname="send_email.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1043"
id="namedview10"
showgrid="false"
inkscape:zoom="8.2807017"
inkscape:cx="88.036216"
inkscape:cy="65.244666"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg4" />
<metadata
id="metadata10">
<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 />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<path
id="path817"
d="M 3.8621242,4.4070108 30.859027,32.600653 c 0,0 10.017786,11.850409 21.207654,0 C 68.137354,15.581325 79.709909,3.9950038 79.709909,3.9950038"
style="fill:none;stroke:#000000;stroke-width:6.67276907;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
id="path823"
d="M 3.5728144,4.2106267 79.709909,3.9950038 79.830672,61.118664"
style="fill:none;stroke:#000000;stroke-width:6.57718801;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<path
id="path823-3"
d="M 80.022174,61.299435 3.5728144,61.696575 V 4.2106267"
style="fill:none;stroke:#000000;stroke-width:6.57718801;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0" />
<path
d="M 56.292497,77.917252 V 95.007654 H 88.45805 v 16.606216 l 24.81119,-24.785005 -24.81119,-25.099078 0.0066,16.194007 z"
id="path4"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccc"
style="stroke-width:0.09253246" />
<g
inkscape:groupmode="layer"
id="layer1"
inkscape:label="bg"
style="display:none">
<circle
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path828"
cx="86.758408"
cy="87.016083"
r="35.352345" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="fg" />
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -30,7 +30,7 @@
<path
id="path819"
d="m 19.212364,278.17517 -11.9689358,5.52059 11.9388628,5.50669"
style="fill:none;stroke-width:2.43863511;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;stroke:#000000" />
style="fill:none !important;stroke-width:2.43863511;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;stroke:#000000" />
<circle
r="3.9119694"
cy="283.69574"

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

35
assets/svg/square.svg Normal file
View file

@ -0,0 +1,35 @@
<?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"
id="svg3"
width="100"
height="100"
viewBox="0 0 100 100"
version="1.1"
style="fill:none">
<metadata
id="metadata9">
<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="defs7" />
<rect
y="-1.4210855e-14"
x="-0.42372882"
height="100.42373"
width="100.84746"
id="rect819"
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
</svg>

After

Width:  |  Height:  |  Size: 1 KiB

63
assets/svg/star_half.svg Normal file
View file

@ -0,0 +1,63 @@
<?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"
version="1.0"
width="1278.000000pt"
height="1280.000000pt"
viewBox="0 0 1278.000000 1280.000000"
preserveAspectRatio="xMidYMid meet"
id="svg8"
sodipodi:docname="star_half.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<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="1920"
inkscape:window-height="995"
id="namedview10"
showgrid="false"
inkscape:zoom="0.39111844"
inkscape:cx="773.36927"
inkscape:cy="1236.855"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" />
<metadata
id="metadata2">
Created by potrace 1.15, written by Peter Selinger 2001-2017
<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>
<g
transform="translate(0.000000,1280.000000) scale(0.100000,-0.100000)"
fill="#000000"
stroke="none"
id="g6">
<path
d="m 6760,12443 c -137,-26 -302,-163 -453,-375 -207,-293 -384,-645 -802,-1598 -347,-790 -486,-1070 -667,-1337 -211,-311 -357,-373 -878,-374 -303,0 -573,22 -1315,106 -310,36 -666,73 -930,97 -191,17 -792,17 -905,0 -359,-56 -525,-174 -538,-382 -7,-128 43,-265 161,-442 197,-294 514,-612 1317,-1323 955,-845 1247,-1174 1290,-1452 37,-234 -95,-656 -453,-1458 -364,-816 -430,-963 -490,-1110 -252,-611 -352,-998 -318,-1236 31,-222 145,-333 357,-346 311,-21 768,169 1699,704 749,431 885,508 1051,596 451,240 718,338 924,341 z"
id="path4"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccccccccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -0,0 +1,57 @@
<?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"
version="1.0"
width="1278.000000pt"
height="1280.000000pt"
viewBox="0 0 1278.000000 1280.000000"
preserveAspectRatio="xMidYMid meet"
id="svg8"
sodipodi:docname="star_outline.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<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="1920"
inkscape:window-height="995"
id="namedview10"
showgrid="false"
inkscape:zoom="0.2765625"
inkscape:cx="372.04589"
inkscape:cy="721.1437"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" />
<metadata
id="metadata2">
Created by potrace 1.15, written by Peter Selinger 2001-2017
<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>
<path
style="fill:none;stroke:#000000;stroke-width:107.38591003;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0"
id="path4"
d="m 674.32114,62.94898 c -13.07722,2.481807 -28.82715,15.559025 -43.24073,35.795304 -19.759,27.968066 -36.65439,61.567926 -76.55422,152.535726 -33.12259,75.40877 -46.39071,102.13593 -63.66791,127.62219 -20.14083,29.68623 -34.07713,35.60439 -83.80874,35.69985 -28.92261,0 -54.69523,-2.1 -125.5222,-10.11814 -29.59079,-3.43635 -63.57246,-6.96816 -88.77235,-9.25906 -18.23175,-1.62272 -75.59969,-1.62272 -86.386,0 -34.268043,5.34544 -50.11343,16.60903 -51.354334,36.46349 -0.668179,12.21813 4.104528,25.29535 15.368117,42.19073 18.804466,28.06352 49.063427,58.41794 125.713107,126.28583 91.15871,80.65875 119.03132,112.06317 123.13585,138.59942 3.5318,22.33627 -9.06815,62.61792 -43.24073,139.17214 -34.74531,77.89058 -41.04528,91.92234 -46.77253,105.9541 -24.05445,58.32244 -33.59986,95.26324 -30.35442,117.98134 2.95908,21.1908 13.84085,31.7862 34.07713,33.0271 29.68624,2.0046 73.30878,-16.1317 162.17659,-67.1997 71.49515,-41.1407 84.47692,-48.4907 100.32231,-56.8907 43.04981,-22.90897 68.53607,-32.26347 88.19962,-32.54983 11.54996,-0.0955 15.36812,0.95454 29.59079,8.01814 25.29535,12.69541 54.79068,36.27259 124.09039,99.27229 96.02687,87.436 134.11307,115.1177 167.23566,121.7995 9.73632,2.0045 16.51356,1.2409 24.3408,-2.5773 9.83178,-4.7727 15.27267,-12.8863 19.47265,-29.018 2.00454,-7.7318 2.19544,-10.5954 2.19544,-30.0681 0,-11.9317 -0.47727,-25.4862 -1.14545,-30.5453 -4.86816,-36.1771 -10.21359,-64.3361 -24.14989,-127.43127 -21.859,-98.69959 -26.63171,-126.66765 -26.63171,-157.21298 0,-15.46357 1.52727,-24.81808 5.24998,-33.02713 9.64087,-21.09537 44.09981,-46.77253 121.70404,-90.87235 63.0952,-35.7953 79.3224,-45.14981 95.9314,-55.17249 70.5406,-42.57255 101.6587,-72.64061 101.6587,-98.03141 0,-14.79539 -9.1636,-26.05898 -29.209,-36.08167 -28.6362,-14.31812 -71.3997,-22.52717 -168.3811,-32.64531 C 925.17463,474.35634 898.25656,470.53817 869.33396,463.18821 832.3932,453.64279 820.27053,444.00192 807.47967,414.02932 796.31154,387.68398 787.33885,353.98866 770.1571,272.56628 757.27079,211.09381 749.92082,179.6894 742.57085,154.4895 731.59363,116.49875 719.66186,90.726135 706.29828,75.835289 697.32559,65.812604 685.20291,60.944443 674.32114,62.94898 Z" />
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -0,0 +1,63 @@
<?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"
version="1.0"
width="1278.000000pt"
height="1280.000000pt"
viewBox="0 0 1278.000000 1280.000000"
preserveAspectRatio="xMidYMid meet"
id="svg8"
sodipodi:docname="star_outline_half.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<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="1920"
inkscape:window-height="995"
id="namedview10"
showgrid="false"
inkscape:zoom="0.2765625"
inkscape:cx="-194.78152"
inkscape:cy="790.56206"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" />
<metadata
id="metadata2">
Created by potrace 1.15, written by Peter Selinger 2001-2017
<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>
<path
style="fill:none;stroke:#000000;stroke-width:107.38591003;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0"
id="path4"
d="m 674.32114,62.94898 c -13.07722,2.481807 -28.82715,15.559025 -43.24073,35.795304 -19.759,27.968066 -36.65439,61.567926 -76.55422,152.535726 -33.12259,75.40877 -46.39071,102.13593 -63.66791,127.62219 -20.14083,29.68623 -34.07713,35.60439 -83.80874,35.69985 -28.92261,0 -54.69523,-2.1 -125.5222,-10.11814 -29.59079,-3.43635 -63.57246,-6.96816 -88.77235,-9.25906 -18.23175,-1.62272 -75.59969,-1.62272 -86.386,0 -34.268043,5.34544 -50.11343,16.60903 -51.354334,36.46349 -0.668179,12.21813 4.104528,25.29535 15.368117,42.19073 18.804466,28.06352 49.063427,58.41794 125.713107,126.28583 91.15871,80.65875 119.03132,112.06317 123.13585,138.59942 3.5318,22.33627 -9.06815,62.61792 -43.24073,139.17214 -34.74531,77.89058 -41.04528,91.92234 -46.77253,105.9541 -24.05445,58.32244 -33.59986,95.26324 -30.35442,117.98134 2.95908,21.1908 13.84085,31.7862 34.07713,33.0271 29.68624,2.0046 73.30878,-16.1317 162.17659,-67.1997 71.49515,-41.1407 84.47692,-48.4907 100.32231,-56.8907 43.04981,-22.90897 68.53607,-32.26347 88.19962,-32.54983 11.54996,-0.0955 15.36812,0.95454 29.59079,8.01814 25.29535,12.69541 54.79068,36.27259 124.09039,99.27229 96.02687,87.436 134.11307,115.1177 167.23566,121.7995 9.73632,2.0045 16.51356,1.2409 24.3408,-2.5773 9.83178,-4.7727 15.27267,-12.8863 19.47265,-29.018 2.00454,-7.7318 2.19544,-10.5954 2.19544,-30.0681 0,-11.9317 -0.47727,-25.4862 -1.14545,-30.5453 -4.86816,-36.1771 -10.21359,-64.3361 -24.14989,-127.43127 -21.859,-98.69959 -26.63171,-126.66765 -26.63171,-157.21298 0,-15.46357 1.52727,-24.81808 5.24998,-33.02713 9.64087,-21.09537 44.09981,-46.77253 121.70404,-90.87235 63.0952,-35.7953 79.3224,-45.14981 95.9314,-55.17249 70.5406,-42.57255 101.6587,-72.64061 101.6587,-98.03141 0,-14.79539 -9.1636,-26.05898 -29.209,-36.08167 -28.6362,-14.31812 -71.3997,-22.52717 -168.3811,-32.64531 C 925.17463,474.35634 898.25656,470.53817 869.33396,463.18821 832.3932,453.64279 820.27053,444.00192 807.47967,414.02932 796.31154,387.68398 787.33885,353.98866 770.1571,272.56628 757.27079,211.09381 749.92082,179.6894 742.57085,154.4895 731.59363,116.49875 719.66186,90.726135 706.29828,75.835289 697.32559,65.812604 685.20291,60.944443 674.32114,62.94898 Z" />
<path
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:107.38574982;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
inkscape:connector-curvature="0"
id="path4-3"
d="m 674.32114,62.94898 c -13.0772,2.48181 -28.8271,15.55903 -43.2407,35.795312 -19.759,27.968058 -36.6544,61.567928 -76.5542,152.535718 -33.1226,75.40878 -46.3907,102.13593 -63.6679,127.62219 -20.1408,29.68623 -34.0771,35.60439 -83.8088,35.69985 -28.9226,0 -54.6952,-2.1 -125.5222,-10.11814 -29.5907,-3.43635 -63.5724,-6.96816 -88.7723,-9.25906 -18.2318,-1.62272 -75.5997,-1.62272 -86.386,0 -34.268097,5.34544 -50.113397,16.60903 -51.354297,36.4635 -0.6682,12.21813 4.1045,25.29534 15.3681,42.19072 18.8044,28.06352 49.063397,58.41794 125.713097,126.28583 91.1587,80.65878 119.0313,112.06318 123.1358,138.59948 3.5318,22.33615 -9.0681,62.61785 -43.2407,139.17205 -34.7453,77.8906 -41.0453,91.9224 -46.7725,105.9541 -24.0545,58.32247 -33.5999,95.26327 -30.3545,117.98137 2.9591,21.1908 13.8409,31.7862 34.0772,33.0271 29.6862,2.0046 73.3088,-16.1317 162.1766,-67.1997 71.4951,-41.1407 84.4769,-48.4907 100.3223,-56.8907 44.4196,-22.95047 93.6333,-33.02397 88.1996,-32.54977 z"
sodipodi:nodetypes="cccccccccccccccccccc" />
</svg>

After

Width:  |  Height:  |  Size: 5.1 KiB

6
assets/svg/wikidata.svg Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.2" width="1050" height="590">
<path d="m 120,545 h 30 V 45 H 120 V 545 z m 60,0 h 90 V 45 H 180 V 545 z M 300,45 V 545 h 90 V 45 h -90 z" style="fill:#990000" />
<path d="m 840,545 h 30 V 45 H 840 V 545 z M 900,45 V 545 h 30 V 45 H 900 z M 420,545 h 30 V 45 H 420 V 545 z M 480,45 V 545 h 30 V 45 h -30 z" style="fill:#339966" />
<path d="m 540,545 h 90 V 45 h -90 V 545 z m 120,0 h 30 V 45 H 660 V 545 z M 720,45 V 545 h 90 V 45 H 720 z" style="fill:#006699" />
</svg>

After

Width:  |  Height:  |  Size: 621 B

View file

@ -1,4 +1,60 @@
{
"wikipedialink": {
"render": "<a href='https://wikipedia.org/wiki/{wikipedia}' target='_blank'><img src='./assets/svg/wikipedia.svg' alt='WP'/></a>",
"condition": "wikipedia~*",
"mappings": [
{
"if": {
"and": [
"wikipedia=",
"wikidata~*"
]
},
"then": "<a href='https://www.wikidata.org/wiki/{wikidata}' target='_blank'><img src='./assets/svg/wikidata.svg' alt='WD'/></a>"
}
]
},
"isOpen": {
"#": "Shows a coloured clock if opening hours are parsed. Uses the metatagging, suitable to use as a (badged) overlay",
"mappings": [
{
"if": "_isOpen=yes",
"then": "clock:#0f0;ring:#0f0"
},
{
"if": "_isOpen=no",
"then": "circle:#f00;clock:#fff"
},
{
"#": "Still loading the country",
"if": {
"and": [
"_isOpen=",
"opening_hours~*"
]
},
"then": "clock:#ff0;ring:#ff0"
},
{
"#": "Still loading the country",
"if": {
"and": [
"_isOpen=parse_error",
"opening_hours~*"
]
},
"then": "circle:#f0f;clock:#fff"
}
]
},
"phonelink": {
"render": "<a href='tel:{phone}'><img src='./assets/svg/phone.svg'/></a>",
"condition": "phone~*"
},
"emaillink": {
"render": "<a href='mailto:{email}'><img src='./assets/svg/send_email.svg'/></a>",
"condition": "email~*"
},
"osmlink": {
"render": "<a href='https://openstreetmap.org/{id}' target='_blank'><img src='./assets/svg/osm-logo-us.svg'/></a>",
"mappings": [
@ -8,14 +64,6 @@
}
]
},
"wikipedialink": {
"render": "<a href='https://wikipedia.org/wiki/{wikipedia}' target='_blank'><img src='./assets/wikipedia.svg' alt='WP'/></a>",
"condition": "wikipedia~*"
},
"phonelink": {
"render": "<a href='tel:{phone}'><img src='./assets/svg/phone.svg'/></a>",
"condition": "phone~*"
},
"sharelink": {
"render": "{share_link()}"
}

View file

@ -2,6 +2,9 @@
"images": {
"render": "{image_carousel()}{image_upload()}"
},
"reviews": {
"render": "{reviews()}"
},
"phone": {
"question": {
"en": "What is the phone number of {name}?",

View file

@ -192,9 +192,13 @@
},
{
"question": {
"en": "In which direction are you looking when sitting on the bench?"
"en": "In which direction are you looking when sitting on the bench?",
"de": "In welche Richtung schaut man, wenn man auf der Bank sitzt?"
},
"render": {
"en": "When sitting on the bench, one looks towards {direction}°.",
"de": "Wenn man auf der Bank sitzt, schaut man in Richtung {direction}°."
},
"render": "When sitting on the bench, one looks towards {direction}*",
"freeform": {
"key": "direction",
"type": "direction"
@ -417,7 +421,7 @@
"render": "8"
},
"iconSize": {
"render": "20,20,center"
"render": "30,30,center"
},
"color": {
"render": "#00f"

View file

@ -28,353 +28,6 @@
"widenFactor": 0.05,
"roamingRenderings": [],
"layers": [
{
"id": "bookcases",
"name": {
"en": "Bookcases",
"nl": "Boekenruilkastjes",
"de": "Bücherschränke",
"fr": "Microbibliothèque"
},
"description": {
"en": "A streetside cabinet with books, accessible to anyone",
"nl": "Een straatkastje met boeken voor iedereen",
"de": "Ein Bücherschrank am Straßenrand mit Büchern, für jedermann zugänglich",
"fr": "Une armoire ou une boite contenant des livres en libre accès"
},
"overpassTags": "amenity=public_bookcase",
"minzoom": 12,
"title": {
"render": {
"en": "Bookcase",
"nl": "Boekenruilkast",
"de": "Bücherschrank",
"fr": "Microbibliothèque"
},
"mappings": [
{
"if": "name~*",
"then": {
"en": "Public bookcase <i>{name}</i>",
"nl": "Boekenruilkast <i>{name}</i>",
"de": "Öffentlicher Bücherschrank <i>{name}</i>",
"fr": "Microbibliothèque <i>{name}</i>"
}
}
]
},
"icon": {
"render": "./assets/themes/bookcases/bookcase.svg"
},
"color": {
"render": "#0000ff"
},
"width": {
"render": "8"
},
"presets": [
{
"title": {
"en": "Bookcase",
"nl": "Boekenruilkast",
"de": "Bücherschrank",
"fr": "Microbibliothèque"
},
"tags": [
"amenity=public_bookcase"
]
}
],
"tagRenderings": [
"images",
{
"render": {
"en": "The name of this bookcase is {name}",
"nl": "De naam van dit boekenruilkastje is {name}",
"de": "Der Name dieses Bücherschrank lautet {name}",
"fr": "Le nom de cette microbibliothèque est {name}"
},
"question": {
"en": "What is the name of this public bookcase?",
"nl": "Wat is de naam van dit boekenuilkastje?",
"de": "Wie heißt dieser öffentliche Bücherschrank?",
"fr": "Quel est le nom de cette microbibliothèque ?"
},
"freeform": {
"key": "name"
},
"mappings": [
{
"if": {
"and": [
"noname=yes",
"name="
]
},
"then": {
"en": "This bookcase doesn't have a name",
"nl": "Dit boekenruilkastje heeft geen naam",
"de": "Dieser Bücherschrank hat keinen Namen",
"fr": "Cette microbibliothèque n'a pas de nom"
}
}
]
},
{
"render": {
"en": "{capacity} books fit in this bookcase",
"nl": "Er passen {capacity} boeken",
"de": "{capacity} Bücher passen in diesen Bücherschrank",
"fr": "{capacity} livres rentrent dans cette microbibliothèque"
},
"question": {
"en": "How many books fit into this public bookcase?",
"nl": "Hoeveel boeken passen er in dit boekenruilkastje?",
"de": "Wie viele Bücher passen in diesen öffentlichen Bücherschrank?",
"fr": "Combien de livre rentrent dans cette microbibliothèque ?"
},
"freeform": {
"key": "capacity",
"type": "nat"
}
},
{
"question": {
"en": "What kind of books can be found in this public bookcase?",
"nl": "Voor welke doelgroep zijn de meeste boeken in dit boekenruilkastje?",
"de": "Welche Art von Büchern sind in diesem öffentlichen Bücherschrank zu finden?",
"fr": "Quel type de livres peuvent être trouvés dans cette microbibliothèque ?"
},
"mappings": [
{
"if": "books=children",
"then": {
"en": "Mostly children books",
"nl": "Voornamelijk kinderboeken",
"de": "Vorwiegend Kinderbücher",
"fr": "Livres pour enfants"
}
},
{
"if": "books=adults",
"then": {
"en": "Mostly books for adults",
"nl": "Voornamelijk boeken voor volwassenen",
"de": "Vorwiegend Bücher für Erwachsene",
"fr": "Livres pour les adultes"
}
},
{
"if": "books=children;adults",
"then": {
"en": "Both books for kids and adults",
"nl": "Boeken voor zowel kinderen als volwassenen",
"de": "Sowohl Bücher für Kinder als auch für Erwachsene",
"fr": "Livres pour enfants et adultes également"
}
}
]
},
{
"question": {
"en": "Is this bookcase located outdoors?",
"nl": "Staat dit boekenruilkastje binnen of buiten?",
"de": "Befindet sich dieser Bücherschrank im Freien?",
"fr": "Cette microbiliothèque est-elle en extérieur ?"
},
"mappings": [
{
"then": {
"en": "This bookcase is located indoors",
"nl": "Dit boekenruilkastje staat binnen",
"de": "Dieser Bücherschrank befindet sich im Innenbereich",
"fr": "Cette microbibliothèque est en intérieur"
},
"if": "indoor=yes"
},
{
"then": {
"en": "This bookcase is located outdoors",
"nl": "Dit boekenruilkastje staat buiten",
"de": "Dieser Bücherschrank befindet sich im Freien",
"fr": "Cette microbibliothèque est en extérieur"
},
"if": "indoor=no"
},
{
"then": {
"en": "This bookcase is located outdoors",
"nl": "Dit boekenruilkastje staat buiten",
"de": "Dieser Bücherschrank befindet sich im Freien",
"fr": "Cette microbibliothèque est en extérieur"
},
"if": "indoor=",
"hideInAnswer": true
}
]
},
{
"question": {
"en": "Is this public bookcase freely accessible?",
"nl": "Is dit boekenruilkastje publiek toegankelijk?",
"de": "Ist dieser öffentliche Bücherschrank frei zugänglich?",
"fr": "Cette microbibliothèque est-elle librement accèssible ?"
},
"condition": "indoor=yes",
"mappings": [
{
"then": {
"en": "Publicly accessible",
"nl": "Publiek toegankelijk",
"de": "Öffentlich zugänglich",
"fr": "Accèssible au public"
},
"if": "access=yes"
},
{
"then": {
"en": "Only accessible to customers",
"nl": "Enkel toegankelijk voor klanten",
"de": "Nur für Kunden zugänglich",
"fr": "Accèssible aux clients"
},
"if": "access=customers"
}
]
},
{
"question": {
"en": "Who maintains this public bookcase?",
"nl": "Wie is verantwoordelijk voor dit boekenruilkastje?",
"de": "Wer unterhält diesen öffentlichen Bücherschrank?",
"fr": "Qui entretien cette microbibliothèque"
},
"render": {
"en": "Operated by {operator}",
"nl": "Onderhouden door {operator}",
"de": "Betrieben von {operator}",
"fr": "Entretenue par {operator}"
},
"freeform": {
"type": "string",
"key": "operator"
}
},
{
"question": {
"en": "Is this public bookcase part of a bigger network?",
"nl": "Is dit boekenruilkastje deel van een netwerk?",
"de": "Ist dieser öffentliche Bücherschrank Teil eines größeren Netzwerks?",
"fr": "Cette microbibliothèque fait-elle partie d'un réseau/groupe ?"
},
"render": {
"en": "This public bookcase is part of {brand}",
"nl": "Dit boekenruilkastje is deel van het netwerk {brand}",
"de": "Dieser Bücherschrank ist Teil von {brand}",
"fr": "Cette microbibliothèque fait partie du groupe {brand}"
},
"condition": "ref=",
"freeform": {
"key": "brand"
},
"mappings": [
{
"then": {
"en": "Part of the network 'Little Free Library'",
"nl": "Deel van het netwerk 'Little Free Library'",
"de": "Teil des Netzwerks 'Little Free Library'",
"fr": "Fait partie du réseau 'Little Free Library'"
},
"if": "brand=Little Free Library"
},
{
"if": {
"and": [
"nobrand=yes",
"brand="
]
},
"then": {
"en": "This public bookcase is not part of a bigger network",
"nl": "Dit boekenruilkastje maakt geen deel uit van een netwerk",
"de": "Dieser öffentliche Bücherschrank ist nicht Teil eines größeren Netzwerks",
"fr": "Cette microbibliothèque ne fait pas partie d'un réseau/groupe"
}
}
]
},
{
"render": {
"en": "The reference number of this public bookcase within {brand} is {ref}",
"nl": "Het referentienummer binnen {brand} is {ref}",
"de": "Die Referenznummer dieses öffentlichen Bücherschranks innerhalb {brand} lautet {ref}",
"fr": "Cette microbibliothèque du réseau {brand} possède le numéro {ref}"
},
"question": {
"en": "What is the reference number of this public bookcase?",
"nl": "Wat is het referentienummer van dit boekenruilkastje?",
"de": "Wie lautet die Referenznummer dieses öffentlichen Bücherschranks?",
"fr": "Quelle est le numéro de référence de cette microbibliothèque ?"
},
"condition": "brand~*",
"freeform": {
"key": "ref"
},
"mappings": [
{
"then": {
"en": "This bookcase is not part of a bigger network",
"nl": "Dit boekenruilkastje maakt geen deel uit van een netwerk",
"de": "Dieser Bücherschrank ist nicht Teil eines größeren Netzwerks",
"fr": "Cette microbibliothèque ne fait pas partie d'un réseau/groupe"
},
"if": {
"and": [
"nobrand=yes",
"brand=",
"ref="
]
}
}
]
},
{
"question": {
"en": "When was this public bookcase installed?",
"nl": "Op welke dag werd dit boekenruilkastje geinstalleerd?",
"de": "Wann wurde dieser öffentliche Bücherschrank installiert?",
"fr": "Quand a été installée cette microbibliothèque ?"
},
"render": {
"en": "Installed on {start_date}",
"nl": "Geplaatst op {start_date}",
"de": "Installiert am {start_date}",
"fr": "Installée le {start_date}"
},
"freeform": {
"key": "start_date",
"type": "date"
}
},
{
"render": {
"en": "More info on <a href='{website}' target='_blank'>the website</a>",
"nl": "Meer info op <a href='{website}' target='_blank'>de website</a>",
"de": "Weitere Informationen auf <a href='{website}' target='_blank'>der Webseite</a>",
"fr": "Plus d'info sur <a href='{website} target='_blank'>le site web</a>"
},
"question": {
"en": "Is there a website with more information about this public bookcase?",
"nl": "Is er een website over dit boekenruilkastje?",
"de": "Gibt es eine Webseite mit weiteren Informationen über diesen öffentlichen Bücherschrank?",
"fr": "Existe-t-il un site web avec plus d'information sur cette microbibliothèque ?"
},
"freeform": {
"key": "website",
"type": "url"
}
}
]
}
"public_bookcases"
]
}

View file

@ -0,0 +1,54 @@
<?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="800"
height="800"
version="1.1"
id="svg4"
sodipodi:docname="bicycle.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata10">
<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="defs8" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="697"
inkscape:window-height="480"
id="namedview6"
showgrid="false"
inkscape:zoom="0.295"
inkscape:cx="400"
inkscape:cy="400"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg4" />
<path
style="fill:#000000;fill-opacity:1;stroke:none"
d="m 600.236,251.91425 c 60.2012,0 109.004,48.8057 109.004,109.005 0,60.1993 -48.8027,108.997 -109.002,108.997 -60.1993,0 -108.998,-48.7988 -108.998,-108.996 0,-44.4746 26.6719,-82.6602 64.8594,-99.6094 l -0.007,-0.0215 -10.0693,-31.8105 -132.35,132.34 12.1113,34.5869 h 8.17188 c 6.19629,0 11.2207,5.02441 11.2207,11.2197 0,6.19824 -5.02246,11.2227 -11.2207,11.2227 h -32.5234 c -6.19824,0 -11.2227,-5.02246 -11.2227,-11.2227 0,-6.19531 5.02246,-11.2197 11.2227,-11.2197 h 2.61035 l -11.0225,-26.5186 h -31.6738 c -4.56836,55.9932 -51.3721,100.03 -108.544,100.03 -60.2012,0 -109,-48.7988 -109,-108.996 0,0 0.8418,-14.7031 2.94238,-24.2158 9.46094,-42.8682 40.7471,-71.4756 96.4258,-86.7461 22.4062,-6.14453 28.418,-22.749 26.748,-35.0977 -1.38965,-10.3242 -8.90234,-22.375 -25.5273,-22.375 h -30.7402 v 20.5322 c 0,8.71191 -7.06348,15.7773 -15.7754,15.7773 h -49.7246 c -8.71289,0 -15.7744,-7.06543 -15.7744,-15.7773 v -0.14063 h -29.8203 c -1.41309,0 -2.558586,-1.14551 -2.558586,-2.55859 v -12.7158 c 0,-1.41602 1.145506,-2.56348 2.558586,-2.56348 h 29.8203 v -27.4355 h -29.8203 c -1.41309,0 -2.558586,-1.14551 -2.558586,-2.55859 v -12.7158 c 0,-1.41602 1.145506,-2.56152 2.558586,-2.56152 h 29.8203 v -0.13671 c 0,-8.7168 7.06152,-15.7822 15.7744,-15.7822 h 49.7246 c 8.71191,0 15.7754,7.06641 15.7754,15.7812 v 20.5254 h 30.7383 c 24.7568,0 44.3525,17.1572 47.6641,41.7256 3.09082,22.959 -9.00195,50.2939 -42.9834,59.6162 -42.9551,11.7803 -68.0293,30.791 -77.835,59.9746 0,0 -3.86914,19.7227 -3.86621,29.4443 0.0205,47.1816 38.25,85.4307 85.4346,85.4307 44.1533,0 80.4727,-33.4951 84.958,-76.46 h -32.8154 c -4.28125,25.002 -25.9209,44.0781 -52.1455,44.0781 -29.2988,0 -53.0488,-23.7568 -53.0488,-53.0508 0,-29.3027 23.75,-53.0508 53.0488,-53.0508 3.06934,0 6.0332,0.40234 8.95996,0.90527 l 14.4961,-30.0234 10.3301,-21.3975 33.1113,-68.5654 -13.958,-34.6377 h -23.3193 c -6.54102,0 -6.61426,-5.29004 -6.61426,-11.8242 0,-6.53223 0.0732,-11.834 6.61426,-11.834 h 75.9678 c 6.53027,0 11.832,5.2998 11.832,11.834 0,6.5342 -5.2998,11.8242 -11.832,11.8242 h -27.1416 l 9.17383,22.7344 h 188.943 l -9.22949,-29.1465 c -0.75,-1.58789 -5.55371,-10.9756 -15.6143,-10.9756 h -28.417 c -6.53027,0 -6.60547,-5.2998 -6.60547,-11.8301 0,-6.53223 0.0752,-11.834 6.60547,-11.834 h 28.417 c 21.3887,0 33.7207,16.3057 37.6396,25.9385 0.11036,0.31348 8.87891,27.9746 20.1582,63.5801 0.11817,0.26562 0.16504,0.54297 0.25879,0.82031 5.0332,15.8916 10.5586,33.333 16.0273,50.6309 l 0.007,0.0147 c 6.99023,-1.40625 14.2188,-2.16406 21.624,-2.16406 z m -296.703,94.302 h 33.3389 c -4.24121,-24.3848 -18.7734,-45.1855 -39.0098,-57.7891 l -14.2266,29.4658 c 9.53125,6.84277 16.5479,16.7695 19.8975,28.3232 z m 57.226,0 22.4229,9.8e-4 -10.4668,-25.959 -6.52051,-0.0254 c -6.19629,-0.0186 -11.207,-4.82812 -11.1885,-10.7363 0.0166,-5.22168 3.95703,-9.55273 9.14844,-10.4766 l -32.5,-80.5928 -23.4658,48.6123 c 28.0762,16.6035 48.0186,45.4414 52.5703,79.1768 z m 44.237,-9.173 132.979,-132.968 -1.11523,-3.53027 h -186.895 l 39.6582,98.3652 9.16406,0.0283 c 6.19824,0.0215 11.208,4.82422 11.1875,10.7324 -0.0186,5.91309 -5.05664,10.6885 -11.2568,10.667 h -0.45605 z m 195.247,109.3036 c 47.1846,0 85.4336,-38.249 85.4336,-85.4268 0,-47.1895 -38.249,-85.4385 -85.4336,-85.4385 -5.13477,0 -10.1055,0.64258 -14.9932,1.51074 l 0.47949,1.51465 c 14.0137,44.2676 23.7354,77.6143 23.7354,77.6143 1.94824,6.16797 -1.46484,12.75 -7.64355,14.709 -6.16992,1.94824 -12.7588,-1.47461 -14.709,-7.63672 l -23.7188,-77.5771 -0.39746,-1.25781 c -28.4307,13.8711 -48.1846,42.7881 -48.1846,76.5576 0,47.1816 38.249,85.4307 85.4316,85.4307 z"
id="path2"
inkscape:connector-curvature="0" />
</svg>

After

Width:  |  Height:  |  Size: 5 KiB

View file

@ -0,0 +1,45 @@
<?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"
version="1.1"
x="0px"
y="0px"
viewBox="0 0 100 100"
enable-background="new 0 0 100 100"
xml:space="preserve"
id="svg8"
sodipodi:docname="car.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="697"
inkscape:window-height="480"
id="namedview6"
showgrid="false"
inkscape:zoom="2.36"
inkscape:cx="50"
inkscape:cy="50"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg8" /><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 /></cc:Work></rdf:RDF></metadata><defs
id="defs12" /><path
style="fill:#000000;stroke-width:0.89789873"
d="m 91.489281,42.886869 -2.620068,-0.0099 v -1.820041 c 0,-5.78157 -4.688827,-10.470397 -10.471295,-10.470397 h -1.03438 L 69.323753,19.26046 C 67.912256,17.378464 66.552838,16.643983 64.38531,16.643983 H 42.424503 c -2.166629,0 -3.524252,0.734481 -4.938443,2.616477 l -8.037091,11.326094 -13.578922,0.0018 c -2.312988,0 -4.188698,1.873017 -4.188698,4.188698 v 8.099944 l -2.765528,0.01078 c -0.869166,0 -1.5704249,0.697667 -1.5704249,1.569527 v 4.138415 c 0,0.866472 0.7012589,1.571323 1.5704249,1.571323 l 7.814413,-0.0018 c -0.152643,0.655466 -0.232556,1.343256 -0.232556,2.046311 0,5.052476 4.097112,9.14869 9.14869,9.14869 5.051578,0 9.147792,-4.096214 9.147792,-9.14869 0,-0.706646 -0.08081,-1.394437 -0.232556,-2.05529 l 13.059937,-0.0054 17.140887,0.0099 c -0.149051,0.657262 -0.23076,1.345053 -0.23076,2.049903 0,5.052476 4.096214,9.147792 9.147792,9.147792 5.051578,0 9.147792,-4.096214 9.147792,-9.147792 0,-0.701259 -0.07901,-1.385458 -0.228066,-2.040026 l 8.890095,-0.0036 c 0.868268,0 1.571323,-0.704851 1.571323,-1.571323 v -4.139313 c 0,-0.870064 -0.703953,-1.569527 -1.571323,-1.569527 z M 25.64547,56.685776 c -2.470119,0 -4.474229,-2.002314 -4.474229,-4.473331 0,-2.471017 2.00411,-4.473331 4.474229,-4.473331 2.471017,0 4.472433,2.002314 4.472433,4.473331 0,2.471017 -2.002314,4.473331 -4.472433,4.473331 z M 56.130029,19.710307 c 1.972684,-1.974479 4.936648,0.985893 2.96127,2.962168 l -4.241673,4.240776 -2.960372,-2.963066 z m 3.034898,19.659493 -0.348385,-0.346589 -2.300416,2.300416 c -2.872378,2.873276 -7.41395,3.060937 -10.506313,0.567472 l -6.387652,6.38855 -2.96127,-2.962168 6.433445,-6.433445 c -2.18369,-3.076201 -1.896362,-7.366361 0.858391,-10.123808 l 2.300417,-2.300416 -0.678812,-0.67971 c -1.974479,-1.973581 0.988587,-4.935749 2.963066,-2.962168 l 13.588799,13.587902 c 1.974479,1.976275 -0.989484,4.938443 -2.96127,2.963964 z m 6.064408,-10.561983 -4.243469,4.241673 -2.960372,-2.962167 4.240775,-4.240776 c 1.97448,-1.974479 4.936647,0.987688 2.963066,2.96127 z m 8.448329,27.877959 c -2.471017,0 -4.472433,-2.002314 -4.472433,-4.473331 0,-2.471017 2.001416,-4.473331 4.472433,-4.473331 2.471915,0 4.473332,2.002314 4.473332,4.473331 0,2.471017 -2.001417,4.473331 -4.473332,4.473331 z"
id="path2"
inkscape:connector-curvature="0" /></svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

View file

@ -1,60 +0,0 @@
<?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="2.533375in"
height="2.5232947in"
viewBox="0 0 228.00356 227.09669"
version="1.1"
id="svg4"
sodipodi:docname="Charging_station.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata10">
<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="defs8" />
<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="namedview6"
showgrid="false"
inkscape:zoom="0.43553183"
inkscape:cx="-194.63523"
inkscape:cy="121.06786"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg4" />
<path
id="bg"
d="m 30.503636,0.59549459 c 0,0 36,0 36,0 0,0 112.000004,0 112.000004,0 0,0 32,0 32,0 5.2,0.03 8.87,0.24 12.78,4.21000001 4.27,4.34 4.21,9.1600004 4.22,14.7900004 0,0 0,158.999995 0,158.999995 0,0 0,31 0,31 -0.08,6.67 -1.61,12.02 -8.01,15.31 -3.62,1.86 -7.06,1.68 -10.99,1.69 0,0 -160.000004,0 -160.000004,0 0,0 -31,0 -31,0 -6.7,-0.08 -12.2400004,-1.49 -15.5500004,-8 -1.63999999,-3.24 -1.43999999,-6.49 -1.44999999,-10 0,0 0,-155.999995 0,-155.999995 0,0 0,-34 0,-34 0.01,-8.7100004 0.96999999,-13.8900004 10.00000039,-17.4300004 5.53,-1.00000001 14.12,-0.57000001 20,-0.57000001 z M 186.50364,60.595495 c 0,0 0,-31 0,-31 0,0 -1.02,-11.4 -1.02,-11.4 0,0 -7.98,-1.6 -7.98,-1.6 0,0 -69,0 -69,0 0,0 -15.000004,0 -15.000004,0 0,0 -5.98,1.6 -5.98,1.6 0,0 -1.02,7.4 -1.02,7.4 0,0 0,76.999995 0,76.999995 -11.8,0.54 -17.34,3.3 -28,7 0,0 0,-19.999995 0,-19.999995 2.73,-0.01 6.32,0.33 8.49,-1.6 2.08,-1.84 3.9,-8.56 4.84,-11.4 5.31,-15.91 5.67,-13.21 5.67,-30 0,0 -7,0 -7,0 0,0 0,-19 0,-19 -0.01,-3.03 0.45,-10.21 -4.87,-8.34 -3.65,1.28 -3.12,6.26 -3.13,9.34 0,0 0,18 0,18 0,0 -19,0 -19,0 0,0 0,-21 0,-21 -0.05,-2.48 0.13,-5.95 -3.11,-6.42 -4.5,-0.66 -4.83,4.3 -4.89,7.42 0,0 0,20 0,20 0,0 -7,0 -7,0 0,14.73 1.38,17.01 6,31 0.84,2.55 2.72,9.52 4.7,11.01 1.76,1.31 6.11,0.99 8.3,0.99 0,0 0,18.999995 0,18.999995 -0.03,13.87 -5.49,8.96 -17.64,27 -8.66,12.86 -12.45,26.73 -13.65,42 0.02,2.8 -0.4,4.03 0,7 1.25,21.17 19.36,30.73 32.25,20.47 8.21,-6.54 10.02,-16.6 10.04,-26.47 0,0 0,-48 0,-48 0.02,-2.26 -0.1,-4.87 1.02,-6.9 3.46,-6.23 20.19,-9.79 26.98,-10.1 0,0 0,71 0,71 0,4.15 -1.03,18.69 1.6,21.26 2.11,2.06 6.63,1.74 9.4,1.74 0,0 56.000004,0 56.000004,0 10.14,0 23.3,0.74 33,-1 0,0 0,-145.999995 0,-145.999995 z m -65,-19 c 0,0 43,0 43,0 8.64,0.02 8.98,0.36 9,9 0,0 0,34 0,34 0,2.77 0.5,11.48 -1.02,13.4 -1.57,1.98 -5.68,1.6 -7.98,1.6 0,0 -55,0 -55,0 -8.64,-0.02 -8.98,-0.36 -9,-9 0,0 0,-25 0,-25 0,-5.44 -1.280004,-18.97 1.6,-22.98 4.36,-1.85 14.28,-1.02 19.4,-1.02 z M 47.503636,147.59549 c 0,0 0,31 0,31 -0.01,6.38 -1.24,19.35 -10,19.56 -9.06,0.23 -11.25,-11.77 -10.96,-18.56 0.81,-19.23 8.06,-33.34 19.96,-48 1.69,4.25 1,11.29 1,16 z"
inkscape:connector-curvature="0"
style="fill:#0000ff;stroke:#000000;stroke-width:1" />
<path
id="itm"
d="m 86.503636,37.595495 c 0,-3.68 -0.95,-17.96 1.6,-19.98 1.59,-1.25 5.41,-1.02 7.4,-1.02 0,0 69.000004,0 69.000004,0 0,0 15,0 15,0 1.95,0.04 4.63,-0.1 5.98,1.6 1.25,1.59 1.02,5.41 1.02,7.4 0,0 0,180.999995 0,180.999995 0,0 -76,0 -76,0 0,0 -17.000004,0 -17.000004,0 0,0 -5.98,-1.6 -5.98,-1.6 0,0 -1.02,-7.4 -1.02,-7.4 0,0 0,-84 0,-84 -6.85,0.32 -22.23,3.61 -26.4,9.21 -1.59,2.13 -1.55,4.28 -1.6,6.79 0,0 0,51 0,51 -0.16,13.5 -6.97,29.52 -23,28.22 -13.37,-1.1 -20.26,-15.03 -19.49,-27.22 1.32,-20.83 5.19,-35.3 18.49,-52 10.46,-13.13 12.98,-8.75 13,-21 0,0 0,-18.999995 0,-18.999995 -2.19,0 -6.54,0.32 -8.3,-0.99 -1.96,-1.47 -3.89,-8.49 -4.68,-11.01 -4.66,-15.01 -6.02,-15.17 -6.02,-31 0,0 7,0 7,0 0,0 0,-19 0,-19 0.02,-3.22 -0.04,-9.15 4.89,-8.42 3.77,0.55 3.11,5.66 3.11,8.42 0,0 0,19 0,19 0,0 19,0 19,0 0,0 0,-20 0,-20 0.06,-3.11 0.86,-9.21 5.69,-7.34 2.82,1.08 2.31,5.89 2.31,8.34 0,0 0,19 0,19 0,0 7,0 7,0 0,16.42 -0.13,13.38 -5.33,29 -3.22,9.66 -2.28,13.74 -13.67,14 0,0 0,19.999995 0,19.999995 11.48,-3.25 14.31,-6.37 28,-7 0,0 0,-64.999995 0,-64.999995 z m 69.000004,62 c 3.39,0 15,0.899995 16.98,-1.6 1.25,-1.59 1.02,-5.41 1.02,-7.4 0,0 0,-34 0,-34 0,-2.77 0.5,-11.48 -1.02,-13.4 -1.57,-1.98 -5.68,-1.6 -7.98,-1.6 0,0 -55,0 -55,0 -8.64,0.02 -8.98,0.36 -9,9 0,0 0,49 0,49 0,0 55,0 55,0 z M 26.543636,179.59549 c -0.29,6.89 2.22,20.2 11.95,18.47 8.01,-1.43 9,-13.12 9.01,-19.47 0,0 0,-47 0,-47 -12.67,10.48 -20.28,31.82 -20.96,48 z"
inkscape:connector-curvature="0"
style="fill:#ffffff;stroke:#000000;stroke-width:1" />
</svg>

Before

Width:  |  Height:  |  Size: 5.2 KiB

View file

@ -13,7 +13,7 @@
"en"
],
"maintainer": "",
"icon": "./assets/themes/charging_stations/charging_station.svg",
"icon": "./assets/themes/charging_stations/logo.svg",
"version": "0",
"startLat": 0,
"startLon": 0,
@ -44,14 +44,56 @@
"images",
{
"#": "Type",
"question": "Is this charging station meant for cars or bicycles?",
"mappings": [
{
"if": "bicycle=yes",
"then": "This is a charging station for <b>bicycles</b>"
"if": {
"and": [
"motorcar=yes",
"bicycle=yes"
]
},
"then": "This is a charging station for <b>both bicycles and cars</b>"
},
{
"if": "motorcar=yes",
"then": "This is a charging station for <b>electric vehicles</b>"
"if": {
"and": [
"motorcar=",
"car=",
"bicycle=yes"
]
},
"then": "This is a charging station exclusively for <b>bicycles</b>"
},
{
"if": {
"and": [
"motorcar=yes",
"car=",
"bicycle="
]
},
"then": "This is a charging station exclusively for <b>electric cars and similar vehicles</b>"
},
{
"if": {
"and": [
"car=yes",
"bicycle="
]
},
"then": "This is a charging station exclusively for <b>electric cars</b>",
"hideInAnswer": true
},
{
"if": {
"and": [
"car=yes",
"bicycle=yes"
]
},
"then": "This is a charging station for <b>both electric cars and bicycles</b>",
"hideInAnswer": true
}
]
},
@ -189,13 +231,45 @@
],
"hideUnderlayingFeaturesMinPercentage": 0,
"icon": {
"render": "./assets/themes/charging_stations/charging_station.svg"
"render": "pin:#fff;./assets/themes/charging_stations/plug.svg",
"mappings": [
{
"if": "bicycle=yes",
"then": "pin:#fff;./assets/themes/charging_stations/bicycle.svg"
},
{
"if": {
"or": [
"car=yes",
"motorcar=yes"
]
},
"then": "pin:#fff;./assets/themes/charging_stations/car.svg"
}
]
},
"iconOverlays": [
{
"if": {
"and": [
"bicycle=yes",
{
"or": [
"motorcar=yes",
"car=yes"
]
}
]
},
"then": "circle:#fff;./assets/themes/charging_stations/car.svg",
"badge": true
}
],
"width": {
"render": "8"
},
"iconSize": {
"render": "40,40,center"
"render": "50,50,bottom"
},
"color": {
"render": "#00f"

View file

@ -0,0 +1,62 @@
<?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"
version="1.1"
x="0px"
y="0px"
viewBox="0 0 24.152542 24.152542"
enable-background="new 0 0 24 24"
xml:space="preserve"
id="svg8"
sodipodi:docname="logo.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
width="24.152542"
height="24.152542"><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="1920"
inkscape:window-height="995"
id="namedview10"
showgrid="false"
inkscape:zoom="11.125147"
inkscape:cx="-5.1237331"
inkscape:cy="7.0769496"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<g
inkscape:groupmode="layer"
id="layer1"
inkscape:label="bg"
style="display:inline"
transform="translate(0.12711811)"><circle
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path814"
cx="11.949153"
cy="12.076271"
r="12.076271" /></g><g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="fg"
transform="translate(0.12711811)"><path
d="m 16.739623,11.453018 2.12132,-2.1213204 c 0.424264,-0.4242641 0.424264,-0.9899495 0,-1.4142136 -0.424264,-0.424264 -0.98995,-0.424264 -1.414214,0 l -2.12132,2.121321 -1.414213,-1.4142142 2.12132,-2.1213203 c 0.424264,-0.4242641 0.424264,-0.9899495 0,-1.4142136 -0.424264,-0.4242638 -1.06066,-0.3535532 -1.414214,2e-7 L 12.496982,7.2103775 11.082769,5.7961639 8.4664736,8.4124588 C 6.769417,10.109515 6.557285,12.72581 7.830077,14.705709 l -5.1618795,5.16188 1.4142136,1.414213 5.1618795,-5.161879 c 1.9798994,1.272792 4.5961944,1.06066 6.2932504,-0.636396 l 2.616295,-2.616295 z"
id="path2"
inkscape:connector-curvature="0" /></g></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -0,0 +1,46 @@
<?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"
version="1.1"
x="0px"
y="0px"
viewBox="0 0 24 30"
enable-background="new 0 0 24 24"
xml:space="preserve"
id="svg8"
sodipodi:docname="plug.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="1920"
inkscape:window-height="995"
id="namedview10"
showgrid="false"
inkscape:zoom="7.8666667"
inkscape:cx="-9.1016949"
inkscape:cy="15"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" /><path
d="m 18.328606,12.15217 2.12132,-2.12132 c 0.424264,-0.4242635 0.424264,-0.9899493 0,-1.4142133 -0.424264,-0.4242641 -0.989949,-0.4242641 -1.414214,0 l -2.12132,2.1213203 -1.414213,-1.4142135 2.12132,-2.1213204 c 0.424264,-0.4242641 0.424264,-0.9899495 0,-1.4142135 -0.424264,-0.4242641 -1.06066,-0.3535534 -1.414214,0 L 14.085965,7.9095299 12.671751,6.4953163 10.055456,9.1116115 C 8.3584001,10.808667 8.1462681,13.424962 9.4190603,15.404861 l -5.1618795,5.16188 1.4142135,1.414213 5.1618797,-5.161879 c 1.979899,1.272792 4.596194,1.06066 6.29325,-0.636396 l 2.616295,-2.616295 z"
id="path2"
inkscape:connector-curvature="0" />
</svg>

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -31,7 +31,7 @@
"en": "Shop",
"fr": "Magasin"
},
"minzoom": 14,
"minzoom": 16,
"overpassTags": {
"and": [
"shop~*"
@ -73,6 +73,16 @@
},
"tagRenderings": [
"images",
{
"question": {
"en": "What is the name of this shop?",
"fr": "Qu'est-ce que le nom de ce magasin?"
},
"render": "This shop is called <i>{name}</i>",
"freeform": {
"key": "name"
}
},
{
"render": {
"en": "This shop sells {shop}",
@ -220,12 +230,21 @@
"key": "opening_hours",
"type": "opening_hours"
}
}
},
"questions",
"reviews"
],
"hideUnderlayingFeaturesMinPercentage": 0,
"icon": {
"render": "./assets/themes/shops/shop.svg"
},
"iconOverlays": [
{
"if": "opening_hours~*",
"then": "isOpen",
"badge": true
}
],
"width": {
"render": "8"
},

View file

@ -14,7 +14,7 @@
"nl": "Bezig met een foto te uploaden...",
"es": "Subiendo tu imagen ...",
"ca": "Pujant la teva imatge ...",
"fr": "Mettre votre photo en ligne",
"fr": "Mise en ligne de votre photo...",
"gl": "Subindo a túa imaxe...",
"de": "Ihr Bild hochladen..."
},
@ -23,7 +23,7 @@
"nl": "Bezig met {count} foto's te uploaden...",
"ca": "Pujant {count} de la teva imatge...",
"es": "Subiendo {count} de tus fotos...",
"fr": "Mettre votre {count} photos en ligne",
"fr": "Mise en ligne de {count} photos...",
"gl": "Subindo {count} das túas imaxes...",
"de": "{count} Ihrer Bilder hochgeladen..."
},
@ -32,7 +32,7 @@
"nl": "Gelieve je aan te melden om een foto toe te voegen",
"es": "Entra para subir una foto",
"ca": "Entra per pujar una foto",
"fr": "Connectez vous pour mettre une photo en ligne",
"fr": "Connectez-vous pour mettre une photo en ligne",
"gl": "Inicia a sesión para subir unha imaxe",
"de": "Bitte einloggen, um ein Bild hinzuzufügen"
},
@ -41,7 +41,7 @@
"es": "Tu foto será publicada: ",
"ca": "La teva foto serà publicada: ",
"nl": "Jouw foto wordt gepubliceerd: ",
"fr": "Votre photo va être publié: ",
"fr": "Votre photo va être publiée: ",
"gl": "A túa imaxe será publicada: ",
"de": "Ihr Bild wird veröffentlicht: "
},
@ -86,7 +86,7 @@
"ca": "Respecta la privacitat. No fotografiïs gent o matrícules",
"es": "Respeta la privacidad. No fotografíes gente o matrículas",
"nl": "Fotografeer geen mensen of nummerplaten. Voeg geen Google Maps, Google Streetview of foto's met auteursrechten toe.",
"fr": "Merci de respecter la vie privée. Ne publiez pas les plaques d'immatriculation",
"fr": "Merci de respecter la vie privée. Ne publiez pas les plaques d'immatriculation.",
"gl": "Respecta a privacidade. Non fotografes xente ou matrículas",
"de": "Bitte respektieren Sie die Privatsphäre. Fotografieren Sie weder Personen noch Nummernschilder"
},
@ -95,7 +95,7 @@
"ca": "<span class='thanks'>La teva imatge ha estat afegida. Gràcies per ajudar.</span>",
"es": "<span class='thanks'>Tu imagen ha sido añadida. Gracias por ayudar.</span>",
"nl": "<span class='thanks'>Je afbeelding is toegevoegd. Bedankt om te helpen!</span>",
"fr": "<span class='thanks'>Votre photo est ajouté. Merci beaucoup!</span>",
"fr": "<span class='thanks'>Votre photo est ajoutée. Merci beaucoup!</span>",
"gl": "<span class='thanks'>A túa imaxe foi engadida. Grazas por axudar.</span>",
"de": "<span class='thanks'>Ihr Bild wurde hinzugefügt. Vielen Dank für Ihre Hilfe!</span>"
},
@ -104,6 +104,7 @@
"en": "Cancel",
"ca": "Cancel·lar",
"es": "Cancelar",
"fr": "Annuler",
"de": "Abbrechen"
},
"doDelete": {
@ -111,6 +112,7 @@
"en": "Remove image",
"ca": "Esborrar imatge",
"es": "Borrar imagen",
"fr": "Supprimer l'image",
"de": "Bild entfernen"
},
"isDeleted": {
@ -118,6 +120,7 @@
"en": "Deleted",
"ca": "Esborrada",
"es": "Borrada",
"fr": "Supprimé",
"de": "Gelöscht"
}
},
@ -127,7 +130,7 @@
"ca": "Carregant dades...",
"es": "Cargando datos...",
"nl": "Data wordt geladen...",
"fr": "Chargement des données",
"fr": "Chargement des données...",
"gl": "Cargando os datos...",
"de": "Daten werden geladen..."
},
@ -136,7 +139,7 @@
"ca": "Amplia per veure o editar les dades",
"es": "Amplía para ver o editar los datos",
"nl": "Zoom in om de data te zien en te bewerken",
"fr": "Rapprochez vous sur la carte pour voir ou éditer les données",
"fr": "Rapprochez-vous sur la carte pour voir ou éditer les données",
"gl": "Achégate para ollar ou editar os datos",
"de": "Vergrößern, um die Daten anzuzeigen oder zu bearbeiten"
},
@ -153,7 +156,7 @@
"en": "Loading data failed. Trying again... ({count})",
"ca": "La càrrega de dades ha fallat.Tornant-ho a intentar... ({count})",
"es": "La carga de datos ha fallado.Volviéndolo a probar... ({count})",
"gl": "A carga dos datos fallou. Tentándoo de novo... ({count})",
"gl": "A carga dos datos fallou. Tentándoo de novo... ({count})", "fr": "Le chargement a échoué. Essayer à nouveau... ({count})",
"de": "Laden von Daten fehlgeschlagen. Erneuter Versuch... ({count})"
}
},
@ -172,7 +175,7 @@
"ca": "Has entrat, benvingut.",
"es": "Has entrado, bienvenido.",
"nl": "Je bent aangemeld. Welkom terug!",
"fr": "Vous êtes connecté, bienvenue",
"fr": "Vous êtes connecté. Bienvenue!",
"gl": "Iniciaches a sesión, benvido.",
"de": "Sie sind eingeloggt, willkommen zurück!"
},
@ -181,7 +184,7 @@
"ca": "Entra per contestar aquesta pregunta",
"es": "Entra para contestar esta pregunta",
"nl": "Meld je aan om deze vraag te beantwoorden",
"fr": "Connectez vous pour répondre à cette question",
"fr": "Connectez-vous pour répondre à cette question",
"gl": "Inicia a sesión para responder esta pregunta",
"de": "Anmelden, um diese Frage zu beantworten"
},
@ -191,7 +194,7 @@
"ca": "Cerca una ubicació",
"es": "Busca una ubicación",
"nl": "Zoek naar een locatie",
"fr": "Chercher une location",
"fr": "Chercher un lieu",
"gl": "Procurar unha localización",
"de": "Einen Ort suchen"
},
@ -200,7 +203,7 @@
"ca": "Cercant...",
"es": "Buscando...",
"nl": "Aan het zoeken...",
"fr": "Chargement",
"fr": "Chargement...",
"gl": "Procurando...",
"de": "Auf der Suche..."
},
@ -209,7 +212,7 @@
"ca": "Res trobat.",
"es": "Nada encontrado.",
"nl": "Niet gevonden...",
"fr": "Rien n'a été trouvé ",
"fr": "Rien n'a été trouvé...",
"gl": "Nada atopado...",
"de": "Nichts gefunden..."
},
@ -264,7 +267,7 @@
"ca": "Has ignorat una pregunta",
"es": "Has ignorado una pregunta",
"nl": "Een vraag is overgeslaan",
"fr": "Une question a été passé",
"fr": "Une question a été passée",
"gl": "Ignoraches unha pregunta",
"de": "Eine Frage wurde übersprungen"
},
@ -282,7 +285,7 @@
"ca": "nombre",
"es": "número",
"nl": "getal",
"fr": "Nombre",
"fr": "nombre",
"gl": "número",
"de": "Zahl"
},
@ -310,7 +313,7 @@
"ca": "<h2>Vols afegir un punt?</h2>Has marcat un lloc on no coneixem les dades.<br/>",
"es": "<h2>Quieres añadir un punto?</h2>Has marcado un lugar del que no conocemos los datos.<br/>",
"nl": "<h2>Punt toevoegen?</h2>Je klikte ergens waar er nog geen data is. Kies hieronder welk punt je wilt toevoegen<br/>",
"fr": "<h2>Pas de données</h2>Vous avez cliqué sur un endroit ou il n'y a pas encore de données. <br/>",
"fr": "<h2>Pas de données</h2>Vous avez cliqué sur un endroit où il n'y a pas encore de données. <br/>",
"gl": "<h2>Queres engadir un punto?</h2>Marcaches un lugar onde non coñecemos os datos.<br/>",
"de": "<h2>Punkt hinzufügen?</h2>Sie haben irgendwo geklickt, wo noch keine Daten bekannt sind.<br/>"
},
@ -337,7 +340,7 @@
"ca": "Les dades es segueixen carregant. Espera una mica abans d'afegir cap punt.",
"es": "Los datos se siguen cargando. Espera un poco antes de añadir ningún punto.",
"nl": "De data wordt nog geladen. Nog even geduld en dan kan je een punt toevoegen.",
"fr": "Chargement des donnés. Patientez un instant avant d'ajouter un nouveau point.",
"fr": "Chargement des données en cours. Patientez un instant avant d'ajouter un nouveau point.",
"gl": "Os datos seguen a cargarse. Agarda un intre antes de engadir ningún punto.",
"de": "Die Daten werden noch geladen. Bitte warten Sie etwas, bevor Sie einen neuen Punkt hinzufügen."
},
@ -346,15 +349,15 @@
"ca": "<h3>Afegir {title} aquí?</h3>El punt que estàs creant <b>el veurà tothom</b>. Només afegeix coses que realment existeixin. Moltes aplicacions fan servir aquestes dades.",
"es": "<h3>Añadir {title} aquí?</h3>El punto que estás creando <b>lo verá todo el mundo</b>. Sólo añade cosas que realmente existan. Muchas aplicaciones usan estos datos.",
"nl": "<h3>Voeg hier een {title} toe?</h3>Het punt dat je hier toevoegt, is <b>zichtbaar voor iedereen</b>. Veel applicaties gebruiken deze data, voeg dus enkel punten toe die echt bestaan.",
"fr": "<h3>Ajouter un/une {title} ici?</h3>Le point que vous ajouter sera visible par tout le monde. Merci d'etre sûr que ce point existe réellement. Beaucoup d'autres applications reposent sur ces données.",
"fr": "<h3>Ajouter un/une {title} ici?</h3>Le point que vous ajouter sera visible par tout le monde. Merci de vous assurer que ce point existe réellement. Beaucoup d'autres applications utilisent ces données.",
"gl": "<h3>Engadir {title} aquí?</h3>O punto que estás a crear <b>será ollado por todo o mundo</b>. Só engade cousas que realmente existan. Moitas aplicacións empregan estes datos.",
"de": "<h3>Hier einen {title} hinzufügen?</h3>Der Punkt, den Sie hier anlegen, wird <b>für alle sichtbar sein</b>. Bitte fügen Sie der Karte nur dann Dinge hinzu, wenn sie wirklich existieren. Viele Anwendungen verwenden diese Daten."
},
"confirmButton": {
"en": "Add a {category} here",
"en": "Add a {category} here.<br/><div class='alert'>Your addition is visble for everyone</div>",
"ca": "Afegir {category} aquí",
"es": "Añadir {category} aquí",
"nl": "Voeg hier een {category} toe",
"nl": "Voeg hier een {category} toe<br/><div class='alert'>Je toevoeging is voor iedereen zichtbaar</div>",
"fr": "Ajouter un/une {category} ici",
"gl": "Engadir {category} aquí",
"de": "Hier eine {category} hinzufügen"
@ -363,14 +366,15 @@
"en": "Open the layer control box",
"ca": "Obrir el control de capes",
"es": "Abrir el control de capas",
"nl": "Open de laag-instellingen",
"nl": "Open de laag-instellingen", "fr": "Ouvrir la panneau de contrôle",
"de": "Das Ebenen-Kontrollkästchen öffnen"
},
"layerNotEnabled": {
"en": "The layer {layer} is not enabled. Enable this layer to add a point",
"ca": "La capa {layer} no està habilitada. Fes-ho per poder afegir un punt a aquesta capa",
"es": "La capa {layer} no está habilitada. Hazlo para poder añadir un punto en esta capa",
"nl": "De laag {layer} is gedeactiveerd. Activeer deze om een punt toe te voegn",
"nl": "De laag {layer} is gedeactiveerd. Activeer deze om een punt toe te voegen",
"fr": "La couche [layer] est désactivée. Activez-la pour ajouter un point.",
"de": "Die Ebene {layer} ist nicht aktiviert. Aktivieren Sie diese Ebene, um einen Punkt hinzuzufügen"
}
},
@ -387,8 +391,8 @@
"en": "Easily edit and add OpenStreetMap for a certain theme",
"ca": "Edita facilment i afegeix punts a OpenStreetMap d'una temàtica determinada",
"es": "Edita facilmente y añade puntos en OpenStreetMap de un tema concreto",
"nl": "Easily edit and add OpenStreetMap for a certain theme",
"fr": "Édition facile et ajouter OpenStreetMap pour un certain thème",
"nl": "Bewerk en voeg data toe aan OpenStreetMap over een specifiek onderwerp op een gemakkelijke manier",
"fr": "Éditer facilement et ajouter OpenStreetMap pour un certain thème",
"gl": "Editar doadamente e engadir puntos no OpenStreetMap dun eido en concreto",
"de": "OpenStreetMap für ein bestimmtes Thema einfach bearbeiten und hinzufügen"
},
@ -443,7 +447,7 @@
"ca": "Pàgina web: <a href='{website}' target='_blank'>{website}</a>",
"es": "Página web: <a href='{website}' target='_blank'>{website}</a>",
"nl": "Website: <a href='{website}' target='_blank'>{website}</a>",
"fr": "Website: <a href='{website}' target='_blank'>{website}</a>",
"fr": "Site web: <a href='{website}' target='_blank'>{website}</a>",
"gl": "Páxina web: <a href='{website}' target='_blank'>{website}</a>",
"de": "Webseite: <a href='{website}' target='_blank'>{website}</a>"
},
@ -475,7 +479,7 @@
"es": "<h3>Un mapa abierto</h3><p></p>¿No sería genial si hubiera un solo mapa, que todos pudieran usar y editar libremente?¿Un solo lugar para almacenar toda la información geográfica? Entonces, todos esos sitios web con mapas diferentes, pequeños e incompatibles (que siempre están desactualizados) ya no serían necesarios.</p><p><b><a href='https://OpenStreetMap.org' target='_blank'>OpenStreetMap</a></b> es ese mapa. Los datos del mapa se pueden utilizar de forma gratuita (con <a href='https://osm.org/copyright' target='_blank'> atribución y publicación de cambios en esos datos</a>).Además de eso, todos pueden agregar libremente nuevos datos y corregir errores. Este sitio web también usa OpenStreetMap. Todos los datos provienen de allí, y tus respuestas y correcciones también se añadirán allí.</p><p>Muchas personas y aplicaciones ya usan OpenStreetMap: <a href='https://maps.me/' target='_blank'>Maps.me</a>, <a href='https://osmAnd.net' target='_blank'>OsmAnd</a>, pero también los mapas de Facebook, Instagram, Apple y Bing son (en parte) impulsados por OpenStreetMap .Si cambias algo aquí, también se reflejará en esas aplicaciones, en su próxima actualización</p>",
"ca": "<h3>Un mapa obert</h3><p></p>No seria genial si hagués un únic mapa, que tothom pogués utilitzar i editar lliurement?Un sol lloc on emmagatzemar tota la informació geogràfica? Llavors tots aquests llocs web amb mapes diferents petits i incompatibles (que sempre estaran desactulitzats) ja no serien necessaris.</p><p><b><a href='https://OpenStreetMap.org' target='_blank'>OpenStreetMap</a></b> és aquest mapa. Les dades del mapa es poden utilitzar de franc (amb <a href='https://osm.org/copyright' target='_blank'> atribució i publicació de canvis en aquestes dades</a>).A més a més, tothom pot agregar lliurement noves dades i corregir errors. De fet, aquest lloc web també fa servir OpenStreetMap. Totes les dades provenen d'allà i les teves respostes i correccions també s'afegiran allà.</p><p>Moltes persones i aplicacions ja utilitzen OpenStreetMap: <a href='https://maps.me/' target='_blank'>Maps.me</a>, <a href='https://osmAnd.net' target='_blank'>OsmAnd</a>, però també els mapes de Facebook, Instagram, Apple i Bing són (en part) impulsats per OpenStreetMap.Si canvies alguna cosa aquí també es reflectirà en aquestes aplicacions en la seva propera actualització.</p>",
"nl": "<h3>Een open kaart</h3><p>Zou het niet fantastisch zijn als er een open kaart zou zijn die door iedereen aangepast én gebruikt kan worden? Een kaart waar iedereen zijn interesses aan zou kunnen toevoegen? Dan zouden er geen duizend-en-één verschillende kleine kaartjes, websites, ... meer nodig zijn</p><p><b><a href='https://OpenStreetMap.org' target='_blank'>OpenStreetMap</a></b> is deze open kaart. Je mag de kaartdata gratis gebruiken (mits <a href='https://osm.org/copyright' target='_blank'>bronvermelding en herpublicatie van aanpassingen</a>). Daarenboven mag je de kaart ook gratis aanpassen als je een account maakt. Ook deze website is gebaseerd op OpenStreetMap. Als je hier een vraag beantwoord, gaat het antwoord daar ook naartoe</p><p>Tenslotte zijn er reeds vele gebruikers van OpenStreetMap. Denk maar <a href='https://maps.me/' target='_blank'>Maps.me</a>, <a href='https://osmAnd.net' target='_blank'>OsmAnd</a>, verschillende gespecialiseerde routeplanners, de achtergrondkaarten op Facebook, Instagram,...<br/>Zelfs Apple Maps en Bing-Maps gebruiken OpenStreetMap in hun kaarten!</p></p><p>Kortom, als je hier een punt toevoegd of een vraag beantwoord, zal dat na een tijdje ook in al dié applicaties te zien zijn.</p>",
"fr": "<h3>Une carte ouverte</h3><p></p>How incroyable se serait d'avoir sur une carte que tout le monde pourrait éditer ouvertement?Une seule et unique plateforme regroupant toutes les informations geographiques? Ainsi nous n'aurons plus besoin de toutes ces petites et incompatibles cartes (souvent non mises à jour).</p><p><b><a href='https://OpenStreetMap.org' target='_blank'>OpenStreetMap</a></b> est la carte qu'il vous faut!. Toutes les donnees de cette carte peuvent être utilisé gratuitement (avec <a href='https://osm.org/copyright' target='_blank'> d'attribution et de publication des changements de données</a>). De plus tout le monde est libre d'ajouter de nouvelles données et corriger les erreurs. Ce site internet utilise également OpenStreetMap. Toutes les données y proviennent et tous les ajouts et modifications y seront également ajoutés.</p><p>De nombreux individus et d'applications utilisent déjà OpenStreetMap: <a href='https://maps.me/' target='_blank'>Maps.me</a>, <a href='https://osmAnd.net' target='_blank'>OsmAnd</a>, mais aussi les cartes de Facebook, Instagram, Apple-maps et Bing-maps sont(en partie) supporté par OpenStreetMap.Si vous modifié quelque chose ici, ces changement seront retranscris sur ces applications aussi - des lors de leur mise à jour! </p>",
"fr": "<h3>Une carte ouverte</h3><p></p>Ne serait-il pas génial d'avoir sur une carte que tout le monde pourrait éditer ouvertement? Une seule et unique plateforme regroupant toutes les informations geographiques? Ainsi nous n'aurons plus besoin de toutes ces cartes petites et incompatibles cartes (souvent non mises à jour).</p><p><b><a href='https://OpenStreetMap.org' target='_blank'>OpenStreetMap</a></b> est la carte qu'il vous faut!. Toutes les données de cette carte peuvent être utilisé gratuitement (avec <a href='https://osm.org/copyright' target='_blank'> d'attribution et de publication des changements de données</a>). De plus tout le monde est libre d'ajouter de nouvelles données et de corriger les erreurs. Ce site internet utilise également OpenStreetMap. Toutes les données en proviennent et tous les ajouts et modifications y seront également ajoutés.</p><p>De nombreux individus et d'applications utilisent déjà OpenStreetMap: <a href='https://maps.me/' target='_blank'>Maps.me</a>, <a href='https://osmAnd.net' target='_blank'>OsmAnd</a>, mais aussi les cartes de Facebook, Instagram, Apple-maps et Bing-maps sont (en partie) supporté par OpenStreetMap. Si vous modifié quelque chose ici, ces changements seront incorporer dans ces applications dès leurs mises à jour!</p>",
"gl": "<h3>Un mapa aberto</h3><p></p>Non sería xenial se houbera un só mapa, que todos puideran empregar e editar de xeito libre?Un só lugar para almacenar toda a información xeográfica? Entón, todos eses sitios web con mapas diferentes, pequenos e incompatíbeis (que sempre están desactualizados) xa non serían necesarios.</p><p><b><a href='https://OpenStreetMap.org' target='_blank'>OpenStreetMap</a></b> é ese mapa. Os datos do mapa pódense empregar de balde (con <a href='https://osm.org/copyright' target='_blank'> atribución e publicación de modificacións neses datos</a>).Ademais diso, todos poden engadir de xeito ceibe novos datos e corrixir erros. Este sitio web tamén emprega o OpenStreetMap. Todos os datos proveñen de alí, e as túas respostas e correccións tamén serán engadidas alí.</p><p>Moitas persoas e aplicacións xa empregan o OpenStreetMap: <a href='https://maps.me/' target='_blank'>Maps.me</a>, <a href='https://osmAnd.net' target='_blank'>OsmAnd</a>, pero tamén os mapas do Facebook, Instagram, Apple e Bing son (en parte) impulsados polo OpenStreetMap.Se mudas algo aquí, tamén será reflexado nesas aplicacións, na súa seguinte actualización!</p>",
"de": "<h3>Eine offene Karte</h3><p>Wäre es nicht toll, wenn es eine offene Karte gäbe, die von jedem angepasst und benutzt werden könnte? Eine Karte, zu der jeder seine Interessen hinzufügen kann? Dann bräuchte man all diese Websites mit unterschiedlichen, kleinen und inkompatiblen Karten (die immer veraltet sind) nicht mehr.</p><p><b><a href='https://OpenStreetMap.org' target='_blank'>OpenStreetMap</a></b> ist diese offene Karte. Die Kartendaten können kostenlos verwendet werden (mit <a href='https://osm.org/copyright' target='_blank'>Attribution und Veröffentlichung von Änderungen an diesen Daten</a>). Darüber hinaus können Sie die Karte kostenlos ändern und Fehler beheben, wenn Sie ein Konto erstellen. Diese Website basiert ebenfalls auf OpenStreetMap. Wenn Sie eine Frage hier beantworten, geht die Antwort auch dorthin.</p>Viele Menschen und Anwendungen nutzen OpenStreetMap bereits: <a href='https://maps.me/' target='_blank'>Maps.me</a>, <a href='https://osmAnd.net' target='_blank'>OsmAnd</a>, verschiedene spezialisierte Routenplaner, die Hintergrundkarten auf Facebook, Instagram,...<br/>Sogar Apple Maps und Bing Maps verwenden OpenStreetMap in ihren Karten!</p></p><p>Wenn Sie hier einen Punkt hinzufügen oder eine Frage beantworten, wird er nach einer Weile in all diesen Anwendungen sichtbar sein.</p>"
},
@ -484,7 +488,7 @@
"en": "<h3>Share this map</h3> Share this map by copying the link below and sending it to friends and family:",
"ca": "<h3>Comparteix aquest mapa</h3> Comparteix aquest mapa copiant l'enllaç de sota i enviant-lo a amics i família:",
"es": "<h3>Comparte este mapa</h3> Comparte este mapa copiando el enlace de debajo y enviándolo a amigos y familia:",
"fr": "<h3>Partager cette carte</h3> Partagez cette carte en copiant le lien suivant et envoyer le à vos amis:",
"fr": "<h3>Partager cette carte</h3> Partagez cette carte en copiant le lien suivant et envoyez-le à vos amis:",
"nl": "<h3>Deel deze kaart</h3> Kopieer onderstaande link om deze kaart naar vrienden en familie door te sturen:",
"gl": "<h3>Comparte este mapa</h3> Comparte este mapa copiando a ligazón de embaixo e enviándoa ás amizades e familia:",
"de": "<h3>Diese Karte teilen</h3> Sie können diese Karte teilen, indem Sie den untenstehenden Link kopieren und an Freunde und Familie schick"
@ -493,7 +497,7 @@
"en": "<h3>Add to your home screen</h3>You can easily add this website to your smartphone home screen for a native feel. Click the 'add to home screen button' in the URL bar to do this.",
"ca": "<h3>Afegir-lo a la pantalla d'inici</h3>Pots afegir aquesta web a la pantalla d'inici del teu smartphone per a que es vegi més nadiu. Apreta al botó 'afegir a l'inici' a la barra d'adreces URL per fer-ho.",
"es": "<h3>Añadir a la pantalla de inicio</h3>Puedes añadir esta web en la pantalla de inicio de tu smartphone para que se vea más nativo. Aprieta el botón 'añadir a inicio' en la barra de direcciones URL para hacerlo.",
"fr": "<h3>Ajouter à votre page d'accueil</h3> Vous pouvez facilement ajouter la carte à votre écran d'accueil de téléphone. Cliquer sur le boutton 'ajouter à l'evran d'accueil' dans la barre d'URL pour éffecteur cette tâche",
"fr": "<h3>Ajouter à votre page d'accueil</h3> Vous pouvez facilement ajouter la carte à votre écran d'accueil de téléphone. Cliquer sur le boutton 'ajouter à l'ecran d'accueil' dans la barre d'adresse pour éffectuer cette tâche.",
"gl": "<h3>Engadir á pantalla de inicio</h3>Podes engadir esta web na pantalla de inicio do teu smartphone para que se vexa máis nativo. Preme o botón 'engadir ó inicio' na barra de enderezos URL para facelo.",
"nl": "<h3>Voeg toe aan je thuis-scherm</h3>Je kan deze website aan je thuisscherm van je smartphone toevoegen voor een native feel",
"de": "<h3>Zum Startbildschirm hinzufügen</h3> Sie können diese Website einfach zum Startbildschirm Ihres Smartphones hinzufügen, um ein natives Gefühl zu erhalten. Klicken Sie dazu in der URL-Leiste auf die Schaltfläche 'Zum Startbildschirm hinzufügen'."
@ -502,7 +506,7 @@
"en": "<h3>Embed on your website</h3>Please, embed this map into your website. <br/>We encourage you to do it - you don't even have to ask permission. <br/> It is free, and always will be. The more people using this, the more valuable it becomes.",
"ca": "<h3>Inclou-ho a la teva pàgina web</h3>Inclou aquest mapa dins de la teva pàgina web. <br/> T'animem a que ho facis, no cal que demanis permís. <br/> És de franc, i sempre ho serà. A més gent que ho faci servir més valuós serà.",
"es": "<h3>Inclúyelo en tu página web</h3>Incluye este mapa en tu página web. <br/> Te animamos a que lo hagas, no hace falta que pidas permiso. <br/> Es gratis, y siempre lo será. A más gente que lo use más valioso será.",
"fr": "<h3>Incorporer à votre website</h3>AJouter la carte à votre website. <br/>On vous en encourage - pas besoin de permission. <br/> C'est gratuit et pour toujours. Le plus de personnes l'utilisent, le mieux ce sera.",
"fr": "<h3>Incorporer à votre website</h3>AJouter la carte à votre website. <br/>Nous vous y encourageons - pas besoin de permission.<br/> C'est gratuit et pour toujours. Au plus de personnes l'utilisent, au mieux.",
"gl": "<h3>Inclúeo na túa páxina web</h3>Inclúe este mapa na túa páxina web. <br/> Animámoche a que o fagas, non fai falla que pidas permiso. <br/> É de balde, e sempre será. Canta máis xente que o empregue máis valioso será.",
"nl": "<h3>Plaats dit op je website</h3>Voeg dit kaartje toe op je eigen website.<br/>We moedigen dit zelfs aan - je hoeft geen toestemming te vragen.<br/> Het is gratis en zal dat altijd blijven. Hoe meer het gebruikt wordt, hoe waardevoller",
"de": "<h3>Auf Ihrer Website einbetten</h3>Bitte, betten Sie diese Karte in Ihre Website ein. <br/>Wir ermutigen Sie, es zu tun - Sie müssen nicht einmal um Erlaubnis fragen. <br/> Es ist kostenlos und wird es immer sein. Je mehr Leute sie benutzen, desto wertvoller wird sie."
@ -512,7 +516,7 @@
"ca": "Enllaç copiat al portapapers",
"es": "Enlace copiado en el portapapeles",
"gl": "Ligazón copiada ó portapapeis",
"nl": "Link gekopieerd naar klembord",
"nl": "Link gekopieerd naar klembord","fr": "Lien copié dans le presse-papier",
"de": "Link in die Zwischenablage kopiert"
},
"thanksForSharing": {
@ -520,7 +524,7 @@
"ca": "Gràcies per compartir",
"es": "Gracias por compartir",
"gl": "Grazas por compartir!",
"nl": "Bedankt om te delen!",
"nl": "Bedankt om te delen!", "fr": "Merci d'avoir partagé!",
"de": "Danke für das Teilen!"
},
"editThisTheme": {
@ -528,7 +532,7 @@
"ca": "Editar aquest repte",
"es": "Editar este reto",
"gl": "Editar este tema",
"nl": "Pas dit thema aan",
"nl": "Pas dit thema aan", "fr": "Editer ce thème",
"de": "Dieses Thema bearbeiten"
},
"editThemeDescription": {
@ -536,15 +540,15 @@
"ca": "Afegir o canviar preguntes d'aquest repte",
"es": "Añadir o cambiar preguntas de este reto",
"gl": "Engadir ou mudar preguntas a este tema do mapa",
"nl": "Pas vragen aan of voeg vragen toe aan dit kaartthema",
"nl": "Pas vragen aan of voeg vragen toe aan dit kaartthema", "fr": "Ajouter ou modifier des questions à ce thème",
"de": "Fragen zu diesem Kartenthema hinzufügen oder ändern"
},
"fsUserbadge": {
"en": "Enable the login-button",
"en": "Enable the login button",
"ca": "Activar el botó d'entrada",
"es": "Activar el botón de entrada",
"gl": "Activar botón de inicio de sesión",
"nl": "Activeer de login-knop",
"nl": "Activeer de login-knop", "fr": "Activer le bouton de connexion",
"de": " Anmelde-Knopf aktivieren"
},
"fsSearch": {
@ -552,7 +556,7 @@
"ca": "Activar la barra de cerca",
"es": "Activar la barra de búsqueda",
"gl": "Activar a barra de procura",
"nl": "Activeer de zoekbalk",
"nl": "Activeer de zoekbalk","fr": "Activer la barre de recherche",
"de": " Suchleiste aktivieren"
},
"fsWelcomeMessage": {
@ -560,15 +564,15 @@
"ca": "Mostra el missatge emergent de benvinguda i pestanyes associades",
"es": "Muestra el mensaje emergente de bienvenida y pestañas asociadas",
"gl": "Amosar a xanela emerxente da mensaxe de benvida e as lapelas asociadas",
"nl": "Toon het welkomstbericht en de bijhorende tabbladen",
"nl": "Toon het welkomstbericht en de bijhorende tabbladen", "fr": "Afficher le message de bienvenue et les onglets associés",
"de": "Popup der Begrüßungsnachricht und zugehörige Registerkarten anzeigen"
},
"fsLayers": {
"en": "Enable thelayer control",
"en": "Enable the layer control",
"ca": "Activar el control de capes",
"es": "Activar el control de capas",
"gl": "Activar o control de capas",
"nl": "Toon de knop voor laagbediening",
"nl": "Toon de knop voor laagbediening", "fr": "Activer le contrôle des couches",
"de": "Aktivieren der Layersteuerung"
},
"fsLayerControlToggle": {
@ -576,7 +580,7 @@
"gl": "Comenza co control de capas expandido",
"ca": "Iniciar el control de capes avançat",
"es": "Iniciar el control de capas avanzado",
"nl": "Toon de laagbediening meteen volledig",
"nl": "Toon de laagbediening meteen volledig", "fr": "Démarrer avec le contrôle des couches ouvert",
"de": "Mit der erweiterten Ebenenkontrolle beginnen"
},
"fsAddNew": {
@ -585,6 +589,7 @@
"es": "Activar el botón de añadir nuevo PDI'",
"nl": "Activeer het toevoegen van nieuwe POI",
"gl": "Activar o botón de 'engadir novo PDI'",
"fr": "Activer le bouton 'ajouter un POI'",
"de": "Schaltfläche 'neuen POI hinzufügen' aktivieren"
},
"fsGeolocation": {
@ -593,6 +598,7 @@
"es": "Activar el botón de 'geolocalízame' (només mòbil)",
"gl": "Activar o botón de 'xeolocalizarme' (só móbil)",
"nl": "Toon het knopje voor geolocalisatie (enkel op mobiel)",
"fr": "Activer le bouton 'Localisez-moi' (seulement sur mobile)",
"de": "Die Schaltfläche 'Mich geolokalisieren' aktivieren (nur für Mobil)"
},
"fsIncludeCurrentBackgroundMap": {
@ -600,6 +606,7 @@
"ca": "Incloure l'opció de fons actual <b>{name}</b>",
"es": "Incluir la opción de fondo actual <b>{name}</b>",
"nl": "Gebruik de huidige achtergrond <b>{name}</b>",
"fr": "Include le choix actuel d'arrière plan <b>{name}</b>",
"de": "Die aktuelle Hintergrundwahl einschließen <b>{name}</b>"
},
"fsIncludeCurrentLayers": {
@ -607,6 +614,7 @@
"ca": "Incloure les opcions de capa actual",
"es": "Incluir las opciones de capa actual",
"nl": "Toon enkel de huidig getoonde lagen",
"fr": "Inclure la couche selectionnée",
"de": "Die aktuelle Ebenenauswahl einbeziehen"
},
"fsIncludeCurrentLocation": {
@ -614,6 +622,7 @@
"es": "Incluir localización actual",
"ca": "Incloure localització actual",
"nl": "Start op de huidige locatie",
"fr": "Inclure l'emplacement actuel",
"de": "Aktuelle Position einbeziehen"
}
},
@ -622,7 +631,7 @@
"en": "<h3>More thematic maps?</h3>Do you enjoy collecting geodata? <br/>There are more themes available.",
"ca": "<h3>Més peticions</h3>T'agrada captar dades? <br/>Hi ha més capes disponibles.",
"es": "<h3>Más peticiones</h3>Te gusta captar datos? <br/>Hay más capas disponibles.",
"fr": "<h3>Plus de thème </h3>Vous aimez collecter des données? <br/>Il y a plus de thèmes disponible.",
"fr": "<h3>Plus de thèmes </h3>Vous aimez collecter des données? <br/>Il y a plus de thèmes disponibles.",
"nl": "<h3>Meer thematische kaarten</h3>Vind je het leuk om geodata te verzamelen? <br/> Hier vind je meer kaartthemas.",
"gl": "<h3>Máis tarefas</h3>Góstache captar datos? <br/>Hai máis capas dispoñíbeis.",
"de": "<h3>Weitere Quests</h3>Sammeln Sie gerne Geodaten? <br/>Es sind weitere Themen verfügbar."
@ -632,7 +641,7 @@
"ca": "Si vols que et fem una petició pròpia , demana-la <a href='https://github.com/pietervdvn/MapComplete/issues' target='_blank'>aquí</a>",
"es": "Si quieres que te hagamos una petición propia , pídela <a href='https://github.com/pietervdvn/MapComplete/issues' target='_blank'>aquí</a>",
"nl": "Wil je een eigen kaartthema, vraag dit <a href='https://github.com/pietervdvn/MapComplete/issues' target='_blank'>hier aan</a>",
"fr": "Si vous voulez une autre carte thématique, demandez <a href='https://github.com/pietervdvn/MapComplete/issues' target='_blank'>ici</a>",
"fr": "Si vous voulez une autre carte thématique, demande-la <a href='https://github.com/pietervdvn/MapComplete/issues' target='_blank'>ici</a>",
"gl": "Se queres que che fagamos unha tarefa propia , pídea <a href='https://github.com/pietervdvn/MapComplete/issues' target='_blank'>aquí</a>",
"de": "Wenn Sie einen speziell angefertigte Quest wünschen, können Sie diesen <a href='https://github.com/pietervdvn/MapComplete/issues' target='_blank'>hier</a> anfragen"
},
@ -660,7 +669,7 @@
"ca": "Llegeix tots els teus missatges d'OpenStreetMap abans d'afegir nous punts.",
"es": "Lee todos tus mensajes de OpenStreetMap antes de añadir nuevos puntos.",
"nl": "Gelieve eerst je berichten op OpenStreetMap te lezen alvorens nieuwe punten toe te voegen.",
"fr": "Merci de lire tout vos messages d'OpenStreetMap avant d'ajouter un nouveau point.",
"fr": "Merci de lire tous vos messages sur OpenStreetMap avant d'ajouter un nouveau point.",
"gl": "Le todos a túas mensaxes do OpenStreetMap antes de engadir novos puntos.",
"de": "Bitte lesen Sie alle Ihre OpenStreetMap-Nachrichten, bevor Sie einen neuen Punkt hinzufügen"
},
@ -669,7 +678,7 @@
"ca": "Contesta unes quantes preguntes sobre punts existents abans d'afegir-ne un de nou.",
"es": "Contesta unas cuantas preguntas sobre puntos existentes antes de añadir nuevos.",
"nl": "Gelieve eerst enkele vragen van bestaande punten te beantwoorden vooraleer zelf punten toe te voegen.",
"fr": "Merci de répondre à quelques questions à propos de point déjà existant avant d'ajouter de nouveaux points",
"fr": "Merci de répondre à quelques questions à propos de points déjà existants avant d'ajouter de nouveaux points",
"gl": "Responde unhas cantas preguntas sobre puntos existentes antes de engadir novos.",
"de": "Bitte beantworten Sie ein paar Fragen zu bestehenden Punkten, bevor Sie einen neuen Punkt hinzufügen."
},
@ -687,13 +696,13 @@
"es": "Entra en OpenStreetMap para empezar",
"ca": "Entra a OpenStreetMap per començar",
"nl": "Login met OpenStreetMap om te beginnen",
"fr": "Connectez vous avec OpenStreetMap pour commencer",
"fr": "Connectez-vous avec OpenStreetMap pour commencer",
"de": "Mit OpenStreetMap einloggen und loslegen"
},
"getStartedNewAccount": {
"en": " or <a href='https://www.openstreetmap.org/user/new' target='_blank'>create a new account</a>",
"nl": " of <a href='https://www.openstreetmap.org/user/new' target='_blank'>maak een nieuwe account aan</a> ",
"fr": " ou <a href='https://www.openstreetmap.org/user/new' target='_blank'>registrez vous</a>",
"fr": " ou <a href='https://www.openstreetmap.org/user/new' target='_blank'>enregistrez-vous</a>",
"es": " o <a href='https://www.openstreetmap.org/user/new' target='_blank'>crea una nueva cuenta</a>",
"ca": " o <a href='https://www.openstreetmap.org/user/new' target='_blank'>crea un nou compte</a>",
"gl": " ou <a href='https://www.openstreetmap.org/user/new' target='_blank'>crea unha nova conta</a>",
@ -704,11 +713,14 @@
"es": "No se han seleccionado etiquetas",
"ca": "No s'han seleccionat etiquetes",
"gl": "Non se seleccionaron etiquetas",
"nl": "Geen tags geselecteerd",
"fr": "Aucune balise sélectionnée",
"de": "Keine Tags ausgewählt"
},
"customThemeIntro": {
"en": "<h3>Custom themes</h3>These are previously visited user-generated themes.",
"nl": "<h3>Onofficiële themea's</h3>Je bezocht deze thema's gemaakt door andere OpenStreetMappers eerder",
"fr": "<h3>Thèmes personnalisés</h3>Vous avez déjà visité ces thèmes personnalisés.",
"gl": "<h3>Temas personalizados</h3>Estes son temas xerados por usuarios previamente visitados.",
"de": "<h3>Kundenspezifische Themen</h3>Dies sind zuvor besuchte benutzergenerierte Themen"
},
@ -722,6 +734,7 @@
"ca": "Mapa de fons",
"es": "Mapa de fondo",
"nl": "Achtergrondkaart",
"fr": "Carte de fonds",
"de": "Hintergrundkarte"
},
"zoomInToSeeThisLayer": {
@ -729,6 +742,7 @@
"ca": "Amplia per veure aquesta capa",
"es": "Amplía para ver esta capa",
"nl": "Vergroot de kaart om deze laag te zien",
"fr": "Aggrandissez la carte pour voir cette couche",
"de": "Vergrößern, um diese Ebene zu sehen"
},
"weekdays": {
@ -752,21 +766,21 @@
"ca": "Dic",
"es": "Mie",
"nl": "Woe",
"fr": "Mercr"
"fr": "Mer"
},
"thursday": {
"en": "Thu",
"ca": "Dij",
"es": "Jue",
"nl": "Don",
"fr": "Jeudi"
"fr": "Jeu"
},
"friday": {
"en": "Fri",
"ca": "Div",
"es": "Vie",
"nl": "Vrij",
"fr": "Vendr"
"fr": "Ven"
},
"saturday": {
"en": "Sat",
@ -830,30 +844,38 @@
"ca": "Diumenge",
"es": "Domingo",
"nl": "Zondag",
"fr": "Dimance"
"fr": "Dimanche"
}
},
"opening_hours": {
"error_loading": {
"en": "Error: could not visualize these opening hours.",
"nl": "Sorry, deze openingsuren kunnen niet getoond worden"
},
"open_during_ph": {
"nl": "Op een feestdag is deze zaak",
"ca": "Durant festes aquest servei és",
"es": "Durante fiestas este servicio está",
"en": "During a public holiday, this amenity is"
"en": "During a public holiday, this amenity is",
"fr": "Pendant les congés, ce lieu est"
},
"opensAt": {
"en": "from",
"ca": "des de",
"es": "desde",
"nl": "vanaf"
"nl": "vanaf",
"fr": "à partir de"
},
"openTill": {
"en": "till",
"ca": "fins",
"es": " hasta",
"nl": "tot"
"nl": "tot",
"fr": "jusqu'à"
},
"not_all_rules_parsed": {
"en": "The opening hours of this shop are complicated. The following rules are ignored in the input element:",
"fr": "Les heures d'ouvertures de ce magasin sont trop compliquées. Les heures suivantes ont été ignorées:",
"ca": "L'horari d'aquesta botiga és complicat. Les normes següents seran ignorades en l'entrada:",
"es": "El horario de esta tienda es complejo. Las normas siguientes serán ignoradas en la entrada:"
},
@ -861,13 +883,15 @@
"en": "Closed until {date}",
"ca": "Tancat fins {date}",
"es": "Cerrado hasta {date}",
"nl": "Gesloten - open op {date}"
"nl": "Gesloten - open op {date}",
"fr": "Fermé jusqu'à"
},
"closed_permanently": {
"en": "Closed - no opening day known",
"en": "Closed for an unkown duration",
"ca": "Tancat - sense dia d'obertura conegut",
"es": "Cerrado - sin día de apertura conocido",
"nl": "Gesloten"
"nl": "Gesloten voor onbepaalde tijd",
"fr": "Fermé"
},
"ph_not_known": {
"en": " ",
@ -879,13 +903,15 @@
"en": "closed",
"ca": "tancat",
"es": "cerrado",
"nl": "gesloten"
"nl": "gesloten",
"fr": "fermé"
},
"ph_open": {
"en": "opened",
"ca": "tancat",
"es": "abierto",
"nl": "open"
"nl": "open",
"fr": "ouvert"
}
}
},
@ -895,21 +921,78 @@
"ca": "<h3>La teva interfície personal</h3>Activa les teves capes favorites de totes les interfícies oficials",
"es": "<h3>Tu interficie personal</h3>Activa tus capas favoritas de todas las interficies oficiales",
"gl": "<h3>O teu tema personalizado</h3>Activa as túas capas favoritas de todos os temas oficiais",
"de": "<h3>Ihr persönliches Thema</h3>Aktivieren Sie Ihre Lieblingsebenen aus allen offiziellen Themen"
"de": "<h3>Ihr persönliches Thema</h3>Aktivieren Sie Ihre Lieblingsebenen aus allen offiziellen Themen",
"fr": "<h3>Votre thème personnel</h3>Activer vos couches favorites depuis les thèmes officiels"
},
"loginNeeded": {
"en": "<h3>Log in</h3>A personal layout is only available for OpenStreetMap users",
"es": "<h3>Entrar</h3>El diseño personalizado sólo está disponible para los usuarios de OpenstreetMap",
"ca": "<h3>Entrar</h3>El disseny personalizat només està disponible pels usuaris d' OpenstreetMap",
"gl": "<h3>Iniciar a sesión</h3>O deseño personalizado só está dispoñíbel para os usuarios do OpenstreetMap",
"de": "<h3>Anmelden</h3>Ein persönliches Layout ist nur für OpenStreetMap-Benutzer verfügbar"
"de": "<h3>Anmelden</h3>Ein persönliches Layout ist nur für OpenStreetMap-Benutzer verfügbar",
"fr": "<h3>Connexion</h3>La mise en forme personnalisée requiert un compte OpenStreetMap"
},
"reload": {
"en": "Reload the data",
"es": "Recargar datos",
"ca": "Recarregar dades",
"gl": "Recargar os datos",
"de": "Daten neu laden"
"de": "Daten neu laden",
"fr": "Recharger les données"
}
},
"reviews": {
"title": {
"en": "{count} reviews",
"nl": "{count} beoordelingen"
},
"name_required": {
"en": "A name is required in order to display and create reviews",
"nl": "De naam van dit object moet gekend zijn om een review te kunnen maken"
},
"no_reviews_yet": {
"en": "There are no reviews yet. Be the first to write one and help open data and the business!",
"nl": "Er zijn nog geen beoordelingen. Wees de eerste om een beoordeling te schrijven en help open data en het bedrijf"
},
"write_a_comment": {
"en": "Leave a review...",
"nl": "Schrijf een beoordeling..."
},
"no_rating": {
"en": "No rating given",
"nl": "Geen score bekend"
},
"posting_as": {
"en": "Posting as",
"nl": "Ingelogd als"
},
"i_am_affiliated": {
"en": "<div'><span>I am affiliated with this object</span><br/><span class='subtle'>Check if you are an owner, creator, employee, ...</span></div>",
"nl": "<div style='display:inline-block;max-width: 40%;'><span>I am affiliated with this object</span><br/><span class='subtle'>Vink aan indien je de oprichter, maker, werknemer, ... of dergelijke bent</span></div>"
},
"affiliated_reviewer_warning": {
"en": "(Affiliated review)",
"nl": "(Review door betrokkene)"
},
"saving_review": {
"en": "Saving...",
"nl": "Opslaan..."
},
"saved": {
"en": "<span class='thanks'>Review saved. Thanks for sharing!</span>",
"nl": "<span class='thanks'>Bedankt om je beoordeling te delen!</span>"
},
"tos": {
"en": "If you create a review, you agree to <a href='https://mangrove.reviews/terms' target='_blank'>the TOS and privacy policy of Mangrove.reviews</a>",
"nl": "Als je je review publiceert, ga je akkoord met de <a href='https://mangrove.reviews/terms' target='_blank'>de gebruiksvoorwaarden en privacy policy van Mangrove.reviews</a>"
},
"attribution": {
"en": "Reviews are powered by <a href='https://mangrove.reviews/' target='_blank'>Mangrove Reviews</a> and are available under <a href='https://mangrove.reviews/terms#8-licensing-of-content' target='_blank'>CC-BY 4.0</a>.",
"nl": "De beoordelingen worden voorzien door <a href='https://mangrove.reviews/' target='_blank'>Mangrove Reviews</a> en zijn beschikbaar onder de<a href='https://mangrove.reviews/terms#8-licensing-of-content' target='_blank'>CC-BY 4.0-licentie</a>. "
},
"plz_login": {
"en": "Login to leave a review",
"nl": "Meld je aan om een beoordeling te geven"
}
}
}

BIN
assets/weblogo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

2634
assets/weblogo.svg Normal file

File diff suppressed because it is too large Load diff

After

Width:  |  Height:  |  Size: 113 KiB

128
css/ReviewElement.css Normal file
View file

@ -0,0 +1,128 @@
.review {
display: block;
margin-top: 1em;
}
.review-title {
font-size: x-large;
display: flex;
justify-content: space-between;
align-items: center;
padding-left: 1em;
padding-right: 1em;
}
.review-title img {
max-width: 1.5em;
height: 1.5em;
}
.review-rating img {
max-width: 1em;
height: 1em;
}
.review-by-current-user {
border: 5px solid var(--catch-detail-color);
}
.review-rating {
display: flex;
flex-direction: row;
width: 5em;
margin-right: 0.5em;
flex-shrink: 0;
}
.review-date {
color: var(--subtle-detail-color-light-contrast);
}
.review-stars-comment {
display: flex;
margin-bottom: 0.5em;
}
.review-author {
font-weight: bold;
}
.review-author-date {
display: flex;
margin-bottom: 0.5em;
justify-content: flex-end;
}
.review-element {
padding: 1em;
margin: 0.5em;
display: block;
border-radius: 1em;
background-color: var(--subtle-detail-color);
color: var(--subtle-detail-color-contrast);
}
.review-attribution {
display: flex;
color: var(--subtle-detail-color-light-contrast);
justify-content: flex-end;
margin-right: 1em;
}
.review-attribution span {
width: calc(75% - 3em);
text-align: right;
max-width: 20em;
}
.review-attribution img {
height: 3em;
margin-left: 0.5em;
}
.review-form {
display: block;
border-radius: 1em;
padding: 1em;
background-color: var(--subtle-detail-color);
color: var(--subtle-detail-color-contrast);
border: 2px solid var(--subtle-detail-color-contrast)
}
.review-form-bottom {
display: flex;
justify-content: space-between;
margin-top: 0.5em;
}
.review-form-top {
display: flex;
justify-content: space-between;
}
.review-form-rating {
}
.review-form .save {
display: block ruby;
}
.review-form .save-non-active {
display: block ruby;
}
.review-form textarea {
resize: unset;
}
.review-form-rating svg {
width: 2em;
height: 2em;
margin: 0;
padding: 0;
display: inline-block;
}

View file

@ -8,7 +8,7 @@
}
.fullscreenmessage-content .featureinfobox {
padding: 1em;
padding-top: 1em;
position: relative;
}
@ -34,6 +34,12 @@
}
.fullscreenmessage-content .featureinfobox-tail {
display: block;
height: 1em;
}
.to-the-map span {
font-size: xx-large;
}

View file

@ -10,10 +10,6 @@ Contains tweaks for small screens
@media only screen and (max-width: 600px), only screen and (max-height: 600px) {
.leaflet-control-attribution {
display: none;
}
.only-on-mobile {
display: unset;
background-color: var(--background-color);
@ -94,6 +90,11 @@ Contains tweaks for small screens
max-width: 100vw;
}
.userbadge-login {
min-width: unset;
width: calc(100vw - 5px);
}
#topleft-tools {
padding: 0.2em !important;
padding-top: 0.3em !important;
@ -102,4 +103,6 @@ Contains tweaks for small screens
#userbadge {
margin-bottom: 0.3em;
}
}
}

View file

@ -28,10 +28,11 @@
}
.featureinfobox-content {
display:block;
display: block;
max-height: 75vh;
overflow-y: auto;
overflow-x: hidden;
padding-top: 1em;
}
@media only screen and (max-width: 600px), only screen and (max-height: 600px) {
.featureinfobox-content {
@ -41,6 +42,37 @@
}
}
@media only screen and (max-height: 600px) and (min-width: 600px){
/* landscape mode: the first tagrendering of the infobox gets a special treatment and is placed on the right*/
.featureinfobox-content {
position: relative;
width: 100% !important;
max-width: unset !important;
max-height: unset !important;
height: 100vh;
}
.answer {
max-width: 48% !important;
padding-right: 0.3em;
box-sizing: border-box;
}
.question {
max-width: 48% !important;
padding-right: 0.3em;
box-sizing: border-box;
}
.first-rendering{
position: absolute;
left: 50%;
width: 94%;
padding-right: 0.3em;
box-sizing: border-box;
}
}
.answer {
display: flex;

View file

@ -91,7 +91,8 @@
</head>
<body>
<div id="maindiv">
'maindiv' not attached
Loading the MapComplete custom theme builder...<br/>
If this message persists, make sure javascript is enabled and no script blocker is blocking this.
</div>
<script src="./customGenerator.ts"></script>
</body>

View file

@ -1,6 +1,8 @@
:root {
--subtle-detail-color: #e5f5ff;
--subtle-detail-color-contrast: black;
--subtle-detail-color-light-contrast: lightgrey;
--catch-detail-color: #3a3aeb;
--catch-detail-color-contrast: white;
--alert-color: #fee4d1;
@ -96,6 +98,40 @@ a {
box-shadow: 0 0 10px var(--shadow-color);
}
.single-layer-selection-toggle{
position: relative;
width: 2em;
height: 2em;
}
.single-layer-selection-toggle img{
max-height: 2em !important;
max-width: 2em !important;
}
.single-layer-selection-toggle svg{
max-height:2em !important;
max-width: 2em !important;
}
.simple-add-ui-icon{
position: relative;
display: block;
width: 3.5em;
height: 3.5em;
padding-right: 0.3em;
padding-left: 0.3em;
}
.simple-add-ui-icon img{
max-height:3.5em !important;
max-width: 3.5em !important;
}
.simple-add-ui-icon svg{
max-height:3.5em !important;
max-width: 3.5em !important;
}
.layer-selection-toggle {
border-radius: 1em;
display: flex;
@ -521,16 +557,16 @@ a {
width: 1.5em;
padding: 0.5em;
padding-left: 0.4em;
fill: var(--subtle-detail-color-contrast);
stroke: var(--subtle-detail-color-contrast);
fill: var(--subtle-detail-color-contrast) !important;
stroke: var(--subtle-detail-color-contrast) !important;
}
.share-button svg path{
fill: var(--subtle-detail-color-contrast);
stroke: var(--subtle-detail-color-contrast);
fill: var(--subtle-detail-color-contrast) !important;
stroke: var(--subtle-detail-color-contrast) !important;
}
.share-button svg circle{
fill: var(--subtle-detail-color-contrast);
stroke: var(--subtle-detail-color-contrast);
fill: var(--subtle-detail-color-contrast) !important;
stroke: var(--subtle-detail-color-contrast) !important;
}

View file

@ -15,6 +15,7 @@
<link rel="stylesheet" href="./css/tagrendering.css"/>
<link rel="stylesheet" href="./css/imageUploadFlow.css"/>
<link rel="stylesheet" href="./css/fullscreenmessagebox.css"/>
<link href="css/ReviewElement.css" rel="stylesheet"/>
<!-- $$$CUSTOM-CSS -->
<link rel="manifest" href="./manifest.manifest">
<link rel="icon" href="assets/themes/climbing/climbing_no_rope.svg" sizes="any" type="image/svg+xml">

View file

@ -107,5 +107,7 @@ if (layoutFromBase64.startsWith("wiki:")) {
} else {
InitUiElements.InitAll(layoutToUse, layoutFromBase64, testing, defaultLayout);
}
window.addEventListener('contextmenu', function (e) { // Not compatible with IE < 9
e.preventDefault();
}, false);
// console.log(QueryParameters.GenerateQueryParameterDocs())

2921
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -4,14 +4,6 @@
"repository": "https://github.com/pietervdvn/MapComplete",
"description": "A small website to edit OSM easily",
"main": "index.js",
"staticFiles": {
"staticPath": [
{
"staticPath": "tiles/",
"staticOutDir": "tiles/"
}
]
},
"scripts": {
"start": "parcel *.html UI/** Logic/** assets/** assets/**/** assets/**/**/** vendor/* vendor/*/*",
"test": "ts-node test/*",
@ -20,11 +12,11 @@
"generate:translations": "ts-node scripts/generateTranslations.ts",
"generate:layouts": "ts-node scripts/createLayouts.ts",
"optimize-images": "cd assets/generated/ && find -name '*.png' -exec optipng '{}' \\; && echo 'PNGs are optimized'",
"generate": "npm run generate:images && npm run generate:translations && npm run generate:layouts && npm run generate:editor-layer-index",
"generate": "npm run generate:images && npm run generate:translations",
"build": "rm -rf dist/ && npm run generate && parcel build --public-url ./ *.html assets/** assets/**/** assets/**/**/** vendor/* vendor/*/*",
"prepare-deploy": "npm run generate && npm run build && rm -rf .cache",
"deploy:staging": "npm run prepare-deploy && rm -rf /home/pietervdvn/git/pietervdvn.github.io/Staging/* && cp -r dist/* /home/pietervdvn/git/pietervdvn.github.io/Staging/ && cd /home/pietervdvn/git/pietervdvn.github.io/ && git add * && git commit -m 'New MapComplete Version' && git push && cd - && npm run clean",
"deploy:production": "rm -rf ./assets/generated && npm run prepare-deploy && npm run optimize-images && rm -rf /home/pietervdvn/git/pietervdvn.github.io/MapComplete/* && cp -r dist/* /home/pietervdvn/git/pietervdvn.github.io/MapComplete/ && cd /home/pietervdvn/git/pietervdvn.github.io/ && git add * && git commit -m 'New MapComplete Version' && git push && cd - && npm run clean",
"prepare-deploy": "npm run generate:editor-layer-index && npm run generate:layouts && npm run generate && npm run build && rm -rf .cache",
"deploy:staging": "npm run prepare-deploy && rm -rf /home/pietervdvn/git/pietervdvn.github.io/MapComplete/* && cp -r dist/* /home/pietervdvn/git/pietervdvn.github.io/MapComplete/ && cd /home/pietervdvn/git/pietervdvn.github.io/ && git add * && git commit -m 'New MapComplete Version' && git push && cd - && npm run clean",
"deploy:production": "rm -rf ./assets/generated && npm run prepare-deploy && npm run optimize-images && rm -rf /home/pietervdvn/git/mapcomplete.github.io/* && cp -r dist/* /home/pietervdvn/git/mapcomplete.github.io/ && cd /home/pietervdvn/git/mapcomplete.github.io/ && echo \"mapcomplete.osm.be\" > CNAME && git add * && git commit -m 'New MapComplete Version' && git push && cd - && npm run clean",
"clean": "rm -rf .cache/ && (find *.html | grep -v \"\\(index\\|land\\|test\\|preferences\\|customGenerator\\).html\" | xargs rm) && (find *.webmanifest | xargs rm)"
},
"keywords": [
@ -35,16 +27,17 @@
"license": "MIT",
"dependencies": {
"@types/leaflet-providers": "^1.2.0",
"codegrid-js": "git://github.com/hlaw/codegrid-js.git",
"country-language": "^0.1.7",
"email-validator": "^2.0.4",
"escape-html": "^1.0.3",
"i18next-client": "^1.11.4",
"jquery": "latest",
"latlon2country": "^1.0.8",
"leaflet": "^1.7.1",
"leaflet-providers": "^1.10.2",
"libphonenumber": "0.0.10",
"libphonenumber-js": "^1.7.55",
"mangrove-reviews": "^0.1.3",
"moment": "^2.29.0",
"opening_hours": "^3.5.0",
"osm-auth": "^1.0.2",
@ -59,7 +52,6 @@
"canvas": "^2.6.1",
"fs": "0.0.1-security",
"marked": "^1.1.1",
"parcel-plugin-static-files-copy": "^2.4.3",
"promise-svg2img": "^0.2.0",
"read-file": "^0.2.0",
"ts-node": "^9.0.0",

View file

@ -270,7 +270,7 @@ for (const layoutName in all) {
};
const layout = all[layoutName];
validate(layout)
const manif = JSON.stringify(createManifest(layout, "/MapComplete"));
const manif = JSON.stringify(createManifest(layout, ""));
const manifestLocation = encodeURIComponent(layout.id.toLowerCase()) + ".webmanifest";
writeFile(manifestLocation, manif, err);
@ -281,7 +281,7 @@ for (const layoutName in all) {
wikiPage += "\n"+generateWikiEntry(layout);
}
wikiPage += "|}"
wikiPage += "\n|}"
writeFile(generatedDir + "/wikiIndex", wikiPage, (err) => {
if (err !== null) {

View file

@ -7,28 +7,12 @@
<link href="css/tabbedComponent.css" rel="stylesheet"/>
<link href="css/openinghourstable.css" rel="stylesheet"/>
<link href="css/tagrendering.css" rel="stylesheet"/>
<link href="css/ReviewElement.css" rel="stylesheet"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<style>
.tag-input-row {
display: block ruby;
box-sizing: border-box;
margin-right: 2em;
width: 100%;
}
.bordered {
border: 1px solid black;
display: block;
padding: 0.5em;
border-radius: 0.5em;
}
</style>
</head>
<body>
<div class="question">
<div id="maindiv">'maindiv' not attached</div>
</div>
<div id="extradiv">'extradiv' not attached</div>
<script src="./test.ts"></script>
</body>

58
test.ts
View file

@ -1,20 +1,54 @@
//*
import Direction from "./UI/Input/DirectionInput";
import MangroveReviews from "./Logic/Web/MangroveReviews";
import ReviewElement from "./UI/Reviews/ReviewElement";
import {UIEventSource} from "./Logic/UIEventSource";
import {VariableUiElement} from "./UI/Base/VariableUIElement";
import ReviewForm from "./UI/Reviews/ReviewForm";
import Combine from "./UI/Base/Combine";
import {FixedUiElement} from "./UI/Base/FixedUiElement";
const d = new UIEventSource("90");
new Direction(d).AttachTo("maindiv")
new VariableUiElement(d.map(d => "" + d + "°")).AttachTo("extradiv")
const identity = '{"crv":"P-256","d":"6NHPmTFRedjNl-ZfLRAXhOaNKtRR9GYzPHsO1CzN5wQ","ext":true,"key_ops":["sign"],"kty":"EC","x":"Thm_pL5m0m9Jl41z9vgMTHNyja-9H58v0stJWT4KhTI","y":"PjBldCW85b8K6jEZbw0c2UZskpo-rrkwfPnD7s1MXSM","metadata":"Mangrove private key"}'
UIEventSource.Chronic(25, () => {
const degr = (Number(d.data) + 1) % 360;
d.setData(""+ degr);
return true;
})
const mangroveReviews = new MangroveReviews(0, 0, "Null Island",
new UIEventSource<string>(identity), true)
new ReviewElement(mangroveReviews.GetSubjectUri(), mangroveReviews.GetReviews()).AttachTo("maindiv");
const form = new ReviewForm((r,done) => {
mangroveReviews.AddReview(r, done);
});
form.AttachTo("extradiv")
form.GetValue().map(r => form.IsValid(r)).addCallback(d => console.log(d))
/*
window.setTimeout(
() => {
mangroveReviews.AddReview({
comment: "These are liars - not even an island here!",
author: "Lost Tourist",
date: new Date(),
affiliated: false,
rating: 10
}, (() => {alert("Review added");return undefined;}));
}, 1000
)
window.setTimeout(
() => {
mangroveReviews.AddReview({
comment: "Excellent conditions to measure weather!!",
author: "Weather-Boy",
date: new Date(),
affiliated: true,
rating: 90
}, (() => {
alert("Review added");
return undefined;
}));
}, 1000
)
*/
/*/

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1 +0,0 @@
{"9":{"5":{"256":{"keys":[1,""],"grid":[" #!/","!","!","!","!","!","!","!","!","!","!","!","!","!","!","!"]}},"4":{"256":{"keys":["",1],"grid":[" /!#"," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "]}}},"13":{"80":{"4096":{"keys":[4,3,""],"grid":[" "," "," "," /!#","!,#&","#","#","#","#","#","#","#","#","#","#","#"]}},"81":{"4096":{"keys":[4,3,""],"grid":[" ,!##$"," )!##'"," %!##+","!##/","#","#","#","#","#","#","#","#","#","#","#","#"]}},"79":{"4096":{"keys":[4,3,""],"grid":[" "," ","!! 0","#$!% *","#,!&","#","#","#","#","#","#","#","#","#","#","#"]}},"78":{"4096":{"keys":["",3,4],"grid":[" )!##'"," ,!##$"," 0!!"," "," "," "," "," "," "," "," "," "," "," "," "," "]}}}}

View file

@ -1 +0,0 @@
{"9":{"12":{"276":{"keys":[6,"",5],"grid":[" !!!","!","!!!#","!"]}}}}

View file

@ -1 +0,0 @@
{"9":{"15":{"129":{"keys":[2,"",3,1],"grid":[" -!%","00","00","00","00","00","00","00","00","00","00","00"," -#%"," ,$!#%","13","13"]},"131":{"keys":[2,1,3,""],"grid":[" +!!#&","00"," *!##&"," *!!#'","03","03","03","03","$% &!!#'","08","$% %$##'","$% %$%#%","$","$","$","$"]},"130":{"keys":[2,1,3],"grid":[" +!##%"," +!!#&","01","01","01","01","01","01","01","01","01","01","01","01","01","01"]}}},"13":{"250":{"2088":{"keys":[2,3],"grid":[" *!(","00","00","00","00","00","00","00","00","00","00","00","00","00","00","00"]},"2089":{"keys":[2,3],"grid":[" *!("," )!)","01","01","01","01","01","01","01","01","01","01","01","01","01","01"]},"2082":{"keys":[2,3],"grid":[" 0!!","00","00","00"," /!#","04","04","04","04","04","04","04","04","04","04","04"]},"2083":{"keys":[2,3],"grid":[" /!#","00","00","00","00","00"," .!$","06","06","06","06","06","06","06","06","06"]},"2080":{"keys":[2],"grid":[" "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "]},"2081":{"keys":[2,3],"grid":[" "," "," 0!!","02","02","02","02","02","02","02","02","02","02","02","02","02"]},"2086":{"keys":[2,3],"grid":[" ,!&","00","00","00","00","00","00","00","00","00","00","00"," +!'","12","12","12"]},"2087":{"keys":[2,3],"grid":[" +!'","00","00","00","00","00","00","00","00","00","00","00","00","00","00"," *!("]},"2084":{"keys":[2,3],"grid":[" .!$","00","00","00","00","00","00","00"," -!%","08","08","08","08","08","08","08"]},"2085":{"keys":[2,3],"grid":[" -!%","00","00","00","00","00","00","00","00","00"," ,!&","10","10","10","10","10"]},"2095":{"keys":[2,3],"grid":[" $!.","00","00","00","00","00","00","00","00","00","00","00","00"," #!/","13","13"]},"2094":{"keys":[2,3],"grid":[" %!-","00","00","00","00","00","00","00","00","00","00"," $!.","11","11","11","11"]},"2097":{"keys":[2,3],"grid":[" !!0","00","00","00","00","00","00","00","00","00","00","00","00","00","00","00"]},"2096":{"keys":[2,3],"grid":[" #!/","00","00","00","00","00","00","00","00","00","00","00","00","00","00"," !!0"]},"2091":{"keys":[2,3],"grid":[" (!*","00","00","00","00"," '!+","05","05","05","05","05","05","05","05","05","05"]},"2090":{"keys":[2,3],"grid":[" )!)","00","00"," (!*","03","03","03","03","03","03","03","03","03","03","03","03"]},"2093":{"keys":[2,3],"grid":[" &!,","00","00","00","00","00","00","00","00"," %!-","09","09","09","09","09","09"]},"2092":{"keys":[2,3],"grid":[" '!+","00","00","00","00","00","00"," &!,","07","07","07","07","07","07","07","07"]},"2098":{"keys":[2,3],"grid":[" !!0","!","!","!","!","!","!","!","!","!","!","!","!","!","!","!"]}},"251":{"2080":{"keys":[3],"grid":[" "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "]},"2078":{"keys":[2,3],"grid":[" #!/","00","00","00","00","00","00","00","00","00","00","00","00"," !!0","13","13"]},"2077":{"keys":[2,"",3],"grid":[" %!-","00","00","00","00","00","00","00","00","00","00","00"," $!!#-","12"," ##/","14"]},"2079":{"keys":[2,3],"grid":[" !!0","00","00","00","00","00","00","00","00","00","00","00","00","00","00","!"]}},"249":{"2103":{"keys":[2,3],"grid":[" -!%","00","00","00","00","00","00","00","00","00","00"," ,!&","11","11","11","11"]},"2102":{"keys":[2,3],"grid":[" .!$","00","00","00","00","00","00","00","00"," -!%","09","09","09","09","09","09"]},"2101":{"keys":[2,3],"grid":[" /!#","00","00","00","00","00","00"," .!$","07","07","07","07","07","07","07","07"]},"2100":{"keys":[2,3],"grid":[" 0!!","00","00","00","00"," /!#","05","05","05","05","05","05","05","05","05","05"]},"2099":{"keys":[2,3],"grid":[" "," "," "," 0!!","03","03","03","03","03","03","03","03","03","03","03","03"]},"2098":{"keys":[2],"grid":[" "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "]},"2105":{"keys":[2,3,""],"grid":[" +!'","00","00","00","#% '!'","04","04","04","#*!(","#,!&","#-!%","10","10","10","10","10"]},"2104":{"keys":[2,3],"grid":[" ,!&","00","00","00","00","00","00","00","00","00","00","00","00"," +!'","13","13"]}}}}

Some files were not shown because too many files have changed in this diff Show more