Merge branch 'RobinLinde-patch-1'

This commit is contained in:
Pieter Vander Vennet 2024-02-26 13:40:58 +01:00
commit ff395c5acc
74 changed files with 1621 additions and 58 deletions

35
.vscode/settings.json vendored
View file

@ -7,6 +7,41 @@
{
"fileMatch": ["/assets/themes/*/*.json", "!/assets/themes/*/license_info.json"],
"url": "./Docs/Schemas/LayoutConfigJson.schema.json"
},
{
"fileMatch": ["/assets/themes/*/license_info.json", "/assets/layers/*/license_info.json"],
"schema": {
"type": "array",
"title": "License Info",
"items": {
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "Path to the file"
},
"authors": {
"type": "array",
"description": "Authors of the file",
"items": {
"type": "string"
}
},
"license": {
"type": "string",
"description": "License of the file"
},
"sources": {
"type": "array",
"description": "Sources of the file",
"items": {
"type": "string"
}
}
},
"required": ["path", "authors", "license", "sources"]
}
}
}
],
"editor.tabSize": 2,

View file

@ -18,7 +18,7 @@
"osmTags": {
"and": [
"amenity=vending_machine",
"vending=elongated_coin"
"vending~.*elongated_coin.*"
]
}
},
@ -440,8 +440,5 @@
"accepts_credit_cards"
],
"deletion": true,
"allowMove": {
"enableImproveAccuracy": true,
"enableRelocation": true
}
}
"allowMove": true
}

