Add about, game, with feather-icons and leafletjs

This commit is contained in:
Samuel Ortion 2022-08-24 18:37:57 +02:00
parent daaf8524d7
commit f1f87afbae
23 changed files with 469 additions and 16 deletions

15
.editorconfig Normal file
View File

@ -0,0 +1,15 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = false
insert_final_newline = false
[pug]
indent_size = 2

4
.gitignore vendored
View File

@ -59,3 +59,7 @@ typings/
# next.js build output
.next
# IDE junks
.vscode
.ideas

4
app.js
View File

@ -25,6 +25,10 @@ i18n.expressBind(app, {
cookieName: 'locale'
});
app.use('/dist/leaflet', express.static('node_modules/leaflet/dist'));
app.use('/dist/feather', express.static('node_modules/feather-icons/dist'));
app.use(function(req, res, next) {
req.i18n.setLocaleFromQuery();
req.i18n.setLocaleFromCookie();

3
controllers/api.js Normal file
View File

@ -0,0 +1,3 @@
function getRecord(req, res) {
}

View File

@ -1,8 +1,13 @@
function getIndex(req, res, next) {
function getIndex(req, res) {
res.render('index', { title: 'SoundBirder' });
}
function getAbout(req, res) {
res.render('about', { title: 'About SoundBirder' });
}
module.exports = {
getIndex,
getAbout
}

View File

@ -1,4 +1,11 @@
{
"Home": "Home",
"About": "About"
"About": "About",
"Game": "Game",
"Contact": "Contact",
"SoundBirder is an open-source web application to learn bird song identification. It is based on bird records from Xeno-Canto and data from eBird": "SoundBirder is an open-source web application to learn bird song identification. It is based on bird records from Xeno-Canto and data from eBird",
"Author": "Author",
"The project is made with ♥ by Samuel ORTION": "The project is made with ♥ by Samuel ORTION",
"SoundBirder is an open-source web application to learn bird song identification. It is based on bird records from Xeno-Canto and data from eBird.": "SoundBirder is an open-source web application to learn bird song identification. It is based on bird records from Xeno-Canto and data from eBird.",
"The project is made with ♥ by Samuel ORTION.": "The project is made with ♥ by Samuel ORTION."
}

View File

@ -1 +1,8 @@
{}
{
"Game": "Jeu",
"About": "À propos",
"Contact": "Contact",
"SoundBirder is an open-source web application to learn bird song identification. It is based on bird records from Xeno-Canto and data from eBird": "SoundBirder est une application web open-source qui permet d'apprendre à reconnaitre les chants d'oiseaux. Elle se base sur les enregistrements audio de Xeno-Canto est sur les données de répartitions d'eBird",
"Author": "Auteur",
"The project is made with ♥ by Samuel ORTION": "Ce projet est fait avec ♥ par Samuel ORTION"
}

55
package-lock.json generated
View File

@ -12,8 +12,10 @@
"cookie-parser": "~1.4.4",
"debug": "~2.6.9",
"express": "~4.16.1",
"feather-icons": "^4.29.0",
"http-errors": "~1.6.3",
"i18n-2": "^0.7.3",
"leaflet": "^1.8.0",
"morgan": "~1.9.1",
"pug": "^3.0.2"
}
@ -180,6 +182,11 @@
"is-regex": "^1.0.3"
}
},
"node_modules/classnames": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz",
"integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@ -241,6 +248,16 @@
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
},
"node_modules/core-js": {
"version": "3.24.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.24.1.tgz",
"integrity": "sha512-0QTBSYSUZ6Gq21utGzkfITDylE8jWC9Ne1D2MrhvlsZBI1x39OdDIVbzSqtgMndIy6BlHxBXpMGqzZmnztg2rg==",
"hasInstallScript": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/core-js"
}
},
"node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@ -349,6 +366,15 @@
"node": ">= 0.6"
}
},
"node_modules/feather-icons": {
"version": "4.29.0",
"resolved": "https://registry.npmjs.org/feather-icons/-/feather-icons-4.29.0.tgz",
"integrity": "sha512-Y7VqN9FYb8KdaSF0qD1081HCkm0v4Eq/fpfQYQnubpqi0hXx14k+gF9iqtRys1SIcTEi97xDi/fmsPFZ8xo0GQ==",
"dependencies": {
"classnames": "^2.2.5",
"core-js": "^3.1.3"
}
},
"node_modules/finalhandler": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
@ -585,6 +611,11 @@
"promise": "^7.0.1"
}
},
"node_modules/leaflet": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.8.0.tgz",
"integrity": "sha512-gwhMjFCQiYs3x/Sf+d49f10ERXaEFCPr+nVTryhAW8DWbMGqJqt9G4XuIaHmFW08zYvhgdzqXGr8AlW8v8dQkA=="
},
"node_modules/media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@ -1156,6 +1187,11 @@
"is-regex": "^1.0.3"
}
},
"classnames": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz",
"integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@ -1202,6 +1238,11 @@
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
},
"core-js": {
"version": "3.24.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.24.1.tgz",
"integrity": "sha512-0QTBSYSUZ6Gq21utGzkfITDylE8jWC9Ne1D2MrhvlsZBI1x39OdDIVbzSqtgMndIy6BlHxBXpMGqzZmnztg2rg=="
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@ -1294,6 +1335,15 @@
}
}
},
"feather-icons": {
"version": "4.29.0",
"resolved": "https://registry.npmjs.org/feather-icons/-/feather-icons-4.29.0.tgz",
"integrity": "sha512-Y7VqN9FYb8KdaSF0qD1081HCkm0v4Eq/fpfQYQnubpqi0hXx14k+gF9iqtRys1SIcTEi97xDi/fmsPFZ8xo0GQ==",
"requires": {
"classnames": "^2.2.5",
"core-js": "^3.1.3"
}
},
"finalhandler": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
@ -1467,6 +1517,11 @@
"promise": "^7.0.1"
}
},
"leaflet": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.8.0.tgz",
"integrity": "sha512-gwhMjFCQiYs3x/Sf+d49f10ERXaEFCPr+nVTryhAW8DWbMGqJqt9G4XuIaHmFW08zYvhgdzqXGr8AlW8v8dQkA=="
},
"media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",

