Better social images

This commit is contained in:
pietervdvn 2022-03-08 04:09:03 +01:00
parent 54158767d2
commit 135d8644da
25 changed files with 6032 additions and 668 deletions

View file

@ -8,6 +8,7 @@ import {ExtractImages} from "./Conversion/FixImages";
import ExtraLinkConfig from "./ExtraLinkConfig"; import ExtraLinkConfig from "./ExtraLinkConfig";
export default class LayoutConfig { export default class LayoutConfig {
public static readonly defaultSocialImage = "assets/SocialImage.png"
public readonly id: string; public readonly id: string;
public readonly maintainer: string; public readonly maintainer: string;
public readonly credits?: string; public readonly credits?: string;
@ -54,7 +55,7 @@ export default class LayoutConfig {
public readonly usedImages: string[] public readonly usedImages: string[]
public readonly extraLink?: ExtraLinkConfig public readonly extraLink?: ExtraLinkConfig
constructor(json: LayoutConfigJson, official = true, context?: string) { constructor(json: LayoutConfigJson, official = true, context?: string) {
this.official = official; this.official = official;
this.id = json.id; this.id = json.id;
@ -103,10 +104,10 @@ export default class LayoutConfig {
this.shortDescription = json.shortDescription === undefined ? this.description.FirstSentence() : new Translation(json.shortDescription, context + ".shortdescription"); this.shortDescription = json.shortDescription === undefined ? this.description.FirstSentence() : new Translation(json.shortDescription, context + ".shortdescription");
this.descriptionTail = json.descriptionTail === undefined ? undefined : new Translation(json.descriptionTail, context + ".descriptionTail"); this.descriptionTail = json.descriptionTail === undefined ? undefined : new Translation(json.descriptionTail, context + ".descriptionTail");
this.icon = json.icon; this.icon = json.icon;
this.socialImage = json.socialImage; this.socialImage = json.socialImage ?? LayoutConfig.defaultSocialImage;
if (this.socialImage === null || this.socialImage === "" || this.socialImage === undefined) { if (this.socialImage === "") {
if (official) { if (official) {
throw "Theme " + json.id + " has no social image defined" throw "Theme " + json.id + " has empty string as social image"
} }
} }
this.startZoom = json.startZoom; this.startZoom = json.startZoom;

View file

@ -432,27 +432,32 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
/** /**
* Apply a function on every leaf of the JSON; used to rewrite parts of the JSON * Apply a function on every leaf of the JSON; used to rewrite parts of the JSON
* @param json
* @param f
* @constructor
*/ */
static WalkJson(json: any, f: (v: number | string | boolean | undefined) => any) { static WalkJson(json: any, f: (v: number | string | boolean | undefined) => any, isLeaf: (object) => boolean = undefined) {
if (json === undefined) { if (json === undefined) {
return f(undefined) return f(undefined)
} }
const jtp = typeof json const jtp = typeof json
if (jtp === "boolean" || jtp === "string" || jtp === "number") { if(isLeaf !== undefined) {
if(jtp === "object"){
if(isLeaf(json)){
return f(json)
}
} else {
return json
}
}else if (jtp === "boolean" || jtp === "string" || jtp === "number") {
return f(json) return f(json)
} }
if (json.map !== undefined) { if (Array.isArray(json)) {
return json.map(sub => { return json.map(sub => {
return Utils.WalkJson(sub, f); return Utils.WalkJson(sub, f, isLeaf);
}) })
} }
const cp = {...json} const cp = {...json}
for (const key in json) { for (const key in json) {
cp[key] = Utils.WalkJson(json[key], f) cp[key] = Utils.WalkJson(json[key], f, isLeaf)
} }
return cp return cp
} }

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 3.1 MiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 3.1 MiB

View file

@ -1 +1,55 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 141.73 141.73"><defs><style>.cls-1{fill:#fff;}.cls-2{fill:#3c3d3c;}</style></defs><g id="Laag_1" data-name="Laag 1"><circle class="cls-1" cx="70.87" cy="70.87" r="70.87"/></g><g id="Laag_2" data-name="Laag 2"><path class="cls-2" d="M102.39,75a18.18,18.18,0,0,0-3.92.43L92.87,57a7,7,0,0,0-6.77-5H80.67v2.59H86.1a4.45,4.45,0,0,1,4.29,3.19l1.72,5.66H55.54l-2-4.89h3.72S62,57.77,62,54.14H46.39v4.33h4.35l2.55,6.25L47.67,76.27A18.31,18.31,0,1,0,59,96.27h8l1-.43L93.33,67.37,96,76.15a18.28,18.28,0,1,0,6.4-1.17ZM41,109a15.72,15.72,0,1,1,5.58-30.4l-7.69,15.8L40,96.27H56.38A15.74,15.74,0,0,1,41,109Zm15.7-15.33H42.07l6.8-14a15.71,15.71,0,0,1,7.8,13.56C56.67,93.42,56.66,93.55,56.65,93.68ZM50,77.39l4.61-9.45,10.5,25.74H59.24c0-.13,0-.26,0-.39A18.33,18.33,0,0,0,50,77.39ZM67.45,92.56,56.59,66H91.13ZM102.39,109a15.71,15.71,0,0,1-5.65-30.38l4.56,15,2.48-.76-4.56-15A15.72,15.72,0,1,1,102.39,109Z"/><path class="cls-2" d="M78.72,40.26a13.89,13.89,0,0,1-5.58,1.25,9.86,9.86,0,0,1-5.6-1.61,9,9,0,0,1-3.39-4.41h9.4l1.07-2.89-.13-.36h-11a2.91,2.91,0,0,1,0-.4v-.57c0-.4,0-.79.05-1.17h12l1.08-2.93L76.36,27H64.13a8.69,8.69,0,0,1,3.48-4.43A10.82,10.82,0,0,1,73.55,21a16.47,16.47,0,0,1,4.55.68l.13,0,1.08-3-.15-.05a16.56,16.56,0,0,0-5.3-.81,14.91,14.91,0,0,0-8.42,2.35A11.73,11.73,0,0,0,60.66,27h-2.3l-1.08,2.93.19.19h2.69c0,.16,0,.32,0,.49v1.23c0,.14,0,.29,0,.42h-1.8L57.28,35.3l.19.19h3.21a12.2,12.2,0,0,0,4.48,6.72,12.47,12.47,0,0,0,7.64,2.46A16.44,16.44,0,0,0,79,43.39l.09,0v-3l-.28-.16Z"/></g></svg> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 141.73 141.73"
version="1.1"
id="svg14"
sodipodi:docname="rental.svg"
inkscape:version="1.1.1 (1:1.1+202109281949+c3084ef5ed)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview16"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="2.6516417"
inkscape:cx="41.10661"
inkscape:cy="42.615109"
inkscape:current-layer="svg14" />
<defs
id="defs4">
<style
id="style2">.cls-1{fill:#fff;}.cls-2{fill:#3c3d3c;}</style>
</defs>
<g
id="g838">
<g
id="Laag_1"
data-name="Laag 1">
<circle
class="cls-1"
cx="70.87"
cy="70.87"
r="70.87"
id="circle6" />
</g>
<g
id="Laag_2"
data-name="Laag 2">
<path
class="cls-2"
d="M102.39,75a18.18,18.18,0,0,0-3.92.43L92.87,57a7,7,0,0,0-6.77-5H80.67v2.59H86.1a4.45,4.45,0,0,1,4.29,3.19l1.72,5.66H55.54l-2-4.89h3.72S62,57.77,62,54.14H46.39v4.33h4.35l2.55,6.25L47.67,76.27A18.31,18.31,0,1,0,59,96.27h8l1-.43L93.33,67.37,96,76.15a18.28,18.28,0,1,0,6.4-1.17ZM41,109a15.72,15.72,0,1,1,5.58-30.4l-7.69,15.8L40,96.27H56.38A15.74,15.74,0,0,1,41,109Zm15.7-15.33H42.07l6.8-14a15.71,15.71,0,0,1,7.8,13.56C56.67,93.42,56.66,93.55,56.65,93.68ZM50,77.39l4.61-9.45,10.5,25.74H59.24c0-.13,0-.26,0-.39A18.33,18.33,0,0,0,50,77.39ZM67.45,92.56,56.59,66H91.13ZM102.39,109a15.71,15.71,0,0,1-5.65-30.38l4.56,15,2.48-.76-4.56-15A15.72,15.72,0,1,1,102.39,109Z"
id="path9" />
<path
class="cls-2"
d="M78.72,40.26a13.89,13.89,0,0,1-5.58,1.25,9.86,9.86,0,0,1-5.6-1.61,9,9,0,0,1-3.39-4.41h9.4l1.07-2.89-.13-.36h-11a2.91,2.91,0,0,1,0-.4v-.57c0-.4,0-.79.05-1.17h12l1.08-2.93L76.36,27H64.13a8.69,8.69,0,0,1,3.48-4.43A10.82,10.82,0,0,1,73.55,21a16.47,16.47,0,0,1,4.55.68l.13,0,1.08-3-.15-.05a16.56,16.56,0,0,0-5.3-.81,14.91,14.91,0,0,0-8.42,2.35A11.73,11.73,0,0,0,60.66,27h-2.3l-1.08,2.93.19.19h2.69c0,.16,0,.32,0,.49v1.23c0,.14,0,.29,0,.42h-1.8L57.28,35.3l.19.19h3.21a12.2,12.2,0,0,0,4.48,6.72,12.47,12.47,0,0,0,7.64,2.46A16.44,16.44,0,0,0,79,43.39l.09,0v-3l-.28-.16Z"
id="path11" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -2,16 +2,34 @@
<!-- Created with Inkscape (http://www.inkscape.org/) --> <!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg <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"
version="1.1" version="1.1"
width="100%" width="14px"
height="100%" height="14px"
viewBox="0 0 14 14" viewBox="0 0 14 14"
id="svg2"> id="svg2"
sodipodi:docname="recycling-14.svg"
inkscape:version="1.1.1 (1:1.1+202109281949+c3084ef5ed)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
id="namedview7"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
showgrid="false"
units="px"
inkscape:zoom="60.071429"
inkscape:cx="6.9916766"
inkscape:cy="7.0083234"
inkscape:current-layer="svg2" />
<metadata <metadata
id="metadata8"> id="metadata8">
<rdf:RDF> <rdf:RDF>
@ -20,7 +38,6 @@
<dc:format>image/svg+xml</dc:format> <dc:format>image/svg+xml</dc:format>
<dc:type <dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work> </cc:Work>
</rdf:RDF> </rdf:RDF>
</metadata> </metadata>
@ -32,9 +49,9 @@
x="0" x="0"
y="0" y="0"
id="canvas" id="canvas"
style="fill:none;stroke:none;visibility:hidden" /> style="visibility:hidden;fill:none;stroke:none" />
<path <path
d="M 5.111113,8.690628 3.513352,5.804047 0.3,5.804047 1.60621,6.5880837 0.798678,8.031102 c -0.06887,0.130859 -0.103304,0.267511 -0.103301,0.409961 -3e-6,0.142456 0.03443,0.27911 0.103301,0.40996 l 1.271077,2.298282 c 0.05733,-0.166376 0.11466,-0.309011 0.171995,-0.427902 L 3.82273,7.906591 5.111113,8.690628 z m -2.38799,2.316224 c -0.09194,0.154416 -0.137914,0.320611 -0.13791,0.498585 -4e-6,0.273307 0.09456,0.504931 0.283685,0.694868 0.189119,0.189939 0.415298,0.284906 0.678537,0.284906 l 3.161963,0 0,-2.654413 -3.333432,0 C 3.352886,9.878288 3.266892,10.0327 3.117975,10.294041 l -0.394852,0.712811 z m 4.278351,-6.5745954 3.196047,0 L 11.812587,1.54622 10.506901,2.3302555 9.698844,0.8866933 C 9.549912,0.6137609 9.320934,0.4772893 9.011916,0.4772767 l -2.543205,0 c 0.10312,0.1185426 0.189116,0.2372528 0.257992,0.3561331 L 8.289856,3.6482199 8.032389,3.8086154 7.001474,4.4322566 z M 5.437797,0.6197306 C 5.07108,0.6197421 4.796134,0.7859374 4.61296,1.1183163 L 3.015198,3.9690109 C 3.622066,4.3372941 4.360906,4.7767964 5.231719,5.2875185 5.746994,4.372999 6.302478,3.3752843 6.898173,2.2943703 L 6.262635,1.1183163 C 6.079446,0.7859374 5.804501,0.6197421 5.437797,0.6197306 l 0,0 z m 4.106882,9.1751824 0,-0.320793 0,-1.228795 L 7.946393,11.131363 9.544679,14 l 0,-1.55013 1.597761,0 c 0.309366,0 0.54411,-0.136653 0.704231,-0.409962 l 1.271602,-2.298279 c -0.171656,0.04749 -0.314811,0.07123 -0.42946,0.07123 L 9.544679,9.794909 z m 2.37121,-4.88147 c -0.05735,0.035533 -0.79636,0.4750321 -2.217045,1.3185066 0.710337,1.2708484 1.271764,2.2745434 1.684282,3.0110934 l 1.288383,0 c 0.378233,2e-6 0.658946,-0.166373 0.842142,-0.499132 0.171629,-0.320788 0.165862,-0.647379 -0.01731,-0.979774 l -1.58045,-2.850694 z" d="M 5.111113,8.690628 3.513352,5.804047 H 0.3 L 1.60621,6.5880837 0.798678,8.031102 c -0.06887,0.130859 -0.103304,0.267511 -0.103301,0.409961 -3e-6,0.142456 0.03443,0.27911 0.103301,0.40996 l 1.271077,2.298282 c 0.05733,-0.166376 0.11466,-0.309011 0.171995,-0.427902 L 3.82273,7.906591 Z m -2.38799,2.316224 c -0.09194,0.154416 -0.137914,0.320611 -0.13791,0.498585 -4e-6,0.273307 0.09456,0.504931 0.283685,0.694868 0.189119,0.189939 0.415298,0.284906 0.678537,0.284906 H 6.709398 V 9.830798 H 3.375966 C 3.352886,9.878288 3.266892,10.0327 3.117975,10.294041 Z M 7.001474,4.4322566 h 3.196047 L 11.812587,1.54622 10.506901,2.3302555 9.698844,0.8866933 C 9.549912,0.6137609 9.320934,0.4772893 9.011916,0.4772767 H 6.468711 c 0.10312,0.1185426 0.189116,0.2372528 0.257992,0.3561331 L 8.289856,3.6482199 8.032389,3.8086154 Z M 5.437797,0.6197306 C 5.07108,0.6197421 4.796134,0.7859374 4.61296,1.1183163 L 3.015198,3.9690109 C 3.622066,4.3372941 4.360906,4.7767964 5.231719,5.2875185 5.746994,4.372999 6.302478,3.3752843 6.898173,2.2943703 L 6.262635,1.1183163 C 6.079446,0.7859374 5.804501,0.6197421 5.437797,0.6197306 Z M 9.544679,9.794913 V 9.47412 8.245325 L 7.946393,11.131363 9.544679,14 v -1.55013 h 1.597761 c 0.309366,0 0.54411,-0.136653 0.704231,-0.409962 l 1.271602,-2.298279 c -0.171656,0.04749 -0.314811,0.07123 -0.42946,0.07123 L 9.544679,9.794909 Z m 2.37121,-4.88147 c -0.05735,0.035533 -0.79636,0.4750321 -2.217045,1.3185066 0.710337,1.2708484 1.271764,2.2745434 1.684282,3.0110934 h 1.288383 c 0.378233,2e-6 0.658946,-0.166373 0.842142,-0.499132 0.171629,-0.320788 0.165862,-0.647379 -0.01731,-0.979774 l -1.58045,-2.850694 z"
id="recycling" id="recycling"
style="fill:#000000;fill-opacity:1;stroke:none" /> style="fill:#000000;fill-opacity:1;stroke:none" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -352,7 +352,8 @@
"zh_Hant": "這間商業空間是否允許犬隻?", "zh_Hant": "這間商業空間是否允許犬隻?",
"ru": "Впускают ли собак в это здание?", "ru": "Впускают ли собак в это здание?",
"pl": "Czy w tej firmie psy są dozwolone?", "pl": "Czy w tej firmie psy są dozwolone?",
"ja": "犬を飼うことができますか?" "ja": "犬を飼うことができますか?",
"id": "Apakah anjing diperbolehkan dalam bisnis ini?"
}, },
"mappings": [ "mappings": [
{ {
@ -435,7 +436,8 @@
"zh_Hant": "允許犬隻而且可以自由跑動", "zh_Hant": "允許犬隻而且可以自由跑動",
"ru": "Собак свободно впускают", "ru": "Собак свободно впускают",
"pl": "Psy dozwolone i mogą biegać bez ograniczeń", "pl": "Psy dozwolone i mogą biegać bez ograniczeń",
"ja": "犬同伴可能、自由に走り回れる" "ja": "犬同伴可能、自由に走り回れる",
"id": "Anjing diperbolehkan dan dapat berkeliaran dengan bebas"
} }
} }
] ]
@ -754,7 +756,8 @@
"it": "Si trova sotto il livello stradale", "it": "Si trova sotto il livello stradale",
"nb_NO": "Under bakken", "nb_NO": "Under bakken",
"ca": "Situat a planta subterrani", "ca": "Situat a planta subterrani",
"ja": "地下にあります" "ja": "地下にあります",
"id": "Terletak di bawah tanah"
}, },
"hideInAnswer": true "hideInAnswer": true
}, },
@ -776,7 +779,8 @@
"it": "Si trova al pianoterra", "it": "Si trova al pianoterra",
"nb_NO": "På gateplan", "nb_NO": "På gateplan",
"ca": "Situat a planta zero", "ca": "Situat a planta zero",
"ja": "1階にあります" "ja": "1階にあります",
"id": "Terletak di lantai dasar"
} }
}, },
{ {
@ -798,7 +802,8 @@
"it": "Si trova al pianoterra", "it": "Si trova al pianoterra",
"nb_NO": "På gateplan", "nb_NO": "På gateplan",
"ca": "Situat a planta zero", "ca": "Situat a planta zero",
"ja": "1階にあります" "ja": "1階にあります",
"id": "Terletak di lantai dasar"
} }
}, },
{ {
@ -830,7 +835,8 @@
"nl": "Bevindt zich in de eerste kelderverdieping", "nl": "Bevindt zich in de eerste kelderverdieping",
"zh_Hant": "位於地下一樓", "zh_Hant": "位於地下一樓",
"de": "Ist im 1. Untergeschoss", "de": "Ist im 1. Untergeschoss",
"hu": "Az első alagsori szinten" "hu": "Az első alagsori szinten",
"id": "Terletak di lantai basement pertama"
} }
} }
] ]