View file

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 128 128" style="display:inline;enable-background:new" version="1.0" id="svg11300" height="128" width="128">
<title id="title4162">Adwaita Icon Template</title>
<defs id="defs3">
<linearGradient id="linearGradient1200">
<stop id="stop1196" offset="0" style="stop-color:#f66151;stop-opacity:1"/>
<stop id="stop1198" offset="1" style="stop-color:#c01c28;stop-opacity:1"/>
</linearGradient>
<linearGradient id="linearGradient1194">
<stop style="stop-color:#9a9996;stop-opacity:1" offset="0" id="stop1182"/>
<stop id="stop1184" offset="0.03571429" style="stop-color:#deddda;stop-opacity:1"/>
<stop style="stop-color:#c0bfbc;stop-opacity:1" offset="0.07142857" id="stop1186"/>
<stop id="stop1188" offset="0.9285714" style="stop-color:#c0bfbc;stop-opacity:1"/>
<stop style="stop-color:#deddda;stop-opacity:1" offset="0.96428573" id="stop1190"/>
<stop style="stop-color:#9a9996;stop-opacity:1" offset="1" id="stop1192"/>
</linearGradient>
<radialGradient gradientTransform="matrix(0.20374131,0.02574915,-0.13347722,1.0561446,5.11727,292.38679)" gradientUnits="userSpaceOnUse" r="111.99999" fy="-70.410965" fx="322.32892" cy="-70.410965" cx="322.32892" id="radialGradient957" xlink:href="#linearGradient1039"/>
<linearGradient id="linearGradient1039">
<stop style="stop-color:#949390;stop-opacity:1" offset="0" id="stop1035"/>
<stop style="stop-color:#191622;stop-opacity:1" offset="1" id="stop1037"/>
</linearGradient>
<radialGradient gradientTransform="matrix(0.36230333,0,0,0.36230333,-41.78098,227.028)" gradientUnits="userSpaceOnUse" r="80.368896" fy="82.548996" fx="318.92401" cy="82.548996" cx="318.92401" id="radialGradient1116" xlink:href="#linearGradient1045"/>
<linearGradient id="linearGradient1045">
<stop style="stop-color:#68676b;stop-opacity:1" offset="0" id="stop1041"/>
<stop style="stop-color:#191622;stop-opacity:1" offset="1" id="stop1043"/>
</linearGradient>
<radialGradient gradientTransform="matrix(0.7272972,0,0,0.7272972,-159.07258,-233.33112)" gradientUnits="userSpaceOnUse" r="49.999992" fy="-31.994987" fx="320.70712" cy="-31.994987" cx="320.70712" id="radialGradient2192" xlink:href="#linearGradient1087"/>
<linearGradient id="linearGradient1087">
<stop style="stop-color:#1a4172;stop-opacity:1" offset="0" id="stop1083"/>
<stop style="stop-color:#000000;stop-opacity:1" offset="1" id="stop1085"/>
</linearGradient>
<linearGradient gradientUnits="userSpaceOnUse" y2="13" x2="319.99997" y1="93.000008" x1="319.99997" id="linearGradient2224" xlink:href="#linearGradient1075" gradientTransform="matrix(0.25,0,0,0.25,-5.99995,-248.60224)"/>
<linearGradient id="linearGradient1075">
<stop style="stop-color:#ffffff;stop-opacity:1" offset="0" id="stop1071"/>
<stop style="stop-color:#4a86cf;stop-opacity:0" offset="1" id="stop1073"/>
</linearGradient>
<linearGradient y2="619.96387" x2="624" y1="619.96387" x1="177" gradientTransform="matrix(0.25,0,0,0.24305558,-35.999947,93.564314)" gradientUnits="userSpaceOnUse" id="linearGradient1444-3-9-0-9" xlink:href="#linearGradient1194"/>
<linearGradient gradientTransform="translate(188.00001,-239.99999)" gradientUnits="userSpaceOnUse" y2="212" x2="35.999992" y1="212" x1="19.999992" id="linearGradient1202" xlink:href="#linearGradient1200"/>
</defs>
<metadata id="metadata4">
</metadata>
<g transform="translate(0,-172)" style="display:inline" id="layer1">
<g style="display:inline" id="layer9">
<rect style="display:inline;opacity:1;vector-effect:none;fill:url(#linearGradient1444-3-9-0-9);fill-opacity:1;stroke:none;stroke-width:0.01114019px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;enable-background:new" id="rect1480-3-7-1-3-6" width="112" height="70" x="7.9999914" y="218" rx="8" ry="7.7777786"/>
<path style="display:inline;opacity:1;vector-effect:none;fill:#424048;fill-opacity:1;stroke:none;stroke-width:0.00279558px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;enable-background:new" d="m 60.89285,196 h 26.2143 c 1.11788,0 1.950682,0.77034 2.01785,1.72191 L 90,210.1181 c 0.07133,1.01051 -0.95572,1.82857 -2.14285,1.82857 h -27.7143 c -1.18712,0 -2.21417,-0.81806 -2.14285,-1.82857 l 0.875,-12.39619 C 58.9422,196.77034 59.77498,196 60.89285,196 Z" id="rect971"/>
<rect ry="2" rx="12" y="201.21478" x="17.99999" height="7.0392466" width="24" id="rect1647-3-3-8" style="display:inline;opacity:1;vector-effect:none;fill:#949390;fill-opacity:1;stroke:none;stroke-width:0.01725831px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;enable-background:new"/>
<rect ry="7.8530612" rx="8" y="206" x="8" height="78" width="111.99999" id="rect1480-6-7" style="display:inline;opacity:1;vector-effect:none;fill:#f6f5f4;fill-opacity:1;stroke:none;stroke-width:0.01119398px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;enable-background:new"/>
<path id="rect1482-1-3" d="m 8,216 v 56 H 120 V 216 H 38 c 0,5.52284 -4.47715,10 -10,10 -5.52285,0 -10,-4.47716 -10,-10 z" style="display:inline;opacity:1;vector-effect:none;fill:#2a2a3b;fill-opacity:1;stroke:none;stroke-width:0.01129822px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;enable-background:new"/>
<circle style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#68676b;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.91564989;marker:none;enable-background:new" id="path15832-3-1-9-8" cx="73.999992" cy="246" r="30"/>
<circle style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:new" id="path15832-3-2-9-4-5" cx="73.999992" cy="246" r="26.999998"/>
<circle style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#3d3846;fill-opacity:1;fill-rule:nonzero;stroke:url(#radialGradient957);stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker:none;enable-background:new" id="path15832-3-2-9-4" cx="73.999992" cy="244" r="26.999998"/>
<circle transform="rotate(90)" style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#linearGradient1202);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.8584218;marker:none;enable-background:new" id="path15832-3-2-9-7-4-6" cx="216" cy="-27.999992" r="8"/>
<circle style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#radialGradient1116);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.79114366;marker:none;enable-background:new" id="path15894-3" cx="73.907768" cy="244.05173" r="16.092224"/>
<circle style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.79114354;marker:none;enable-background:new" id="path15894-6" cx="73.999992" cy="-244.10229" transform="scale(1,-1)" r="13.999999"/>
<circle style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:url(#radialGradient2192);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.79114342;marker:none;enable-background:new" id="path15894-6-9" cx="73.999992" cy="-244.10229" transform="scale(1,-1)" r="12.499998"/>
<circle style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#15365f;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.79114342;marker:none;enable-background:new" id="path15894-6-9-6" cx="73.999992" cy="-244.10229" transform="scale(1,-1)" r="5.5000019"/>
<circle style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#2864b0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.79114342;marker:none;enable-background:new" id="path15894-6-9-7" cx="69.999992" cy="-239.60229" transform="scale(1,-1)" r="4"/>
<ellipse style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#2864b0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.79114342;marker:none;enable-background:new" id="path15894-6-9-7-3" cx="79.999992" cy="-249.60229" transform="scale(1,-1)" rx="2.0000017" ry="2"/>
<ellipse style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#2864b0;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.79114342;marker:none;enable-background:new" id="path15894-6-9-7-3-2" cx="76.999992" cy="-246.60229" transform="scale(1,-1)" rx="1.0000008" ry="1"/>
<circle style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.66399997;fill:url(#linearGradient2224);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.79114342;marker:none;enable-background:new" id="path15894-6-9-1" cx="73.999992" cy="-244.10229" transform="scale(1,-1)" r="12.499998"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.8 KiB

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: https://gitlab.gnome.org/jimmac
SPDX-License-Identifier: GPL3

View file

@ -0,0 +1,47 @@
{
"id": "item_with_image",
"description": "All items with an image. All alone, not a layer which is relevant for any MapComplete theme, as it is a random collection of items. However, when put into the databank, this allows to quickly fetch (the URL of) pictures nearby a different object, to quickly link this",
"minzoom": 14,
"source": {
"osmTags": {
"or": [
"image~*",
"image:0~*",
"image:1~*",
"image:2~*",
"image:3~*",
"image:4~*",
"image:5~*"
]
}
},
"tagRenderings": [
"images"
],
"title": {
"render": {
"en": "POI with image"
},
"mappings": [{
"if": "name~*",
"then": {"*": "name"}
}]
},
"name": {
"en": "Items with at least one image"
},
"lineRendering": [],
"pointRendering": [
{
"marker": [
{
"icon": "./assets/layers/item_with_image/camera.svg"
}
],
"location": [
"centroid",
"point"
]
}
]
}

View file

@ -0,0 +1,12 @@
[
{
"path": "camera.svg",
"license": "GPL3",
"authors": [
"https://gitlab.gnome.org/jimmac"
],
"sources": [
"https://commons.wikimedia.org/wiki/File:GNOME_Photos_icon_2018.svg"
]
}
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: Damian stawowy
SPDX-License-Identifier: CC-BY-SA 4.0

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: Pavtron (talk)
SPDX-License-Identifier: Public domain

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: M.Minderhoud
SPDX-License-Identifier: Public domain

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: Peter Wanders
SPDX-License-Identifier: Public domain

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 MiB

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: Reda Kerbouche
SPDX-License-Identifier: CC-BY-SA 4.0

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: Jleedev
SPDX-License-Identifier: CC-BY-SA 4.0

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: Mktravel
SPDX-License-Identifier: Public Domain

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 KiB

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: Roger Kidd
SPDX-License-Identifier: CC-BY-SA 2.0

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 MiB

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: Kritzolina
SPDX-License-Identifier: CC-BY-SA 4.0

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: Saku
SPDX-License-Identifier: CC-BY-SA 3.0

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 KiB

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: self
SPDX-License-Identifier: Public domain

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: Itsmine
SPDX-License-Identifier: Public domain

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: Jose1711
SPDX-License-Identifier: CC0 1.0

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: Mc on avon
SPDX-License-Identifier: Public domain

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 MiB

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: Pece
SPDX-License-Identifier: CC-BY 3.0

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: Phil Champion
SPDX-License-Identifier: CC-BY-SA 2.0

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: Glogger
SPDX-License-Identifier: CC-BY-SA 3.0

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: Waerth
SPDX-License-Identifier: CC-BY-SA 3.0

View file

@ -0,0 +1,182 @@
[
{
"path": "DeimosXL1.jpg",
"license": "CC-BY-SA 4.0",
"authors": [
"Damian stawowy"
],
"sources": [
"https://commons.wikimedia.org/wiki/File:DeimosXL1.jpg"
]
},
{
"path": "Funnel_ball.jpg",
"license": "Public domain",
"authors": [
"Pavtron (talk)"
],
"sources": [
"https://commons.wikimedia.org/wiki/File:Funnel_ball.jpg"
]
},
{
"path": "Hinkelbaan_tegels.jpg",
"license": "Public domain",
"authors": [
"M.Minderhoud"
],
"sources": [
"https://commons.wikimedia.org/wiki/File:Hinkelbaan_tegels.jpg"
]
},
{
"path": "Hupfkissen.jpg",
"license": "Public domain",
"authors": [
"Peter Wanders"
],
"sources": [
"https://commons.wikimedia.org/wiki/File:H%C3%BCpfkissen.jpg"
]
},
{
"path": "Manually_powered_carousel_on_a_playground_in_Saint-Petersburg.JPG",
"license": "CC-BY-SA 4.0",
"authors": [
"Reda Kerbouche"
],
"sources": [
"https://commons.wikimedia.org/wiki/File:Manually_powered_carousel_on_a_playground_in_Saint-Petersburg.JPG"
]
},
{
"path": "Playground_Map,_Washington_Elementary.jpg",
"license": "CC-BY-SA 4.0",
"authors": [
"Jleedev"
],
"sources": [
"https://commons.wikimedia.org/wiki/File:Playground_Map,_Washington_Elementary.jpg"
]
},
{
"path": "Playground_climbingwall.jpg",
"license": "Public Domain",
"authors": [
"Mktravel"
],
"sources": [
"https://wiki.openstreetmap.org/wiki/File:Playground_climbingwall.jpg"
]
},
{
"path": "Playground_in_Muchall_Park,_Wolverhampton_-_geograph.org.uk_-_2735437.jpg",
"license": "CC-BY-SA 2.0",
"authors": [
"Roger Kidd"
],
"sources": [
"https://commons.wikimedia.org/wiki/File:Playground_in_Muchall_Park,_Wolverhampton_-_geograph.org.uk_-_2735437.jpg"
]
},
{
"path": "Playground_swing_03.jpg",
"license": "CC-BY-SA 4.0",
"authors": [
"Kritzolina"
],
"sources": [
"https://commons.wikimedia.org/wiki/File:Playground_swing_03.jpg"
]
},
{
"path": "Playhouse.jpg",
"license": "CC-BY-SA 3.0",
"authors": [
"Saku"
],
"sources": [
"https://commons.wikimedia.org/wiki/File:Playhouse.jpg"
]
},
{
"path": "Rekstok.JPG",
"license": "Public domain",
"authors": [
"self"
],
"sources": [
"https://commons.wikimedia.org/wiki/File:Rekstok.JPG"
]
},
{
"path": "Seesaw-aa.jpg",
"license": "Public domain",
"authors": [
"Itsmine"
],
"sources": [
"https://commons.wikimedia.org/wiki/File:Seesaw-aa.jpg"
]
},
{
"path": "Spinning_circle.jpg",
"license": "CC0 1.0",
"authors": [
"Jose1711"
],
"sources": [
"https://wiki.openstreetmap.org/wiki/File:Spinning_circle.jpg"
]
},
{
"path": "SunwardCohousingPlayStructure2005.jpg",
"license": "Public domain",
"authors": [
"Mc on avon"
],
"sources": [
"https://commons.wikimedia.org/wiki/File:SunwardCohousingPlayStructure2005.jpg"
]
},
{
"path": "Szwedy_-_plac_zabaw_-_kotko_i_krzyzyk.jpg",
"license": "CC-BY 3.0",
"authors": [
"Pece"
],
"sources": [
"https://commons.wikimedia.org/wiki/File:Szwedy_-_plac_zabaw_-_k%C3%B3%C5%82ko_i_krzy%C5%BCyk.jpg"
]
},
{
"path": "Teen_shelter_near_former_coastguard_lookout,_Watchet_-_geograph.org.uk_-_1714960.jpg",
"license": "CC-BY-SA 2.0",
"authors": [
"Phil Champion"
],
"sources": [
"https://commons.wikimedia.org/wiki/File:Teen_shelter_near_former_coastguard_lookout,_Watchet_-_geograph.org.uk_-_1714960.jpg"
]
},
{
"path": "Urbeach-high-park-splashpad.jpg",
"license": "CC-BY-SA 3.0",
"authors": [
"Glogger"
],
"sources": [
"https://commons.wikimedia.org/wiki/File:Urbeach-high-park-splashpad.jpg"
]
},
{
"path": "Zandbakw.jpg",
"license": "CC-BY-SA 3.0",
"authors": [
"Waerth"
],
"sources": [
"https://commons.wikimedia.org/wiki/File:Zandbakw.jpg"
]
}
]

View file

@ -0,0 +1,337 @@
{
"minzoom": 18,
"pointRendering": [
{
"location": [
"point",
"centroid"
],
"marker": [
{
"icon": "circle",
"color": "white"
},
{
"icon": "./assets/themes/playgrounds/playground.svg"
}
],
"iconSize": "20,20"
}
],
"tagRenderings": [
"images",
{
"render": {
"en": "This is a {playground}"
},
"id": "type",
"freeform": {
"key": "playground",
"placeholder": {
"en": "Type of device"
},
"addExtraTags": [
"fixme=Freeform input used"
]
},
"question": {
"en": "What kind of device is this?",
"nl": "Wat voor speeltoestel is dit?"
},
"invalidValues": "playground=yes",
"mappings": [
{
"if": "playground=swing",
"then": {
"en": "This is a swing",
"nl": "Dit is een schommel"
}
},
{
"if": "playground=structure",
"then": {
"en": "This is a structure consisting of several connected playground devices"
},
"icon": {
"path": "./assets/layers/playground_equipment/SunwardCohousingPlayStructure2005.jpg",
"class": "large"
}
},
{
"if": "playground=slide",
"then": {
"en": "This is a slide"
}
},
{
"if": "playground=sandpit",
"then": {
"en": "This is a sand pit",
"nl": "Dit is een zandbak"
},
"searchTerms": {
"en": [
"sandbox"
]
},
"icon": {
"path": "./assets/layers/playground_equipment/Zandbakw.jpg",
"class": "large"
}
},
{
"if": "playground=springy",
"then": {
"en": "This is a spring rider",
"nl": "Dit is een veertoestel"
},
"searchTerms": {
"en": [
"springy"
],
"nl": [
"wipkip"
]
}
},
{
"if": "playground=climbingframe",
"then": {
"en": "This is a climbing frame",
"nl": "Dit is een klimrek"
},
"searchTerms": {
"en": [
"jungle gym",
"rope spider"
]
},
"icon": {
"path": "./assets/layers/playground_equipment/DeimosXL1.jpg",
"class": "large"
}
},
{
"if": "playground=seesaw",
"then": {
"en": "This is a seesaw",
"nl": "Dit is een wipwap"
},
"searchTerms": {
"en": [
"teeter-totter",
"teeterboard"
]
},
"icon": {
"path": "./assets/layers/playground_equipment/Seesaw-aa.jpg",
"class": "large"
}
},
{
"if": "playground=playhouse",
"then": {
"en": "This is a playhouse"
},
"searchTerms": {
"en": [
"Wendyhouse"
]
},
"icon": {
"path": "./assets/layers/playground_equipment/Playhouse.jpg",
"class": "large"
}
},
{
"if": "playground=roundabout",
"then": {
"en": "This is a roundabout"
},
"searchTerms": {
"en": [
"merry-go-round"
]
},
"icon": {
"path": "./assets/layers/playground_equipment/Manually_powered_carousel_on_a_playground_in_Saint-Petersburg.JPG",
"class": "large"
}
},
{
"if": "playground=basketswing",
"then": {
"en": "This is a basket swing"
},
"icon": {
"path": "./assets/layers/playground_equipment/Playground_swing_03.jpg",
"class": "large"
}
},
{
"if": "playground=zipwire",
"then": {
"en": "This is a zip wire"
}
},
{
"if": "playground=horizontal_bar",
"then": {
"en": "This is a horizontal bar",
"nl": "Dit is een rekstok"
},
"icon": {
"path": "./assets/layers/playground_equipment/Rekstok.JPG",
"class": "large"
}
},
{
"if": "playground=hopscotch",
"then": {
"en": "This is a hopscotch"
},
"icon": {
"path": "./assets/layers/playground_equipment/Hinkelbaan_tegels.jpg",
"class": "large"
}
},
{
"if": "playground=splash_pad",
"then": {
"en": "This is a splash pad"
},
"searchTerms": {
"en": "spray pool"
},
"icon": {
"path": "./assets/layers/playground_equipment/Urbeach-high-park-splashpad.jpg",
"class": "large"
}
},
{
"if": "playground=climbingwall",
"then": {
"en": "This is a climbing wall"
},
"icon": {
"path": "./assets/layers/playground_equipment/Playground_climbingwall.jpg",
"class": "large"
}
},
{
"if": "playground=map",
"then": {
"en": "This is a map"
},
"icon": {
"path": "./assets/layers/playground_equipment/Playground_Map,_Washington_Elementary.jpg",
"class": "large"
}
},
{
"if": "playground=bridge",
"then": {
"en": "This is a bridge (either as a standalone device or as part of a larger structure)"
},
"icon": {
"path": "./assets/layers/playground_equipment/Playground_in_Muchall_Park,_Wolverhampton_-_geograph.org.uk_-_2735437.jpg",
"class": "large"
}
},
{
"if": "playground=cushion",
"then": {
"en": "This is a bouncy cushion"
},
"icon": {
"path": "./assets/layers/playground_equipment/Hupfkissen.jpg",
"class": "large"
}
},
{
"if": "playground=activitypanel",
"then": {
"en": "This is an activity panel"
},
"icon": {
"path": "./assets/layers/playground_equipment/Szwedy_-_plac_zabaw_-_kotko_i_krzyzyk.jpg",
"class": "large"
}
},
{
"if": "playground=teenshelter",
"then": {
"en": "This is a teen shelter"
},
"icon": {
"path": "./assets/layers/playground_equipment/Teen_shelter_near_former_coastguard_lookout,_Watchet_-_geograph.org.uk_-_1714960.jpg",
"class": "large"
}
},
{
"if": "playground=funnel_ball",
"then": {
"en": "This is a funnel used to play with funnel ball"
},
"icon": {
"path": "./assets/layers/playground_equipment/Funnel_ball.jpg",
"class": "large"
}
},
{
"if": "playground=spinning_circle",
"then": {
"en": "This is a spinning circle"
},
"icon": {
"path": "./assets/layers/playground_equipment/Spinning_circle.jpg",
"class": "large"
}
}
]
},
{
"builtin": "wheelchair-access",
"override": {
"question": {
"en": "Is this device accessible by wheelchair?"
}
}
}
],
"lineRendering": [
{
"width": 1,
"color": "blue"
}
],
"id": "playground_equipment",
"name": {
"en": "Playground equipment"
},
"description": {
"en": "Layer showing playground equipment"
},
"source": {
"osmTags": "playground~*"
},
"title": {
"render": {
"en": "Playground device"
}
},
"allowMove": true,
"presets": [
{
"tags": [
"playground=yes"
],
"title": {
"en": "a playground device"
},
"description": {
"en": "An exact type is asked later"
}
}
]
}

View file

@ -552,6 +552,86 @@
}
],
"filter": [
"open_now"
"open_now",
{
"id": "letter_from",
"options": [
{
"question": {
"en": "Offers letter posting"
},
"osmTags": {
"and": [
"post_office:letter_from~*",
"post_office:letter_from!~i~no"
]
}
}
]
},
{
"id": "parcel_from",
"options": [
{
"question": {
"en": "Offers parcel posting"
},
"osmTags": {
"and": [
"post_office:parcel_from~*",
"post_office:parcel_from!~i~no"
]
}
}
]
},
{
"id": "parcel_pickup",
"options": [
{
"question": {
"en": "Offers pickup of missed parcels"
},
"osmTags": {
"and": [
"post_office:parcel_pickup~*",
"post_office:parcel_pickup!~i~no"
]
}
}
]
},
{
"id": "parcel_to",
"options": [
{
"question": {
"en": "Accepts pickup of parcels sent here"
},
"osmTags": {
"and": [
"post_office:parcel_to~*",
"post_office:parcel_to!~i~no"
]
}
}
]
},
{
"id": "stamps",
"options": [
{
"question": {
"en": "Sells stamps"
},
"osmTags": {
"and": [
"post_office:stamps~*",
"post_office:stamps!~i~no"
]
}
}
]
}
]
}
}