View File

@ -10,8 +10,10 @@
"cookie-parser": "~1.4.4",
"debug": "~2.6.9",
"express": "~4.16.1",
"feather-icons": "^4.29.0",
"http-errors": "~1.6.3",
"i18n-2": "^0.7.3",
"leaflet": "^1.8.0",
"morgan": "~1.9.1",
"pug": "^3.0.2"
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:cc="http://creativecommons.org/ns#" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" id="svg39145" sodipodi:docname="_svgclean2.svg" viewBox="0 0 475.28 396.78" version="1.1" inkscape:version="0.48.5 r10040">
<sodipodi:namedview id="namedview23" bordercolor="#666666" inkscape:pageshadow="2" guidetolerance="10" pagecolor="#ffffff" gridtolerance="10" inkscape:window-maximized="0" inkscape:zoom="0.22425739" objecttolerance="10" borderopacity="1" inkscape:current-layer="svg39145" inkscape:cx="38.071362" inkscape:cy="-15.497501" inkscape:window-y="0" inkscape:window-x="683" inkscape:window-width="681" showgrid="false" inkscape:pageopacity="0" inkscape:window-height="766"/>
<defs id="defs39147">
<linearGradient id="linearGradient39245" y2="428.08" gradientUnits="userSpaceOnUse" x2="-788.21" y1="428.08" x1="-897.51">
<stop id="stop38892-5-5-7" style="stop-color:#000000;stop-opacity:.91373" offset="0"/>
</linearGradient>
</defs>
<g id="layer1" transform="translate(-333.98 -113.9)">
<g id="g39232" transform="matrix(.58448 0 0 .58448 297.22 109.18)">
<path id="path31178" style="stroke-opacity:.093567;fill-opacity:.74405;stroke-dashoffset:64.401;stroke:#000000;stroke-linecap:square;stroke-width:5.5533;fill:#1a1a1a" inkscape:connector-curvature="0" d="m320.34 624.59c11.023-14.204 19.973-30.2 30.528-44.804 9.5553-13.221 11.331-14.474 22.408-26.72 17.398-19.47 36.589-36.67 56.716-52.48 19.042-13.146 38.193-30.251 61.537-30.641 2.9729-0.0503 5.9362 0.38952 8.9043 0.58451 24.501 3.749 45.957 17.67 66.837 31.527 10.085 7.6291 20.822 14.287 30.664 22.318 4.3336 3.5359 7.7072 6.985 11.74 10.909 11.092 10.96 20.146 24.207 28.037 38.111 1.5411 2.6562 3.0823 5.3123 4.6234 7.9684l-28.837 18.735c-1.5295-2.6652-3.059-5.3301-4.5885-7.9953-7.8924-13.505-17.163-26.064-27.759-37.066-12.876-12.488-27.175-22.73-41.42-33.169-20.415-14.044-41.929-27.293-66.313-29.617-8.0656 0.0397-14.804 0.3999-22.559 3.0777-2.1695 0.74913-8.2722 4.0449-6.3934 2.6241 5.3274-4.0284 36.284-23.818 16.618-10.971-20.799 15.63-40.59 32.91-58.455 52.58-10.477 11.404-13.17 13.664-22.252 26.077-10.247 14.004-18.55 29.589-28.558 43.791l-31.478 15.16z"/>
<path id="path28681-5" style="stroke-opacity:.093567;fill-opacity:.74405;stroke-dashoffset:64.401;stroke:#000000;stroke-linecap:square;stroke-width:6.44;fill:#ff6600" inkscape:connector-curvature="0" d="m-51.304 455.49c-1.1634-6.4894 84.495-43.289 86.064-48.204 1.5683-4.9151 14.551-144.39 19.628-143.92 5.0768 0.47402 97.709 145.05 100.71 150.01 2.999 4.9656-2.0368 55.225-5.7355 59.234-3.6988 4.0096-89.287-11.271-94.577-10.612-5.2901 0.65934-104.92-0.0215-106.09-6.5109z" transform="matrix(1.4496 -.47604 .47604 1.4496 -74.5 -284.99)"/>
<path id="path28681-8-1" style="stroke-opacity:.093567;fill-opacity:.74405;stroke-dashoffset:64.401;stroke:#000000;stroke-linecap:square;stroke-width:6.44;fill:#ff6600" inkscape:connector-curvature="0" d="m-51.304 455.49c-1.1634-6.4894 84.495-43.289 86.064-48.204 1.5683-4.9151 14.551-144.39 19.628-143.92 5.0768 0.47402 97.709 145.05 100.71 150.01 2.999 4.9656-2.0368 55.225-5.7355 59.234-3.6988 4.0096-89.287-11.271-94.577-10.612-5.2901 0.65934-104.92-0.0215-106.09-6.5109z" transform="matrix(-.14358 -0.26 .57358 -.24637 104.25 764.53)"/>
<path id="path39021-5" style="stroke-opacity:.94086;fill-opacity:.96237;stroke-dashoffset:64.401;stroke:#000000;stroke-linecap:square;stroke-width:6.44;fill:#0c000c" inkscape:connector-curvature="0" d="m-665.71 1049.5a171.43 177.14 0 1 1 -342.86 0 171.43 177.14 0 1 1 342.86 0z" transform="matrix(1.5257 0 0 1.5257 1745.5 -1318)"/>
<path id="path39023-2" style="stroke-opacity:.94086;fill-opacity:.96237;stroke-dashoffset:64.401;stroke:#000000;stroke-linecap:square;stroke-width:6.44;fill:#0c000c" inkscape:connector-curvature="0" d="m-681.57 118.54c-8.746 19.054-421.55-32.079-426.48-48.481-4.9277-16.402 215.86-219.89 232.59-211.99 16.733 7.9016 202.64 241.41 193.89 260.47z" transform="matrix(-.13076 -.89838 1.023 -.11483 645.52 -494.19)"/>
<g id="g38937-6-7" transform="matrix(.52159 0 0 .52976 -78.953 80.604)">
<path id="path31180-4-2" style="stroke-opacity:.093567;fill-opacity:.74405;stroke-dashoffset:64.401;stroke:#000000;stroke-linecap:square;stroke-width:6.44;fill:#1a1a1a" inkscape:connector-curvature="0" d="m1408.6 683.79a248.57 220 0 1 1 -497.14 0 248.57 220 0 1 1 497.14 0z" transform="translate(-202.86 -400)"/>
<g id="g38896-0-1-9" transform="matrix(1.1321 0 0 1.0127 1880.7 -117.02)">
<path id="path38820-7-7-7" style="stroke-opacity:.94086;fill-opacity:.74405;stroke-dashoffset:64.401;stroke:#000000;stroke-linecap:square;stroke-width:6.44;fill:#ff6600" inkscape:connector-curvature="0" d="m-742.86 419.51a105.71 118.57 0 1 1 -211.43 0 105.71 118.57 0 1 1 211.43 0z" transform="matrix(1 0 0 .92637 0 39.617)"/>
<path id="path38822-3-0-6" style="stroke-opacity:.96774;fill-opacity:.96237;stroke-dashoffset:64.401;stroke:url(#linearGradient39245);stroke-linecap:square;stroke-width:6.44;fill:#0c000c" inkscape:connector-curvature="0" d="m-791.43 428.08a51.429 44.286 0 1 1 -102.86 0 51.429 44.286 0 1 1 102.86 0z" transform="matrix(1.2045 0 0 1.3665 169.51 -154.04)"/>
</g>
</g>
<path id="path28681-8-3" style="stroke-opacity:.093567;fill-opacity:.74405;stroke-dashoffset:64.401;stroke:#000000;stroke-linecap:square;stroke-width:6.44;fill:#ff6600" inkscape:connector-curvature="0" d="m-51.304 455.49c-1.1634-6.4894 84.495-43.289 86.064-48.204 1.5683-4.9151 14.551-144.39 19.628-143.92 5.0768 0.47402 97.709 145.05 100.71 150.01 2.999 4.9656-2.0368 55.225-5.7355 59.234-3.6988 4.0096-89.287-11.271-94.577-10.612-5.2901 0.65934-104.92-0.0215-106.09-6.5109z" transform="matrix(-.16872 -.24443 .54625 -.30218 412.36 758.51)"/>
</g>
</g>
<metadata id="metadata21">
<rdf:RDF>
<cc:Work>
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<cc:license rdf:resource="http://creativecommons.org/licenses/publicdomain/"/>
<dc:publisher>
<cc:Agent rdf:about="http://openclipart.org/">
<dc:title>Openclipart</dc:title>
</cc:Agent>
</dc:publisher>
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/publicdomain/">
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
</cc:License>
</rdf:RDF>
</metadata>
</svg>

