Merge branch 'master' into master

This commit is contained in:
ToastHawaii 2020-09-17 22:23:27 +02:00 committed by GitHub
commit 9bd7da1b7c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
76 changed files with 1624 additions and 1289 deletions

View file

@ -1,10 +1,7 @@
import {LayerDefinition} from "./LayerDefinition"; import {LayerDefinition} from "./LayerDefinition";
import {Layout} from "./Layout"; import {Layout} from "./Layout";
import {Groen} from "./Layouts/Groen";
import Cyclofix from "./Layouts/Cyclofix";
import {StreetWidth} from "./Layouts/StreetWidth"; import {StreetWidth} from "./Layouts/StreetWidth";
import {MetaMap} from "./Layouts/MetaMap"; import {MetaMap} from "./Layouts/MetaMap";
import {Natuurpunt} from "./Layouts/Natuurpunt";
import {FromJSON} from "./JSON/FromJSON"; import {FromJSON} from "./JSON/FromJSON";
import * as bookcases from "../assets/themes/bookcases/Bookcases.json"; import * as bookcases from "../assets/themes/bookcases/Bookcases.json";
import * as aed from "../assets/themes/aed/aed.json"; import * as aed from "../assets/themes/aed/aed.json";
@ -12,29 +9,55 @@ import * as toilets from "../assets/themes/toilets/toilets.json";
import * as artworks from "../assets/themes/artwork/artwork.json"; import * as artworks from "../assets/themes/artwork/artwork.json";
import * as cyclestreets from "../assets/themes/cyclestreets/cyclestreets.json"; import * as cyclestreets from "../assets/themes/cyclestreets/cyclestreets.json";
import * as ghostbikes from "../assets/themes/ghostbikes/ghostbikes.json" import * as ghostbikes from "../assets/themes/ghostbikes/ghostbikes.json"
import * as cyclofix from "../assets/themes/cyclofix/cyclofix.json"
import * as buurtnatuur from "../assets/themes/buurtnatuur/buurtnatuur.json"
import {PersonalLayout} from "../Logic/PersonalLayout"; import {PersonalLayout} from "../Logic/PersonalLayout";
export class AllKnownLayouts { export class AllKnownLayouts {
public static allLayers: Map<string, LayerDefinition> = undefined; public static allLayers: Map<string, LayerDefinition> = undefined;
private static GenerateCycloFix(): Layout {
const layout = FromJSON.LayoutFromJSON(cyclofix)
const now = new Date();
const m = now.getMonth() + 1;
const day = new Date().getDay() + 1;
const date = day + "/" + m;
if (date === "31/10" || date === "1/11" || date === "2/11") {
// Around Halloween/Fiesta de muerte/Allerzielen, we remember the dead
layout.layers.push(
FromJSON.sharedLayers.get("ghost_bike")
);
}
return layout;
}
private static GenerateBuurtNatuur(): Layout {
const layout = FromJSON.LayoutFromJSON(buurtnatuur);
layout.enableMoreQuests = false;
layout.enableShareScreen = false;
return layout;
}
public static layoutsList: Layout[] = [ public static layoutsList: Layout[] = [
new PersonalLayout(), new PersonalLayout(),
new Natuurpunt(), // new Natuurpunt(),
new Cyclofix(), AllKnownLayouts.GenerateBuurtNatuur(),
FromJSON.LayoutFromJSON(bookcases), FromJSON.LayoutFromJSON(bookcases),
FromJSON.LayoutFromJSON(aed), FromJSON.LayoutFromJSON(aed),
FromJSON.LayoutFromJSON(toilets), FromJSON.LayoutFromJSON(toilets),
FromJSON.LayoutFromJSON(artworks), FromJSON.LayoutFromJSON(artworks),
FromJSON.LayoutFromJSON(cyclestreets), FromJSON.LayoutFromJSON(cyclestreets),
FromJSON.LayoutFromJSON(ghostbikes), FromJSON.LayoutFromJSON(ghostbikes),
AllKnownLayouts.GenerateCycloFix(),
new MetaMap(), new MetaMap(),
new StreetWidth(), new StreetWidth(),
new Groen(),
]; ];
public static allSets: Map<string, Layout> = AllKnownLayouts.AllLayouts(); public static allSets: Map<string, Layout> = AllKnownLayouts.AllLayouts();
@ -51,7 +74,6 @@ export class AllKnownLayouts {
} }
} }
if (this.allLayers[layer.id] !== undefined) { if (this.allLayers[layer.id] !== undefined) {
continue; continue;
} }

View file

@ -18,7 +18,7 @@ import * as birdhides from "../../assets/layers/bird_hide/birdhides.json"
import * as nature_reserve from "../../assets/layers/nature_reserve/nature_reserve.json" import * as nature_reserve from "../../assets/layers/nature_reserve/nature_reserve.json"
import * as bike_cafes from "../../assets/layers/bike_cafe/bike_cafes.json" import * as bike_cafes from "../../assets/layers/bike_cafe/bike_cafes.json"
import * as cycling_themed_objects from "../../assets/layers/cycling_themed_object/cycling_themed_objects.json" import * as cycling_themed_objects from "../../assets/layers/cycling_themed_object/cycling_themed_objects.json"
import * as bike_shops from "../../assets/layers/bike_shop/bike_shop.json"
import {Utils} from "../../Utils"; import {Utils} from "../../Utils";
import ImageCarouselWithUploadConstructor from "../../UI/Image/ImageCarouselWithUpload"; import ImageCarouselWithUploadConstructor from "../../UI/Image/ImageCarouselWithUpload";
import {ImageCarouselConstructor} from "../../UI/Image/ImageCarousel"; import {ImageCarouselConstructor} from "../../UI/Image/ImageCarousel";
@ -44,7 +44,8 @@ export class FromJSON {
FromJSON.Layer(birdhides), FromJSON.Layer(birdhides),
FromJSON.Layer(nature_reserve), FromJSON.Layer(nature_reserve),
FromJSON.Layer(bike_cafes), FromJSON.Layer(bike_cafes),
FromJSON.Layer(cycling_themed_objects) FromJSON.Layer(cycling_themed_objects),
FromJSON.Layer(bike_shops)
]; ];
for (const layer of sharedLayersList) { for (const layer of sharedLayersList) {
@ -77,6 +78,10 @@ export class FromJSON {
json.startLat, json.startLat,
json.startLon, json.startLon,
new Combine(["<h3>", tr(json.title), "</h3>", tr(json.description)]), new Combine(["<h3>", tr(json.title), "</h3>", tr(json.description)]),
undefined,
undefined,
tr(json.descriptionTail)
); );
layout.widenFactor = json.widenFactor ?? 0.07; layout.widenFactor = json.widenFactor ?? 0.07;
@ -84,6 +89,7 @@ export class FromJSON {
layout.maintainer = json.maintainer; layout.maintainer = json.maintainer;
layout.version = json.version; layout.version = json.version;
layout.socialImage = json.socialImage; layout.socialImage = json.socialImage;
layout.description = tr(json.shortDescription) ?? tr(json.description)?.FirstSentence();
layout.changesetMessage = json.changesetmessage; layout.changesetMessage = json.changesetmessage;
return layout; return layout;
} }

View file

@ -37,11 +37,21 @@ export interface LayoutConfigJson {
* The title, as shown in the welcome message and the more-screen * The title, as shown in the welcome message and the more-screen
*/ */
title: string | any; title: string | any;
/**
* A short description, showed as social description and in the 'more theme'-buttons
*/
shortDescription?: string | any;
/** /**
* The description, as shown in the welcome message and the more-screen * The description, as shown in the welcome message and the more-screen
*/ */
description: string | any; description: string | any;
/**
* A part of the description, shown under the login-button.
*/
descriptionTail?: string | any;
/** /**
* The icon representing this theme. * The icon representing this theme.

View file

@ -1,94 +0,0 @@
import {LayerDefinition} from "../LayerDefinition";
import Translations from "../../UI/i18n/Translations";
import {And, RegexTag, Tag} from "../../Logic/Tags";
import ImageCarouselWithUploadConstructor from "../../UI/Image/ImageCarouselWithUpload";
import ShopRetail from "../Questions/bike/ShopRetail";
import ShopPump from "../Questions/bike/ShopPump";
import ShopRental from "../Questions/bike/ShopRental";
import ShopRepair from "../Questions/bike/ShopRepair";
import ShopDiy from "../Questions/bike/ShopDiy";
import ShopName from "../Questions/bike/ShopName";
import ShopSecondHand from "../Questions/bike/ShopSecondHand";
import {PhoneNumberQuestion} from "../Questions/PhoneNumberQuestion";
import Website from "../Questions/Website";
import {TagRenderingOptions} from "../TagRenderingOptions";
export default class BikeOtherShops extends LayerDefinition {
private readonly sellsBikes = new Tag("service:bicycle:retail", "yes")
private readonly to = Translations.t.cyclofix.nonBikeShop
constructor() {
super("bikeOtherShop");
this.name = this.to.name
this.icon = "./assets/bike/non_bike_repair_shop.svg"
this.overpassFilter = new And([
new RegexTag("shop", /^bicycle$/, true),
new RegexTag(/^service:bicycle:/, /.*/),
])
this.presets = []
this.maxAllowedOverlapPercentage = 10
this.wayHandling = LayerDefinition.WAYHANDLING_CENTER_AND_WAY
this.minzoom = 13;
this.style = this.generateStyleFunction();
this.title = new TagRenderingOptions({
mappings: [
{
k: new And([new Tag("name", "*"), this.sellsBikes]),
txt: this.to.titleShopNamed
},
{
k: new And([new Tag("name", "*"), new Tag("service:bicycle:retail", "")]),
txt: this.to.titleShop
},
{
k: new And([new Tag("name", "*"), new Tag("service:bicycle:retail", "no")]),
txt: this.to.titleRepairNamed
},
{k: this.sellsBikes, txt: this.to.titleShop},
{k: new Tag("service:bicycle:retail", " "), txt: this.to.title},
{k: new Tag("service:bicycle:retail", "no"), txt: this.to.titleRepair},
{
k: new And([new Tag("name", "*")]),
txt: this.to.titleNamed
},
{k: null, txt: this.to.title},
]
})
this.elementsToShow = [
new ImageCarouselWithUploadConstructor(),
new ShopName(),
new PhoneNumberQuestion("{name}"),
new Website("{name}"),
new ShopRetail(),
new ShopRental(),
new ShopRepair(),
new ShopPump(),
new ShopDiy(),
new ShopSecondHand()
]
}
private generateStyleFunction() {
const self = this;
return function (tags: any) {
let icon = "assets/bike/non_bike_repair_shop.svg";
if (self.sellsBikes.matchesProperties(tags)) {
icon = "assets/bike/non_bike_shop.svg";
}
return {
color: "#00bb00",
icon: {
iconUrl: icon,
iconSize: [50, 50],
iconAnchor: [25, 50]
}
}
}
}
}

View file

@ -1,88 +0,0 @@
import {LayerDefinition} from "../LayerDefinition";
import Translations from "../../UI/i18n/Translations";
import {And, Tag} from "../../Logic/Tags";
import ImageCarouselWithUploadConstructor from "../../UI/Image/ImageCarouselWithUpload";
import ShopRetail from "../Questions/bike/ShopRetail";
import ShopPump from "../Questions/bike/ShopPump";
import ShopRental from "../Questions/bike/ShopRental";
import ShopRepair from "../Questions/bike/ShopRepair";
import ShopDiy from "../Questions/bike/ShopDiy";
import ShopName from "../Questions/bike/ShopName";
import ShopSecondHand from "../Questions/bike/ShopSecondHand";
import {PhoneNumberQuestion} from "../Questions/PhoneNumberQuestion";
import Website from "../Questions/Website";
import {EmailQuestion} from "../Questions/EmailQuestion";
import {TagRenderingOptions} from "../TagRenderingOptions";
export default class BikeShops extends LayerDefinition {
private readonly sellsBikes = new Tag("service:bicycle:retail", "yes")
constructor() {
super("bikeshop");
this.name = Translations.t.cyclofix.shop.name
this.icon = "./assets/bike/repair_shop.svg"
this.overpassFilter = new Tag("shop", "bicycle");
this.presets = [{
title: Translations.t.cyclofix.shop.title,
tags: [
new Tag("shop", "bicycle"),
]
}]
this.maxAllowedOverlapPercentage = 10
this.wayHandling = LayerDefinition.WAYHANDLING_CENTER_AND_WAY
this.minzoom = 13;
this.style = this.generateStyleFunction();
this.title = new TagRenderingOptions({
mappings: [
{k: new And([new Tag("name", "*"), this.sellsBikes]), txt: Translations.t.cyclofix.shop.titleShopNamed},
{
k: new And([new Tag("name", "*"), new Tag("service:bicycle:retail", "")]),
txt: Translations.t.cyclofix.shop.titleShop
},
{
k: new And([new Tag("name", "*"), new Tag("service:bicycle:retail", "no")]),
txt: Translations.t.cyclofix.shop.titleRepairNamed
},
{k: this.sellsBikes, txt: Translations.t.cyclofix.shop.titleShop},
{k: new Tag("service:bicycle:retail", " "), txt: Translations.t.cyclofix.shop.title},
{k: new Tag("service:bicycle:retail", "no"), txt: Translations.t.cyclofix.shop.titleRepair},
]
})
this.elementsToShow = [
new ImageCarouselWithUploadConstructor(),
new ShopName(),
new Website("{name}"),
new PhoneNumberQuestion("{name}"),
new EmailQuestion("{name}"),
new ShopRetail(),
new ShopRental(),
new ShopRepair(),
new ShopPump(),
new ShopDiy(),
new ShopSecondHand()
]
}
private generateStyleFunction() {
const self = this;
return function (tags: any) {
let icon = "assets/bike/repair_shop.svg";
if (self.sellsBikes.matchesProperties(tags)) {
icon = "assets/bike/shop.svg";
}
return {
color: "#00bb00",
icon: {
iconUrl: icon,
iconSize: [50, 50],
iconAnchor: [25, 50]
}
}
}
}
}

View file

@ -1,84 +0,0 @@
import {LayerDefinition} from "../LayerDefinition";
import {Or, Tag} from "../../Logic/Tags";
import {AccessTag} from "../Questions/AccessTag";
import {OperatorTag} from "../Questions/OperatorTag";
import {NameQuestion} from "../Questions/NameQuestion";
import {NameInline} from "../Questions/NameInline";
import {DescriptionQuestion} from "../Questions/DescriptionQuestion";
import ImageCarouselWithUploadConstructor from "../../UI/Image/ImageCarouselWithUpload";
export class Bos extends LayerDefinition {
constructor() {
super("bos");
this.name = "Bos";
this.icon = "";
this.overpassFilter = new Or([
new Tag("natural", "wood"),
new Tag("landuse", "forest"),
new Tag("natural", "scrub")
]
);
this.presets = [{
title: "Bos",
description: "Voeg een ontbrekend bos toe aan de kaart",
icon: undefined,
tags: [
new Tag("landuse", "forest"),
new Tag("fixme", "Toegevoegd met MapComplete, geometry nog uit te tekenen")
]
}];
this.maxAllowedOverlapPercentage = 10;
this.minzoom = 13;
this.style = this.generateStyleFunction();
this.title = new NameInline("Bos");
this.elementsToShow = [
new ImageCarouselWithUploadConstructor(),
new NameQuestion(),
new AccessTag(),
new OperatorTag(),
new DescriptionQuestion("bos")
];
}
private generateStyleFunction() {
const self = this;
return function (properties: any) {
let questionSeverity = 0;
for (const qd of self.elementsToShow) {
if(qd instanceof DescriptionQuestion){
continue;
}
if (qd.IsQuestioning(properties)) {
questionSeverity = Math.max(questionSeverity, qd.Priority());
}
}
let colormapping = {
0: "#00bb00",
1: "#00ff00",
10: "#dddd00",
20: "#ff0000"
};
let colour = colormapping[questionSeverity];
while (colour == undefined) {
questionSeverity--;
colour = colormapping[questionSeverity];
}
return {
color: colour,
icon: undefined
};
};
}
}

View file

@ -1,11 +1,6 @@
import {LayerDefinition} from "../LayerDefinition"; import {LayerDefinition} from "../LayerDefinition";
import {Or, Tag} from "../../Logic/Tags"; import {Or, Tag} from "../../Logic/Tags";
import {AccessTag} from "../Questions/AccessTag";
import {OperatorTag} from "../Questions/OperatorTag";
import {NameQuestion} from "../Questions/NameQuestion";
import {NameInline} from "../Questions/NameInline"; import {NameInline} from "../Questions/NameInline";
import {DescriptionQuestion} from "../Questions/DescriptionQuestion";
import ImageCarouselWithUploadConstructor from "../../UI/Image/ImageCarouselWithUpload";
import {TagRenderingOptions} from "../TagRenderingOptions"; import {TagRenderingOptions} from "../TagRenderingOptions";
export class NatureReserves extends LayerDefinition { export class NatureReserves extends LayerDefinition {
@ -27,13 +22,13 @@ export class NatureReserves extends LayerDefinition {
]; ];
this.minzoom = 13; this.minzoom = 13;
this.title = new NameInline("Natuurreservaat"); this.title = new NameInline("Natuurreservaat");
this.style = this.generateStyleFunction(); this.style = function () {
return {
color: "#00bb00",
icon: undefined
};
};
this.elementsToShow = [ this.elementsToShow = [
new ImageCarouselWithUploadConstructor(),
new NameQuestion(),
new AccessTag(),
new OperatorTag(),
new DescriptionQuestion("natuurgebied")
]; ];
@ -97,38 +92,4 @@ export class NatureReserves extends LayerDefinition {
} }
private generateStyleFunction() {
const self = this;
return function (properties: any) {
let questionSeverity = 0;
for (const qd of self.elementsToShow) {
//if(qd instanceof DescriptionQuestion){
// continue;
//}
if (qd.IsQuestioning(properties)) {
questionSeverity = Math.max(questionSeverity, qd.Priority() ?? 0);
}
}
let colormapping = {
0: "#00bb00",
10: "#dddd00",
20: "#ff0000"
};
let colour = colormapping[questionSeverity];
while (colour == undefined) {
questionSeverity--;
colour = colormapping[questionSeverity];
}
return {
color: colour,
icon: undefined
};
};
}
} }

View file