View file

@ -0,0 +1,10 @@
[
{
"path": "souvenir_coin.svg",
"license": "CC0-1.0",
"authors": [
"Robin van der Linde"
],
"sources": []
}
]

View file

@ -0,0 +1,160 @@
{
"pointRendering": [
{
"location": [
"point",
"centroid"
],
"iconBadges": [
{
"if": "opening_hours~*",
"then": "icons.isOpen"
}
],
"marker": [
{
"icon": "circle",
"color": "#FFFFFF00"
},
{
"icon": "./assets/layers/souvenir_coin/souvenir_coin.svg"
}
]
}
],
"tagRenderings": [
"images",
"opening_hours_24_7",
{
"builtin": "elongated_coin.designs",
"id": "designs",
"override": {
"render": {
"en": "This machine has {coin:design_count} designs available"
},
"mappings": [
{
"if": "coin:design_count=1",
"then": {
"en": "This machine has one design available"
}
},
{
"if": "coin:design_count=2",
"then": {
"en": "This machine has two designs available"
}
},
{
"if": "coin:design_count=3",
"then": {
"en": "This machine has three designs available"
}
},
{
"if": "coin:design_count=4",
"then": {
"en": "This machine has four designs available"
}
}
]
}
},
"payment-options-split",
"website",
{
"question": {
"en": "How much does a souvenir coin cost?"
},
"id": "charge",
"render": {
"en": "A souvenir coins costs {charge}"
},
"freeform": {
"key": "charge",
"placeholder": {
"en": "Cost (e.g. 2 EUR)"
}
},
"mappings": [
{
"if": "charge=2 EUR",
"then": {
"en": "A souvenir coin costs 2 euro"
},
"hideInAnswer": "_currency!~.*EUR.*"
}
]
},
"denominations-coins",
{
"question": {
"en": "Is this machine located indoors?"
},
"id": "indoor",
"mappings": [
{
"if": "indoor=yes",
"then": {
"en": "This machine is located indoors."
}
},
{
"if": "indoor=no",
"then": {
"en": "This machine is located outdoors."
}
}
]
},
"level",
"check_date"
],
"lineRendering": [
{
"width": 1,
"color": "blue"
}
],
"id": "souvenir_coin",
"name": {
"en": "Souvenir Coin Machines"
},
"description": {
"en": "Layer showing machines selling souvenir coins"
},
"source": {
"osmTags": {
"and": [
"amenity=vending_machine",
"vending~.*souvenir_coins.*"
]
}
},
"title": {
"render": {
"en": "Souvenir Coin Machine"
}
},
"presets": [
{
"title": {
"en": "a souvenir coin machine"
},
"description": {
"en": "Add a machine selling souvenir coins"
},
"tags": [
"amenity=vending_machine",
"vending=souvenir_coins"
]
}
],
"filter": [
"open_now",
"accepts_debit_cards",
"accepts_credit_cards"
],
"deletion": true,
"allowMove": true
}