After

Width:  |  Height:  |  Size: 6.8 KiB

BIN
public/images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

162
public/images/logo.svg Normal file
View File

@ -0,0 +1,162 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
id="svg39145"
sodipodi:docname="logo.svg"
viewBox="0 0 100 100"
version="1.1"
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
width="100"
height="100"
inkscape:export-filename="logo.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
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="namedview23"
bordercolor="#666666"
inkscape:pageshadow="2"
guidetolerance="10"
pagecolor="#ffffff"
gridtolerance="10"
inkscape:window-maximized="1"
inkscape:zoom="8.1139514"
objecttolerance="10"
borderopacity="1"
inkscape:current-layer="svg39145"
inkscape:cx="24.83377"
inkscape:cy="42.889091"
inkscape:window-y="0"
inkscape:window-x="0"
inkscape:window-width="1920"
showgrid="false"
inkscape:pageopacity="0"
inkscape:window-height="1011"
inkscape:showpageshadow="2"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1" />
<defs
id="defs39147">
<linearGradient
id="linearGradient39245"
y2="428.07999"
gradientUnits="userSpaceOnUse"
x2="-788.21002"
y1="428.07999"
x1="-897.51001">
<stop
id="stop38892-5-5-7"
style="stop-color:#000000;stop-opacity:.91373"
offset="0" />
</linearGradient>
</defs>
<circle
style="fill:#ffffff;stroke:none;stroke-width:1.60237"
id="path300"
cx="50.076645"
cy="49.982933"
r="48.902069" />
<g
id="layer1"
transform="matrix(0.17366504,0,0,0.17366504,-45.733241,2.1385579)">
<g
id="g39232"
transform="matrix(0.58448,0,0,0.58448,297.22,109.18)">
<path
id="path31178"
style="fill:#1a1a1a;fill-opacity:0.74405;stroke:#000000;stroke-width:5.5533;stroke-linecap:square;stroke-dashoffset:64.401;stroke-opacity:0.093567"
inkscape:connector-curvature="0"
d="m 320.34,624.59 c 11.023,-14.204 19.973,-30.2 30.528,-44.804 9.5553,-13.221 11.331,-14.474 22.408,-26.72 17.398,-19.47 36.589,-36.67 56.716,-52.48 19.042,-13.146 38.193,-30.251 61.537,-30.641 2.9729,-0.0503 5.9362,0.38952 8.9043,0.58451 24.501,3.749 45.957,17.67 66.837,31.527 10.085,7.6291 20.822,14.287 30.664,22.318 4.3336,3.5359 7.7072,6.985 11.74,10.909 11.092,10.96 20.146,24.207 28.037,38.111 1.5411,2.6562 3.0823,5.3123 4.6234,7.9684 l -28.837,18.735 c -1.5295,-2.6652 -3.059,-5.3301 -4.5885,-7.9953 -7.8924,-13.505 -17.163,-26.064 -27.759,-37.066 -12.876,-12.488 -27.175,-22.73 -41.42,-33.169 -20.415,-14.044 -41.929,-27.293 -66.313,-29.617 -8.0656,0.0397 -14.804,0.3999 -22.559,3.0777 -2.1695,0.74913 -8.2722,4.0449 -6.3934,2.6241 5.3274,-4.0284 36.284,-23.818 16.618,-10.971 -20.799,15.63 -40.59,32.91 -58.455,52.58 -10.477,11.404 -13.17,13.664 -22.252,26.077 -10.247,14.004 -18.55,29.589 -28.558,43.791 l -31.478,15.16 z" />
<path
id="path28681-5"
style="fill:#ff6600;fill-opacity:0.74405;stroke:#000000;stroke-width:6.44;stroke-linecap:square;stroke-dashoffset:64.401;stroke-opacity:0.093567"
inkscape:connector-curvature="0"
d="m -51.304,455.49 c -1.1634,-6.4894 84.495,-43.289 86.064,-48.204 1.5683,-4.9151 14.551,-144.39 19.628,-143.92 5.0768,0.47402 97.709,145.05 100.71,150.01 2.999,4.9656 -2.0368,55.225 -5.7355,59.234 -3.6988,4.0096 -89.287,-11.271 -94.577,-10.612 -5.2901,0.65934 -104.92,-0.0215 -106.09,-6.5109 z"
transform="matrix(1.4496,-0.47604,0.47604,1.4496,-74.5,-284.99)" />
<path
id="path28681-8-1"
style="fill:#ff6600;fill-opacity:0.74405;stroke:#000000;stroke-width:6.44;stroke-linecap:square;stroke-dashoffset:64.401;stroke-opacity:0.093567"
inkscape:connector-curvature="0"
d="m -51.304,455.49 c -1.1634,-6.4894 84.495,-43.289 86.064,-48.204 1.5683,-4.9151 14.551,-144.39 19.628,-143.92 5.0768,0.47402 97.709,145.05 100.71,150.01 2.999,4.9656 -2.0368,55.225 -5.7355,59.234 -3.6988,4.0096 -89.287,-11.271 -94.577,-10.612 -5.2901,0.65934 -104.92,-0.0215 -106.09,-6.5109 z"
transform="matrix(-0.14358,-0.26,0.57358,-0.24637,104.25,764.53)" />
<path
id="path39021-5"
style="fill:#0c000c;fill-opacity:0.96237;stroke:#000000;stroke-width:6.44;stroke-linecap:square;stroke-dashoffset:64.401;stroke-opacity:0.94086"
inkscape:connector-curvature="0"
d="m -665.71,1049.5 a 171.43,177.14 0 1 1 -342.86,0 171.43,177.14 0 1 1 342.86,0 z"
transform="matrix(1.5257,0,0,1.5257,1745.5,-1318)" />
<path
id="path39023-2"
style="fill:#0c000c;fill-opacity:0.96237;stroke:#000000;stroke-width:6.44;stroke-linecap:square;stroke-dashoffset:64.401;stroke-opacity:0.94086"
inkscape:connector-curvature="0"
d="m -681.57,118.54 c -8.746,19.054 -421.55,-32.079 -426.48,-48.481 -4.9277,-16.402 215.86,-219.89 232.59,-211.99 16.733,7.9016 202.64,241.41 193.89,260.47 z"
transform="matrix(-0.13076,-0.89838,1.023,-0.11483,645.52,-494.19)" />
<g
id="g38937-6-7"
transform="matrix(0.52159,0,0,0.52976,-78.953,80.604)">
<path
id="path31180-4-2"
style="fill:#1a1a1a;fill-opacity:0.74405;stroke:#000000;stroke-width:6.44;stroke-linecap:square;stroke-dashoffset:64.401;stroke-opacity:0.093567"
inkscape:connector-curvature="0"
d="m 1408.6,683.79 a 248.57,220 0 1 1 -497.14,0 248.57,220 0 1 1 497.14,0 z"
transform="translate(-202.86,-400)" />
<g
id="g38896-0-1-9"
transform="matrix(1.1321,0,0,1.0127,1880.7,-117.02)">
<path
id="path38820-7-7-7"
style="fill:#ff6600;fill-opacity:0.74405;stroke:#000000;stroke-width:6.44;stroke-linecap:square;stroke-dashoffset:64.401;stroke-opacity:0.94086"
inkscape:connector-curvature="0"
d="m -742.86,419.51 a 105.715,118.57561 0 1 1 -211.43,0 105.715,118.57561 0 1 1 211.43,0 z"
transform="matrix(1,0,0,0.92637,0,39.617)" />
<path
id="path38822-3-0-6"
style="fill:#0c000c;fill-opacity:0.96237;stroke:url(#linearGradient39245);stroke-width:6.44;stroke-linecap:square;stroke-dashoffset:64.401;stroke-opacity:0.96774"
inkscape:connector-curvature="0"
d="m -791.43,428.08 a 51.43,44.286861 0 1 1 -102.86,0 51.43,44.286861 0 1 1 102.86,0 z"
transform="matrix(1.2045,0,0,1.3665,169.51,-154.04)" />
</g>
</g>
<path
id="path28681-8-3"
style="fill:#ff6600;fill-opacity:0.74405;stroke:#000000;stroke-width:6.44;stroke-linecap:square;stroke-dashoffset:64.401;stroke-opacity:0.093567"
inkscape:connector-curvature="0"
d="m -51.304,455.49 c -1.1634,-6.4894 84.495,-43.289 86.064,-48.204 1.5683,-4.9151 14.551,-144.39 19.628,-143.92 5.0768,0.47402 97.709,145.05 100.71,150.01 2.999,4.9656 -2.0368,55.225 -5.7355,59.234 -3.6988,4.0096 -89.287,-11.271 -94.577,-10.612 -5.2901,0.65934 -104.92,-0.0215 -106.09,-6.5109 z"
transform="matrix(-0.16872,-0.24443,0.54625,-0.30218,412.36,758.51)" />
</g>
</g>
<metadata
id="metadata21">
<rdf:RDF>
<cc:Work>
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<cc:license
rdf:resource="http://creativecommons.org/publicdomain/zero/1.0/" />
<dc:publisher>
<cc:Agent
rdf:about="http://openclipart.org/">
<dc:title>Openclipart</dc:title>
</cc:Agent>
</dc:publisher>
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/publicdomain/zero/1.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
</cc:License>
</rdf:RDF>
</metadata>
</svg>