View file

@ -19,7 +19,7 @@
"pt_BR": "Abrir mapa AED" "pt_BR": "Abrir mapa AED"
}, },
"maintainer": "MapComplete", "maintainer": "MapComplete",
"icon": "./assets/themes/aed/logo.svg", "icon": "./assets/themes/aed/aed.svg",
"description": { "description": {
"en": "On this map, one can find and mark nearby defibrillators", "en": "On this map, one can find and mark nearby defibrillators",
"ca": "En aquest mapa , qualsevol pot trobar i marcar els desfibril·ladors externs automàtics més propers", "ca": "En aquest mapa , qualsevol pot trobar i marcar els desfibril·ladors externs automàtics més propers",

View file

@ -1,8 +1,30 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" width="375px" height="375px" viewBox="0 0 375 375" version="1.1"> <svg
<g id="surface1"> width="375px"
<rect x="0" y="0" width="375" height="375" style="fill:rgb(0%,53.333336%,33.333334%);fill-opacity:1;stroke:none;"/> height="375px"
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 279.210938 32.8125 L 309.375 32.8125 L 309.375 63.179688 L 339.742188 63.179688 L 339.742188 93.34375 L 309.375 93.34375 L 309.375 123.710938 L 279.210938 123.710938 L 279.210938 93.34375 L 248.84375 93.34375 L 248.84375 63.179688 L 279.210938 63.179688 Z M 279.210938 32.8125 "/> viewBox="0 0 375 375"
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 96.808594 114.742188 C 57.675781 115.148438 22.621094 154.074219 33.21875 205.433594 C 41.167969 244.769531 82.949219 295.71875 155.707031 345.039062 C 228.464844 295.515625 270.246094 244.566406 278.191406 205.433594 C 288.789062 153.871094 253.941406 115.148438 214.605469 114.742188 C 194.429688 114.335938 169.15625 125.136719 155.707031 150.816406 C 142.253906 125.136719 116.984375 114.335938 96.808594 114.742188 Z M 187.09375 145.925781 L 152.851562 216.238281 L 196.261719 216.238281 L 120.246094 304.6875 L 149.59375 235.394531 L 107.40625 235.394531 Z M 187.09375 145.925781 "/> version="1.1"
id="svg9"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs13" />
<g
id="surface1">
<rect
x="0"
y="0"
width="375"
height="375"
style="fill:rgb(0%,53.333336%,33.333334%);fill-opacity:1;stroke:none;"
id="rect2" />
<path
style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;"
d="M 279.210938 32.8125 L 309.375 32.8125 L 309.375 63.179688 L 339.742188 63.179688 L 339.742188 93.34375 L 309.375 93.34375 L 309.375 123.710938 L 279.210938 123.710938 L 279.210938 93.34375 L 248.84375 93.34375 L 248.84375 63.179688 L 279.210938 63.179688 Z M 279.210938 32.8125 "
id="path4" />
<path
style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;"
d="M 96.808594 114.742188 C 57.675781 115.148438 22.621094 154.074219 33.21875 205.433594 C 41.167969 244.769531 82.949219 295.71875 155.707031 345.039062 C 228.464844 295.515625 270.246094 244.566406 278.191406 205.433594 C 288.789062 153.871094 253.941406 115.148438 214.605469 114.742188 C 194.429688 114.335938 169.15625 125.136719 155.707031 150.816406 C 142.253906 125.136719 116.984375 114.335938 96.808594 114.742188 Z M 187.09375 145.925781 L 152.851562 216.238281 L 196.261719 216.238281 L 120.246094 304.6875 L 149.59375 235.394531 L 107.40625 235.394531 Z M 187.09375 145.925781 "
id="path6" />
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -4,7 +4,7 @@
"nl": "Open AED-kaart - Brugge edition" "nl": "Open AED-kaart - Brugge edition"
}, },
"maintainer": "MapComplete", "maintainer": "MapComplete",
"icon": "./assets/themes/aed/logo.svg", "icon": "./assets/themes/aed/aed.svg",
"description": { "description": {
"nl": "Op deze kaart kan je informatie over AEDs vinden en verbeteren + een export van de brugse defibrillatoren" "nl": "Op deze kaart kan je informatie over AEDs vinden en verbeteren + een export van de brugse defibrillatoren"
}, },