View file

@ -0,0 +1,9 @@
<svg width="250" height="250" viewBox="0 0 250 250" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="125" cy="125" r="121" fill="#CABFB9" stroke="#6D6662" stroke-width="8"/>
<rect x="60" y="82.5" width="26" height="39" fill="#6D6662"/>
<rect x="164" y="82.5" width="26" height="39" fill="#6D6662"/>
<path d="M73 63L84.2583 82.5H61.7417L73 63Z" fill="#6D6662"/>
<path d="M177 63L188.258 82.5H165.742L177 63Z" fill="#6D6662"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M60 121.5H190V186.5H138V160.5C138 153.32 132.18 147.5 125 147.5C117.82 147.5 112 153.32 112 160.5V186.5H60V121.5Z" fill="#6D6662"/>
<circle cx="125" cy="125" r="109.5" stroke="#6D6662" stroke-dasharray="4 12"/>
</svg>

After

Width:  |  Height:  |  Size: 703 B

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: Robin van der Linde
SPDX-License-Identifier: CC0-1.0

View file

@ -0,0 +1,10 @@
[
{
"path": "souvenir_note.svg",
"license": "CC0-1.0",
"authors": [
"Robin van der Linde"
],
"sources": []
}
]

View file

@ -0,0 +1,178 @@
{
"pointRendering": [
{
"location": [
"point",
"centroid"
],
"iconBadges": [
{
"if": "opening_hours~*",
"then": "icons.isOpen"
}
],
"marker": [
{
"icon": "circle",
"color": "#FFFFFF00"
},
{
"icon": "./assets/layers/souvenir_note/souvenir_note.svg"
}
]
}
],
"tagRenderings": [
"images",
"opening_hours_24_7",
{
"id": "designs",
"question": {
"en": "How many designs are available?"
},
"freeform": {
"key": "note:design_count",
"type": "pnat",
"placeholder": {
"en": "Number of designs (e.g. 5)",
"de": "Motivanzahl (z.B. 5)",
"es": "Número de diseños (por ejemplo, 5)",
"ca": "Nombre de dissenys (p. e. 5)",
"cs": "Počet vzorů (např. 5)"
}
},
"render": {
"en": "This machine has {note:design_count} designs available."
},
"mappings": [
{
"if": "note:design_count=1",
"then": {
"en": "This machine has one design available."
}
},
{
"if": "note:design_count=2",
"then": {
"en": "This machine has two designs available."
}
},
{
"if": "note:design_count=3",
"then": {
"en": "This machine has three designs available."
}
},
{
"if": "note:design_count=4",
"then": {
"en": "This machine has four designs available."
}
}
]
},
"payment-options-split",
"website",
{
"question": {
"en": "How much does a souvenir note cost?"
},
"id": "charge",
"render": {
"en": "A souvenir note costs {charge}"
},
"freeform": {
"key": "charge",
"placeholder": {
"en": "Cost (e.g. 2 EUR)"
}
},
"mappings": [
{
"if": "charge=2 EUR",
"then": {
"en": "A souvenir note costs 2 euro"
},
"hideInAnswer": "_currency!~.*EUR.*"
},
{
"if": "charge=3 EUR",
"then": {
"en": "A souvenir note costs 3 euro"
},
"hideInAnswer": "_currency!~.*EUR.*"
}
]
},
"denominations-coins",
{
"question": {
"en": "Is this machine located indoors?"
},
"id": "indoor",
"mappings": [
{
"if": "indoor=yes",
"then": {
"en": "This machine is located indoors."
}
},
{
"if": "indoor=no",
"then": {
"en": "This machine is located outdoors."
}
}
]
},
"level",
"check_date"
],
"lineRendering": [
{
"width": 1,
"color": "blue"
}
],
"id": "souvenir_note",
"name": {
"en": "Souvenir Banknote Machines"
},
"description": {
"en": "Layer showing machines selling souvenir banknotes"
},
"source": {
"osmTags": {
"and": [
"amenity=vending_machine",
"vending~.*souvenir_notes.*"
]
}
},
"title": {
"render": {
"en": "Souvenir Banknote Machine"
}
},
"presets": [
{
"title": {
"en": "a souvenir banknote machine"
},
"description": {
"en": "Add a machine selling souvenir banknotes"
},
"tags": [
"amenity=vending_machine",
"vending=souvenir_notes"
]
}
],
"filter": [
"open_now",
"accepts_debit_cards",
"accepts_credit_cards"
],
"deletion": true,
"allowMove": true
}