After

Width:  |  Height:  |  Size: 8.2 KiB

13
public/javascripts/app.js Normal file
View File

@ -0,0 +1,13 @@
import { geoLocationHandler } from './map.js';
import './game.js';
feather.replace();
(function () {
if (document.getElementById('map') != undefined)
geoLocationHandler();
let start_button = document.querySelector('.game .start-button');
if (start_button != undefined)
start_button.addEventListener('click', launchGame);
}());

View File

@ -0,0 +1,15 @@
const API_VERSION = "1";
function launch() {
}
function get_new_record() {
const endpoint = `/api/${API_VERSION}/record`;
}
const Game = {
launch
}
export default Game;

44
public/javascripts/map.js Normal file
View File

@ -0,0 +1,44 @@
import { getCookie, setCookie } from './utils.js'
function geoLocationHandler() {
let location = [51.505, -0.09]; // London by default on leaflet
let lat = getCookie("lat");
let lng = getCookie("lng");
if (lat != undefined && lng != undefined) {
location = [lat, lng];
console.log(`Got a previous geolocation cookie at ${location[0]}, ${location[1]}`)
}
let message = document.querySelector('.message');
// Init map
let map = L.map('map').setView(location, 15);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map);
// Init marker
let marker = L.marker(location).addTo(map);
// Get geolocation
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(setLocation);
} else {
message.innerHTML = "Geolocation is not supported by this browser.";
}
}
function setLocation(position) {
location = [position.coords.latitude, position.coords.longitude];
marker.setLatLng(location);
map.setView(location, 15);
setCookie("lat", position.coords.latitude, 10);
setCookie("lng", position.coords.longitude, 10);
console.log("Geolocation cookie saved for future games");
}
document.querySelector('.geolocation-button')
.addEventListener('click', getLocation);
}
export {
geoLocationHandler
}