View file

@ -8,15 +8,5 @@
"sources": [ "sources": [
"https://commons.wikimedia.org/wiki/File:ISO_7010_E010.svg" "https://commons.wikimedia.org/wiki/File:ISO_7010_E010.svg"
] ]
},
{
"path": "logo.svg",
"license": "CC-BY-SA 4.0",
"authors": [
"M!dgard"
],
"sources": [
"https://commons.wikimedia.org/wiki/File:ISO_7010_E010.svg"
]
} }
] ]

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 54 KiB

View file

@ -25,7 +25,8 @@
"zh_Hant": "長椅的地圖", "zh_Hant": "長椅的地圖",
"nb_NO": "Et benkekart", "nb_NO": "Et benkekart",
"pt_BR": "Um mapa de bancadas", "pt_BR": "Um mapa de bancadas",
"hu": "Padtérkép" "hu": "Padtérkép",
"id": "Peta bangku"
}, },
"description": { "description": {
"en": "This map shows all benches that are recorded in OpenStreetMap: Individual benches, and benches belonging to public transport stops or shelters. With an OpenStreetMap account, you can map new benches or edit details of existing benches.", "en": "This map shows all benches that are recorded in OpenStreetMap: Individual benches, and benches belonging to public transport stops or shelters. With an OpenStreetMap account, you can map new benches or edit details of existing benches.",

View file

@ -3,12 +3,14 @@
"title": { "title": {
"en": "Bicycle rental", "en": "Bicycle rental",
"nl": "Fietsverhuur", "nl": "Fietsverhuur",
"de": "Fahrradverleih" "de": "Fahrradverleih",
"id": "Sewa sepeda"
}, },
"shortDescription": { "shortDescription": {
"en": "A map with bicycle rental stations and bicycle rental shops", "en": "A map with bicycle rental stations and bicycle rental shops",
"nl": "Een kaart met fietsverhuurpunten en fietsverhuurzaken", "nl": "Een kaart met fietsverhuurpunten en fietsverhuurzaken",
"de": "Eine Karte mit Fahrradverleihstationen und Fahrradverleihern" "de": "Eine Karte mit Fahrradverleihstationen und Fahrradverleihern",
"id": "Peta dengan stasiun persewaan sepeda dan toko penyewaan sepeda"
}, },
"description": { "description": {
"en": "On this map, you'll find the many bicycle rental stations as they are known by OpenStreetMap", "en": "On this map, you'll find the many bicycle rental stations as they are known by OpenStreetMap",

View file

@ -1 +1,56 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 141.73 141.73"><defs><style>.cls-1{fill:#fff;}.cls-2{fill:#3c3d3c;}</style></defs><g id="Laag_1" data-name="Laag 1"><circle class="cls-1" cx="70.87" cy="70.87" r="70.87"/></g><g id="Laag_2" data-name="Laag 2"><path class="cls-2" d="M102.39,75a18.18,18.18,0,0,0-3.92.43L92.87,57a7,7,0,0,0-6.77-5H80.67v2.59H86.1a4.45,4.45,0,0,1,4.29,3.19l1.72,5.66H55.54l-2-4.89h3.72S62,57.77,62,54.14H46.39v4.33h4.35l2.55,6.25L47.67,76.27A18.31,18.31,0,1,0,59,96.27h8l1-.43L93.33,67.37,96,76.15a18.28,18.28,0,1,0,6.4-1.17ZM41,109a15.72,15.72,0,1,1,5.58-30.4l-7.69,15.8L40,96.27H56.38A15.74,15.74,0,0,1,41,109Zm15.7-15.33H42.07l6.8-14a15.71,15.71,0,0,1,7.8,13.56C56.67,93.42,56.66,93.55,56.65,93.68ZM50,77.39l4.61-9.45,10.5,25.74H59.24c0-.13,0-.26,0-.39A18.33,18.33,0,0,0,50,77.39ZM67.45,92.56,56.59,66H91.13ZM102.39,109a15.71,15.71,0,0,1-5.65-30.38l4.56,15,2.48-.76-4.56-15A15.72,15.72,0,1,1,102.39,109Z"/><path class="cls-2" d="M78.72,40.26a13.89,13.89,0,0,1-5.58,1.25,9.86,9.86,0,0,1-5.6-1.61,9,9,0,0,1-3.39-4.41h9.4l1.07-2.89-.13-.36h-11a2.91,2.91,0,0,1,0-.4v-.57c0-.4,0-.79.05-1.17h12l1.08-2.93L76.36,27H64.13a8.69,8.69,0,0,1,3.48-4.43A10.82,10.82,0,0,1,73.55,21a16.47,16.47,0,0,1,4.55.68l.13,0,1.08-3-.15-.05a16.56,16.56,0,0,0-5.3-.81,14.91,14.91,0,0,0-8.42,2.35A11.73,11.73,0,0,0,60.66,27h-2.3l-1.08,2.93.19.19h2.69c0,.16,0,.32,0,.49v1.23c0,.14,0,.29,0,.42h-1.8L57.28,35.3l.19.19h3.21a12.2,12.2,0,0,0,4.48,6.72,12.47,12.47,0,0,0,7.64,2.46A16.44,16.44,0,0,0,79,43.39l.09,0v-3l-.28-.16Z"/></g></svg> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 150 150"
version="1.1"
id="svg14"
sodipodi:docname="logo.svg"
width="150"
height="150"
inkscape:version="1.1.1 (1:1.1+202109281949+c3084ef5ed)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview16"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="4.78212"
inkscape:cx="65.661254"
inkscape:cy="75.280419"
inkscape:current-layer="svg14" />
<defs
id="defs4">
<style
id="style2">.cls-1{fill:#fff;}.cls-2{fill:#3c3d3c;}</style>
</defs>
<g
id="Laag_1"
data-name="Laag 1"
transform="scale(1.0573395)">
<circle
class="cls-1"
cx="70.870003"
cy="70.870003"
r="70.870003"
id="circle6" />
</g>
<g
id="Laag_2"
data-name="Laag 2"
transform="scale(1.0573395)">
<path
class="cls-2"
d="m 102.39,75 a 18.18,18.18 0 0 0 -3.92,0.43 L 92.87,57 A 7,7 0 0 0 86.1,52 h -5.43 v 2.59 h 5.43 a 4.45,4.45 0 0 1 4.29,3.19 l 1.72,5.66 H 55.54 l -2,-4.89 h 3.72 c 0,0 4.74,-0.78 4.74,-4.41 H 46.39 v 4.33 h 4.35 l 2.55,6.25 -5.62,11.55 a 18.31,18.31 0 1 0 11.33,20 h 8 L 68,95.84 93.33,67.37 96,76.15 a 18.28,18.28 0 1 0 6.4,-1.17 z M 41,109 A 15.72,15.72 0 1 1 46.58,78.6 L 38.89,94.4 40,96.27 H 56.38 A 15.74,15.74 0 0 1 41,109 Z M 56.7,93.67 H 42.07 l 6.8,-14 a 15.71,15.71 0 0 1 7.8,13.56 c 0,0.19 -0.01,0.32 -0.02,0.45 z M 50,77.39 l 4.61,-9.45 10.5,25.74 h -5.87 c 0,-0.13 0,-0.26 0,-0.39 A 18.33,18.33 0 0 0 50,77.39 Z M 67.45,92.56 56.59,66 H 91.13 Z M 102.39,109 A 15.71,15.71 0 0 1 96.74,78.62 l 4.56,15 2.48,-0.76 -4.56,-15 a 15.72,15.72 0 1 1 3.17,31.14 z"
id="path9" />
<path
class="cls-2"
d="m 78.72,40.26 a 13.89,13.89 0 0 1 -5.58,1.25 9.86,9.86 0 0 1 -5.6,-1.61 9,9 0 0 1 -3.39,-4.41 h 9.4 l 1.07,-2.89 -0.13,-0.36 h -11 a 2.91,2.91 0 0 1 0,-0.4 v -0.57 c 0,-0.4 0,-0.79 0.05,-1.17 h 12 L 76.62,27.17 76.36,27 H 64.13 a 8.69,8.69 0 0 1 3.48,-4.43 10.82,10.82 0 0 1 5.94,-1.57 16.47,16.47 0 0 1 4.55,0.68 h 0.13 l 1.08,-3 -0.15,-0.05 a 16.56,16.56 0 0 0 -5.3,-0.81 14.91,14.91 0 0 0 -8.42,2.35 11.73,11.73 0 0 0 -4.78,6.83 h -2.3 l -1.08,2.93 0.19,0.19 h 2.69 c 0,0.16 0,0.32 0,0.49 v 1.23 c 0,0.14 0,0.29 0,0.42 h -1.8 l -1.08,3.04 0.19,0.19 h 3.21 a 12.2,12.2 0 0 0 4.48,6.72 12.47,12.47 0 0 0 7.64,2.46 16.44,16.44 0 0 0 6.2,-1.28 h 0.09 v -3 l -0.28,-0.16 z"
id="path11" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -14,7 +14,8 @@
"de": "Fahrradbibliothek", "de": "Fahrradbibliothek",
"pt_BR": "Bibliotecas de bicicletas", "pt_BR": "Bibliotecas de bicicletas",
"pl": "Wypożyczalnie rowerów", "pl": "Wypożyczalnie rowerów",
"hu": "Kerékpárkönyvtárak" "hu": "Kerékpárkönyvtárak",
"id": "Perpustakaan sepeda"
}, },
"description": { "description": {
"nl": "Een fietsbibliotheek is een plaats waar men een fiets kan lenen, vaak voor een klein bedrag per jaar. Een typisch voorbeeld zijn kinderfietsbibliotheken, waar men een fiets op maat van het kind kan lenen. Is het kind de fiets ontgroeid, dan kan het te kleine fietsje omgeruild worden voor een grotere.", "nl": "Een fietsbibliotheek is een plaats waar men een fiets kan lenen, vaak voor een klein bedrag per jaar. Een typisch voorbeeld zijn kinderfietsbibliotheken, waar men een fiets op maat van het kind kan lenen. Is het kind de fiets ontgroeid, dan kan het te kleine fietsje omgeruild worden voor een grotere.",

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View file

@ -1,16 +1,13 @@
{ {
"id": "mapcomplete-changes", "id": "mapcomplete-changes",
"title": { "title": {
"en": "Changes made with MapComplete", "en": "Changes made with MapComplete"
"de": "Änderungen mit MapComplete"
}, },
"shortDescription": { "shortDescription": {
"en": "Shows changes made by MapComplete", "en": "Shows changes made by MapComplete"
"de": "Zeigt Änderungen, die von MapComplete vorgenommen wurden"
}, },
"description": { "description": {
"en": "This maps shows all the changes made with MapComplete", "en": "This maps shows all the changes made with MapComplete"
"de": "Diese Karte zeigt alle mit MapComplete vorgenommenen Änderungen"
}, },
"maintainer": "", "maintainer": "",
"icon": "./assets/svg/logo.svg", "icon": "./assets/svg/logo.svg",
@ -25,8 +22,7 @@
{ {
"id": "mapcomplete-changes", "id": "mapcomplete-changes",
"name": { "name": {
"en": "Changeset centers", "en": "Changeset centers"
"de": "Schwerpunkte von Änderungssätzen"
}, },
"minzoom": 0, "minzoom": 0,
"source": { "source": {
@ -40,41 +36,35 @@
], ],
"title": { "title": {
"render": { "render": {
"en": "Changeset for {theme}", "en": "Changeset for {theme}"
"de": "Änderungssatz für {theme}"
} }
}, },
"description": { "description": {
"en": "Shows all MapComplete changes", "en": "Shows all MapComplete changes"
"de": "Zeigt alle MapComplete-Änderungen"
}, },
"tagRenderings": [ "tagRenderings": [
{ {
"id": "render_id", "id": "render_id",
"render": { "render": {
"en": "Changeset <a href='https://openstreetmap.org/changeset/{id}' target='_blank'>{id}</a>", "en": "Changeset <a href='https://openstreetmap.org/changeset/{id}' target='_blank'>{id}</a>"
"de": "Änderungssatz <a href='https://openstreetmap.org/changeset/{id}' target='_blank'>{id}</a>"
} }
}, },
{ {
"id": "contributor", "id": "contributor",
"render": { "render": {
"en": "Change made by <a href='https://openstreetmap.org/user/{_last_edit:contributor}' target='_blank'>{_last_edit:contributor}</a>", "en": "Change made by <a href='https://openstreetmap.org/user/{_last_edit:contributor}' target='_blank'>{_last_edit:contributor}</a>"
"de": "Geändert von <a href='https://openstreetmap.org/user/{_last_edit:contributor}' target='_blank'>{_last_edit:contributor}</a>"
} }
}, },
{ {
"id": "theme", "id": "theme",
"render": { "render": {
"en": "Change with theme <a href='https://mapcomplete.osm.be/{theme}'>{theme}</a>", "en": "Change with theme <a href='https://mapcomplete.osm.be/{theme}'>{theme}</a>"
"de": "Änderung mit Thema <a href='https://mapcomplete.osm.be/{theme}'>{theme}</a>"
}, },
"mappings": [ "mappings": [
{ {
"if": "theme~http.*", "if": "theme~http.*",
"then": { "then": {
"en": "Change with <b>unofficial</b> theme <a href='https://mapcomplete.osm.be/theme.html?userlayout={theme}'>{theme}</a>", "en": "Change with <b>unofficial</b> theme <a href='https://mapcomplete.osm.be/theme.html?userlayout={theme}'>{theme}</a>"
"de": "Änderung mit <b>inoffiziellem</b> Thema <a href='https://mapcomplete.osm.be/theme.html?userlayout={theme}'>{theme}</a>"
} }
} }
] ]
@ -91,11 +81,11 @@
"mappings": [ "mappings": [
{ {
"if": "theme=aed", "if": "theme=aed",
"then": "./assets/themes/aed/logo.svg" "then": "./assets/themes/aed/aed.svg"
}, },
{ {
"if": "theme=aed_brugge", "if": "theme=aed_brugge",
"then": "./assets/themes/aed/logo.svg" "then": "./assets/themes/aed/aed.svg"
}, },
{ {
"if": "theme=artwork", "if": "theme=artwork",
@ -338,8 +328,7 @@
} }
], ],
"question": { "question": {
"en": "Themename contains {search}", "en": "Themename contains {search}"
"de": "Themenname enthält {search}"
} }
} }
] ]
@ -355,8 +344,7 @@
} }
], ],
"question": { "question": {
"en": "Made by contributor {search}", "en": "Made by contributor {search}"
"de": "Erstellt von Mitwirkendem {search}"
} }
} }
] ]
@ -372,8 +360,7 @@
} }
], ],
"question": { "question": {
"en": "<b>Not</b> made by contributor {search}", "en": "<b>Not</b> made by contributor {search}"
"de": "<b> Nicht</b> erstellt von Mitwirkendem {search}"
} }
} }
] ]
@ -388,8 +375,7 @@
{ {
"id": "link_to_more", "id": "link_to_more",
"render": { "render": {
"en": "More statistics can be found <a href='https://github.com/pietervdvn/MapComplete/tree/develop/Docs/Tools/graphs' target='_blank'>here</a>", "en": "More statistics can be found <a href='https://github.com/pietervdvn/MapComplete/tree/develop/Docs/Tools/graphs' target='_blank'>here</a>"
"de": "Weitere Statistiken finden Sie <a href='https://github.com/pietervdvn/MapComplete/tree/develop/Docs/Tools/graphs' target='_blank'>hier</a>"
} }
}, },
{ {

View file

@ -9,52 +9,52 @@
"orientation": "portrait-primary, landscape-primary", "orientation": "portrait-primary, landscape-primary",
"icons": [ "icons": [
{ {
"src": "assets/generated/svg_mapcomplete_logo72.png", "src": "assets/generated/images/mapcomplete_logo72.png",
"sizes": "72x72", "sizes": "72x72",
"type": "image/png" "type": "image/png"
}, },
{ {
"src": "assets/generated/svg_mapcomplete_logo96.png", "src": "assets/generated/images/mapcomplete_logo96.png",
"sizes": "96x96", "sizes": "96x96",
"type": "image/png" "type": "image/png"
}, },
{ {
"src": "assets/generated/svg_mapcomplete_logo120.png", "src": "assets/generated/images/mapcomplete_logo120.png",
"sizes": "120x120", "sizes": "120x120",
"type": "image/png" "type": "image/png"
}, },
{ {
"src": "assets/generated/svg_mapcomplete_logo128.png", "src": "assets/generated/images/mapcomplete_logo128.png",
"sizes": "128x128", "sizes": "128x128",
"type": "image/png" "type": "image/png"
}, },
{ {
"src": "assets/generated/svg_mapcomplete_logo144.png", "src": "assets/generated/images/mapcomplete_logo144.png",
"sizes": "144x144", "sizes": "144x144",
"type": "image/png" "type": "image/png"
}, },
{ {
"src": "assets/generated/svg_mapcomplete_logo152.png", "src": "assets/generated/images/mapcomplete_logo152.png",
"sizes": "152x152", "sizes": "152x152",
"type": "image/png" "type": "image/png"
}, },
{ {
"src": "assets/generated/svg_mapcomplete_logo180.png", "src": "assets/generated/images/mapcomplete_logo180.png",
"sizes": "180x180", "sizes": "180x180",
"type": "image/png" "type": "image/png"
}, },
{ {
"src": "assets/generated/svg_mapcomplete_logo192.png", "src": "assets/generated/images/mapcomplete_logo192.png",
"sizes": "192x192", "sizes": "192x192",
"type": "image/png" "type": "image/png"
}, },
{ {
"src": "assets/generated/svg_mapcomplete_logo384.png", "src": "assets/generated/images/mapcomplete_logo384.png",
"sizes": "384x384", "sizes": "384x384",
"type": "image/png" "type": "image/png"
}, },
{ {
"src": "assets/generated/svg_mapcomplete_logo512.png", "src": "assets/generated/images/mapcomplete_logo512.png",
"sizes": "512x512", "sizes": "512x512",
"type": "image/png" "type": "image/png"
}, },

View file

@ -8,12 +8,12 @@
"delete": { "delete": {
"cancel": "Batal", "cancel": "Batal",
"cannotBeDeleted": "Fitur ini tidak dapat dihapus", "cannotBeDeleted": "Fitur ini tidak dapat dihapus",
"delete": "Hapus",
"explanations": { "explanations": {
"selectReason": "Silahkan pilih mengapa fitur ini harus dihapus" "selectReason": "Silahkan pilih mengapa fitur ini harus dihapus"
}, },
"isntAPoint": "Hanya titik yang dapat dihapus, fitur yang dipilih adalah jalan, area, atau relasi.", "isDeleted": "Fitur ini telah dihapus",
"delete": "Hapus", "isntAPoint": "Hanya titik yang dapat dihapus, fitur yang dipilih adalah jalan, area, atau relasi."
"isDeleted": "Fitur ini telah dihapus"
}, },
"favourite": { "favourite": {
"reload": "Muat ulang data" "reload": "Muat ulang data"
@ -115,4 +115,4 @@
"split": { "split": {
"cancel": "Batal" "cancel": "Batal"
} }
} }

View file

@ -25,18 +25,18 @@
}, },
"level": { "level": {
"mappings": { "mappings": {
"3": { "0": {
"then": "Berlokasi di lantai pertama" "then": "Terletak di bawah tanah"
}, },
"1": { "1": {
"then": "Terletak di lantai dasar" "then": "Terletak di lantai dasar"
}, },
"0": {
"then": "Terletak di bawah tanah"
},
"2": { "2": {
"then": "Terletak di lantai dasar" "then": "Terletak di lantai dasar"
}, },
"3": {
"then": "Berlokasi di lantai pertama"
},
"4": { "4": {
"then": "Terletak di lantai basement pertama" "then": "Terletak di lantai basement pertama"
} }
@ -61,4 +61,4 @@
"question": "Apa situs web dari {title()}?" "question": "Apa situs web dari {title()}?"
} }
} }
} }