View file

@ -0,0 +1,12 @@
<svg width="500" height="250" viewBox="0 0 500 250" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="140" height="250" fill="#F7EBF4"/>
<rect x="140" width="360" height="250" fill="#E1BBD9"/>
<rect x="4" y="4" width="492" height="242" stroke="black" stroke-width="8"/>
<rect x="250" y="82.5" width="26" height="39" fill="#81576D"/>
<rect x="354" y="82.5" width="26" height="39" fill="#81576D"/>
<path d="M263 63L274.258 82.5H251.742L263 63Z" fill="#81576D"/>
<path d="M367 63L378.258 82.5H355.742L367 63Z" fill="#81576D"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M250 121.5H380V186.5H328V160.5C328 153.32 322.18 147.5 315 147.5C307.82 147.5 302 153.32 302 160.5V186.5H250V121.5Z" fill="#81576D"/>
<rect x="20" y="30" width="65" height="50" fill="#003399"/>
<path d="M139.023 103.705C132.932 103.705 127.682 102.261 123.273 99.375C118.864 96.4659 115.466 92.2955 113.08 86.8636C110.693 81.4091 109.511 74.8523 109.534 67.1932C109.557 59.5341 110.75 53.0341 113.114 47.6932C115.5 42.3295 118.886 38.25 123.273 35.4545C127.682 32.6364 132.932 31.2273 139.023 31.2273C145.114 31.2273 150.364 32.6364 154.773 35.4545C159.205 38.25 162.614 42.3295 165 47.6932C167.386 53.0568 168.568 59.5568 168.545 67.1932C168.545 74.875 167.352 81.4432 164.966 86.8977C162.58 92.3523 159.182 96.5227 154.773 99.4091C150.386 102.273 145.136 103.705 139.023 103.705ZM139.023 89.8977C142.659 89.8977 145.602 88.0455 147.852 84.3409C150.102 80.6136 151.216 74.8977 151.193 67.1932C151.193 62.1477 150.682 57.9886 149.659 54.7159C148.636 51.4205 147.216 48.9659 145.398 47.3523C143.58 45.7386 141.455 44.9318 139.023 44.9318C135.409 44.9318 132.489 46.7614 130.261 50.4205C128.034 54.0568 126.909 59.6477 126.886 67.1932C126.864 72.3068 127.352 76.5455 128.352 79.9091C129.375 83.2727 130.807 85.7841 132.648 87.4432C134.489 89.0795 136.614 89.8977 139.023 89.8977Z" fill="#81576D"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -0,0 +1,2 @@
SPDX-FileCopyrightText: Robin van der Linde
SPDX-License-Identifier: CC0-1.0

View file

@ -21,6 +21,8 @@
"startLat": 53.0565,
"startLon": 8.7492,
"layers": [
"elongated_coin"
"elongated_coin",
"souvenir_coin",
"souvenir_note"
]
}

View file