View File

@ -0,0 +1,27 @@
function setCookie(cname, cvalue, exdays) {
const d = new Date();
d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
let expires = "expires=" + d.toUTCString();
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}
function getCookie(cname) {
let name = cname + "=";
let decodedCookie = decodeURIComponent(document.cookie);
let ca = decodedCookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return undefined;
}
export {
getCookie,
setCookie
}

View File

@ -7,6 +7,10 @@ body {
margin: 0;
}
body > * {
padding: 1em;
}
.link {
position: relative;
display: inline-block;
@ -37,13 +41,31 @@ body {
footer {
color: white;
background-color: black;
position: absolute;
text-align: center;
bottom: 0;
width: 100vw;
padding: 2rem;
}
footer .link:after {
border-bottom: 2px dotted white;
}
}
main {
min-height: calc(100vh - 15em);
}
#map { height: 50vh; }
nav {
}
nav li {
list-style: none;
}
nav ul {
display: flex;
flex-direction: row;
justify-content: space-evenly;
}

View File

@ -3,6 +3,10 @@ var router = express.Router();
var homeController = require('../controllers/home');
/* GET home page. */
router.route('/')
.get(homeController.getIndex);
.get(homeController.getIndex);
router.route('/about')
.get(homeController.getAbout);
module.exports = router;

8
views/about.pug Normal file
View File

@ -0,0 +1,8 @@
extends layout.pug
block content
p #{ __("SoundBirder is an open-source web application to learn bird song identification. It is based on bird records from Xeno-Canto and data from eBird.") }
h2 #{ __("Author") }
p #{ __("The project is made with ♥ by Samuel ORTION.") }

8
views/game.pug Normal file
View File

@ -0,0 +1,8 @@
.game
#map
button.button.geolocation-button
i(data-feather="map-pin")
button.button.start-button
i(data-feather="play")
link(rel="stylesheet", href="/dist/leaflet/leaflet.css")
script(src="/dist/leaflet/leaflet.js")

View File

@ -1,4 +1,4 @@
extends layout
block content
include game

View File

@ -2,23 +2,25 @@ doctype html
html
head
title= title
meta(name="viewport", content="width=device-width, initial-scale=1.0")
link(rel='stylesheet', href='/stylesheets/style.css')
meta(name="iewport", content="width=device-width, initial-scale=1.0")
link(rel="stylesheet", href="/stylesheets/style.css")
body
header
h1= title
nav
ul
li
a(href='/') #{ __('Home') }
a(href="/") #{ __("Game") }
li
a(href='/about') #{ __('About') }
a(href="/about") #{ __("About") }
li
a(href='/contact') Contact
block content
a(href="/contact") #{ __("Contact") }
main
block content
footer
.description
.copyright Copyright &copy; 2022 -
span.author
a(href="//samuel.ortion.fr", class="link") Samuel ORTION
a(href="https://samuel.ortion.fr", class="link") Samuel ORTION
script(src="/javascripts/app.js" type="module")
script(src="/dist/feather/feather.min.js")