View file

@ -8,8 +8,15 @@
"title": "Buka Peta Karya Seni" "title": "Buka Peta Karya Seni"
}, },
"benches": { "benches": {
"title": "Bangku", "shortDescription": "Peta bangku",
"shortDescription": "Peta bangku" "title": "Bangku"
},
"bicycle_rental": {
"shortDescription": "Peta dengan stasiun persewaan sepeda dan toko penyewaan sepeda",
"title": "Sewa sepeda"
},
"bicyclelib": {
"title": "Perpustakaan sepeda"
}, },
"cafes_and_pubs": { "cafes_and_pubs": {
"title": "Kafe dan pub" "title": "Kafe dan pub"
@ -283,12 +290,5 @@
}, },
"waste_basket": { "waste_basket": {
"title": "Keranjang Sampah" "title": "Keranjang Sampah"
},
"bicyclelib": {
"title": "Perpustakaan sepeda"
},
"bicycle_rental": {
"title": "Sewa sepeda",
"shortDescription": "Peta dengan stasiun persewaan sepeda dan toko penyewaan sepeda"
} }
} }

View file

@ -1,5 +1,5 @@
import * as fs from "fs"; import * as fs from "fs";
import {lstatSync, readdirSync, readFileSync} from "fs"; import {existsSync, lstatSync, readdirSync, readFileSync} from "fs";
import {Utils} from "../Utils"; import {Utils} from "../Utils";
import * as https from "https"; import * as https from "https";
import {LayoutConfigJson} from "../Models/ThemeConfig/Json/LayoutConfigJson"; import {LayoutConfigJson} from "../Models/ThemeConfig/Json/LayoutConfigJson";
@ -146,6 +146,9 @@ export default class ScriptUtils {
} }
public static async ReadSvg(path: string): Promise<any>{ public static async ReadSvg(path: string): Promise<any>{
if(!existsSync(path)){
throw "File not found: "+path
}
const root = await xml2js.parseStringPromise(readFileSync(path, "UTF8")) const root = await xml2js.parseStringPromise(readFileSync(path, "UTF8"))
return root.svg return root.svg
} }