@ -0,0 +1,179 @@
{
"id": "ghostsigns",
"title": {
"en": "Ghost Signs"
},
"description": {
"en": "A map showing disused signs on buildings"
},
"icon": "./assets/themes/advertising/wall_painting.svg",
"layers": [
{
"id": "ghostsigns",
"title": {
"render": {
"en": "Ghost Sign"
}
},
"description": {
"en": "Layer showing disused signs on buildings"
},
"name": {
"en": "Ghost Signs"
},
"source": {
"osmTags": {
"and": [
"historic~*",
"advertising=wall_painting"
]
}
},
"minzoom": 10,
"allowMove": {
"enableImproveAccuracy": true
},
"tagRenderings": [
{
"id": "historic",
"question": {
"en": "Is this a ghost sign?"
},
"questionHint": {
"en": "Is this sign for a business that no longer exists or no longer being maintained?"
},
"mappings": [
{
"if": "historic=advertising",
"then": {
"en": "This is a ghost sign"
},
"alsoShowIf": "historic=yes"
},
{
"if": "historic=",
"then": {
"en": "This is not a ghost sign, answering this will hide the sign from the map"
}
}
]
},
"images",
{
"id": "name",
"condition": "name~*",
"render": {
"*": "{name}"
}
},
{
"id": "inscription",
"question": {
"en": "What is the text on the sign?"
},
"freeform": {
"key": "inscription",
"type": "string",
"placeholder": {
"en": "Text on the sign"
}
},
"render": {
"en": "The text on the sign is: {inscription}"
}
},
{
"id": "brand",
"question": {
"en": "For what business was this sign made?"
},
"freeform": {
"key": "brand",
"type": "string",
"placeholder": {
"en": "Business name"
}
},
"render": {
"en": "This sign was made for: {brand}"
}
}
],
"lineRendering": [
{
"color": "blue",
"width": 2
}
],
"pointRendering": [
{
"location": [
"point",
"centroid"
],
"marker": [
{
"icon": "./assets/themes/advertising/wall_painting.svg"
}
]
}
],
"presets": [
{
"tags": [
"historic=advertising",
"advertising=wall_painting"
],
"title": {
"en": "a ghost sign"
},
"snapToLayer": [
"walls_and_buildings"
],
"maxSnapDistance": 5
}
]
},
{
"builtin": "advertising",
"override": {
"source": {
"osmTags": "advertising=wall_painting"
},
"minzoom": 18,
"+tagRenderings": [
{
"id": "historic",
"question": {
"en": "Is this a ghost sign?"
},
"questionHint": {
"en": "Is this sign for a business that no longer exists or no longer being maintained?"
},
"mappings": [
{
"if": "historic=advertising",
"then": {
"en": "This is a ghost sign"
},
"alsoShowIf": "historic=yes"
},
{
"if": "historic=",
"then": {
"en": "This is not a ghost sign"
}
}
]
}
],
"=presets": [],
"pointRendering": [
{
"iconSize": "20,20"
}
]
}
}
]
}

View file

@ -0,0 +1,14 @@
{
"id": "items_with_image",
"hideFromOverview": true,
"title": {
"en": "All items with images"
},
"description": {
"en": "A map showing all items on OSM which have an image. This theme is a very bad fit for MapComplete as someone is not able to directly add a picture. However, this theme is mostly here to include this all into the database, which'll allow this to quickly fetch images nearby for other features"
},
"icon": "./assets/layers/item_with_image/camera.svg",
"layers": [
"item_with_image"
]
}

View file