@ -1,110 +0,0 @@
import {LayerDefinition} from "../LayerDefinition";
import {Or, Tag} from "../../Logic/Tags";
import {NameQuestion} from "../Questions/NameQuestion";
import {NameInline} from "../Questions/NameInline";
import {DescriptionQuestion} from "../Questions/DescriptionQuestion";
import ImageCarouselWithUploadConstructor from "../../UI/Image/ImageCarouselWithUpload";
import {TagRenderingOptions} from "../TagRenderingOptions";
export class Park extends LayerDefinition {
private accessByDefault = new TagRenderingOptions({
question: "Is dit park publiek toegankelijk?",
mappings: [
{k: new Tag("access", "yes"), txt: "Publiek toegankelijk"},
{k: new Tag("access", ""), txt: "Publiek toegankelijk", hideInAnswer: true},
{k: new Tag("access", "no"), txt: "Niet publiek toegankelijk"},
{k: new Tag("access", "private"), txt: "Niet publiek toegankelijk, want privaat"},
{k: new Tag("access", "guided"), txt: "Enkel toegankelijk met een gids of op een activiteit"},
],
freeform: {
key: "access",
renderTemplate: "Dit park is niet toegankelijk: {access}",
template: "De toegankelijkheid van dit park is: $$$"
},
priority: 20
})
private operatorByDefault = new
TagRenderingOptions({
question: "Wie beheert dit park?",
freeform: {
key: "operator",
renderTemplate: "Dit park wordt beheerd door {operator}",
template: "$$$",
},
mappings: [{
k: null, txt: "De gemeente beheert dit park"
}],
priority: 15
});
constructor() {
super("park");
this.name = "Park";
this.icon = undefined;
this.overpassFilter =
new Or([new Tag("leisure", "park"), new Tag("landuse", "village_green")]);
this.presets = [{
title: "Park",
description: "Voeg een ontbrekend park toe. Een park is een groene ruimte die openbaar is." +
"Typisch vind je er banken, vuilbakken, standbeelden, ... ",
tags: [new Tag("leisure", "park"),
new Tag("fixme", "Toegevoegd met MapComplete, geometry nog uit te tekenen")]
}];
this.maxAllowedOverlapPercentage = 25;
this.minzoom = 13;
this.style = this.generateStyleFunction();
this.title = new NameInline("Park");
this.elementsToShow = [
new ImageCarouselWithUploadConstructor(),
new NameQuestion(),
this.accessByDefault,
this.operatorByDefault,
new DescriptionQuestion("park"),
];
}
private generateStyleFunction() {
const self = this;
return function (properties: any) {
let questionSeverity = 0;
for (const qd of self.elementsToShow) {
if (qd instanceof DescriptionQuestion) {
continue;
}
if (qd.IsQuestioning(properties)) {
questionSeverity = Math.max(questionSeverity, qd.Priority() ?? 0);
}
}
let colormapping = {
0: "#00bb00",
1: "#00ff00",
10: "#dddd00",
20: "#ff0000"
};
let colour = colormapping[questionSeverity];
while (colour == undefined) {
questionSeverity--;
colour = colormapping[questionSeverity];
}
return {
color: colour,
icon: undefined
};
};
}
}

View file

@ -1,42 +0,0 @@
import {Layout} from "../Layout";
import BikeShops from "../Layers/BikeShops";
import Translations from "../../UI/i18n/Translations";
import Combine from "../../UI/Base/Combine";
import BikeOtherShops from "../Layers/BikeOtherShops";
export default class Cyclofix extends Layout {
private static RememberTheDead(): boolean {
const now = new Date();
const m = now.getMonth() + 1;
const day = new Date().getDay() + 1;
const date = day + "/" + m;
return (date === "31/10" || date === "1/11" || date === "2/11");
}
constructor() {
super(
"cyclofix",
["en", "nl", "fr", "gl","de"],
Translations.t.cyclofix.title,
["bike_repair_station", "bike_cafes", new BikeShops(), "drinking_water", "bike_parking", new BikeOtherShops(),"bike_themed_object",
// The first of november, halloween and the second of november, we remember our dead
...(Cyclofix.RememberTheDead() ? ["ghost_bike"] : [])],
16,
50.8465573,
4.3516970,
new Combine([
"<h3>",
Translations.t.cyclofix.title,
"</h3><br/><p>",
Translations.t.cyclofix.description,
"</p>"
])
);
this.icon = "./assets/bike/logo.svg"
this.description = "Easily search and contribute bicycle data nearby";
this.socialImage = "./assets/bike/cyclofix.jpeg";
this.widenFactor = 0.05;
}
}

View file

@ -1,23 +0,0 @@
import {Layout} from "../Layout";
import {GrbToFix} from "../Layers/GrbToFix";
export class GRB extends Layout {
constructor() {
super("grb",
["en"],
"Grb import fix tool",
[new GrbToFix()],
15,
51.2083,
3.2279,
"<h3>GRB Fix tool</h3>\n" +
"\n" +
"Expert use only"
,
"", "");
this.hideFromOverview = true;
}
}

View file

@ -1,61 +0,0 @@
import {Park} from "../Layers/Park";
import {Bos} from "../Layers/Bos";
import {Layout} from "../Layout";
import {NatureReserves} from "../Layers/NatureReserves";
export class Groen extends Layout {
constructor() {
super("buurtnatuur",
["nl"],
"Buurtnatuur.be",
[new NatureReserves(), new Park(), new Bos(), "viewpoint"],
10,
50.8435,
4.3688,
"\n" +
"<img style='float:right;margin: 1em;width: 10em;height: auto;' src='./assets/themes/buurtnatuur/groen_logo.svg' alt='logo-groen' class='logo'> <br />" +
"<h3>Breng jouw buurtnatuur in kaart</h3>" +
"<b>Natuur maakt gelukkig.</b> Aan de hand van deze website willen we de natuur dicht bij ons beter inventariseren. Met als doel meer mensen te laten genieten van toegankelijke natuur én te strijden voor meer natuur in onze buurten. \n" +
"<ul>" +
"<li>In welke natuurgebieden kan jij terecht? Hoe toegankelijk zijn ze?</li>" +
"<li>In welke bossen kan een gezin in jouw gemeente opnieuw op adem komen?</li>" +
"<li>Op welke onbekende plekjes is het zalig spelen?</li>" +
"</ul>" +
"<p>Samen kleuren we heel Vlaanderen en Brussel groen.</p>" +
"<p>Blijf op de hoogte van de resultaten van buurtnatuur.be: <a href=\"https://www.groen.be/buurtnatuur\" target='_blank'>meld je aan voor e-mailupdates</a>.</p> \n"
,
"<b>Begin meteen door <a href=\"https://www.openstreetmap.org/user/new\" target=\"_blank\">een account te maken\n" +
" te maken</a> of\n" +
" <span onclick=\"authOsm()\" class=\"activate-osm-authentication\">in te loggen</span>.</b>",
"",
"<h4>Tips</h4>" +
"<ul>" +
"<li>Over groen ingekleurde gebieden weten we alles wat we willen weten.</li>" +
"<li>Bij rood ingekleurde gebieden ontbreekt nog heel wat info: klik een gebied aan en beantwoord de vragen.</li>" +
"<li>Je kan altijd een vraag overslaan als je het antwoord niet weet of niet zeker bent</li>" +
"<li>Je kan altijd een foto toevoegen</li>" +
"<li>Je kan ook zelf een gebied toevoegen door op de kaart te klikken</li>" +
"<li>Open buurtnatuur.be <b>op je smartphone</b> om al wandelend foto's te maken en vragen te beantwoorden</li>" +
"</ul>" +
"<small>" +
"<p>" +
"De oorspronkelijke data komt van <b>OpenStreetMap</b> en je antwoorden worden daar bewaard.<br/> Omdat iedereen vrij kan meewerken aan dit project, kunnen we niet garanderen dat er geen fouten opduiken." +
"Kan je hier niet aanpassen wat je wilt, dan kan je dat zelf via OpenStreetMap.org doen. Groen kan <b>geen enkele verantwoordelijkheid</b> nemen over de kaart." +
"</p>" +
"Je privacy is belangrijk. We tellen wel hoeveel gebruikers deze website bezoeken. We plaatsen een cookie waar geen persoonlijke informatie in bewaard wordt. " +
"Als je inlogt, komt er een tweede cookie bij met je inloggegevens." +
"</small>"
);
this.icon = "./assets/themes/buurtnatuur/groen_logo.svg"
this.socialImage = "assets/themes/buurtnatuur/social_image.jpg"
this.description = "Met deze tool kan je natuur in je buurt in kaart brengen en meer informatie geven over je favoriete plekje"
this.enableMoreQuests = false;
this.enableShareScreen = false
}
}

View file

@ -36,10 +36,6 @@ export class OnlyShowIfConstructor implements TagDependantUIElementConstructor{
return this._embedded.IsQuestioning(properties); return this._embedded.IsQuestioning(properties);
} }
Priority(): number {
return this._embedded.Priority();
}
GetContent(tags: any): Translation { GetContent(tags: any): Translation {
if(!this.IsKnown(tags)){ if(!this.IsKnown(tags)){
return undefined; return undefined;
@ -78,10 +74,6 @@ class OnlyShowIf extends UIElement implements TagDependantUIElement {
} }
} }
Priority(): number {
return this._embedded.Priority();
}
IsKnown(): boolean { IsKnown(): boolean {
if(!this.Matches()){ if(!this.Matches()){
return false; return false;

View file

@ -1,35 +0,0 @@
import {And, Tag} from "../../Logic/Tags";
import {TagRenderingOptions} from "../TagRenderingOptions";
export class AccessTag extends TagRenderingOptions {
private static options = {
priority: 20,
question: "Is dit gebied toegankelijk?",
freeform: {
key: "access:description",
template: "Iets anders: $$$",
renderTemplate: "De toegankelijkheid van dit gebied is: {access:description}",
placeholder: "Specifieer"
},
mappings: [
{k: new And([new Tag("access", "yes"), new Tag("fee", "")]), txt: "Publiek toegankelijk"},
{k: new And([new Tag("access", "no"), new Tag("fee", "")]), txt: "Niet toegankelijk"},
{k: new And([new Tag("access", "private"), new Tag("fee", "")]), txt: "Niet toegankelijk, want privegebied"},
{k: new And([new Tag("access", "permissive"), new Tag("fee", "")]), txt: "Toegankelijk, maar het is privegebied"},
{k: new And([new Tag("access", "guided"), new Tag("fee", "")]), txt: "Enkel met een gids of tijdens een activiteit toegankelijk"},
{
k: new And([new Tag("access", "yes"),
new Tag("fee", "yes")]),
txt: "Toegankelijk mits betaling",
priority: 10
},
]
}
constructor() {
super(AccessTag.options);
}
}

View file

@ -1,18 +0,0 @@
import {UIElement} from "../../UI/UIElement";
import Translations from "../../UI/i18n/Translations";
import {TagRenderingOptions} from "../TagRenderingOptions";
export class EmailQuestion extends TagRenderingOptions {
constructor(category: string | UIElement) {
super({
question: Translations.t.general.questions.emailOf.Subs({category: category}),
freeform: {
renderTemplate: Translations.t.general.questions.emailIs.Subs({category: category}),
template: "$email$",
key: "email"
}
});
}
}

View file

@ -5,24 +5,21 @@ import {TagRenderingOptions} from "../TagRenderingOptions";
export class OperatorTag extends TagRenderingOptions { export class OperatorTag extends TagRenderingOptions {
private static options = {
priority: 15,
question: "Wie beheert dit gebied?",
freeform: {
key: "operator",
template: "Beheer door $$$",
renderTemplate: "Beheer door {operator}",
placeholder: "organisatie"
},
mappings: [
{k: new Tag("operator", "Natuurpunt"), txt: "Natuurpunt"},
{k: new Tag("operator", "Agentschap Natuur en Bos"), txt: "het Agentschap Natuur en Bos (ANB)"},
{k: new Tag("operator", "private"), txt: "Beheer door een privépersoon"}
]
}
constructor() { constructor() {
super(OperatorTag.options); super({
question: "Wie beheert dit gebied?",
freeform: {
key: "operator",
template: "Beheer door $$$",
renderTemplate: "Beheer door {operator}",
placeholder: "organisatie"
},
mappings: [
{k: new Tag("operator", "Natuurpunt"), txt: "Natuurpunt"},
{k: new Tag("operator", "Agentschap Natuur en Bos"), txt: "het Agentschap Natuur en Bos (ANB)"},
{k: new Tag("operator", "private"), txt: "Beheer door een privépersoon"}
]
});
} }
} }

View file

@ -1,18 +0,0 @@
import {UIElement} from "../../UI/UIElement";
import Translations from "../../UI/i18n/Translations";
import {TagRenderingOptions} from "../TagRenderingOptions";
export class PhoneNumberQuestion extends TagRenderingOptions {
constructor(category: string | UIElement) {
super({
question: Translations.t.general.questions.phoneNumberOf.Subs({category: category}),
freeform: {
renderTemplate: Translations.t.general.questions.phoneNumberIs.Subs({category: category}),
template: "$phone$",
key: "phone"
}
});
}
}

View file

@ -1,17 +0,0 @@
import {UIElement} from "../../UI/UIElement";
import Translations from "../../UI/i18n/Translations";
import {TagRenderingOptions} from "../TagRenderingOptions";
export default class Website extends TagRenderingOptions {
constructor(category: string | UIElement) {
super({
question: Translations.t.general.questions.websiteOf.Subs({category: category}),
freeform: {
renderTemplate: Translations.t.general.questions.websiteIs,
template: "$$$",
key: "website"
}
});
}
}

View file

@ -1,18 +0,0 @@
import {Tag} from "../../../Logic/Tags";
import Translations from "../../../UI/i18n/Translations";
import {TagRenderingOptions} from "../../TagRenderingOptions";
export default class ShopDiy extends TagRenderingOptions {
constructor() {
const key = 'service:bicycle:diy'
const to = Translations.t.cyclofix.shop.diy
super({
question: to.question,
mappings: [
{k: new Tag(key, "yes"), txt: to.yes},
{k: new Tag(key, "no"), txt: to.no},
]
});
}
}

View file

@ -1,17 +0,0 @@
import Translations from "../../../UI/i18n/Translations";
import {TagRenderingOptions} from "../../TagRenderingOptions";
export default class ShopPump extends TagRenderingOptions {
constructor() {
const to = Translations.t.cyclofix.shop.qName
super({
question: to.question,
freeform: {
key: "name",
renderTemplate: to.render,
template: to.template
}
})
}
}

View file

@ -1,18 +0,0 @@
import {Tag} from "../../../Logic/Tags";
import Translations from "../../../UI/i18n/Translations";
import {TagRenderingOptions} from "../../TagRenderingOptions";
export default class ShopPump extends TagRenderingOptions {
constructor() {
const key = 'service:bicycle:pump'
const to = Translations.t.cyclofix.shop.pump
super({
question: to.question,
mappings: [
{k: new Tag(key, "yes"), txt: to.yes},
{k: new Tag(key, "no"), txt: to.no},
]
});
}
}

View file

@ -1,18 +0,0 @@
import {Tag} from "../../../Logic/Tags";
import Translations from "../../../UI/i18n/Translations";
import {TagRenderingOptions} from "../../TagRenderingOptions";
export default class ShopRental extends TagRenderingOptions {
constructor() {
const key = 'service:bicycle:rental'
const to = Translations.t.cyclofix.shop.rental
super({
question: to.question,
mappings: [
{k: new Tag(key, "yes"), txt: to.yes},
{k: new Tag(key, "no"), txt: to.no},
]
});
}
}

View file

@ -1,20 +0,0 @@
import {Tag} from "../../../Logic/Tags";
import Translations from "../../../UI/i18n/Translations";
import {TagRenderingOptions} from "../../TagRenderingOptions";
export default class ShopRepair extends TagRenderingOptions {
constructor() {
const key = 'service:bicycle:repair'
const to = Translations.t.cyclofix.shop.repair
super({
question: to.question,
mappings: [
{k: new Tag(key, "yes"), txt: to.yes},
{k: new Tag(key, "only_sold"), txt: to.sold},
{k: new Tag(key, "brand"), txt: to.brand},
{k: new Tag(key, "no"), txt: to.no},
]
});
}
}

View file

@ -1,18 +0,0 @@
import {Tag} from "../../../Logic/Tags";
import Translations from "../../../UI/i18n/Translations";
import {TagRenderingOptions} from "../../TagRenderingOptions";
export default class ShopRetail extends TagRenderingOptions {
constructor() {
const key = 'service:bicycle:retail'
const to = Translations.t.cyclofix.shop.retail
super({
question: to.question,
mappings: [
{k: new Tag(key, "yes"), txt: to.yes},
{k: new Tag(key, "no"), txt: to.no},
]
});
}
}

View file

@ -1,19 +0,0 @@
import {Tag} from "../../../Logic/Tags";
import Translations from "../../../UI/i18n/Translations";
import {TagRenderingOptions} from "../../TagRenderingOptions";
export default class ShopPump extends TagRenderingOptions {
constructor() {
const key = 'service:bicycle:second_hand'
const to = Translations.t.cyclofix.shop.secondHand
super({
question: to.question,
mappings: [
{k: new Tag(key, "yes"), txt: to.yes},
{k: new Tag(key, "no"), txt: to.no},
{k: new Tag(key, "only"), txt: to.only},
]
});
}
}

View file

@ -11,7 +11,6 @@ export class TagRenderingOptions implements TagDependantUIElementConstructor {
* Notes: by not giving a 'question', one disables the question form alltogether * Notes: by not giving a 'question', one disables the question form alltogether
*/ */
public options: { public options: {
priority?: number;
question?: string | Translation; question?: string | Translation;
freeform?: { freeform?: {
key: string; key: string;
@ -22,7 +21,7 @@ export class TagRenderingOptions implements TagDependantUIElementConstructor {
extraTags?: TagsFilter extraTags?: TagsFilter
}; };
multiAnswer?: boolean, multiAnswer?: boolean,
mappings?: { k: TagsFilter; txt: string | Translation; priority?: number, substitute?: boolean, hideInAnwser?: boolean }[] mappings?: { k: TagsFilter; txt: string | Translation; substitute?: boolean, hideInAnwser?: boolean }[]
}; };
constructor(options: { constructor(options: {
@ -146,8 +145,4 @@ export class TagRenderingOptions implements TagDependantUIElementConstructor {
return !this.IsQuestioning(properties); return !this.IsQuestioning(properties);
} }
Priority(): number {
return this.options.priority ?? 0;
}
} }

View file

@ -12,7 +12,6 @@ export interface TagDependantUIElementConstructor {
construct(dependencies: Dependencies): TagDependantUIElement; construct(dependencies: Dependencies): TagDependantUIElement;
IsKnown(properties: any): boolean; IsKnown(properties: any): boolean;
IsQuestioning(properties: any): boolean; IsQuestioning(properties: any): boolean;
Priority(): number;
GetContent(tags: any): Translation; GetContent(tags: any): Translation;
} }
@ -23,7 +22,5 @@ export abstract class TagDependantUIElement extends UIElement {
abstract IsQuestioning(): boolean; abstract IsQuestioning(): boolean;
abstract Priority() : number;
abstract IsSkipped() : boolean; abstract IsSkipped() : boolean;
} }

View file

@ -355,11 +355,12 @@ export class InitUiElements {
let baseLayerOptions = BaseLayers.baseLayers.map((layer) => { let baseLayerOptions = BaseLayers.baseLayers.map((layer) => {
return {value: layer, shown: layer.name} return {value: layer, shown: layer.name}
}); });
let layerControlPanel = new Combine([new DropDown(Translations.t.general.backgroundMap, baseLayerOptions, State.state.bm.CurrentLayer)]); let layerControlPanel = new Combine(
[new DropDown(Translations.t.general.backgroundMap, baseLayerOptions, State.state.bm.CurrentLayer)]);
layerControlPanel.SetStyle("margin:1em"); layerControlPanel.SetStyle("margin:1em");
if (State.state.filteredLayers.data.length > 1) { if (State.state.filteredLayers.data.length > 1) {
const layerSelection = new LayerSelection(); const layerSelection = new LayerSelection();
layerControlPanel = new Combine([layerSelection, layerControlPanel]); layerControlPanel = new Combine([layerSelection, "<br/>",layerControlPanel]);
} }
return layerControlPanel; return layerControlPanel;
} }
@ -375,6 +376,7 @@ export class InitUiElements {
new Combine([ new Combine([
closeButton, closeButton,
layerControlPanel]).SetStyle("display:flex;flex-direction:row;") layerControlPanel]).SetStyle("display:flex;flex-direction:row;")
.SetClass("hidden-on-mobile")
, ,
new Combine([Img.closedFilterButton]) new Combine([Img.closedFilterButton])
.SetStyle("display:block;border-radius:50%;background:white;padding:1em;"), .SetStyle("display:block;border-radius:50%;background:white;padding:1em;"),
@ -408,15 +410,21 @@ export class InitUiElements {
static InitBaseMap(){ static InitBaseMap(){
const bm = new Basemap("leafletDiv", State.state.locationControl, new VariableUiElement( const bm = new Basemap("leafletDiv", State.state.locationControl, new VariableUiElement(
State.state.locationControl.map((location) => { State.state.locationControl.map((location) => {
const mapComplete = `<a href='https://github.com/pietervdvn/MapComplete' target='_blank'>Mapcomplete ${State.vNumber}</a> <a href='https://github.com/pietervdvn/MapComplete/issues' target='_blank'><img src='./assets/bug.svg' alt='Report bug' class='small-userbadge-icon'></a>`; const mapComplete = `<a href='https://github.com/pietervdvn/MapComplete' target='_blank'>Mapcomplete ${State.vNumber}</a>`
const reportBug = `<a href='https://github.com/pietervdvn/MapComplete/issues' target='_blank'><img src='./assets/bug.svg' class='small-userbadge-icon'></a>`;
const layoutId = State.state.layoutToUse.data.id;
const osmChaLink = `https://osmcha.org/?filters=%7B%22comment%22%3A%5B%7B%22label%22%3A%22%23${layoutId}%22%2C%22value%22%3A%22%23${layoutId}%22%7D%5D%2C%22date__gte%22%3A%5B%7B%22label%22%3A%222020-07-05%22%2C%22value%22%3A%222020-07-05%22%7D%5D%2C%22editor%22%3A%5B%7B%22label%22%3A%22MapComplete%22%2C%22value%22%3A%22MapComplete%22%7D%5D%7D`
console.log("OsmCha link is",osmChaLink);
const stats = `<a href='${osmChaLink}' target='_blank'><img src='./assets/statistics.svg' class='small-userbadge-icon'></a>`;
let editHere = ""; let editHere = "";
if (location !== undefined) { if (location !== undefined) {
editHere = " | " + editHere =
"<a href='https://www.openstreetmap.org/edit?editor=id#map=" + location.zoom + "/" + location.lat + "/" + location.lon + "' target='_blank'>" + "<a href='https://www.openstreetmap.org/edit?editor=id#map=" + location.zoom + "/" + location.lat + "/" + location.lon + "' target='_blank'>" +
"<img src='./assets/pencil.svg' alt='edit here' class='small-userbadge-icon'>" + "<img src='./assets/pencil.svg' alt='edit here' class='small-userbadge-icon'>" +
"</a>" "</a>"
} }
return mapComplete + editHere; return new Combine([mapComplete, reportBug, " | ", stats, " | ",editHere]).Render();
}) })
)); ));

View file

@ -221,7 +221,7 @@ export class FilteredLayer {
color: style.color color: style.color
}); });
} else if (style.icon.iconUrl.startsWith("$circle ")) { } else if (style.icon.iconUrl.startsWith("$circle")) {
marker = L.circle(latLng, { marker = L.circle(latLng, {
radius: 25, radius: 25,
color: style.color color: style.color

View file

@ -56,7 +56,6 @@ export class LayerUpdater {
continue; continue;
} }
if (state.locationControl.data.zoom < layer.minzoom) { if (state.locationControl.data.zoom < layer.minzoom) {
console.log("Not loading layer ", layer.id, " as it needs at least ", layer.minzoom, "zoom")
continue; continue;
} }
// Check if data for this layer has already been loaded // Check if data for this layer has already been loaded

View file

@ -140,7 +140,6 @@ export class OsmPreferences {
} }
if (this.preferences.data[k] === v) { if (this.preferences.data[k] === v) {
console.log("Not updating preference", k, " to ", v, "not changed");
return; return;
} }
console.log("Updating preference", k, " to ", Utils.EllipsesAfter(v, 15)); console.log("Updating preference", k, " to ", Utils.EllipsesAfter(v, 15));
@ -155,7 +154,6 @@ export class OsmPreferences {
console.log("Could not remove preference", error); console.log("Could not remove preference", error);
return; return;
} }
console.log("Preference ",k,"removed!"); console.log("Preference ",k,"removed!");
}); });

View file

@ -17,6 +17,7 @@ export class PersonalLayout extends Layout {
Translations.t.favourite.description, Translations.t.favourite.description,
); );
this.description = "The personal theme allows to select one or more layers from all the layouts, creating a truly personal editor"
this.icon = "./assets/star.svg" this.icon = "./assets/star.svg"
} }