View file

@ -102,6 +102,9 @@ class LayerOverviewUtils {
.filter(path => !path.startsWith("./assets/generated")) .filter(path => !path.startsWith("./assets/generated"))
let errCount = 0; let errCount = 0;
for (const path of allSvgs) { for (const path of allSvgs) {
if(path.indexOf("assets/SocialImageTemplate") >= 0){
continue
}
const contents = readFileSync(path, "UTF8") const contents = readFileSync(path, "UTF8")
if (contents.indexOf("data:image/png;") < 0) { if (contents.indexOf("data:image/png;") < 0) {
continue; continue;

View file

@ -8,6 +8,7 @@ import {LayoutConfigJson} from "../Models/ThemeConfig/Json/LayoutConfigJson";
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig"; import LayoutConfig from "../Models/ThemeConfig/LayoutConfig";
import xml2js from 'xml2js'; import xml2js from 'xml2js';
import ScriptUtils from "./ScriptUtils"; import ScriptUtils from "./ScriptUtils";
import {Utils} from "../Utils";
const sharp = require('sharp'); const sharp = require('sharp');
const template = readFileSync("theme.html", "utf8"); const template = readFileSync("theme.html", "utf8");
@ -19,72 +20,126 @@ function enc(str: string): string {
} }
async function createIcon(iconPath: string, size: number, alreadyWritten: string[]) { async function createIcon(iconPath: string, size: number, alreadyWritten: string[]) {
let name = iconPath.split(".").slice(0, -1).join("."); let name = iconPath.split(".").slice(0, -1).join("."); // drop svg suffix
if (name.startsWith("./")) { if (name.startsWith("./")) {
name = name.substr(2) name = name.substr(2)
} }
const newname = `${name}${size}.png`
.replace(/\//g, "_") const newname = `assets/generated/images${name.substring(name.lastIndexOf("/"))}${size}.png`;
.replace("assets_", "assets/generated/");
if (alreadyWritten.indexOf(newname) >= 0) { if (alreadyWritten.indexOf(newname) >= 0) {
return newname; return newname;
} }
alreadyWritten.push(newname); alreadyWritten.push(newname);
try { if (existsSync(newname)) {
readFileSync(newname); return newname
return newname; // File already exists - nothing to do }
} catch (e) {
// Errors are normal here if this file does not exists if (!existsSync(iconPath)) {
throw "No file at " + iconPath
} }
try { try {
// We already read to file, in order to crash here if the file is not found // We already read to file, in order to crash here if the file is not found
readFileSync(iconPath);
let img = await sharp(iconPath) let img = await sharp(iconPath)
let resized = await img.resize(size) let resized = await img.resize(size)
await resized.toFile(newname) await resized.toFile(newname)
console.log("Written", newname)
} catch (e) { } catch (e) {
console.error("Could not read icon", iconPath, "due to", e) console.error("Could not read icon", iconPath, " to create a PNG due to", e)
} }
return newname; return newname;
} }
async function createManifest(layout: LayoutConfig, alreadyWritten: string[]) { async function createSocialImage(layout: LayoutConfig, template: "" | "Wide"): Promise<string> {
if (!layout.icon.endsWith(".svg")) {
console.warn("Not creating a social image for " + layout.id + " as it is _not_ a .svg: " + layout.icon)
return undefined
}
const path = `./assets/generated/images/social_image_${layout.id}_${template}.svg`
if(existsSync(path)){
// return path;
}
const svg = await ScriptUtils.ReadSvg(layout.icon)
let width: string = svg.$.width;
if (width === undefined) {
throw "The logo at " + layout.icon + " does not have a defined width"
}
if (width?.endsWith("px")) {
width = width.substring(0, width.length - 2)
}
if (width?.endsWith("%")) {
throw "The logo at " + layout.icon + " has a relative width; this is not supported"
}
delete svg["defs"]
delete svg["$"]
let templateSvg = await ScriptUtils.ReadSvg("./assets/SocialImageTemplate" + template + ".svg")
templateSvg = Utils.WalkJson(templateSvg,
(leaf) => {
const {cx, cy, r} = leaf["circle"][0].$
return {
$: {
id: "icon",
transform: `translate(${cx - r},${cy - r}) scale(${(r * 2) / Number(width)}) `
},
g: [svg]
}
},
(mightBeTokenToReplace) => {
if (mightBeTokenToReplace?.circle === undefined) {
return false
}
return mightBeTokenToReplace.circle[0]?.$?.style?.indexOf("fill:#ff00ff") >= 0
}
)
const builder = new xml2js.Builder();
const xml = builder.buildObject({svg: templateSvg});
writeFileSync(path, xml)
console.log("Written", path)
return path
}
async function createManifest(layout: LayoutConfig, alreadyWritten: string[]): Promise<{
manifest: any,
whiteIcons: string[]
}> {
const name = layout.id; const name = layout.id;
Translation.forcedLanguage = "en" Translation.forcedLanguage = "en"
const icons = []; const icons = [];
const whiteIcons: string[] = []
let icon = layout.icon; let icon = layout.icon;
if (icon.endsWith(".svg") || icon.startsWith("<svg") || icon.startsWith("<?xml")) { if (icon.endsWith(".svg") || icon.startsWith("<svg") || icon.startsWith("<?xml")) {
// This is an svg. Lets create the needed pngs and do some checkes! // This is an svg. Lets create the needed pngs and do some checkes!
const whiteBackgroundPath = "./assets/generated/theme_"+layout.id+"_white_background.svg" const whiteBackgroundPath = "./assets/generated/images/theme_" + layout.id + "_white_background.svg"
{ {
const svg = await ScriptUtils.ReadSvg(icon) const svg = await ScriptUtils.ReadSvg(icon)
const width: string = svg.$.width; const width: string = svg.$.width;
const height: string = svg.$.height; const height: string = svg.$.height;
const builder = new xml2js.Builder(); const builder = new xml2js.Builder();
const withRect = {rect: {"$":{width, height, style: "fill:#ffffff;"}}, ...svg} const withRect = {rect: {"$": {width, height, style: "fill:#ffffff;"}}, ...svg}
const xml = builder.buildObject({svg: withRect}); const xml = builder.buildObject({svg: withRect});
writeFileSync(whiteBackgroundPath, xml) writeFileSync(whiteBackgroundPath, xml)
} }
let path = layout.icon; let path = layout.icon;
if (layout.icon.startsWith("<")) { if (layout.icon.startsWith("<")) {
// THis is already the svg // THis is already the svg
path = "./assets/generated/" + layout.id + "_logo.svg" path = "./assets/generated/images/" + layout.id + "_logo.svg"
writeFileSync(path, layout.icon) writeFileSync(path, layout.icon)
} }
const sizes = [72, 96, 120, 128, 144, 152, 180, 192, 384, 512]; const sizes = [72, 96, 120, 128, 144, 152, 180, 192, 384, 512];
for (const size of sizes) { for (const size of sizes) {
const name = await createIcon(path, size, alreadyWritten); const name = await createIcon(path, size, alreadyWritten);
await createIcon(whiteBackgroundPath, size, alreadyWritten) const whiteIcon = await createIcon(whiteBackgroundPath, size, alreadyWritten)
whiteIcons.push(whiteIcon)
icons.push({ icons.push({
src: name, src: name,
sizes: size + "x" + size, sizes: size + "x" + size,
@ -109,7 +164,7 @@ async function createManifest(layout: LayoutConfig, alreadyWritten: string[]) {
const ogTitle = Translations.WT(layout.title).txt; const ogTitle = Translations.WT(layout.title).txt;
const ogDescr = Translations.WT(layout.description ?? "").txt; const ogDescr = Translations.WT(layout.description ?? "").txt;
return { const manifest = {
name: name, name: name,
short_name: ogTitle, short_name: ogTitle,
start_url: `${layout.id.toLowerCase()}.html`, start_url: `${layout.id.toLowerCase()}.html`,
@ -121,15 +176,32 @@ async function createManifest(layout: LayoutConfig, alreadyWritten: string[]) {
icons: icons, icons: icons,
categories: ["map", "navigation"] categories: ["map", "navigation"]
}; };
return {
manifest,
whiteIcons
}
} }
async function createLandingPage(layout: LayoutConfig, manifest) { async function createLandingPage(layout: LayoutConfig, manifest, whiteIcons, alreadyWritten) {
Locale.language.setData(layout.language[0]); Locale.language.setData(layout.language[0]);
const targetLanguage = layout.language[0] const targetLanguage = layout.language[0]
const ogTitle = Translations.WT(layout.title).textFor(targetLanguage).replace(/"/g, '\\"'); const ogTitle = Translations.WT(layout.title).textFor(targetLanguage).replace(/"/g, '\\"');
const ogDescr = Translations.WT(layout.shortDescription ?? "Easily add and edit geodata with OpenStreetMap").textFor(targetLanguage).replace(/"/g, '\\"'); const ogDescr = Translations.WT(layout.shortDescription ?? "Easily add and edit geodata with OpenStreetMap").textFor(targetLanguage).replace(/"/g, '\\"');
const ogImage = layout.socialImage; let ogImage = layout.socialImage;
let twitterImage = ogImage
if (ogImage === LayoutConfig.defaultSocialImage && layout.official) {
ogImage = await createSocialImage(layout, "") ?? layout.socialImage
twitterImage = await createSocialImage(layout, "Wide") ?? layout.socialImage
}
if (twitterImage.endsWith(".svg")) {
// svgs are badly supported as social image, we use a generated svg instead
twitterImage = await createIcon(twitterImage, 512, alreadyWritten);
}
if(ogImage.endsWith(".svg")){
ogImage = await createIcon(ogImage, 512, alreadyWritten)
}
let customCss = ""; let customCss = "";
if (layout.customCss !== undefined && layout.customCss !== "") { if (layout.customCss !== undefined && layout.customCss !== "") {
@ -147,29 +219,26 @@ async function createLandingPage(layout: LayoutConfig, manifest) {
<meta property="og:title" content="${ogTitle}"> <meta property="og:title" content="${ogTitle}">
<meta property="og:description" content="${ogDescr}"> <meta property="og:description" content="${ogDescr}">
<meta name="twitter:card" content="summary_large_image"> <meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@mapcomplete.osm;be"> <meta name="twitter:site" content="@mapcomplete.osm.be">
<meta name="twitter:creator" content="@pietervdvn"> <meta name="twitter:creator" content="@pietervdvn">
<meta name="twitter:title" content="${ogTitle}"> <meta name="twitter:title" content="${ogTitle}">
<meta name="twitter:description" content="${ogDescr}"> <meta name="twitter:description" content="${ogDescr}">
<meta name="twitter:image" content="${ogImage}">` <meta name="twitter:image" content="${twitterImage}">`
let icon = layout.icon; let icon = layout.icon;
if (icon.startsWith("<?xml") || icon.startsWith("<svg")) { if (icon.startsWith("<?xml") || icon.startsWith("<svg")) {
// This already is an svg // This already is an svg
icon = `./assets/generated/${layout.id}_icon.svg` icon = `./assets/generated/images/${layout.id}_icon.svg`
writeFileSync(icon, layout.icon); writeFileSync(icon, layout.icon);
} }
const apple_icons = [] const apple_icons = []
for (const icon of manifest.icons) { for (const icon of whiteIcons) {
if (icon.type !== "image/png") { if (!existsSync(icon)) {
continue;
}
const whiteBgPath = `./assets/generated/generated_theme_${layout.id}_white_background${icon.sizes.substr(icon.sizes.indexOf("x")+ 1)}.png`
if(!existsSync(whiteBgPath)){
continue continue
} }
apple_icons.push(`<link rel="apple-touch-icon" sizes="${icon.sizes}" href="${whiteBgPath}">`) const size = icon.replace(/[^0-9]/g, "")
apple_icons.push(`<link rel="apple-touch-icon" sizes="${size}x${size}" href="${icon}">`)
} }
let themeSpecific = [ let themeSpecific = [
@ -206,31 +275,32 @@ async function createIndexFor(theme: LayoutConfig) {
appendFileSync(filename, codeTemplate) appendFileSync(filename, codeTemplate)
} }
function createDir(path){ function createDir(path) {
if (!existsSync(path)) { if (!existsSync(path)) {
mkdirSync(path) mkdirSync(path)
} }
} }
async function main(): Promise<void>{ async function main(): Promise<void> {
const alreadyWritten = [] const alreadyWritten = []
createDir("./assets/generated") createDir("./assets/generated")
createDir("./assets/generated/layers") createDir("./assets/generated/layers")
createDir("./assets/generated/themes") createDir("./assets/generated/themes")
createDir("./assets/generated/images")
const blacklist = ["", "test", ".", "..", "manifest", "index", "land", "preferences", "account", "openstreetmap", "custom", "theme"] const blacklist = ["", "test", ".", "..", "manifest", "index", "land", "preferences", "account", "openstreetmap", "custom", "theme"]
// @ts-ignore // @ts-ignore
const all: LayoutConfigJson[] = all_known_layouts.themes; const all: LayoutConfigJson[] = all_known_layouts.themes;
const args = process.argv const args = process.argv
const theme = args[2] const theme = args[2]
if(theme !== undefined){ if (theme !== undefined) {
console.warn("Only generating layout "+theme) console.warn("Only generating layout " + theme)
} }
for (const i in all) { for (const i in all) {
const layoutConfigJson: LayoutConfigJson = all[i] const layoutConfigJson: LayoutConfigJson = all[i]
if(theme !== undefined && layoutConfigJson.id !== theme){ if (theme !== undefined && layoutConfigJson.id !== theme) {
continue continue
} }
const layout = new LayoutConfig(layoutConfigJson, true, "generating layouts") const layout = new LayoutConfig(layoutConfigJson, true, "generating layouts")
@ -244,21 +314,20 @@ async function main(): Promise<void>{
console.log("Could not write manifest for ", layoutName, " because ", err) console.log("Could not write manifest for ", layoutName, " because ", err)
} }
}; };
await createManifest(layout, alreadyWritten).then(manifObj => { const {manifest, whiteIcons} = await createManifest(layout, alreadyWritten)
const manif = JSON.stringify(manifObj, undefined, 2); const manif = JSON.stringify(manifest, undefined, 2);
const manifestLocation = encodeURIComponent(layout.id.toLowerCase()) + ".webmanifest"; const manifestLocation = encodeURIComponent(layout.id.toLowerCase()) + ".webmanifest";
writeFile(manifestLocation, manif, err); writeFile(manifestLocation, manif, err);
// Create a landing page for the given theme // Create a landing page for the given theme
createLandingPage(layout, manifObj).then(landing => { createLandingPage(layout, manifest, whiteIcons, alreadyWritten).then(landing => {
writeFile(enc(layout.id) + ".html", landing, err) writeFile(enc(layout.id) + ".html", landing, err)
}); });
createIndexFor(layout) createIndexFor(layout)
}).catch(e => console.log("Could not generate the manifest: ", e))
} }
await createManifest(new LayoutConfig({
const {manifest, whiteIcons} = await createManifest(new LayoutConfig({
icon: "./assets/svg/mapcomplete_logo.svg", icon: "./assets/svg/mapcomplete_logo.svg",
id: "index", id: "index",
layers: [], layers: [],
@ -270,10 +339,10 @@ async function main(): Promise<void>{
title: {en: "MapComplete"}, title: {en: "MapComplete"},
version: Constants.vNumber, version: Constants.vNumber,
description: {en: "A thematic map viewer and editor based on OpenStreetMap"} description: {en: "A thematic map viewer and editor based on OpenStreetMap"}
}), alreadyWritten).then(manifObj => { }), alreadyWritten);
const manif = JSON.stringify(manifObj, undefined, 2);
writeFileSync("index.manifest", manif) const manif = JSON.stringify(manifest, undefined, 2);
}) writeFileSync("index.manifest", manif)
} }
main().then(() => { main().then(() => {