@ -286,6 +286,10 @@
"if": "theme=ghostbikes",
"then": "./assets/themes/ghostbikes/logo.svg"
},
{
"if": "theme=ghostsigns",
"then": "./assets/themes/advertising/wall_painting.svg"
},
{
"if": "theme=grb",
"then": "./assets/themes/grb/logo.svg"
@ -318,6 +322,10 @@
"if": "theme=indoors",
"then": "./assets/layers/entrance/entrance.svg"
},
{
"if": "theme=items_with_image",
"then": "./assets/layers/item_with_image/camera.svg"
},
{
"if": "theme=kerbs_and_crossings",
"then": "./assets/layers/kerbs/KerbIcon.svg"

View file

@ -60,6 +60,7 @@
"startLon": 4.399,
"layers": [
"playground",
"playground_equipment",
{
"builtin": [
"bench",

View file

@ -54,7 +54,54 @@
"layers": [
"postboxes",
"postoffices",
"parcel_lockers"
"parcel_lockers",
{
"builtin": "shops",
"override": {
"minzoom": 18,
"minzoomVisible": 18,
"description": {
"en": "Add a new post partner to the map in an existing shop"
},
"+tagRenderings": [
{
"id": "post_partner",
"question": {
"en": "Is this shop a post partner?"
},
"mappings": [
{
"if": "post_office=post_partner",
"then": {
"en": "This shop is a post partner"
}
},
{
"if": "post_office=",
"then": {
"en": "This shop is not a post partner"
}
}
]
}
],
"shownByDefault": false,
"=presets": [
{
"tags": [
"shop=yes",
"post_office=post_partner"
],
"title": {
"en": "a missing shop that is a post partner"
},
"description": {
"en": "If a shop is not yet on the map and is a post partner, you can add it here."
}
}
]
}
}
],
"widenFactor": 1.5,
"clustering": {

View file

@ -27,6 +27,7 @@
"selectReason": "Please, select why this feature should be deleted",
"softDelete": "This feature will be updated and hidden from this application. <span class='subtle'>{reason}</span>"
},
"isChanged": "This feature has been changed and no longer matches this layer",
"isDeleted": "This feature is deleted",
"isntAPoint": "Only nodes can be deleted, the selected feature is a way, area or relation.",
"loading": "Inspecting properties to check if this feature can be deleted.",
@ -222,6 +223,10 @@
"example": "Example",
"examples": "Examples",
"fewChangesBefore": "Please, answer a few questions of existing features before adding a new feature.",
"filterPanel": {
"disableAll": "Disable all",
"enableAll": "Enable all"
},
"geopermissionDenied": "Using the geolocation was denied",
"getStartedLogin": "Log in with OpenStreetMap to get started",
"getStartedNewAccount": " or <a href='https://www.openstreetmap.org/user/new' target='_blank'>create a new account</a>",

View file

@ -69,6 +69,30 @@ interface CategoryQueryAPIResponse {
}
}
interface ImagesQueryAPIResponse {
continue: {
imcontinue: string
continue: string
}
query: {
normalized?: {
from: string
to: string
}[]
pages: {
[key: string]: {
pageid: number
ns: number
title: string
images?: {
ns: number
title: string
}[]
}
}
}
}
interface TemplateQueryAPIResponse {
batchcomplete: string
query: {
@ -96,13 +120,14 @@ const licenseMapping = {}
// Map template names to license names
const templateMapping = {
"Template:PD": "Public Domain",
"Template:CC0": "CC0 1.0",
}
async function main(args: string[]) {
if (args.length < 2) {
console.log("Usage: downloadCommons.ts <output folder> <url> <?url> <?url> .. ")
console.log(
"Example: npx vite-node downloadCommons.ts -- assets/svg https://commons.wikimedia.org/wiki/File:Example.jpg"
"Example: npx vite-node scripts/downloadCommons.ts -- assets/svg https://commons.wikimedia.org/wiki/File:Example.jpg"
)
process.exit(1)
}
@ -128,8 +153,24 @@ async function main(args: string[]) {
for (const member of apiDetails.query.categorymembers) {
await downloadImage(member.title, outputFolder, baseUrl)
}
} else {
} else if (url.includes("File:")) {
await downloadImage(commonsFileName, outputFolder, baseUrl)
} else {
// Probably a page url, try to get all images from the page
const apiUrl = `${baseUrl}/w/api.php?action=query&format=json&prop=images&titles=${commonsFileName}&imlimit=250`
const response = await fetch(apiUrl)
const apiDetails: ImagesQueryAPIResponse = await response.json()
const page = apiDetails.query.pages[Object.keys(apiDetails.query.pages)[0]]
if (page.images) {
for (const image of page.images) {
await downloadImage(image.title, outputFolder, baseUrl)
}
} else {
console.log(
"\x1b[31m%s\x1b[0m",
`URL ${url} doesn't seem to contain any images! Skipping...`
)
}
}
} else {
console.log(
@ -154,6 +195,12 @@ async function downloadImage(filename: string, outputFolder: string, baseUrl: st
const apiDetails: ImageQueryAPIResponse = await response.json()
const missingPage = apiDetails.query.pages["-1"]
// Check if the local file already exists, if it does, skip it
if (existsSync(`${outputFolder}/${filename}`)) {
console.log(`\x1b[33m%s\x1b[0m`, `${filename} already exists, skipping...`)
return
}
// Check if the file exists, locally or externally
if (missingPage !== undefined) {
// Image does not exist locally, check if it exists externally
@ -271,8 +318,8 @@ async function downloadImage(filename: string, outputFolder: string, baseUrl: st
// Save the license information
const licenseInfo: SmallLicense = {
path: cleanFileName,
license: licenseMapping[license] || license,
authors: [author],
license: licenseMapping[license] || license.replace("CC BY", "CC-BY"),
authors: [removeLinks(author)],
sources: [wikiUrl],
}
@ -293,4 +340,9 @@ async function downloadImage(filename: string, outputFolder: string, baseUrl: st
}
}
function removeLinks(text: string): string {
// Remove <a> tags
return text.replace(/<a.*?>(.*?)<\/a>/g, "$1")
}
main(process.argv.slice(2))

View file

@ -5,7 +5,7 @@ import ScriptUtils from "./ScriptUtils"
import Script from "./Script"
const knownLanguages = ["en", "nl", "de", "fr", "es", "gl", "ca"]
const ignoreTerms = ["searchTerms"]
class TranslationPart {
contents: Map<string, TranslationPart | string> = new Map<string, TranslationPart | string>()
@ -49,6 +49,7 @@ class TranslationPart {
if (!translations.hasOwnProperty(translationsKey)) {
continue
}
const v = translations[translationsKey]
if (typeof v != "string") {
console.error(
@ -106,6 +107,9 @@ class TranslationPart {
if (!object.hasOwnProperty(key)) {
continue
}
if (ignoreTerms.indexOf(key) >= 0) {
continue
}
if (dontTranslateKeys?.indexOf(key) >= 0) {
continue

View file

@ -10,6 +10,8 @@ import { WikidataImageProvider } from "./WikidataImageProvider"
* A generic 'from the interwebz' image picker, without attribution
*/
export default class AllImageProviders {
private static dontLoadFromPrefixes = ["https://photos.app.goo.gl/"]
public static ImageAttributionSource: ImageProvider[] = [
Imgur.singleton,
Mapillary.singleton,
@ -19,7 +21,8 @@ export default class AllImageProviders {
[].concat(
...Imgur.defaultValuePrefix,
...WikimediaImageProvider.commonsPrefixes,
...Mapillary.valuePrefixes
...Mapillary.valuePrefixes,
...AllImageProviders.dontLoadFromPrefixes
)
),
]

View file

@ -156,7 +156,7 @@ export class On<P, T> extends DesugaringStep<T> {
convert(json: T, context: ConversionContext): T {
const key = this.key
const value: P = json[key]
const value: P = json?.[key]
if (value === undefined || value === null) {
return json
}

View file

@ -366,7 +366,7 @@ class AddDependencyLayersToTheme extends DesugaringStep<LayoutConfigJson> {
themeId: string
): { config: LayerConfigJson; reason: string }[] {
const dependenciesToAdd: { config: LayerConfigJson; reason: string }[] = []
const loadedLayerIds: Set<string> = new Set<string>(alreadyLoaded.map((l) => l.id))
const loadedLayerIds: Set<string> = new Set<string>(alreadyLoaded.map((l) => l?.id))
// Verify cross-dependencies
let unmetDependencies: {

View file

@ -111,7 +111,6 @@ export default class ThemeViewState implements SpecialVisualizationState {
readonly perLayerFiltered: ReadonlyMap<string, FilteringFeatureSource>
readonly availableLayers: Store<RasterLayerPolygon[]>
readonly selectedLayer: UIEventSource<LayerConfig>
readonly userRelatedState: UserRelatedState
readonly geolocation: GeoLocationHandler
readonly geolocationControl: GeolocationControlState
@ -732,7 +731,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
doShowLayer: flayer.isDisplayed,
layer: flayer.layerDef,
metaTags: this.userRelatedState.preferencesAsTags,
selectedElement: this.selectedElement
selectedElement: this.selectedElement,
})
})
}

View file

@ -6,10 +6,14 @@
*/
export let selected: UIEventSource<boolean>
let _c: boolean = selected.data ?? true
let id = `checkbox-input-${Math.round(Math.random()*100000000)}`
$: selected.set(_c)
selected.addCallbackD(s => {
_c = s
})
</script>
<label class="no-image-background flex items-center gap-1">
<input bind:checked={_c} type="checkbox" />
<input bind:checked={_c} type="checkbox" {id} />
<slot />
</label>

View file

@ -1,17 +1,49 @@
<script lang="ts">
/**
* THe panel containing all filter- and layerselection options
*/
/**
* THe panel containing all filter- and layerselection options
*/
import OverlayToggle from "./OverlayToggle.svelte"
import Filterview from "./Filterview.svelte"
import ThemeViewState from "../../Models/ThemeViewState"
import Translations from "../i18n/Translations"
import Tr from "../Base/Tr.svelte"
import Filter from "../../assets/svg/Filter.svelte"
import OverlayToggle from "./OverlayToggle.svelte"
import Filterview from "./Filterview.svelte"
import ThemeViewState from "../../Models/ThemeViewState"
import Translations from "../i18n/Translations"
import Tr from "../Base/Tr.svelte"
import Filter from "../../assets/svg/Filter.svelte"
export let state: ThemeViewState
let layout = state.layout
export let state: ThemeViewState
let layout = state.layout
let allEnabled : boolean
let allDisabled: boolean
function updateEnableState(){
allEnabled = true
allDisabled = true
state.layerState.filteredLayers.forEach((v) => {
if(!v.layerDef.name){
return
}
allEnabled &&= v.isDisplayed.data
allDisabled &&= !v.isDisplayed.data
})
}
updateEnableState()
state.layerState.filteredLayers.forEach((v) => {
if(!v.layerDef.name){
return
}
v.isDisplayed.addCallbackD(_ => updateEnableState())
})
function enableAll(doEnable: boolean){
state.layerState.filteredLayers.forEach((v) => {
if(!v.layerDef.name){
return
}
v.isDisplayed.setData(doEnable)
})
}
</script>
<div class="m-2 flex flex-col">
@ -27,6 +59,15 @@
highlightedLayer={state.guistate.highlightedLayerInFilters}
/>
{/each}
<div class="flex self-end mt-1">
<button class="small" class:disabled={allEnabled} on:click={() => enableAll(true)}>
<Tr t={Translations.t.general.filterPanel.enableAll}/>
</button>
<button class="small" class:disabled={allDisabled} on:click={() => enableAll(false)}>
<Tr t={Translations.t.general.filterPanel.disableAll}/>
</button>
</div>
{#each layout.tileLayerSources as tilesource}
<OverlayToggle
layerproperties={tilesource}

View file

@ -17,6 +17,9 @@
export let tags: UIEventSource<Record<string, string>> = state.featureProperties.getStore(
selectedElement.properties.id
)
let stillMatches = tags.map(tags => !layer?.source?.osmTags || layer.source.osmTags?.matchesProperties(tags))
let _metatags: Record<string, string>
onDestroy(
@ -35,7 +38,11 @@
)
</script>
{#if $tags._deleted === "yes"}
{#if !$stillMatches}
<div class="alert" aria-live="assertive">
<Tr t={Translations.t.delete.isChanged}/>
</div>
{:else if $tags._deleted === "yes"}
<div aria-live="assertive">
<Tr t={Translations.t.delete.isDeleted} />
</div>

View file

@ -90,7 +90,7 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
this.lastClickLocation = lastClickLocation
const self = this
const rasterLayerHandler = new RasterLayerHandler(this._maplibreMap, this.rasterLayer)
new RasterLayerHandler(this._maplibreMap, this.rasterLayer)
function handleClick(e) {
if (e.originalEvent["consumed"]) {
@ -114,7 +114,6 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
self.setMaxzoom(self.maxzoom.data)
self.setBounds(self.bounds.data)
self.setTerrain(self.useTerrain.data)
rasterLayerHandler.setBackground()
this.updateStores(true)
})
self.MoveMapToCurrentLoc(self.location.data)
@ -128,7 +127,6 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
self.setBounds(self.bounds.data)
self.SetRotation(self.rotation.data)
self.setTerrain(self.useTerrain.data)
rasterLayerHandler.setBackground()
this.updateStores(true)
map.on("moveend", () => this.updateStores())
map.on("click", (e) => {
@ -177,7 +175,6 @@ export class MapLibreAdaptor implements MapProperties, ExportableMap {
})
})
this.rasterLayer.addCallbackAndRun((_) => rasterLayerHandler.setBackground())
this.location.addCallbackAndRunD((loc) => {
self.MoveMapToCurrentLoc(loc)
})

View file

@ -11,6 +11,7 @@
import type { MapProperties } from "../../Models/MapProperties"
import { onDestroy } from "svelte"
import type { RasterLayerPolygon } from "../../Models/RasterLayers"
import StyleLoadingIndicator from "./StyleLoadingIndicator.svelte"
export let placedOverMapProperties: MapProperties
export let placedOverMap: Store<MlMap>
@ -64,9 +65,13 @@
updateLocation()
window.setTimeout(updateLocation, 150)
window.setTimeout(updateLocation, 500)
})
}),
)
}
</script>
<div class="absolute w-full h-full flex items-center justify-center"
style="z-index: 100">
<StyleLoadingIndicator map={altmap} />
</div>
<MaplibreMap {interactive} map={altmap} />

View file

@ -71,7 +71,7 @@ class SingleBackgroundHandler {
this.fadeOut()
} else {
this._deactivationTime = undefined
this.enable()
await this.enable()
this.fadeIn()
}
}
@ -85,10 +85,23 @@ class SingleBackgroundHandler {
}
}
private enable() {
private async enable(){
let ttl = 15
await this.awaitStyleIsLoaded()
while(!this.tryEnable() && ttl > 0){
ttl --;
await Utils.waitFor(250)
}
}
/**
* Returns 'false' if should be attempted again
* @private
*/
private tryEnable(): boolean {
const map: MLMap = this._map.data
if (!map) {
return
return true
}
const background = this._targetLayer.properties
console.debug("Enabling", background.id)
@ -101,8 +114,7 @@ class SingleBackgroundHandler {
try {
map.addSource(background.id, RasterLayerHandler.prepareWmsSource(background))
} catch (e) {
console.error("Could not add source", e)
return
return false
}
}
if (!map.getLayer(background.id)) {
@ -126,6 +138,7 @@ class SingleBackgroundHandler {
map.setPaintProperty(background.id, "raster-opacity", o)
})
}
return true
}
private fadeOut() {
@ -144,23 +157,15 @@ class SingleBackgroundHandler {
}
export default class RasterLayerHandler {
private _map: Store<MLMap>
private _background: UIEventSource<RasterLayerPolygon | undefined>
private _singleLayerHandlers: Record<string, SingleBackgroundHandler> = {}
constructor(map: Store<MLMap>, background: UIEventSource<RasterLayerPolygon | undefined>) {
this._map = map
this._background = background
background.addCallbackAndRunD((l) => {
const key = l.properties.id
if (!this._singleLayerHandlers[key]) {
this._singleLayerHandlers[key] = new SingleBackgroundHandler(map, l, background)
}
})
map.addCallback((map) => {
map.on("load", () => this.setBackground())
this.setBackground()
})
}
public static prepareWmsSource(layer: RasterLayerProperties): SourceSpecification {
@ -203,9 +208,4 @@ export default class RasterLayerHandler {
return url
}
/**
* Performs all necessary updates
*/
public setBackground() {}
}

View file

@ -5,6 +5,7 @@
import { Store, UIEventSource } from "../../Logic/UIEventSource"
import { Map as MlMap } from "maplibre-gl"
import { createEventDispatcher, onDestroy } from "svelte"
import StyleLoadingIndicator from "./StyleLoadingIndicator.svelte"
/***
* Chooses a background-layer out of available options
@ -78,7 +79,7 @@
{#if hasLayers}
<form class="flex h-full w-full flex-col" on:submit|preventDefault={() => {}}>
<button tabindex="-1" on:click={() => apply()} class="m-0 h-full w-full cursor-pointer p-1">
<div class="pointer-events-none h-full w-full">
<span class="pointer-events-none h-full w-full relative">
<OverlayMap
interactive={false}
rasterLayer={rasterLayerOnMap}
@ -86,7 +87,7 @@
placedOverMapProperties={mapproperties}
{visible}
/>
</div>
</span>
</button>
<select bind:value={$rasterLayer} class="w-full" on:keydown={handleKeyPress}>
{#each $availableLayers as availableLayer}

View file

@ -0,0 +1,19 @@
<script lang="ts">
import Loading from "../Base/Loading.svelte"
import { Stores, UIEventSource } from "../../Logic/UIEventSource"
import { Map as MlMap } from "maplibre-gl"
import { onDestroy } from "svelte"
let isLoading = false
export let map: UIEventSource<MlMap>
onDestroy(Stores.Chronic(250).addCallback(
() => {
isLoading = !map.data?.isStyleLoaded()
},
))
</script>
{#if isLoading}
<Loading />
{/if}