View file

@ -106,23 +106,18 @@ export class Tag extends TagsFilter {
} }
matches(tags: { k: string; v: string }[]): boolean { matches(tags: { k: string; v: string }[]): boolean {
if (this.value === "") {
return true
}
for (const tag of tags) { for (const tag of tags) {
if (this.key == tag.k) { if (this.key == tag.k) {
return this.value === tag.v;
if (tag.v === "") {
// This tag has been removed -> always matches false
return false;
}
if (this.value === tag.v) {
return true;
}
} }
} }
// The tag was not found
if(this.value === ""){
// and it shouldn't be found!
return true;
}
return false; return false;
} }

View file

@ -172,3 +172,12 @@ Home icon by Timothy Miller, CC-BY-SA 3.0
https://commons.wikimedia.org/wiki/File:Map_icons_by_Scott_de_Jonge_-_bicycle-store.svg https://commons.wikimedia.org/wiki/File:Map_icons_by_Scott_de_Jonge_-_bicycle-store.svg
Bicycle logo, Scott de Jonge Bicycle logo, Scott de Jonge
Nature Reserve icon via http://www.onlinewebfonts.com/icon/389579, CC BY 3.0 (@ Эдуард Черных)
Park icon via http://www.onlinewebfonts.com/icon/425974, CC BY 3.0 (@sterankofrank)
Forest icon via https://www.onlinewebfonts.com/icon/498112, CC BY
Statistics icon via https://www.onlinewebfonts.com/icon/197818

View file

@ -22,10 +22,11 @@ export class State {
// The singleton of the global state // The singleton of the global state
public static state: State; public static state: State;
public static vNumber = "0.0.8"; public static vNumber = "0.0.8a";
// The user journey states thresholds when a new feature gets unlocked // The user journey states thresholds when a new feature gets unlocked
public static userJourney = { public static userJourney = {
addNewPointsUnlock: 1,
moreScreenUnlock: 5, moreScreenUnlock: 5,
personalLayoutUnlock: 20, personalLayoutUnlock: 20,
tagsVisibleAt: 100, tagsVisibleAt: 100,
@ -33,8 +34,7 @@ export class State {
tagsVisibleAndWikiLinked: 150, tagsVisibleAndWikiLinked: 150,
themeGeneratorReadOnlyUnlock: 200, themeGeneratorReadOnlyUnlock: 200,
themeGeneratorFullUnlock: 500, themeGeneratorFullUnlock: 500,
addNewPointWithUnreadMessagesUnlock: 500
}; };
public static runningFromConsole: boolean = false; public static runningFromConsole: boolean = false;
@ -118,7 +118,7 @@ export class State {
str => isNaN(Number(str)) ? 0 : Number(str),[],n => ""+n str => isNaN(Number(str)) ? 0 : Number(str),[],n => ""+n
); );
constructor(layoutToUse: Layout, useDevServer = false) { constructor(layoutToUse: Layout) {
const self = this; const self = this;
this.layoutToUse.setData(layoutToUse) this.layoutToUse.setData(layoutToUse)
this.locationControl = new UIEventSource<{ lat: number, lon: number, zoom: number }>({ this.locationControl = new UIEventSource<{ lat: number, lon: number, zoom: number }>({

View file

@ -19,7 +19,7 @@ export class SubtleButton extends UIElement{
if ((imageUrl ?? "") === "") { if ((imageUrl ?? "") === "") {
this.image = new FixedUiElement(""); this.image = new FixedUiElement("");
} else if (typeof (imageUrl) === "string") { } else if (typeof (imageUrl) === "string") {
this.image = new FixedUiElement(`<img src="${imageUrl}">`); this.image = new FixedUiElement(`<img style="height:3em" src="${imageUrl}">`);
} else { } else {
this.image = imageUrl; this.image = imageUrl;
} }

View file

@ -7,7 +7,6 @@ import Combine from "../Base/Combine";
import {VariableUiElement} from "../Base/VariableUIElement"; import {VariableUiElement} from "../Base/VariableUIElement";
import {TabbedComponent} from "../Base/TabbedComponent"; import {TabbedComponent} from "../Base/TabbedComponent";
import PageSplit from "../Base/PageSplit"; import PageSplit from "../Base/PageSplit";
import HelpText from "../../Customizations/HelpText";
import AllLayersPanel from "./AllLayersPanel"; import AllLayersPanel from "./AllLayersPanel";
import SharePanel from "./SharePanel"; import SharePanel from "./SharePanel";
import {LayoutConfigJson} from "../../Customizations/JSON/LayoutConfigJson"; import {LayoutConfigJson} from "../../Customizations/JSON/LayoutConfigJson";
@ -16,6 +15,7 @@ import {State} from "../../State";
import {FixedUiElement} from "../Base/FixedUiElement"; import {FixedUiElement} from "../Base/FixedUiElement";
import SavePanel from "./SavePanel"; import SavePanel from "./SavePanel";
import {LocalStorageSource} from "../../Logic/Web/LocalStorageSource"; import {LocalStorageSource} from "../../Logic/Web/LocalStorageSource";
import HelpText from "./HelpText";
export default class CustomGeneratorPanel extends UIElement { export default class CustomGeneratorPanel extends UIElement {
@ -42,7 +42,8 @@ export default class CustomGeneratorPanel extends UIElement {
const encoded = es.map(config => btoa(JSON.stringify(config))); const encoded = es.map(config => btoa(JSON.stringify(config)));
encoded.addCallback(encoded => LocalStorageSource.Get("last-custom-theme")) encoded.addCallback(encoded => LocalStorageSource.Get("last-custom-theme"))
const liveUrl = encoded.map(encoded => `./index.html?userlayout=${es.data.id}#${encoded}`) const liveUrl = encoded.map(encoded => `./index.html?userlayout=${es.data.id}#${encoded}`)
const iframe = liveUrl.map(url => `<iframe src='${url}' width='100%' height='99%' style="box-sizing: border-box" title='Theme Preview'></iframe>`); const testUrl = encoded.map(encoded => `./index.html?test=true&userlayout=${es.data.id}#${encoded}`)
const iframe = testUrl.map(url => `<iframe src='${url}' width='100%' height='99%' style="box-sizing: border-box" title='Theme Preview'></iframe>`);
const currentSetting = new UIEventSource<SingleSetting<any>>(undefined) const currentSetting = new UIEventSource<SingleSetting<any>>(undefined)
const generalSettings = new GeneralSettings(es, currentSetting); const generalSettings = new GeneralSettings(es, currentSetting);
const languages = generalSettings.languages; const languages = generalSettings.languages;

View file

@ -43,8 +43,10 @@ export default class GeneralSettingsPanel extends UIElement {
"Supported languages", "Which languages do you want to support in this theme? Type the two letter code representing your language, seperated by <span class='literal-code'>;</span>. For example:<span class='literal-code'>en;nl</span> "), "Supported languages", "Which languages do you want to support in this theme? Type the two letter code representing your language, seperated by <span class='literal-code'>;</span>. For example:<span class='literal-code'>en;nl</span> "),
new SingleSetting(configuration, new MultiLingualTextFields(this.languages), "title", new SingleSetting(configuration, new MultiLingualTextFields(this.languages), "title",
"Title", "The title as shown in the welcome message, in the browser title bar, in the more screen, ..."), "Title", "The title as shown in the welcome message, in the browser title bar, in the more screen, ..."),
new SingleSetting(configuration, new MultiLingualTextFields(this.languages), "shortDescription","Short description",
"The short description is shown as subtext in the social preview and on the 'more screen'-buttons. It should be at most one sentence of around ~25words"),
new SingleSetting(configuration, new MultiLingualTextFields(this.languages, true), new SingleSetting(configuration, new MultiLingualTextFields(this.languages, true),
"description", "Description", "The description is shown in the welcomemessage. It is a small text welcoming users"), "description", "Description", "The description is shown in the welcome-message when opening MapComplete. It is a small text welcoming users"),
new SingleSetting(configuration, TextField.StringInput(), "icon", new SingleSetting(configuration, TextField.StringInput(), "icon",
"Icon", "A visual representation for your theme; used as logo in the welcomeMessage. If your theme is official, used as favicon and webapp logo", "Icon", "A visual representation for your theme; used as logo in the welcomeMessage. If your theme is official, used as favicon and webapp logo",
{ {

View file

@ -32,6 +32,7 @@ export class GenerateEmpty {
return { return {
id: "id", id: "id",
title: {}, title: {},
shortDescription: {},
description: {}, description: {},
language: [], language: [],
maintainer: "", maintainer: "",
@ -51,6 +52,7 @@ export class GenerateEmpty {
return { return {
id: "test", id: "test",
title: {"en": "Test layout"}, title: {"en": "Test layout"},
shortDescription: {},
description: {"en": "A layout for testing"}, description: {"en": "A layout for testing"},
language: ["en"], language: ["en"],
maintainer: "Pieter Vander Vennet", maintainer: "Pieter Vander Vennet",

View file

@ -1,9 +1,9 @@
import {UIElement} from "../UI/UIElement"; import {UIEventSource} from "../../Logic/UIEventSource";
import {SubtleButton} from "../UI/Base/SubtleButton"; import {UIElement} from "../UIElement";
import {VariableUiElement} from "../UI/Base/VariableUIElement"; import {VariableUiElement} from "../Base/VariableUIElement";
import SingleSetting from "../UI/CustomGenerator/SingleSetting"; import {SubtleButton} from "../Base/SubtleButton";
import Combine from "../UI/Base/Combine"; import Combine from "../Base/Combine";
import {UIEventSource} from "../Logic/UIEventSource"; import SingleSetting from "./SingleSetting";
export default class HelpText extends UIElement { export default class HelpText extends UIElement {
@ -32,7 +32,7 @@ export default class HelpText extends UIElement {
return "<h1>Welcome to the Custom Theme Builder</h1>" + return "<h1>Welcome to the Custom Theme Builder</h1>" +
"Here, one can make their own custom mapcomplete themes.<br/>" + "Here, one can make their own custom mapcomplete themes.<br/>" +
"Fill out the fields to get a working mapcomplete theme. More information on the selected field will appear here when you click it.<br/>" + "Fill out the fields to get a working mapcomplete theme. More information on the selected field will appear here when you click it.<br/>" +
"Want to see how the quests are doing in number of visits? All the stats are open on <a href='pietervdvn.goatcounter.com' target='_blank'>goatcounter</a>"; "Want to see how the quests are doing in number of visits? All the stats are open on <a href='https://pietervdvn.goatcounter.com' target='_blank'>goatcounter</a>";
} }
return new Combine(["<h1>", setting._name, "</h1>", setting._description.Render()]).Render(); return new Combine(["<h1>", setting._name, "</h1>", setting._description.Render()]).Render();

View file

@ -96,7 +96,7 @@ export default class LayerPanel extends UIElement {
{value: 2, shown: "Show both the ways/areas and the centerpoints"}, {value: 2, shown: "Show both the ways/areas and the centerpoints"},
{value: 1, shown: "Show everything as centerpoint"}]), "wayHandling", "Way handling", {value: 1, shown: "Show everything as centerpoint"}]), "wayHandling", "Way handling",
"Describes how ways and areas are represented on the map: areas can be represented as the area itself, or it can be converted into the centerpoint"), "Describes how ways and areas are represented on the map: areas can be represented as the area itself, or it can be converted into the centerpoint"),
setting(TextField.NumberInput("nat", n => n <= 100), "hideUnderlayingFeaturesMinPercentage", "Max allowed overlap percentage", setting(TextField.NumberInput("int", n => n <= 100), "hideUnderlayingFeaturesMinPercentage", "Max allowed overlap percentage",
"Consider that we want to show 'Nature Reserves' and 'Forests'. Now, ofter, there are pieces of forest mapped _in_ the nature reserve.<br/>" + "Consider that we want to show 'Nature Reserves' and 'Forests'. Now, ofter, there are pieces of forest mapped _in_ the nature reserve.<br/>" +
"Now, showing those pieces of forest overlapping with the nature reserve truly clutters the map and is very user-unfriendly.<br/>" + "Now, showing those pieces of forest overlapping with the nature reserve truly clutters the map and is very user-unfriendly.<br/>" +
"The features are placed layer by layer. If a feature below a feature on this layer overlaps for more then 'x'-percent, the underlying feature is hidden."), "The features are placed layer by layer. If a feature below a feature on this layer overlaps for more then 'x'-percent, the underlying feature is hidden."),

View file

@ -2,7 +2,7 @@ import {UIElement} from "../UIElement";
import {UIEventSource} from "../../Logic/UIEventSource"; import {UIEventSource} from "../../Logic/UIEventSource";
import SingleSetting from "./SingleSetting"; import SingleSetting from "./SingleSetting";
import LayerPanel from "./LayerPanel"; import LayerPanel from "./LayerPanel";
import HelpText from "../../Customizations/HelpText"; import HelpText from "./HelpText";
import {MultiTagInput} from "../Input/MultiTagInput"; import {MultiTagInput} from "../Input/MultiTagInput";
import {FromJSON} from "../../Customizations/JSON/FromJSON"; import {FromJSON} from "../../Customizations/JSON/FromJSON";
import Combine from "../Base/Combine"; import Combine from "../Base/Combine";

View file

@ -115,30 +115,16 @@ export class FeatureInfoBox extends UIElement {
let questionElement: UIElement; let questionElement: UIElement;
if (!State.state.osmConnection.userDetails.data.loggedIn) { if (questions.length > 0) {
let mostImportantQuestion ;
let score = -1000;
for (const question of questions) {
if (mostImportantQuestion === undefined || question.Priority() > score) {
mostImportantQuestion = question;
score = question.Priority();
}
}
questionElement = mostImportantQuestion;
} else if (questions.length > 0) {
// We select the most important question and render that one // We select the most important question and render that one
let mostImportantQuestion; let mostImportantQuestion;
let score = -1000;
for (const question of questions) { for (const question of questions) {
if (mostImportantQuestion === undefined || question.Priority() > score) { if (mostImportantQuestion === undefined) {
mostImportantQuestion = question; mostImportantQuestion = question;
score = question.Priority(); break;
} }
} }
questionElement = mostImportantQuestion; questionElement = mostImportantQuestion;
} else if (skippedQuestions == 1) { } else if (skippedQuestions == 1) {
questionElement = this._oneSkipped; questionElement = this._oneSkipped;

View file

@ -23,11 +23,13 @@ export class FullScreenMessageBox extends UIElement {
this._uielement = new Combine([State.state.fullScreenMessage.data]).SetStyle( this._uielement = new Combine([State.state.fullScreenMessage.data]).SetStyle(
"display:block;"+ "display:block;"+
"padding: 1em;"+ "padding: 1em;"+
"padding-bottom:5em;"+ "padding-bottom:6em;"+
`margin-bottom:${FullScreenMessageBox._toTheMap_height};`+ `margin-bottom:${FullScreenMessageBox._toTheMap_height};`+
"box-sizing:border-box;"+ "box-sizing:border-box;"+
`height:calc(100vh - ${FullScreenMessageBox._toTheMap_height});`+ `height:calc(100vh - ${FullScreenMessageBox._toTheMap_height});`+
"overflow-y: auto;" + "overflow-y: auto;" +
"max-width:100vw;" +
"overflow-x:hidden;" +
"background:white;" "background:white;"
); );

View file

@ -4,6 +4,8 @@ import Combine from "./Base/Combine";
import {Img} from "./Img"; import {Img} from "./Img";
import {State} from "../State"; import {State} from "../State";
import Translations from "./i18n/Translations"; import Translations from "./i18n/Translations";
import {FixedUiElement} from "./Base/FixedUiElement";
import {VariableUiElement} from "./Base/VariableUIElement";
export class LayerSelection extends UIElement { export class LayerSelection extends UIElement {
@ -14,17 +16,34 @@ export class LayerSelection extends UIElement {
this._checkboxes = []; this._checkboxes = [];
for (const layer of State.state.filteredLayers.data) { for (const layer of State.state.filteredLayers.data) {
const checkbox = Img.checkmark; let iconUrl = "./asets/checkbox.svg";
let icon = ""; let iconUrlBlank = "";
if (layer.layerDef.icon && layer.layerDef.icon !== "") { if (layer.layerDef.icon && layer.layerDef.icon !== "") {
icon = `<img width="20" height="20" src="${layer.layerDef.icon}">` iconUrl = layer.layerDef.icon as string;
iconUrlBlank = layer.layerDef.icon as string;
} }
const name = Translations.WT(layer.layerDef.name).Clone() const icon = new FixedUiElement(`<img style="height:2em;max-width: 2em;" src="${iconUrl}">`);
.SetStyle("font-size:large;");
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;");
const zoomStatus = new VariableUiElement(State.state.locationControl.map(location => {
if (location.zoom < layer.layerDef.minzoom) {
return Translations.t.general.zoomInToSeeThisLayer
.SetClass("alert")
.SetStyle("display: block ruby;width:min-content;")
.Render();
}
return ""
}))
const style = "display:flex;align-items:center;"
this._checkboxes.push(new CheckBox( this._checkboxes.push(new CheckBox(
new Combine([checkbox, icon, name]), new Combine([icon, name, zoomStatus]).SetStyle(style),
new Combine([Img.no_checkmark, icon, name]), new Combine([iconUnselected, "<del>", name, "</del>", zoomStatus]).SetStyle(style),
layer.isDisplayed) layer.isDisplayed)
.SetStyle("margin:0.3em;") .SetStyle("margin:0.3em;")
); );

View file

@ -44,11 +44,15 @@ export class SearchAndGo extends UIElement {
// Triggered by 'enter' or onclick // Triggered by 'enter' or onclick
private RunSearch() { private RunSearch() {
const searchString = this._searchField.GetValue().data; const searchString = this._searchField.GetValue().data;
if(searchString === undefined || searchString === ""){
return;
}
this._searchField.GetValue().setData(""); this._searchField.GetValue().setData("");
this._placeholder.setData(Translations.t.general.search.searching); this._placeholder.setData(Translations.t.general.search.searching);
const self = this; const self = this;
Geocoding.Search(searchString, (result) => { Geocoding.Search(searchString, (result) => {
console.log("Search result", result)
if (result.length == 0) { if (result.length == 0) {
self._placeholder.setData(Translations.t.general.search.nothing); self._placeholder.setData(Translations.t.general.search.nothing);
return; return;

View file

@ -46,6 +46,9 @@ export class SimpleAddUI extends UIElement {
const self = this; const self = this;
for (const layer of State.state.filteredLayers.data) { for (const layer of State.state.filteredLayers.data) {
this.ListenTo(layer.isDisplayed);
for (const preset of layer.layerDef.presets) { for (const preset of layer.layerDef.presets) {
let icon: string = "./assets/bug.svg"; let icon: string = "./assets/bug.svg";
@ -130,6 +133,15 @@ export class SimpleAddUI extends UIElement {
const userDetails = State.state.osmConnection.userDetails; const userDetails = State.state.osmConnection.userDetails;
if (this._confirmPreset.data !== undefined) { if (this._confirmPreset.data !== undefined) {
if(!this._confirmPreset.data.layerToAddTo.isDisplayed.data){
return new Combine([
Translations.t.general.add.layerNotEnabled.Subs({layer: this._confirmPreset.data.layerToAddTo.layerDef.name})
.SetClass("alert"),
this.cancelButton
]).Render();
}
let tagInfo = ""; let tagInfo = "";
const csCount = State.state.osmConnection.userDetails.data.csCount; const csCount = State.state.osmConnection.userDetails.data.csCount;
@ -153,21 +165,22 @@ export class SimpleAddUI extends UIElement {
let header: UIElement = Translations.t.general.add.header; let header: UIElement = Translations.t.general.add.header;
if(userDetails === undefined){ if (userDetails === undefined) {
return header.Render(); return header.Render();
} }
if (!userDetails.data.loggedIn) { if (!userDetails.data.loggedIn) {
return new Combine([header, this._loginButton]).Render() return new Combine([header, this._loginButton]).Render()
} }
if (userDetails.data.unreadMessages > 0) { if (userDetails.data.unreadMessages > 0 && userDetails.data.csCount < State.userJourney.addNewPointWithUnreadMessagesUnlock) {
return new Combine([header, "<span class='alert'>", return new Combine([header, "<span class='alert'>",
Translations.t.general.readYourMessages, Translations.t.general.readYourMessages,
"</span>", "</span>",
this.goToInboxButton this.goToInboxButton
]).Render(); ]).Render();
} }
if (userDetails.data.dryRun) { if (userDetails.data.dryRun) {
@ -178,7 +191,7 @@ export class SimpleAddUI extends UIElement {
]); ]);
} }
if (userDetails.data.csCount < 5) { if (userDetails.data.csCount < State.userJourney.addNewPointsUnlock) {
return new Combine([header, "<span class='alert'>", return new Combine([header, "<span class='alert'>",
Translations.t.general.fewChangesBefore, Translations.t.general.fewChangesBefore,
"</span>"]).Render(); "</span>"]).Render();

View file

@ -21,7 +21,6 @@ import {FixedUiElement} from "./Base/FixedUiElement";
export class TagRendering extends UIElement implements TagDependantUIElement { export class TagRendering extends UIElement implements TagDependantUIElement {
private readonly _priority: number;
private readonly _question: string | Translation; private readonly _question: string | Translation;
private readonly _mapping: { k: TagsFilter, txt: string | UIElement, priority?: number }[]; private readonly _mapping: { k: TagsFilter, txt: string | UIElement, priority?: number }[];
@ -58,8 +57,6 @@ export class TagRendering extends UIElement implements TagDependantUIElement {
} }
constructor(tags: UIEventSource<any>, options: { constructor(tags: UIEventSource<any>, options: {
priority?: number
question?: string | Translation, question?: string | Translation,
freeform?: { freeform?: {
key: string, key: string,
@ -80,8 +77,6 @@ export class TagRendering extends UIElement implements TagDependantUIElement {
const self = this; const self = this;
this._priority = options.priority ?? 0;
this.currentTags = this._source.map(tags => this.currentTags = this._source.map(tags =>
{ {
@ -525,10 +520,6 @@ export class TagRendering extends UIElement implements TagDependantUIElement {
} }
Priority(): number {
return this._priority;
}
private ApplyTemplate(template: string | Translation): UIElement { private ApplyTemplate(template: string | Translation): UIElement {
if (template === undefined || template === null) { if (template === undefined || template === null) {
return undefined; return undefined;

View file

@ -1,6 +1,7 @@
import {UIElement} from "../UIElement" import {UIElement} from "../UIElement"
import Locale from "./Locale" import Locale from "./Locale"
import Combine from "../Base/Combine"; import Combine from "../Base/Combine";
import {Utils} from "../../Utils";
export default class Translation extends UIElement { export default class Translation extends UIElement {
@ -87,4 +88,16 @@ export default class Translation extends UIElement {
} }
FirstSentence() {
const tr = {};
for (const lng in this.translations) {
let txt = this.translations[lng];
txt = txt.replace(/\..*/, "");
txt = Utils.EllipsesAfter(txt, 255);
tr[lng] = txt;
}
return new Translation(tr);
}
} }

View file

@ -12,380 +12,6 @@ export default class Translations {
static t = { static t = {
cyclofix: {
title: new T({
en: 'Cyclofix - an open map for cyclists',
nl: 'Cyclofix - een open kaart voor fietsers',
fr: 'Cyclofix - Une carte ouverte pour les cyclistes',
gl: 'Cyclofix - Un mapa aberto para os ciclistas',
de: 'Cyclofix - eine offene Karte für Radfahrer'
}),
description: new T({
en: "The goal of this map is to present cyclists with an easy-to-use solution to find the appropriate infrastructure for their needs.<br><br>" + //this works in spoken language: ; think about the nearest bike repair station for example
"You can track your precise location (mobile only) and select layers that are relevant for you in the bottom left corner. " +
"You can also use this tool to add or edit pins (points of interest) to the map and provide more data by answering the questions.<br><br>" +
"All changes you make will automatically be saved in the global database of OpenStreetMap and can be freely re-used by others.<br><br>" +
"For more information about the cyclofix project, go to <a href='https://cyclofix.osm.be/'>cyclofix.osm.be</a>.",
nl: "Het doel van deze kaart is om fietsers een gebruiksvriendelijke oplossing te bieden voor het vinden van de juiste infrastructuur voor hun behoeften.<br><br>" + //; denk bijvoorbeeld aan de dichtstbijzijnde fietsherstelplaats.
"U kunt uw exacte locatie volgen (enkel mobiel) en in de linkerbenedenhoek categorieën selecteren die voor u relevant zijn. " +
"U kunt deze tool ook gebruiken om 'spelden' aan de kaart toe te voegen of te bewerken en meer gegevens te verstrekken door de vragen te beantwoorden.<br><br>" +
"Alle wijzigingen die u maakt worden automatisch opgeslagen in de wereldwijde database van OpenStreetMap en kunnen door anderen vrij worden hergebruikt.<br><br>" +
"Bekijk voor meer info over cyclofix ook <a href='https://cyclofix.osm.be/'>cyclofix.osm.be</a>.",
fr: "Le but de cette carte est de présenter aux cyclistes une solution facile à utiliser pour trouver l'infrastructure appropriée à leurs besoins.<br><br>" + //; pensez par exemple à la station de réparation de vélos la plus proche.
"Vous pouvez suivre votre localisation précise (mobile uniquement) et sélectionner les couches qui vous concernent dans le coin inférieur gauche. " +
"Vous pouvez également utiliser cet outil pour ajouter ou modifier des épingles (points d'intérêt) sur la carte et fournir plus de données en répondant aux questions.<br><br>" +
"Toutes les modifications que vous apportez seront automatiquement enregistrées dans la base de données mondiale d'OpenStreetMap et peuvent être librement réutilisées par d'autres.<br><br>" +
"Pour plus d'informations sur le projet cyclofix, rendez-vous sur <a href='https://cyclofix.osm.be/'>cyclofix.osm.be</a>.",
gl: "O obxectivo deste mapa é amosar ós ciclistas unha solución doada de empregar para atopar a infraestrutura axeitada para as súas necesidades.<br><br>" + //isto funciona na lingua falada: ; pensa na estación de arranxo de bicicletas máis preta, por exemplo.
"Podes obter a túa localización precisa (só para dispositivos móbiles) e escoller as capas que sexan relevantes para ti na esquina inferior esquerda. " +
"Tamén podes empregar esta ferramenta para engadir ou editar puntos de interese ó mapa e fornecer máis datos respondendo as cuestións.<br><br>" +
"Todas as modificacións que fagas serán gardadas de xeito automático na base de datos global do OpenStreetMap e outros poderán reutilizalos libremente.<br><br>" +
"Para máis información sobre o proxecto cyclofix, vai a <a href='https://cyclofix.osm.be/'>cyclofix.osm.be</a>.",
de: "Das Ziel dieser Karte ist es, den Radfahrern eine einfach zu benutzende Lösung zu präsentieren, um die geeignete Infrastruktur für ihre Bedürfnisse zu finden.<br><br>" + //dies funktioniert in gesprochener Sprache: ; denken Sie zum Beispiel an die nächste Fahrradreparaturstation
"Sie können Ihren genauen Standort verfolgen (nur mobil) und in der linken unteren Ecke die für Sie relevanten Ebenen auswählen. " +
"Sie können dieses Tool auch verwenden, um Pins (Points of Interest/Interessante Orte) zur Karte hinzuzufügen oder zu bearbeiten und mehr Daten durch Beantwortung der Fragen bereitstellen.<br><br>" +
"Alle Änderungen, die Sie vornehmen, werden automatisch in der globalen Datenbank von OpenStreetMap gespeichert und können von anderen frei wiederverwendet werden.<br><br>" +
"Weitere Informationen über das Projekt Cyclofix finden Sie unter <a href='https://cyclofix.osm.be/'>cyclofix.osm.be</a>."
}),
station: {
name: new T({
en: 'bike station (repair, pump or both)',
nl: 'fietspunt (herstel, pomp of allebei)',
fr: 'station velo (réparation, pompe à vélo)',
gl: 'estación de bicicletas (arranxo, bomba de ar ou ambos)',
de: 'Fahrradstation (Reparatur, Pumpe oder beides)'
}),
// title: new T({en: 'Bike station', nl: 'Fietsstation', fr: 'Station vélo', gl: 'Estación de bicicletas'}), Old, non-dynamic title
titlePump: new T({
}),
titleRepair: new T({
en: 'Bike repair station',
nl: 'Herstelpunt',
fr: 'TODO: fr',
gl: 'Estación de arranxo de bicicletas',
de: 'Fahrradwerkstatt'
}),
titlePumpAndRepair: new T({
en: 'Bike station (pump & repair)',
nl: 'Herstelpunt met pomp',
fr: 'Point station velo avec pompe',
gl: 'Estación de bicicletas (arranxo e bomba de ar)',
de: 'Fahrradstation (Pumpe & Reparatur)'
}),
valves: {
default: new T({
}),
dunlop: new T({}),
sclaverand: new T({
}),
template: new T({
en: 'Some other valve(s): $$$',
nl: 'Een ander type ventiel(en): $$$',
fr: 'Autre(s) type(s) de valve(s): $$$',
gl: 'Algunha outra válvula: $$$',
de: 'Andere(s) Ventil(e): $$$'
})
},
},
shop: {
name: new T({
en: "bike repair/shop",
nl: "fietszaak",
fr: "magasin ou réparateur de vélo",
gl: "tenda/arranxo de bicicletas",
de: "fahrradwerkstatt/geschäft"
}),
title: new T({
en: "Bike repair/shop",
nl: "Fietszaak",
fr: "Magasin et réparateur de vélo",
gl: "Tenda/arranxo de bicicletas",
de: "Fahrradwerkstatt/geschäft"
}),
titleRepair: new T({
en: "Bike repair",
nl: "Fietsenmaker",
fr: "Réparateur de vélo",
gl: "Arranxo de bicicletas",
de: "Fahrradwerkstatt"
}),
titleShop: new T({
en: "Bike shop",
nl: "Fietswinkel",
fr: "Magasin de vélo",
gl: "Tenda de bicicletas",
de: "Fahrradgeschäft"
}),
titleNamed: new T({
en: "Bike repair/shop {name}",
nl: "Fietszaak {name}",
fr: "Magasin et réparateur de vélo {name}",
gl: "Tenda/arranxo de bicicletas {name}",
de: "Fahrradwerkstatt/geschäft {name}"
}),
titleRepairNamed: new T({
en: "Bike repair {name}",
nl: "Fietsenmaker {name}",
fr: "Réparateur de vélo {name}",
gl: "Arranxo de bicicletas {name}",
de: "Fahrradwerkstatt {name}"
}),
titleShopNamed: new T({
en: "Bike shop {name}",
nl: "Fietswinkel {name}",
fr: "Magasin de vélo {name}",
gl: "Tenda de bicicletas {name}",
de: "Fahrradgeschäft {name}"
}),
retail: {
question: new T({
en: "Does this shop sell bikes?",
nl: "Verkoopt deze winkel fietsen?",
fr: "Est-ce que ce magasin vend des vélos?",
gl: "Esta tenda vende bicicletas?",
de: "Verkauft dieser Laden Fahrräder?"
}),
yes: new T({
en: "This shop sells bikes",
nl: "Deze winkel verkoopt fietsen",
fr: "Ce magasin vend des vélos",
gl: "Esta tenda vende bicicletas",
de: "Dieses Geschäft verkauft Fahrräder"
}),
no: new T({
en: "This shop doesn't sell bikes",
nl: "Deze winkel verkoopt geen fietsen",
fr: "Ce magasin ne vend pas de vélo",
gl: "Esta tenda non vende bicicletas",
de: "Dieses Geschäft verkauft keine Fahrräder"
}),
},
repair: {
question: new T({
en: "Does this shop repair bikes?",
nl: "Herstelt deze winkel fietsen?",
fr: "Est-ce que ce magasin répare des vélos?",
gl: "Esta tenda arranxa bicicletas?",
de: "Repariert dieses Geschäft Fahrräder?"
}),
yes: new T({
en: "This shop repairs bikes",
nl: "Deze winkel herstelt fietsen",
fr: "Ce magasin répare des vélos",
gl: "Esta tenda arranxa bicicletas",
de: "Dieses Geschäft repariert Fahrräder",
}),
no: new T({
en: "This shop doesn't repair bikes",
nl: "Deze winkel herstelt geen fietsen",
fr: "Ce magasin ne répare pas les vélos",
gl: "Esta tenda non arranxa bicicletas",
de: "Dieses Geschäft repariert keine Fahrräder"
}),
sold: new T({
en: "This shop only repairs bikes bought here",
nl: "Deze winkel herstelt enkel fietsen die hier werden gekocht",
fr: "Ce magasin ne répare seulement les vélos achetés là-bas",
gl: "Esta tenda só arranxa bicicletas mercadas aquí",
de: "Dieses Geschäft repariert nur hier gekaufte Fahrräder"
}),
brand: new T({
en: "This shop only repairs bikes of a certain brand",
nl: "Deze winkel herstelt enkel fietsen van een bepaald merk",
fr: "Ce magasin ne répare seulement des marques spécifiques",
gl: "Esta tenda só arranxa bicicletas dunha certa marca",
de: "Dieses Geschäft repariert nur Fahrräder einer bestimmten Marke"
}),
},
rental: {
question: new T({
en: "Does this shop rent out bikes?",
nl: "Verhuurt deze winkel fietsen?",
fr: "Est-ce ce magasin loue des vélos?",
gl: "Esta tenda aluga bicicletas?",
de: "Vermietet dieser Laden Fahrräder?"
}),
yes: new T({
en: "This shop rents out bikes",
nl: "Deze winkel verhuurt fietsen",
fr: "Ce magasin loue des vélos",
gl: "Esta tenda aluga bicicletas",
de: "Dieses Geschäft vermietet Fahrräder"
}),
no: new T({
en: "This shop doesn't rent out bikes",
nl: "Deze winkel verhuurt geen fietsen",
fr: "Ce magasin ne loue pas de vélos",
gl: "Esta tenda non aluga bicicletas",
de: "Dieses Geschäft vermietet keine Fahrräder"
}),
},
pump: {
question: new T({
en: "Does this shop offer a bike pump for use by anyone?",
nl: "Biedt deze winkel een fietspomp aan voor iedereen?",
fr: "Est-ce que ce magasin offre une pompe en accès libre?",
gl: "Esta tenda ofrece unha bomba de ar para uso de calquera persoa?",
de: "Bietet dieses Geschäft eine Fahrradpumpe zur Benutzung für alle an?"
}),
yes: new T({
en: "This shop offers a bike pump for anyone",
nl: "Deze winkel biedt geen fietspomp aan voor eender wie",
fr: "Ce magasin offre une pompe en acces libre",
gl: "Esta tenda ofrece unha bomba de ar para uso de calquera persoa",
de: "Dieses Geschäft bietet eine Fahrradpumpe für alle an"
}),
no: new T({
en: "This shop doesn't offer a bike pump for anyone",
nl: "Deze winkel biedt een fietspomp aan voor iedereen",
fr: "Ce magasin n'offre pas de pompe en libre accès",
gl: "Esta tenda non ofrece unha bomba de ar para uso de calquera persoa",
de: "Dieses Geschäft bietet für niemanden eine Fahrradpumpe an"
})
},
qName: {
question: new T({
en: "What is the name of this bicycle shop?",
nl: "Wat is de naam van deze fietszaak?",
fr: "Quel est le nom du magasin de vélo?",
gl: "Cal é o nome desta tenda de bicicletas?",
de: "Wie heißt dieser Fahrradladen?"
}),
render: new T({
en: "This bicycle shop is called {name}",
nl: "Deze fietszaak heet {name}",
fr: "Ce magasin s'appelle {name}",
gl: "Esta tenda de bicicletas chámase {name}",
de: "Dieses Fahrradgeschäft heißt {name}",
}),
template: new T({
en: "This bicycle shop is called: $$$",
nl: "Deze fietszaak heet: <b>$$$</b>",
fr: "Ce magasin s'appelle $$$",
gl: "Esta tenda de bicicletas chámase: $$$",
de: "Dieses Fahrradgeschäft heißt: $$$"
})
},
secondHand: {
question: new T({
en: "Does this shop sell second-hand bikes?",
nl: "Verkoopt deze winkel tweedehands fietsen?",
fr: "Est-ce ce magasin vend des vélos d'occasion",
gl: "Esta tenda vende bicicletas de segunda man?",
de: "Verkauft dieses Geschäft gebrauchte Fahrräder?"
}),
yes: new T({
en: "This shop sells second-hand bikes",
nl: "Deze winkel verkoopt tweedehands fietsen",
fr: "Ce magasin vend des vélos d'occasion",
gl: "Esta tenda vende bicicletas de segunda man",
de: "Dieses Geschäft verkauft gebrauchte Fahrräder"
}),
no: new T({
en: "This shop doesn't sell second-hand bikes",
nl: "Deze winkel verkoopt geen tweedehands fietsen",
fr: "Ce magasin ne vend pas de vélos d'occasion",
gl: "Esta tenda non vende bicicletas de segunda man",
de: "Dieses Geschäft verkauft keine gebrauchten Fahrräder"
}),
only: new T({
en: "This shop only sells second-hand bikes",
nl: "Deze winkel verkoopt enkel tweedehands fietsen",
fr: "Ce magasin vend seulement des vélos d'occasion",
gl: "Esta tenda só vende bicicletas de segunda man",
de: "Dieses Geschäft verkauft nur gebrauchte Fahrräder"
}),
},
diy: {
question: new T({
en: "Are there tools here to repair your own bike?",
nl: "Biedt deze winkel gereedschap aan om je fiets zelf te herstellen?",
fr: "Est-ce qu'il y a des outils pour réparer son vélo dans ce magasin?",
gl: "Hai ferramentas aquí para arranxar a túa propia bicicleta?",
de: "Gibt es hier Werkzeuge, um das eigene Fahrrad zu reparieren?"
}),
yes: new T({
en: "This shop offers tools for DIY repair",
nl: "Deze winkel biedt gereedschap aan om je fiets zelf te herstellen",
fr: "Ce magasin offre des outils pour réparer son vélo soi-même",
gl: "Hai ferramentas aquí para arranxar a túa propia bicicleta",
de: "Dieses Geschäft bietet Werkzeuge für die Heimwerkerreparatur an"
}),
no: new T({
en: "This shop doesn't offer tools for DIY repair",
nl: "Deze winkel biedt geen gereedschap aan om je fiets zelf te herstellen",
fr: "Ce magasin n'offre pas des outils pour réparer son vélo soi-même",
gl: "Non hai ferramentas aquí para arranxar a túa propia bicicleta",
de: "Dieses Geschäft bietet keine Werkzeuge für Heimwerkerreparaturen an"
}),
}
},
nonBikeShop: {
name: new T({
en: "shop that sells/repairs bikes",
nl: "winkel die fietsen verkoopt/herstelt",
fr: "magasin qui repare/vend des vélos",
gl: "tenda que vende/arranxa bicicletas",
de: "geschäft, das Fahrräder verkauft/repariert"
}),
title: new T({
en: "Shop that sells/repairs bikes",
nl: "Winkel die fietsen verkoopt/herstelt",
fr: "Magasin qui répare/vend des vélos",
gl: "Tenda que vende/arranxa bicicletas",
de: "Geschäft, das Fahrräder verkauft/repariert"
}),
titleRepair: new T({
en: "Shop that repairs bikes",
nl: "Winkel die fietsen herstelt",
fr: "Magasin qui répare les vélos",
gl: "Tenda que arranxa bicicletas",
de: "Geschäft, das Fahrräder repariert"
}),
titleShop: new T({
en: "Shop that sells bikes",
nl: "Winkel die fietsen verkoopt",
fr: "Magasin qui vend des vélos",
gl: "Tenda que vende bicicletas",
de: "Geschäft, das Fahrräder verkauft"
}),
titleNamed: new T({
en: "{name} (sells/repairs bikes)",
nl: "{name} (verkoopt/herstelt fietsen)",
fr: "vend/repare les vélos",
gl: "{name} (vende/arranxa bicicletas)",
de: "{name} (verkauft/repariert Fahrräder)"
}),
titleRepairNamed: new T({
en: "{name} (repairs bikes)",
nl: "{name} (herstelt fietsen)",
fr: "{name} (répare les vélos)",
gl: "{name} (arranxa bicicletas)",
de: "{name} (repariert Fahrräder)"
}),
titleShopNamed: new T({
en: "{name} (sells bikes)",
nl: "{name} (verkoopt fietsen)",
fr: "{name} (vend des vélos)",
gl: "{name} (vende bicicletas)",
de: "{name} (verkauft Fahrräder)"
}),
}
},
image: { image: {
addPicture: new T({ addPicture: new T({
en: 'Add picture', en: 'Add picture',
@ -753,6 +379,10 @@ export default class Translations {
fr: "Ajouter un/une {category} ici", fr: "Ajouter un/une {category} ici",
gl: "Engadir {category} aquí", gl: "Engadir {category} aquí",
de: "Hier eine {category} hinzufügen" de: "Hier eine {category} hinzufügen"
}),
layerNotEnabled: new T({
"en":"The layer {layer} is not enabled. Enable this layer to add a point",
"nl":"De laag {layer} is gedeactiveerd. Activeer deze om een punt toe te voegn"
}) })
}, },
pickLanguage: new T({ pickLanguage: new T({
@ -851,7 +481,7 @@ export default class Translations {
}, },
openStreetMapIntro: new T({ openStreetMapIntro: new T({
en: "<h3>An Open Map</h3>" + en: "<h3>An Open Map</h3>" +
"<p>Wouldn't it be cool if there was a single map, which everyone could freely use and edit?" + "<p>Wouldn't it be cool if there was a single map, which everyone could freely use and edit? " +
"A single place to store all geo-information? Then, all those websites with different, small and incompatible maps (which are always outdated) wouldn't be needed anymore.</p>" + "A single place to store all geo-information? Then, all those websites with different, small and incompatible maps (which are always outdated) wouldn't be needed anymore.</p>" +
"<p><b><a href='https://OpenStreetMap.org' target='_blank'>OpenStreetMap</a></b> is this map. The map data can be used for free (with <a href='https://osm.org/copyright' target='_blank'>attribution and publication of changes to that data</a>)." + "<p><b><a href='https://OpenStreetMap.org' target='_blank'>OpenStreetMap</a></b> is this map. The map data can be used for free (with <a href='https://osm.org/copyright' target='_blank'>attribution and publication of changes to that data</a>)." +
" On top of that, everyone can freely add new data and fix errors. This website uses OpenStreetMap as well. All the data is from there, and your answers and corrections are added there as well.</p>" + " On top of that, everyone can freely add new data and fix errors. This website uses OpenStreetMap as well. All the data is from there, and your answers and corrections are added there as well.</p>" +
@ -872,7 +502,7 @@ export default class Translations {
"<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." + "<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>", "Si canvies alguna cosa aquí també es reflectirà en aquestes aplicacions en la seva propera actualització.</p>",
nl: "<h3>Een open kaart</h3>" + 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 iedereen zijn interesses aan zou kunnen toevoegen? " + "<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>" + "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. " + "<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>" + "Ook deze website is gebaseerd op OpenStreetMap. Als je hier een vraag beantwoord, gaat het antwoord daar ook naartoe</p>" +
@ -1165,6 +795,10 @@ export default class Translations {
"en": "Background map", "en": "Background map",
"nl": "Achtergrondkaart", "nl": "Achtergrondkaart",
"de": "Hintergrundkarte" "de": "Hintergrundkarte"
}),
zoomInToSeeThisLayer: new T({
"nl":"Vergroot de kaart om deze laag te zien",
"en":"Zoom in to see this layer"
}) })
}, },
favourite: { favourite: {

View file

@ -1,5 +0,0 @@
<svg width="98" height="123" viewBox="0 0 98 123" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M54.0445 113.094C52.2614 116.981 46.7386 116.981 44.9555 113.094L14.2124 46.085C12.6928 42.7729 15.1129 39 18.7569 39L80.2431 39C83.8871 39 86.3072 42.7729 84.7876 46.085L54.0445 113.094Z" fill="#AB76D5"/>
<circle cx="49" cy="49" r="49" fill="#AB76D5"/>
<path d="M75.163 23.5441C68.1745 16.7447 58.883 13 49 13C39.117 13 29.8255 16.7447 22.837 23.5441C15.8487 30.3437 12 39.3841 12 49C12 58.6159 15.8487 67.6563 22.837 74.4559C29.8255 81.2553 39.117 85 49 85C58.883 85 68.1745 81.2553 75.163 74.4559C82.1513 67.6563 86 58.6159 86 49C86 39.3841 82.1513 30.3437 75.163 23.5441ZM49 22.8438C53.3832 22.8438 56.9492 26.3134 56.9492 30.5781C56.9492 34.8429 53.3832 38.3125 49 38.3125C44.6168 38.3125 41.0508 34.8429 41.0508 30.5781C41.0508 26.3134 44.6168 22.8438 49 22.8438ZM59.1172 72.0625H38.8828V67.8438H43.2188V46.75H38.8828V42.5312H54.7812V67.8438H59.1172V72.0625Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 995 B

View file

@ -191,7 +191,11 @@
"gl": "Cal é o enderezo de correo electrónico de {name}?", "gl": "Cal é o enderezo de correo electrónico de {name}?",
"de": "Wie lautet die E-Mail-Adresse von {name}?" "de": "Wie lautet die E-Mail-Adresse von {name}?"
}, },
"render": "<a href='mailto:{email}' target='_blank'>{email}</a>" "render": "<a href='mailto:{email}' target='_blank'>{email}</a>",
"freeform": {
"key": "email",
"type": "email"
}
} }
], ],
"hideUnderlayingFeaturesMinPercentage": 0, "hideUnderlayingFeaturesMinPercentage": 0,

View file

@ -0,0 +1,468 @@
{
"id": "bike_shops",
"name": {
"en": "Bike repair/shop",
"nl": "Fietszaak",
"fr": "Magasin ou réparateur de vélo",
"gl": "Tenda/arranxo de bicicletas",
"de": "Fahrradwerkstatt/geschäft"
},
"minzoom": 13,
"overpassTags": {
"#": "We select all bicycle shops, sport shops (but we try to weed out non-bicycle related shops), and any shop with a bicycle related tag",
"or": [
"shop=bicycle",
{
"#": "if sport is defined and is not bicycle, it is retrackted; if bicycle retail/repair is marked as 'no', it is retracted too.",
"##": "There will be a few false-positives with this. They will get filtered out by people marking both 'not selling bikes' and 'not repairing bikes'. Furthermore, the OSMers will add a sports-subcategory on it",
"and": [
"shop=sports",
"service:bicycle:retail!=no",
"service:bicycle:repair!=no",
{
"or": [
"sport=bicycle",
"sport=cycling",
"sport="
]
}
]
},
{
"#": "Any shop with any bicycle service",
"and": [
"shop~*",
"service:bicycle:.*~~.*"
]
}
]
},
"title": {
"render": {
"en": "Bike repair/shop",
"nl": "Fietszaak",
"fr": "Magasin ou réparateur de vélo",
"gl": "Tenda/arranxo de bicicletas",
"de": "Fahrradwerkstatt/geschäft"
},
"mappings": [
{
"if": {
"and": [
"shop=sports",
"name~*"
]
},
"then": {
"en": "Sport gear shop <i>{name}</i>",
"nl": "Sportwinkel <i>{name}</i>",
"fr": "Magasin de sport <i>{name}</i>"
}
},
{
"if": "shop=sports",
"then": {
"en": "Sport gear shop",
"nl": "Sportwinkel",
"fr": "Magasin de sport"
}
},
{
"if": "shop!~bicycle",
"then": "Other shop"
},
{
"if": {
"and": [
"name~*",
"service:bicycle:retail!~yes",
"service:bicycle:repair!~no"
]
},
"then": {
"en": "Bike repair <i>{name}</i>",
"nl": "Fietsenmaker <i>{name}</i>",
"fr": "Réparateur de vélo <i>{name}</i>",
"gl": "Arranxo de bicicletas <i>{name}</i>",
"de": "Fahrradwerkstatt <i>{name}</i>"
}
},
{
"if": {
"and": [
"service:bicycle:retail!~yes",
"service:bicycle:repair!~no"
]
},
"then": {
"en": "Bike repair",
"nl": "Fietsenmaker",
"fr": "Réparateur de vélo",
"gl": "Arranxo de bicicletas",
"de": "Fahrradwerkstatt"
}
},
{
"if": {
"and": [
"name~*",
"service:bicycle:repair!~yes"
]
},
"then": {
"en": "Bike shop <i>{name}</i>",
"nl": "Fietswinkel <i>{name}</i>",
"fr": "Magasin de vélo <i>{name}</i>",
"gl": "Tenda de bicicletas <i>{name}</i>",
"de": "Fahrradgeschäft <i>{name}</i>"
}
},
{
"if": "service:bicycle:repair!~yes",
"then": {
"en": "Bike shop",
"nl": "Fietswinkel",
"fr": "Magasin de vélo",
"gl": "Tenda de bicicletas",
"de": "Fahrradgeschäft"
}
},
{
"if": "name~*",
"then": {
"en": "Bike repair/shop <i>{name}</i>",
"nl": "Fietszaak <i>{name}</i>",
"fr": "Magasin ou réparateur de vélo <i>{name}</i>",
"gl": "Tenda/arranxo de bicicletas <i>{name}</i>",
"de": "Fahrradwerkstatt/geschäft <i>{name}</i>"
}
}
]
},
"description": {
"en": "A shop specifically selling bicycles or related items",
"nl": "Een winkel die hoofdzakelijk fietsen en fietstoebehoren verkoopt"
},
"tagRenderings": [
"images",
{
"condition": {
"and": [
"shop!~bicycle",
"shop!~sports"
]
},
"render": {
"en": "This shop is specialized in selling {shop} and does bicycle related activities",
"nl": "Deze winkel verkoopt {shop} en heeft fiets-gerelateerde activiteiten."
}
},
{
"question": {
"en": "What is the name of this bicycle shop?",
"nl": "Wat is de naam van deze fietszaak?",
"fr": "Quel est le nom du magasin de vélo?",
"gl": "Cal é o nome desta tenda de bicicletas?",
"de": "Wie heißt dieser Fahrradladen?"
},
"render": {
"en": "This bicycle shop is called {name}",
"nl": "Deze fietszaak heet {name}",
"fr": "Ce magasin s'appelle {name}",
"gl": "Esta tenda de bicicletas chámase {name}",
"de": "Dieses Fahrradgeschäft heißt {name}"
},
"freeform": {
"key": "name"
}
},
{
"question": {
"en": "What is the website of {name}?",
"nl": "Wat is de website van {name}?",
"fr": "Quel est le site internet de {name}?",
"gl": "Cal é a páxina web de {name}?"
},
"render": "<a href='{website}' target='_blank'>{website}</a>",
"freeform": {
"key": "website"
}
},
{
"question": {
"en": "What is the phone number of {name}?",
"nl": "Wat is het telefoonnummer van {name}?",
"fr": "Quel est le nom de {name}?",
"gl": "Cal é o número de teléfono de {name}?"
},
"render": "<a href='tel:{phone}'>{phone}</a>",
"freeform": {
"key": "phone",
"type": "phone"
}
},
{
"question": {
"en": "What is the email address of {name}?",
"nl": "Wat is het email-adres van {name}?",
"fr": "Quel est l'adresse email de {name}?",
"gl": "Cal é o enderezo de correo electrónico de {name}?"
},
"render": "<a href='mailto:{email}' target='_blank'>{email}</a>",
"freeform": {
"key": "email",
"type": "email"
}
},
{
"question": {
"en": "Does this shop sell bikes?",
"nl": "Verkoopt deze fietszaak fietsen?",
"fr": "Est-ce que ce magasin vend des vélos?",
"gl": "Esta tenda vende bicicletas?",
"de": "Verkauft dieser Laden Fahrräder?"
},
"mappings": [
{
"if": "service:bicycle:retail=yes",
"then": {
"en": "This shop sells bikes",
"nl": "Deze winkel verkoopt fietsen",
"fr": "Ce magasin vend des vélos",
"gl": "Esta tenda vende bicicletas",
"de": "Dieses Geschäft verkauft Fahrräder"
}
},
{
"if": "service:bicycle:retail=no",
"then": {
"en": "This shop doesn't sell bikes",
"nl": "Deze winkel verkoopt geen fietsen",
"fr": "Ce magasin ne vend pas de vélo",
"gl": "Esta tenda non vende bicicletas",
"de": "Dieses Geschäft verkauft keine Fahrräder"
}
}
]
},
{
"question": {
"en": "Does this shop repair bikes?",
"nl": "Herstelt deze winkel fietsen?",
"fr": "Est-ce que ce magasin répare des vélos?",
"gl": "Esta tenda arranxa bicicletas?",
"de": "Repariert dieses Geschäft Fahrräder?"
},
"mappings": [
{
"if": "service:bicycle:repair=yes",
"then": {
"en": "This shop repairs bikes",
"nl": "Deze winkel herstelt fietsen",
"fr": "Ce magasin répare des vélos",
"gl": "Esta tenda arranxa bicicletas",
"de": "Dieses Geschäft repariert Fahrräder"
}
},
{
"if": "service:bicycle:repair=no",
"then": {
"en": "This shop doesn't repair bikes",
"nl": "Deze winkel herstelt geen fietsen",
"fr": "Ce magasin ne répare pas les vélos",
"gl": "Esta tenda non arranxa bicicletas",
"de": "Dieses Geschäft repariert keine Fahrräder"
}
},
{
"if": "service:bicycle:repair=only_sold",
"then": {
"en": "This shop only repairs bikes bought here",
"nl": "Deze winkel herstelt enkel fietsen die hier werden gekocht",
"fr": "Ce magasin ne répare seulement les vélos achetés là-bas",
"gl": "Esta tenda só arranxa bicicletas mercadas aquí",
"de": "Dieses Geschäft repariert nur hier gekaufte Fahrräder"
}
},
{
"if": "service:bicycle:repair=brand",
"then": {
"en": "This shop only repairs bikes of a certain brand",
"nl": "Deze winkel herstelt enkel fietsen van een bepaald merk",
"fr": "Ce magasin ne répare seulement des marques spécifiques",
"gl": "Esta tenda só arranxa bicicletas dunha certa marca",
"de": "Dieses Geschäft repariert nur Fahrräder einer bestimmten Marke"
}
}
]
},
{
"question": {
"en": "Does this shop rent out bikes?",
"nl": "Verhuurt deze winkel fietsen?",
"fr": "Est-ce ce magasin loue des vélos?",
"gl": "Esta tenda aluga bicicletas?",
"de": "Vermietet dieser Laden Fahrräder?"
},
"mappings": [
{
"if": "service:bicycle:rental=yes",
"then": {
"en": "This shop rents out bikes",
"nl": "Deze winkel verhuurt fietsen",
"fr": "Ce magasin loue des vélos",
"gl": "Esta tenda aluga bicicletas",
"de": "Dieses Geschäft vermietet Fahrräder"
}
},
{
"if": "service:bicycle:rental=no",
"then": {
"en": "This shop doesn't rent out bikes",
"nl": "Deze winkel verhuurt geen fietsen",
"fr": "Ce magasin ne loue pas de vélos",
"gl": "Esta tenda non aluga bicicletas",
"de": "Dieses Geschäft vermietet keine Fahrräder"
}
}
]
},
{
"question": {
"en": "Does this shop sell second-hand bikes?",
"nl": "Verkoopt deze winkel tweedehands fietsen?",
"fr": "Est-ce ce magasin vend des vélos d'occasion",
"gl": "Esta tenda vende bicicletas de segunda man?",
"de": "Verkauft dieses Geschäft gebrauchte Fahrräder?"
},
"mappings": [
{
"if": "service:bicycle:second_hand=yes",
"then": {
"en": "This shop sells second-hand bikes",
"nl": "Deze winkel verkoopt tweedehands fietsen",
"fr": "Ce magasin vend des vélos d'occasion",
"gl": "Esta tenda vende bicicletas de segunda man",
"de": "Dieses Geschäft verkauft gebrauchte Fahrräder"
}
},
{
"if": "service:bicycle:second_hand=no",
"then": {
"en": "This shop doesn't sell second-hand bikes",
"nl": "Deze winkel verkoopt geen tweedehands fietsen",
"fr": "Ce magasin ne vend pas de vélos d'occasion",
"gl": "Esta tenda non vende bicicletas de segunda man",
"de": "Dieses Geschäft verkauft keine gebrauchten Fahrräder"
}
},
{
"if": "service:bicycle:second_hand=only",
"then": {
"en": "This shop only sells second-hand bikes",
"nl": "Deze winkel verkoopt enkel tweedehands fietsen",
"fr": "Ce magasin vend seulement des vélos d'occasion",
"gl": "Esta tenda só vende bicicletas de segunda man",
"de": "Dieses Geschäft verkauft nur gebrauchte Fahrräder"
}
}
]
},
{
"question": {
"en": "Does this shop offer a bike pump for use by anyone?",
"nl": "Biedt deze winkel een fietspomp aan voor iedereen?",
"fr": "Est-ce que ce magasin offre une pompe en accès libre?",
"gl": "Esta tenda ofrece unha bomba de ar para uso de calquera persoa?",
"de": "Bietet dieses Geschäft eine Fahrradpumpe zur Benutzung für alle an?"
},
"mappings": [
{
"if": "service:bicycle:pump=yes",
"then": {
"en": "This shop offers a bike pump for anyone",
"nl": "Deze winkel biedt een fietspomp aan voor iedereen",
"fr": "Ce magasin offre une pompe en acces libre",
"gl": "Esta tenda ofrece unha bomba de ar para uso de calquera persoa",
"de": "Dieses Geschäft bietet eine Fahrradpumpe für alle an"
}
},
{
"if": "service:bicycle:pump=no",
"then": {
"en": "This shop doesn't offer a bike pump for anyone",
"nl": "Deze winkel biedt geen fietspomp aan voor eender wie",
"fr": "Ce magasin n'offre pas de pompe en libre accès",
"gl": "Esta tenda non ofrece unha bomba de ar para uso de calquera persoa",
"de": "Dieses Geschäft bietet für niemanden eine Fahrradpumpe an"
}
}
]
},
{
"question": {
"en": "Are there tools here to repair your own bike?",
"nl": "Biedt deze winkel gereedschap aan om je fiets zelf te herstellen?",
"fr": "Est-ce qu'il y a des outils pour réparer son vélo dans ce magasin?",
"gl": "Hai ferramentas aquí para arranxar a túa propia bicicleta?",
"de": "Gibt es hier Werkzeuge, um das eigene Fahrrad zu reparieren?"
},
"mappings": [
{
"if": "service:bicycle:diy=yes",
"then": {
"en": "This shop offers tools for DIY repair",
"nl": "Deze winkel biedt gereedschap aan om je fiets zelf te herstellen",
"fr": "Ce magasin offre des outils pour réparer son vélo soi-même",
"gl": "Hai ferramentas aquí para arranxar a túa propia bicicleta",
"de": "Dieses Geschäft bietet Werkzeuge für die Heimwerkerreparatur an"
}
},
{
"if": "service:bicycle:diy=no",
"then": {
"en": "This shop doesn't offer tools for DIY repair",
"nl": "Deze winkel biedt geen gereedschap aan om je fiets zelf te herstellen",
"fr": "Ce magasin n'offre pas des outils pour réparer son vélo soi-même",
"gl": "Non hai ferramentas aquí para arranxar a túa propia bicicleta",
"de": "Dieses Geschäft bietet keine Werkzeuge für Heimwerkerreparaturen an"
}
}
]
}
],
"hideUnderlayingFeaturesMinPercentage": 1,
"presets": [
{
"title": {
"en": "Bike repair/shop",
"nl": "Fietszaak",
"fr": "Magasin et réparateur de vélo",
"gl": "Tenda/arranxo de bicicletas",
"de": "Fahrradwerkstatt/geschäft"
},
"tags": [
"shop=bicycle"
]
}
],
"icon": {
"render": "./assets/layers/bike_shop/repair_shop.svg",
"mappings": [
{
"if": "service:bicycle:retail=yes",
"then": "./assets/layers/bike_shop/shop.svg"
}
]
},
"width": {
"render": "1"
},
"iconSize": {
"render": "50,50,bottom"
},
"color": {
"render": "#c00"
},
"wayHandling": 2
}

View file

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View file

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -6,7 +6,7 @@
"fr": "Objet cycliste", "fr": "Objet cycliste",
"de": "Mit Fahrrad zusammenhängendes Objekt" "de": "Mit Fahrrad zusammenhängendes Objekt"
}, },
"minzoom": 14, "minzoom": 13,
"overpassTags": "theme~cycling|bicycle", "overpassTags": "theme~cycling|bicycle",
"title": { "title": {
"render": { "render": {

7
assets/statistics.svg Normal file
View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
<metadata> Svg Vector Icons : http://www.onlinewebfonts.com/icon </metadata>
<g><path d="M255,567.4v312.4h147V567.4l-73.5-61.3L255,567.4L255,567.4z M10,879.8h147V640.9L10,757.3V879.8L10,879.8z M745,493.9v385.9h147V371.4L745,493.9L745,493.9z M500,647v232.8h147V573.5l-116.4,98L500,647L500,647z M990,120.3H708.3l116.4,110.2l-300.1,245l-196-165.4L10,561.3v110.2l318.5-251.1l202.1,165.4l361.4-294l98,91.9L990,120.3L990,120.3z"/></g>
</svg>

After

Width:  |  Height:  |  Size: 833 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

View file

@ -0,0 +1,557 @@
{
"id": "buurtnatuur",
"title": {
"nl": "Breng jouw buurtnatuur in kaart"
},
"shortDescription": {
"nl": "Met deze tool kan je natuur in je buurt in kaart brengen en meer informatie geven over je favoriete plekje"
},
"description": {
"nl": "<img style='float:right;margin: 1em;width: 10em;height: auto;' src='./assets/themes/buurtnatuur/groen_logo.svg' alt='logo-groen' class='logo'> <br /><b>Natuur maakt gelukkig.</b> Aan de hand van deze website willen we de natuur dicht bij ons beter inventariseren. Met als doel meer mensen te laten genieten van toegankelijke natuur én te strijden voor meer natuur in onze buurten. \n<ul><li>In welke natuurgebieden kan jij terecht? Hoe toegankelijk zijn ze?</li><li>In welke bossen kan een gezin in jouw gemeente opnieuw op adem komen?</li><li>Op welke onbekende plekjes is het zalig spelen?</li></ul><p>Samen kleuren we heel Vlaanderen en Brussel groen.</p>Blijf op de hoogte van de resultaten van buurtnatuur.be: <a href=\"https://www.groen.be/buurtnatuur\" target='_blank'>meld je aan voor e-mailupdates</a>."},
"descriptionTail":{"nl":"<h4>Tips</h4><ul><li>Over groen ingekleurde gebieden weten we alles wat we willen weten.</li><li>Bij rood ingekleurde gebieden ontbreekt nog heel wat info: klik een gebied aan en beantwoord de vragen.</li><li>Je kan altijd een vraag overslaan als je het antwoord niet weet of niet zeker bent</li><li>Je kan altijd een foto toevoegen</li><li>Je kan ook zelf een gebied toevoegen door op de kaart te klikken</li><li>Open buurtnatuur.be <b>op je smartphone</b> om al wandelend foto's te maken en vragen te beantwoorden</li></ul><small><p>De oorspronkelijke data komt van <b>OpenStreetMap</b> en je antwoorden worden daar bewaard.<br/> Omdat iedereen vrij kan meewerken aan dit project, kunnen we niet garanderen dat er geen fouten opduiken.Kan je hier niet aanpassen wat je wilt, dan kan je dat zelf via OpenStreetMap.org doen. Groen kan <b>geen enkele verantwoordelijkheid</b> nemen over de kaart.</p>Je privacy is belangrijk. We tellen wel hoeveel gebruikers deze website bezoeken. We plaatsen een cookie waar geen persoonlijke informatie in bewaard wordt. Als je inlogt, komt er een tweede cookie bij met je inloggegevens.</small>"
},
"language": [
"nl"
],
"maintainer": "",
"icon": "./assets/themes/buurtnatuur/groen_logo.svg",
"version": "0",
"startLat": 50.8435,
"startLon": 4.3688,
"startZoom": 16,
"widenFactor": 0.05,
"socialImage": "./assets/themes/buurtnatuur/social_image.jpg",
"layers": [
{
"id": "nature_reserve",
"name": {
"nl": "Natuurgebied"
},
"minzoom": 12,
"overpassTags": {
"or": [
"leisure=nature_reserve",
"boundary=protected_area"
]
},
"title": {
"render": {
"nl": "Natuurgebied"
},
"mappings": [
{
"if": {
"and": [
"name:nl~"
]
},
"then": {
"nl": "{name:nl}"
}
},
{
"if": {
"and": [
"name~*"
]
},
"then": {
"nl": "{name}"
}
}
]
},
"description": {
"nl": "Een natuurgebied is een gebied waar actief ruimte gemaakt word voor de natuur. Typisch zijn deze in beheer van Natuurpunt of het Agentschap Natuur en Bos of zijn deze erkend door de overheid."
},
"tagRenderings": [],
"hideUnderlayingFeaturesMinPercentage": 10,
"icon": {
"render": "./assets/themes/buurtnatuur/nature_reserve.svg",
"mappings": [
{
"#": "This is a little bit a hack to force a circle to be shown while keeping the icon in the 'new' menu",
"if": "id~node/[0-9]*",
"then": "$circle"
}
]
},
"width": {
"render": "5"
},
"iconSize": {
"render": "50,50,center"
},
"color": {
"render": "#3c3",
"mappings": [
{
"if": {
"and": [
"name=",
"noname=",
"operator=",
"access=",
"access:description=",
"leisure=park"
]
},
"then": "#cc1100"
},
{
"if": {
"and": [
"name=",
"noname="
]
},
"then": "#fccb37"
}
]
},
"presets": [
{
"tags": [
"leisure=nature_reserve",
"fixme=Toegevoegd met MapComplete, geometry nog uit te tekenen"
],
"title": {
"nl": "Natuurreservaat"
},
"description": {
"nl": "Voeg een ontbrekend, erkend natuurreservaat toe, bv. een gebied dat beheerd wordt door het ANB of natuurpunt"
}
}
]
},
{
"id": "parks",
"name": {
"nl": "Park"
},
"minzoom": 12,
"overpassTags": {
"or": [
"leisure=park",
"landuse=village_green"
]
},
"title": {
"render": {
"nl": "Park"
},
"mappings": [
{
"if": {
"and": [
"name:nl~"
]
},
"then": {
"nl": "{name:nl}"
}
},
{
"if": {
"and": [
"name~*"
]
},
"then": {
"nl": "{name}"
}
}
]
},
"description": {
"nl": "Een park is een publiek toegankelijke, groene ruimte binnen de stad. Ze is typisch ingericht voor recreatief gebruik, met (verharde) wandelpaden, zitbanken, vuilnisbakken, een gezellig vijvertje, ..."
},
"tagRenderings": [],
"hideUnderlayingFeaturesMinPercentage": 10,
"icon": {
"render": "./assets/themes/buurtnatuur/park.svg",
"mappings": [
{
"#": "This is a little bit a hack to force a circle to be shown while keeping the icon in the 'new' menu",
"if": "id~node/[0-9]*",
"then": "$circle"
}
]
},
"width": {
"render": "5"
},
"iconSize": {
"render": "40,40,center"
},
"color": {
"render": "#3c3",
"mappings": [
{
"if": {
"and": [
"name=",
"noname="
]
},
"then": "#fccb37"
}
]
},
"presets": [
{
"tags": [
"leisure=park",
"fixme=Toegevoegd met MapComplete, geometry nog uit te tekenen"
],
"title": {
"nl": "Park"
},
"description": {
"nl": "Voeg een ontbrekend park toe"
}
}
]
},
{
"id": "forest",
"name": {
"nl": "Bos"
},
"minzoom": 12,
"overpassTags": {
"or": [
"landuse=forest",
"natural=wood",
"natural=scrub"
]
},
"title": {
"render": {
"nl": "Bos"
},
"mappings": [
{
"if": {
"and": [
"name:nl~"
]
},
"then": {
"nl": "{name:nl}"
}
},
{
"if": {
"and": [
"name~*"
]
},
"then": {
"nl": "{name}"
}
}
]
},
"description": {
"nl": "Een bos is een verzameling bomen, al dan niet als productiehout."
},
"tagRenderings": [],
"hideUnderlayingFeaturesMinPercentage": 0,
"icon": {
"render": "./assets/themes/buurtnatuur/forest.svg",
"mappings": [
{
"#": "This is a little bit a hack to force a circle to be shown while keeping the icon in the 'new' menu",
"if": "id~node/[0-9]*",
"then": "$circle"
}
]
},
"width": {
"render": "5"
},
"iconSize": {
"render": "40,40,center"
},
"color": {
"render": "#3a3",
"mappings": [
{
"if": {
"and": [
"operator=",
"access=",
"access:description="
]
},
"then": "#cc1100"
},
{
"if": {
"and": [
"operator="
]
},
"then": "#cccc00"
},
{
"if": {
"and": [
"name=",
"noname="
]
},
"then": "#fccb37"
}
]
},
"presets": [
{
"tags": [
"landuse=forest",
"fixme=Toegevoegd met MapComplete, geometry nog uit te tekenen"
],
"title": {
"nl": "Bos"
},
"description": {
"nl": "Voeg een ontbrekend bos toe aan de kaart"
}
}
]
},
"viewpoint"
],
"roamingRenderings": [
{
"#": "Access tag",
"condition": {
"and": [
"tourism!~viewpoint"
]
},
"render": {
"nl": "De toegankelijkheid van dit gebied is: {access:description}"
},
"question": {
"nl": "Is dit gebied toegankelijk?"
},
"freeform": {
"key": "access:description"
},
"mappings": [
{
"if": {
"and": [
"access:description=",
"access=",
"leisure=park"
]
},
"then": {
"nl": "Dit gebied is vrij toegankelijk"
},
"hideInAnswer": true
},
{
"if": {
"and": [
"access=yes",
"fee="
]
},
"then": {
"nl": "Vrij toegankelijk"
}
},
{
"if": {
"and": [
"access=no",
"fee="
]
},
"then": {
"nl": "Niet toegankelijk"
}
},
{
"if": {
"and": [
"access=private",
"fee="
]
},
"then": {
"nl": "Niet toegankelijk, want privégebied"
}
},
{
"if": {
"and": [
"access=permissive",
"fee="
]
},
"then": {
"nl": "Toegankelijk, ondanks dat het privegebied is"
}
},
{
"if": {
"and": [
"access=guided",
"fee="
]
},
"then": {
"nl": "Enkel toegankelijk met een gids of tijdens een activiteit"
}
},
{
"if": {
"and": [
"access=yes",
"fee=yes"
]
},
"then": {
"nl": "Toegankelijk mits betaling"
}
}
]
},
{
"#": "Operator tag",
"render": {
"nl": "Beheer door {operator}"
},
"question": {
"nl": "Wie beheert dit gebied?"
},
"freeform": {
"key": "operator"
},
"mappings": [
{
"if": {
"and": [
"leisure=park",
"operator="
]
},
"then": "Beheer door de gemeente"
},
{
"if": {
"and": [
"operator=Natuurpunt"
]
},
"then": {
"nl": "<img src=\"./assets/themes/buurtnatuur/Natuurpunt.jpg\" style=\"width:1.5em\">Dit gebied wordt beheerd door Natuurpunt"
}
},
{
"if": {
"and": [
"operator~(n|N)atuurpunt.*"
]
},
"then": {
"nl": "<img src=\"./assets/themes/buurtnatuur/Natuurpunt.jpg\" style=\"width:1.5em\">Dit gebied wordt beheerd door {operator}"
},
"hideInAnswer": true
},
{
"if": {
"and": [
"operator=Agentschap Natuur en Bos"
]
},
"then": {
"nl": "<img src=\"./assets/themes/buurtnatuur/ANB.jpg\" style=\"width:1.5em\">Dit gebied wordt beheerd door het Agentschap Natuur en Bos"
}
}
],
"condition": {
"and": [
"leisure!~park",
"tourism!~viewpoint"
]
}
},
{
"#": "Name:nl-tag",
"render": {
"nl": "Dit gebied heet {name:nl}"
},
"question": {
"nl": "Wat is de Nederlandstalige naam van dit gebied?"
},
"freeform": {
"key": "name:nl"
},
"condition": {
"and": [
"name:nl~*",
"viewpoint!~tourism"
]
}
},
{
"#": "Name tag",
"render": {
"nl": "Dit gebied heet {name}"
},
"question": {
"nl": "Wat is de naam van dit gebied?"
},
"freeform": {
"key": "name",
"addExtraTags": [
"noname="
]
},
"condition": {
"and": [
"name:nl=",
"tourism!~viewpoint"
]
},
"mappings": [
{
"if": {
"and": [
"noname=yes",
"name="
]
},
"then": {
"nl": "Dit gebied heeft geen naam"
}
}
]
},
{
"#": "Non-editable description {description}",
"render": {
"nl": "Extra info: <i>{description}</i>"
},
"freeform": {
"key": "description"
}
},
{
"#": "Editable description {description:0}",
"question": "Is er extra info die je kwijt wil?",
"render": {
"nl": "Extra info via buurtnatuur.be: <i>{description:0}</i>"
},
"freeform": {
"key": "description:0"
}
}
]
}

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
<metadata> Svg Vector Icons : http://www.onlinewebfonts.com/icon </metadata>
<g><g transform="translate(0.000000,511.000000) scale(0.100000,-0.100000)"><path d="M3975.1,2900.8c-550.4-468.2-999.6-866.7-999.6-885.7c0-79.1,613.7-430.2,863.6-490.3c47.5-12.6,85.4-34.8,85.4-47.5c0-19-1309.6-1154.6-1483.6-1284.3c-41.1-31.6-41.1-47.5,6.3-120.2c82.3-123.4,449.2-354.3,781.3-490.3l291-120.2l-661.1-563.1c-879.4-749.7-790.8-654.8-708.6-771.9c230.9-319.5,1236.9-752.9,2015-860.4l265.7-38v-313.2v-313.2l151.8-66.4c208.8-94.9,626.3-94.9,838.3,0l148.7,66.4v313.2v313.2l259.4,38c790.8,120.2,1594.3,449.2,1948.6,790.8c72.8,72.7,132.9,142.3,132.9,155c0,15.8-322.7,300.5-714.9,635.8l-718.1,610.5l297.3,123.3C7227-230.8,7666.6,95,7574.9,177.2c-15.8,12.6-360.6,306.8-762.4,651.6c-404.9,341.6-737,635.8-737,648.5c0,12.7,38,34.8,88.6,47.5c246.8,60.1,860.4,411.2,860.4,490.3c0,34.8-1983.4,1739.8-2024.5,1739.8C4984.2,3754.9,4522.3,3372.2,3975.1,2900.8z"/><path d="M1558.3,2015.1c-420.7-363.8-768.7-673.8-771.9-686.4c-9.5-47.5,249.9-221.4,468.2-310c120.2-50.6,230.9-101.2,243.6-110.7c12.7-12.6-240.4-246.7-563.1-521.9S349.9-132.8,349.9-154.9c0-82.3,389.1-335.3,673.8-439.7c82.3-31.6,148.7-66.4,148.7-79.1c0-12.7-240.4-227.8-534.6-477.6C340.4-1401.3,100-1622.7,100-1644.9c-3.2-63.3,256.2-262.5,515.6-392.2c284.7-142.4,680.1-268.9,1009.1-325.8l227.8-37.9l15.8-249.9c15.8-253.1,15.8-253.1,126.5-306.8c79.1-41.1,186.6-56.9,363.8-56.9s284.7,15.8,363.8,56.9c98.1,47.5,110.7,69.6,120.2,196.1l6.3,142.3L2583.2-2480c-145.5,75.9-341.7,202.4-433.4,281.5c-161.3,145.5-344.8,392.3-344.8,471.3c0,22.1,246.7,249.9,547.2,502.9c297.4,256.2,578.9,496.6,620,534.6l72.8,72.7l-262.6,136c-294.2,151.9-594.7,423.9-654.8,588.4l-34.8,101.2l695.9,594.7l692.8,591.5l-234.1,123.4c-246.7,129.7-534.6,382.8-575.7,503c-15.8,53.8,0,88.6,85.4,158.2c56.9,47.5,98.1,91.7,88.6,98c-6.3,3.2-113.9,98.1-237.3,205.6c-126.5,107.6-240.4,196.1-253.1,193C2339.7,2676.2,1982.2,2378.9,1558.3,2015.1z"/><path d="M7499,2575c-63.3-53.8-167.6-148.7-234.1-205.6l-120.2-107.6l101.2-85.4c82.2-66.4,98-101.2,82.2-155c-41.1-120.2-329-373.3-575.7-503l-234.1-123.4l692.8-591.5l695.9-594.7l-34.8-101.2c-56.9-164.5-360.6-436.5-648.5-585.2c-145.5-75.9-262.5-139.2-262.5-145.5c0-6.3,278.4-246.7,616.9-537.8c338.5-287.9,616.8-540.9,616.8-559.9c0-202.5-477.7-639-911-832c-132.9-60.1-136-63.3-126.5-205.6c9.5-129.7,22.1-151.8,120.2-199.3c79.1-41.1,186.7-56.9,363.8-56.9c177.1,0,284.7,15.8,363.8,56.9c110.7,53.8,110.7,53.8,126.5,303.7l15.8,253.1l284.7,53.8c360.6,66.5,730.7,193,1002.8,335.3c227.8,120.2,468.2,310,465,366.9c0,22.1-240.4,243.6-537.8,493.5c-294.2,249.9-534.6,465-534.6,480.8c0,12.7,31.6,34.8,72.8,47.5c256.2,75.9,749.7,385.9,749.7,468.2c0,22.1-262.5,265.7-585.2,540.9s-575.7,509.3-563.1,521.9c12.6,9.5,123.3,60.1,243.6,110.7c237.3,98.1,480.8,265.7,461.8,316.3c-15.8,41.1-1543.7,1344.4-1572.2,1344.4C7619.2,2679.4,7559.1,2632,7499,2575z"/></g></g>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
<metadata> Svg Vector Icons : http://www.onlinewebfonts.com/icon </metadata>
<g><path d="M334.6,797.4c0,60.1,0,120.3,0,180.4c0,9.5,0,9.5-9.8,9.5c-26.3,0-52.7-0.3-79,0.2c-7.6,0.1-9.2-2.5-9.3-9.6c-0.4-117.1-0.9-234.3-1.7-351.4c0-5.8-1.6-12-4.2-17.1c-16.6-33.5-33.8-66.8-50.6-100.3c-2.4-4.9-5.3-6.9-10.9-7.4c-37.8-3.1-73.9-12-105.4-34.4C26.5,440.8,9.3,403.9,10,358.5c0.3-21.2,4.1-41.9,11.5-61.7c3.7-9.9,3.3-18.4-0.6-28.2c-12.4-31.8-14.7-64.5-3.3-97.1c16.1-45.7,49.5-72.7,95.6-84.4c12.3-3.1,25.2-4.3,37.9-5.2c6.4-0.5,10.6-2.8,14.5-7.6c21.9-26.6,48-47.6,81.7-57.3c42.1-12.2,80.5-4.3,114.1,23.5c10.8,8.9,19.6,20.5,28.7,31.4c3.4,4,6.5,6.2,11.8,6.9c33,4.2,65,11.9,94.5,28c44.6,24.4,68.9,71.8,60.6,122.2c-2.8,16.8-8.2,33.2-13.2,49.5c-1.7,5.7-2.1,10.4,0,15.9c10,25.8,14.9,52.6,10.8,80.2c-7.3,48.4-35.6,81.3-77.9,103.2c-26.2,13.6-54.2,20-83.8,19.3c-4.5-0.1-7,1.4-8.9,5.5c-15.8,34.2-31.9,68.3-47.6,102.5c-1.5,3.3-2.1,7.4-2.1,11.2C334.5,676.6,334.5,737,334.6,797.4z M245.3,514.5c-0.5,0.6-1,1.2-1.4,1.7c14.2,24.9,28.5,49.8,43.7,76.4c14.1-26.9,27.1-51.9,41.2-79C299.4,519,272.3,519.7,245.3,514.5z"/><path d="M719.2,987.9c2.8-12.9,5.5-25.3,8.3-37.7c12.8-56.7,25.7-113.5,38.6-170.2c1.2-5.1,0.3-7-5.2-7.1c-50.2-1-100.5-2.3-150.7-3.2c-3.2-0.1-7.5,2.2-9.4,4.8c-9.5,12.8-18.6,25.9-27.2,39.3c-1.7,2.6-1.9,7.4-0.8,10.4c19.7,51.4,39.7,102.7,59.7,154c0.9,2.4,1.8,4.9,3.2,8.9c-7.7,0.4-14.5,0.9-21.3,1.2c-16.1,0.7-16.1,0.7-21.7-14.2c-17.1-44.9-34.3-89.8-51.1-134.8c-2.3-6.1-5.2-8.4-11.7-6.8c-6.1,1.5-12.3,2.5-18.6,3c-6.9,0.5-9.1,3.4-9,10.5c0.4,43.5,0.2,87,0.2,130.4c0,10.9,0,10.9-11.2,10.9c-4.3,0-8.7-0.3-13,0.1c-6.2,0.6-7.7-2.1-7.7-7.9c0.2-34.3,0.1-68.6,0.1-102.9c0-18.6-0.2-37.2,0.2-55.8c0.1-3.6,1.9-8,4.4-10.7c11.6-12.3,23.7-24.2,35.8-35.9c3.6-3.5,4.3-6.4,2.3-11.3c-9.3-23.3-18.1-46.8-27.3-70.2c-1.8-4.5-1.3-7.3,2.3-10.7c19.7-18.8,39.1-38.1,59-56.8c2.9-2.7,8.1-4.3,12.2-4.4c70.3-0.8,140.6-1.4,210.9-1.7c6.3,0,10.2-2.1,13.9-7c17.1-22.8,34.7-45.2,51.9-68c1.7-2.2,3.7-6.8,2.8-7.8c-2-2.3-5.7-3.4-8.9-4.2c-4-0.9-8.2-0.6-12.2-1.5c-10.9-2.5-18.2-15.4-14.3-25.5c0.6-1.6,4.1-2.8,6.3-2.8c13.3-0.2,26.6-0.3,39.9,0c5.8,0.1,8.6-1.5,8-7.7c-0.4-4.1-0.4-8.2,0-12.3c0.6-6.5-2.1-8.2-8.4-8c-35.7,1.3-71.5,1.5-107.2,3.4c-18.4,1-32.2-6.6-44.3-18.8c-12.7-12.8-19.6-28.5-21.6-46.4c-1.1-9.7,3.2-19,9.1-20c6.1-1,13.5,6.6,14,16.6c1.2,20.3,11.4,34.9,26.9,46.7c2.2,1.6,5.1,3.1,7.7,3.2c19.3,0.3,38.6,0.2,58,0.1c0.9,0,1.8-0.4,3.9-0.8c-1.4-2.2-2.4-3.9-3.5-5.5c-4.1-6.2-8.7-12.2-12.2-18.8c-3.8-7-4.6-14.7-2-22.5c2.3-6.8,7.2-8.4,11.8-3.1c4.8,5.6,8.5,12.2,12.4,18.5c3.6,5.7,6.1,12.2,10.4,17.3c7,8.4,15.7,13.8,27.6,13.1c11.3-0.7,22.8-0.9,34,0c16.1,1.3,28-5.4,37.9-17.1c2.5-3,4.4-6.8,7.4-8.8c3.1-2,8-4.1,10.9-2.9c2.8,1.1,4.4,6.1,5.7,9.6c0.6,1.8-0.3,4.3-1,6.3c-5.5,15.1-27.9,31-43.9,31.3c-9.3,0.2-9.3,0.2-9.3,9.9c0,16.4,0,16.4,16.5,16.4c27.3,0,54.6,0.2,81.9-0.1c6.4-0.1,8.3,1.7,9,8.4c1.6,14.5-3,23.1-16.5,30.2c-23.3,12.2-45.2,26.9-67.9,40.3c-13,7.7-20.8,18.5-24.8,33.2c-9.8,36.1-19.8,72.1-30.7,107.9c-5.4,17.8-15.4,33.3-29.4,45.8c-3.9,3.5-4.5,6.6-3,11.4c21.6,66.5,43.1,133.1,64.6,199.7c0.6,1.7,0.9,3.6,1.5,6.4c-11.7,1.1-22.7,2.6-33.7,2.9c-2,0.1-5-4.5-5.9-7.4c-10-30.7-19.7-61.6-29.5-92.4c-5.9-18.6-11.9-37.3-17.8-55.9c-0.5-1.5-1.3-2.9-2.8-6.2c-1.2,4-1.9,6.2-2.4,8.4c-11.1,48-22.2,96-33,144.1c-1.5,6.7-4.3,9.4-11.1,9.1C738.3,987.6,729.2,987.9,719.2,987.9z"/></g>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Svg Vector Icons : http://www.onlinewebfonts.com/icon -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
<metadata> Svg Vector Icons : http://www.onlinewebfonts.com/icon </metadata>
<g><g transform="matrix(1 0 0 -1 0 1920)"><path d="M504,983v19c0,5.3,1.8,9.8,5.5,13.5c3.7,3.7,8.2,5.5,13.5,5.5h19v247.4c-17-12.9-36-19.4-57-19.4c-23.1,0-43.3,7.3-60.8,22c-17.5,14.7-28.2,33.1-32.3,55.1c-0.8,0-1.8-0.1-3.2-0.2c-1.4-0.1-2.6-0.2-3.6-0.2c-30.7,1-56.6,12.5-77.9,34.4c-21.3,21.9-31.9,48.2-31.9,78.8c0,20,4.9,38.5,14.6,55.5s22.9,30.7,39.3,41c-10.1,17.7-15.2,36.2-15.2,55.5c0,31.4,11.1,58.3,33.4,80.6c22.3,22.3,49.1,33.4,80.6,33.4c0,27.6,6.8,53.1,20.3,76.4c13.6,23.3,32,41.7,55.3,55.3c23.3,13.6,48.8,20.3,76.4,20.3c36.5,0,68.7-11.5,96.5-34.6c27.9-23.1,45.3-52.2,52.4-87.4c13.7,5.3,27.4,8,41,8c15.5,0,30.2-3,44.3-9.1c14.1-6.1,26.2-14.2,36.3-24.3s18.2-22.2,24.3-36.3c6.1-14.1,9.1-28.8,9.1-44.3c0-19.5-5.1-38.1-15.2-55.9c16.2-10.4,29.1-24,38.8-40.8c9.6-16.8,14.4-35.3,14.4-55.3c0-31.4-11.1-58.3-33.4-80.6c-22.3-22.3-49.1-33.4-80.6-33.4h-1c0,0-0.3,0.1-0.9,0.4c1.3-6.3,1.9-12.8,1.9-19.4c0-26.3-9.2-48.8-27.7-67.3S739.3,1249,713,1249c-21,0-40,6.5-57,19.4V1021h19c5.3,0,9.8-1.8,13.5-5.5c3.7-3.7,5.5-8.2,5.5-13.5v-19H504z M238,1743c-1.3,1.5-3.2,3.2-5.9,5.1c-2.7,1.9-5.7,3.9-9.1,5.9c-3.4,2-7,4.1-10.6,6.1c-3.7,2-7.3,3.9-10.8,5.7c-3.5,1.8-6.7,3.4-9.5,4.9c-2.8,1.5-5.1,2.7-6.8,3.4l-2.7,1.1c-1,0.5-1.5,1.4-1.5,2.7v1.1c0,1.3,0.6,1.9,1.9,1.9c3.3-0.5,7.5-1.3,12.5-2.3s12.7-3.2,22.8-6.5c10.1-3.3,16.7-6.7,19.8-10.3c1.8,2,4.9,4.1,9.3,6.3c4.4,2.2,9.2,4,14.2,5.5c5.1,1.5,10,2.8,14.8,4c4.8,1.1,8.7,2,11.8,2.5l4.9,0.8c1.3,0,1.9-0.6,1.9-1.9v-1.1c0-1.3-0.5-2.2-1.5-2.7C263.3,1761.4,244.8,1750.6,238,1743z M124,1629c-5.6,6.3-17.5,14.9-35.9,25.6c-18.4,10.8-35.4,19.9-51.1,27.5l-23.6,11.4c-2.3,1.3-3.4,3.2-3.4,5.7v1.9c0,2.5,1.3,3.8,3.8,3.8c2.5-0.5,5.8-1.1,9.9-1.7s11.5-2.2,22.4-4.6c10.9-2.4,21-5,30.2-7.8c9.2-2.8,18.5-6.3,27.7-10.6c9.2-4.3,15.9-8.7,19.9-13.3c5.6,6.8,17.5,13.4,35.9,19.8c18.4,6.3,35.3,10.9,50.7,13.7l23.6,4.6c2.5,0,3.8-1.3,3.8-3.8v-1.9c0-2.5-1.1-4.4-3.4-5.7c-6.6-3-15.1-7.1-25.5-12.2c-10.4-5.1-25.6-13.4-45.8-24.9C143.2,1645,130.1,1635.8,124,1629z M751,983v19c0,5.3,1.8,9.8,5.5,13.5c3.7,3.7,8.2,5.5,13.5,5.5v133.4c-11.4-7.6-24.1-11.4-38-11.4c-8.4,0-17.2,2-26.6,6.1v50.9c2.8-0.3,5.3-0.4,7.6-0.4c23.6,0,45.6,5.3,66.1,16c20.5,10.6,37.4,25.1,50.7,43.5c13.3,18.4,21.8,38.9,25.6,61.7c35.5,10.6,64.1,31.4,85.9,62.3c14.7-7.1,26.5-17.5,35.3-31.3c8.9-13.8,13.3-29.1,13.3-45.8c0-15.5-3.7-29.7-11.2-42.7c-7.5-13-17.5-23.5-30.2-31.3c2.3-7.3,3.4-14.3,3.4-20.9c0-18.7-6.6-34.8-19.9-48.1c-13.3-13.3-29.3-19.9-48.1-19.9c-13.9,0-26.6,3.8-38,11.4V1021c3.5,0,6.8-0.8,9.7-2.5c2.9-1.6,5.2-3.9,6.8-6.8s2.5-6.1,2.5-9.7v-19H751z M86,983v76c-10.4,0-19.3,3.7-26.8,11.2c-7.5,7.5-11.2,16.4-11.2,26.8s3.7,19.3,11.2,26.8c7.5,7.5,16.4,11.2,26.8,11.2h342c10.4,0,19.3-3.7,26.8-11.2c7.5-7.5,11.2-16.4,11.2-26.8s-3.7-19.3-11.2-26.8c-7.5-7.5-16.4-11.2-26.8-11.2v-76h-76v76H162v-76H86z"/></g></g>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -2,6 +2,7 @@
"id": "fietsstraten", "id": "fietsstraten",
"version": "2020-08-30", "version": "2020-08-30",
"title": "Fietsstraten", "title": "Fietsstraten",
"shortDescription": "Een kaart met alle gekende fietsstraten",
"description": "Een fietsstraat is een straat waar <ul><li><b>automobilisten geen fietsers mogen inhalen</b></li><li>Er een maximumsnelheid van <b>30km/u</b> geldt</li><li>Fietsers gemotoriseerde voortuigen links mogen inhalen</li><li>Fietsers nog steeds voorrang aan rechts moeten verlenen - ook aan auto's en voetgangers op het zebrapad</li></ul><br/><br/>Op deze open kaart kan je alle gekende fietsstraten zien en kan je ontbrekende fietsstraten aanduiden. Om de kaart aan te passen, moet je je aanmelden met OpenStreetMap en helemaal inzoomen tot straatniveau.", "description": "Een fietsstraat is een straat waar <ul><li><b>automobilisten geen fietsers mogen inhalen</b></li><li>Er een maximumsnelheid van <b>30km/u</b> geldt</li><li>Fietsers gemotoriseerde voortuigen links mogen inhalen</li><li>Fietsers nog steeds voorrang aan rechts moeten verlenen - ook aan auto's en voetgangers op het zebrapad</li></ul><br/><br/>Op deze open kaart kan je alle gekende fietsstraten zien en kan je ontbrekende fietsstraten aanduiden. Om de kaart aan te passen, moet je je aanmelden met OpenStreetMap en helemaal inzoomen tot straatniveau.",
"icon": "./assets/themes/cyclestreets/F111.svg", "icon": "./assets/themes/cyclestreets/F111.svg",

View file

Before

Width:  |  Height:  |  Size: 136 KiB

After

Width:  |  Height:  |  Size: 136 KiB

View file

@ -0,0 +1,30 @@
{
"id": "cyclofix",
"title": {
"en": "Cyclofix - an open map for cyclists",
"nl": "Cyclofix - een open kaart voor fietsers",
"fr": "Cyclofix - Une carte ouverte pour les cyclistes",
"gl": "Cyclofix - Un mapa aberto para os ciclistas",
"de": "Cyclofix - eine offene Karte für Radfahrer"
},
"description": {
"en": "The goal of this map is to present cyclists with an easy-to-use solution to find the appropriate infrastructure for their needs.<br><br>You can track your precise location (mobile only) and select layers that are relevant for you in the bottom left corner. You can also use this tool to add or edit pins (points of interest) to the map and provide more data by answering the questions.<br><br>All changes you make will automatically be saved in the global database of OpenStreetMap and can be freely re-used by others.<br><br>For more information about the cyclofix project, go to <a href='https://cyclofix.osm.be/'>cyclofix.osm.be</a>.",
"nl": "Het doel van deze kaart is om fietsers een gebruiksvriendelijke oplossing te bieden voor het vinden van de juiste infrastructuur voor hun behoeften.<br><br>U kunt uw exacte locatie volgen (enkel mobiel) en in de linkerbenedenhoek categorieën selecteren die voor u relevant zijn. U kunt deze tool ook gebruiken om 'spelden' aan de kaart toe te voegen of te bewerken en meer gegevens te verstrekken door de vragen te beantwoorden.<br><br>Alle wijzigingen die u maakt worden automatisch opgeslagen in de wereldwijde database van OpenStreetMap en kunnen door anderen vrij worden hergebruikt.<br><br>Bekijk voor meer info over cyclofix ook <a href='https://cyclofix.osm.be/'>cyclofix.osm.be</a>.",
"fr": "Le but de cette carte est de présenter aux cyclistes une solution facile à utiliser pour trouver l'infrastructure appropriée à leurs besoins.<br><br>Vous pouvez suivre votre localisation précise (mobile uniquement) et sélectionner les couches qui vous concernent dans le coin inférieur gauche. Vous pouvez également utiliser cet outil pour ajouter ou modifier des épingles (points d'intérêt) sur la carte et fournir plus de données en répondant aux questions.<br><br>Toutes les modifications que vous apportez seront automatiquement enregistrées dans la base de données mondiale d'OpenStreetMap et peuvent être librement réutilisées par d'autres.<br><br>Pour plus d'informations sur le projet cyclofix, rendez-vous sur <a href='https://cyclofix.osm.be/'>cyclofix.osm.be</a>.",
"gl": "O obxectivo deste mapa é amosar ós ciclistas unha solución doada de empregar para atopar a infraestrutura axeitada para as súas necesidades.<br><br>Podes obter a túa localización precisa (só para dispositivos móbiles) e escoller as capas que sexan relevantes para ti na esquina inferior esquerda. Tamén podes empregar esta ferramenta para engadir ou editar puntos de interese ó mapa e fornecer máis datos respondendo as cuestións.<br><br>Todas as modificacións que fagas serán gardadas de xeito automático na base de datos global do OpenStreetMap e outros poderán reutilizalos libremente.<br><br>Para máis información sobre o proxecto cyclofix, vai a <a href='https://cyclofix.osm.be/'>cyclofix.osm.be</a>.",
"de": "Das Ziel dieser Karte ist es, den Radfahrern eine einfach zu benutzende Lösung zu präsentieren, um die geeignete Infrastruktur für ihre Bedürfnisse zu finden.<br><br>Sie können Ihren genauen Standort verfolgen (nur mobil) und in der linken unteren Ecke die für Sie relevanten Ebenen auswählen. Sie können dieses Tool auch verwenden, um Pins (Points of Interest/Interessante Orte) zur Karte hinzuzufügen oder zu bearbeiten und mehr Daten durch Beantwortung der Fragen bereitstellen.<br><br>Alle Änderungen, die Sie vornehmen, werden automatisch in der globalen Datenbank von OpenStreetMap gespeichert und können von anderen frei wiederverwendet werden.<br><br>Weitere Informationen über das Projekt Cyclofix finden Sie unter <a href='https://cyclofix.osm.be/'>cyclofix.osm.be</a>."
},
"language": ["en", "nl", "fr", "gl","de"],
"maintainer": "MapComplete",
"icon": "./assets/themes/cyclofix/logo.svg",
"version": "0",
"startLat": 50.8465573,
"startLon": 4.3516970,
"startZoom": 16,
"widenFactor": 0.05,
"socialImage": "./assets/themes/cyclofix/logo.svg",
"layers": ["bike_repair_station", "bike_cafes", "bike_shops", "drinking_water", "bike_parking","bike_themed_object"],
"roamingRenderings": []
}

View file

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

View file

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View file

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View file

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

View file

Before

Width:  |  Height:  |  Size: 2.7 MiB

After

Width:  |  Height:  |  Size: 2.7 MiB

View file

@ -70,6 +70,41 @@ function validate(layout: Layout) {
} }
function generateWikiEntry(layout: Layout){
if(layout.hideFromOverview){
return "";
}
let image = "MapComplete_Screenshot.png";
if(layout.socialImage){
// image = layout.socialImage;
}
if(!image.startsWith("http")){
// image = "https://pietervdvn.github.io/MapComplete/"+image
}
return `{{Software
|name = ${layout.id}
|author = ${layout.maintainer ?? "MapComplete builtin"}
|web = https://pietervdvn.github.io/MapComplete/${layout.id}.html
|repo = https://github.com/pietervdvn/MapComplete
|platform = web
|code = Typescript;HTML;CSS
|languages = ${layout.supportedLanguages.join(";")}
|genre = display;editor
|screenshot = ${image}
|description = A MapComplete theme: ${Translations.W(layout.description)?.InnerRender() ?? ""}
|map = yes
|findLocation = yes
|findNearbyPOI = yes
|addPOI = yes
|editPOI = yes
|editTags = yes
|
}}`
}
const alreadyWritten = [] const alreadyWritten = []
function createIcon(iconPath: string, size: number) { function createIcon(iconPath: string, size: number) {
@ -183,6 +218,9 @@ function createLandingPage(layout: Layout) {
const blacklist = ["", "test", ".", "..", "manifest", "index", "land", "preferences", "account", "openstreetmap"] const blacklist = ["", "test", ".", "..", "manifest", "index", "land", "preferences", "account", "openstreetmap"]
const all = AllKnownLayouts.allSets; const all = AllKnownLayouts.allSets;
let wikiPage = "";
for (const layoutName in all) { for (const layoutName in all) {
if (blacklist.indexOf(layoutName.toLowerCase()) >= 0) { if (blacklist.indexOf(layoutName.toLowerCase()) >= 0) {
console.log(`Skipping a layout with name${layoutName}, it is on the blacklist`); console.log(`Skipping a layout with name${layoutName}, it is on the blacklist`);
@ -205,8 +243,10 @@ for (const layoutName in all) {
console.log("Generating html-file for ", layout.id) console.log("Generating html-file for ", layout.id)
writeFile(enc(layout.id) + ".html", landing, err) writeFile(enc(layout.id) + ".html", landing, err)
console.log("done") console.log("done")
wikiPage += "\n\n"+generateWikiEntry(layout);
} }
writeFile("wikiIndex", wikiPage, (err) => {err ?? console.log("Could not save wikiindex", err)});
console.log("Counting all translations") console.log("Counting all translations")
Translations.CountTranslations(); Translations.CountTranslations();
console.log("All done!") console.log("All done!");

View file

@ -8,6 +8,8 @@
justify-content: flex-start; justify-content: flex-start;
align-items: start; align-items: start;
background-color: white; background-color: white;
max-width: 100vw;
overflow-x: auto;
} }

View file

@ -65,7 +65,8 @@ body {
} }
form { form {
display: inline; display: inline-block;
max-width: 90vw;
} }
.invalid { .invalid {
@ -187,8 +188,10 @@ body {
} }
#hidden-on-mobile { #hidden-on-mobile {
display: none; /*Only shown on small screens*/ display: none; /*Only shown on small screens - this is probably named wrongly*/
} }
.add-popup-all-buttons { .add-popup-all-buttons {
max-height: 50vh; max-height: 50vh;
@ -197,21 +200,20 @@ body {
width: 100%; width: 100%;
} }
@media only screen and (max-height: 600px) and (not (max-width: @media only screen and (max-height: 600px) and (not (max-width:700px)) {
700px /* Landscape and portrait */
#topleft-tools {
padding: 0.1em 0.1em 0.1em unset;
}
)) { .hidden-on-mobile {
display: none !important;
}
/* Landscape and portrait */ #userbadge-and-search {
#topleft-tools { position: relative;
padding: 0.1em 0.1em 0.1em unset; display: inline-block;
}
#userbadge-and-search {
position: relative;
display: inline-block;
width: auto; width: auto;
max-width: 50vw; max-width: 50vw;
margin: 0; margin: 0;
@ -237,9 +239,12 @@ body {
width: auto; width: auto;
max-width: 100vw; max-width: 100vw;
} }
.hidden-on-mobile {
display: none !important;
}
#topleft-tools { #topleft-tools {
padding: 0.2em !important; padding: 0.2em !important;
padding-top: 0.3em !important; padding-top: 0.3em !important;
@ -363,6 +368,11 @@ body {
#hidden-on-mobile { #hidden-on-mobile {
display: block; display: block;
} }
.hidden-on-mobile {
display: none !important;
}
#messagesbox-wrapper { #messagesbox-wrapper {
display: none; display: none;
@ -435,6 +445,11 @@ body {
display: unset; display: unset;
} }
.hidden-on-mobile {
display: none !important;
}
#messagesboxmobile { #messagesboxmobile {
position: absolute; position: absolute;
display: block; display: block;

View file

@ -7,6 +7,7 @@ import {UIEventSource} from "./Logic/UIEventSource";
import * as $ from "jquery"; import * as $ from "jquery";
import {FromJSON} from "./Customizations/JSON/FromJSON"; import {FromJSON} from "./Customizations/JSON/FromJSON";
import {TagRendering} from "./UI/TagRendering"; import {TagRendering} from "./UI/TagRendering";
import {State} from "./State";
TagRendering.injectFunction(); TagRendering.injectFunction();
@ -18,6 +19,8 @@ if (location.href.startsWith("http://buurtnatuur.be")) {
window.location.replace("https://buurtnatuur.be"); window.location.replace("https://buurtnatuur.be");
} }
let testing: UIEventSource<string>; let testing: UIEventSource<string>;
if (location.hostname === "localhost" || location.hostname === "127.0.0.1") { if (location.hostname === "localhost" || location.hostname === "127.0.0.1") {
testing = QueryParameters.GetQueryParameter("test", "true"); testing = QueryParameters.GetQueryParameter("test", "true");

View file

@ -9,6 +9,9 @@ import {FromJSON} from "../Customizations/JSON/FromJSON";
import {And, Tag} from "../Logic/Tags"; import {And, Tag} from "../Logic/Tags";
import Locale from "../UI/i18n/Locale"; import Locale from "../UI/i18n/Locale";
import Translations from "../UI/i18n/Translations"; import Translations from "../UI/i18n/Translations";
import {TagRenderingOptions} from "../Customizations/TagRenderingOptions";
import {UIEventSource} from "../Logic/UIEventSource";
import {TagRendering} from "../UI/TagRendering";
new T([ new T([
@ -64,10 +67,58 @@ new T([
equal(undefined, tr.GetContent({"foo": "bar"})); equal(undefined, tr.GetContent({"foo": "bar"}));
})], })],
[
"Select right value test",
() => {
[
"Empty match test",
() => {
const t = new Tag("key","");
equal(false, t.matches([{k: "key", v:"somevalue"}]))
}
],
[
"Tagrendering test",
() => {
const def = {
"render": {
"nl": "De toegankelijkheid van dit gebied is: {access:description}"
},
"question": {
"nl": "Is dit gebied toegankelijk?"
},
"freeform": {
"key": "access:description"
},
"mappings": [
{
"if": {
"and": [
"access:description=",
"access=",
"leisure=park"
]
},
"then": {
"nl": "Dit gebied is vrij toegankelijk"
},
"hideInAnswer": true
},
{
"if":"access=no",
"then":"Niet toegankelijk"
}
]
};
const constr = FromJSON.TagRendering(def, "test");
TagRendering.injectFunction();
const uiEl = constr.construct({
tags: new UIEventSource<any>(
{leisure: "park", "access": "no"})
});
const rendered = uiEl.InnerRender();
equal(true, rendered.indexOf("Niet toegankelijk") > 0)
} }
] ]

202
wikiIndex Normal file
View file

@ -0,0 +1,202 @@
{{Software
|name = personal
|author = MapComplete builtin
|web = https://pietervdvn.github.io/MapComplete/personal.html
|repo = https://github.com/pietervdvn/MapComplete
|platform = web
|code = Typescript;HTML;CSS
|languages = en
|genre = display;editor
|screenshot = MapComplete_Screenshot.png
|description = A MapComplete theme: The personal theme allows to select one or more layers from all the layouts, creating a truly personal editor
|map = yes
|findLocation = yes
|findNearbyPOI = yes
|addPOI = yes
|editPOI = yes
|editTags = yes
|
}}
{{Software
|name = buurtnatuur
|author =
|web = https://pietervdvn.github.io/MapComplete/buurtnatuur.html
|repo = https://github.com/pietervdvn/MapComplete
|platform = web
|code = Typescript;HTML;CSS
|languages = nl
|genre = display;editor
|screenshot = MapComplete_Screenshot.png
|description = A MapComplete theme: Met deze tool kan je natuur in je buurt in kaart brengen en meer informatie geven over je favoriete plekje
|map = yes
|findLocation = yes
|findNearbyPOI = yes
|addPOI = yes
|editPOI = yes
|editTags = yes
|
}}
{{Software
|name = bookcases
|author = MapComplete
|web = https://pietervdvn.github.io/MapComplete/bookcases.html
|repo = https://github.com/pietervdvn/MapComplete
|platform = web
|code = Typescript;HTML;CSS
|languages = en;nl
|genre = display;editor
|screenshot = MapComplete_Screenshot.png
|description = A MapComplete theme: A public bookcase is a small streetside cabinet, box, old phone boot or some other objects where books are stored
|map = yes
|findLocation = yes
|findNearbyPOI = yes
|addPOI = yes
|editPOI = yes
|editTags = yes
|
}}
{{Software
|name = aed
|author = MapComplete
|web = https://pietervdvn.github.io/MapComplete/aed.html
|repo = https://github.com/pietervdvn/MapComplete
|platform = web
|code = Typescript;HTML;CSS
|languages = en;fr;nl
|genre = display;editor
|screenshot = MapComplete_Screenshot.png
|description = A MapComplete theme: On this map, one can find and mark nearby defibrillators
|map = yes
|findLocation = yes
|findNearbyPOI = yes
|addPOI = yes
|editPOI = yes
|editTags = yes
|
}}
{{Software
|name = toilets
|author = MapComplete
|web = https://pietervdvn.github.io/MapComplete/toilets.html
|repo = https://github.com/pietervdvn/MapComplete
|platform = web
|code = Typescript;HTML;CSS
|languages = en
|genre = display;editor
|screenshot = MapComplete_Screenshot.png
|description = A MapComplete theme: A map of public toilets
|map = yes
|findLocation = yes
|findNearbyPOI = yes
|addPOI = yes
|editPOI = yes
|editTags = yes
|
}}
{{Software
|name = artworks
|author = MapComplete
|web = https://pietervdvn.github.io/MapComplete/artworks.html
|repo = https://github.com/pietervdvn/MapComplete
|platform = web
|code = Typescript;HTML;CSS
|languages = en;nl;fr
|genre = display;editor
|screenshot = MapComplete_Screenshot.png
|description = A MapComplete theme: Welcome to Open Artwork Map, a map of statues, busts, grafittis,
|map = yes
|findLocation = yes
|findNearbyPOI = yes
|addPOI = yes
|editPOI = yes
|editTags = yes
|
}}
{{Software
|name = fietsstraten
|author = MapComlete
|web = https://pietervdvn.github.io/MapComplete/fietsstraten.html
|repo = https://github.com/pietervdvn/MapComplete
|platform = web
|code = Typescript;HTML;CSS
|languages = nl
|genre = display;editor
|screenshot = MapComplete_Screenshot.png
|description = A MapComplete theme: Een kaart met alle gekende fietsstraten
|map = yes
|findLocation = yes
|findNearbyPOI = yes
|addPOI = yes
|editPOI = yes
|editTags = yes
|
}}
{{Software
|name = ghostbikes
|author = MapComplete
|web = https://pietervdvn.github.io/MapComplete/ghostbikes.html
|repo = https://github.com/pietervdvn/MapComplete
|platform = web
|code = Typescript;HTML;CSS
|languages = en;nl
|genre = display;editor
|screenshot = MapComplete_Screenshot.png
|description = A MapComplete theme: A <b>ghost bike</b> is a memorial for a cyclist who died in a traffic accident, in the form of a white bicycle placed permanently near the accident location
|map = yes
|findLocation = yes
|findNearbyPOI = yes
|addPOI = yes
|editPOI = yes
|editTags = yes
|
}}
{{Software
|name = cyclofix
|author = MapComplete
|web = https://pietervdvn.github.io/MapComplete/cyclofix.html
|repo = https://github.com/pietervdvn/MapComplete
|platform = web
|code = Typescript;HTML;CSS
|languages = en;nl;fr;gl;de
|genre = display;editor
|screenshot = MapComplete_Screenshot.png
|description = A MapComplete theme: The goal of this map is to present cyclists with an easy-to-use solution to find the appropriate infrastructure for their needs
|map = yes
|findLocation = yes
|findNearbyPOI = yes
|addPOI = yes
|editPOI = yes
|editTags = yes
|
}}
{{Software
|name = metamap
|author = MapComplete builtin
|web = https://pietervdvn.github.io/MapComplete/metamap.html
|repo = https://github.com/pietervdvn/MapComplete
|platform = web
|code = Typescript;HTML;CSS
|languages = en
|genre = display;editor
|screenshot = MapComplete_Screenshot.png
|description = A MapComplete theme:
|map = yes
|findLocation = yes
|findNearbyPOI = yes
|addPOI = yes
|editPOI = yes
|editTags = yes
|
}}