Merge branch 'dev'

This commit is contained in:
Alexis
2026-02-21 18:14:11 +01:00
85 changed files with 4303 additions and 1522 deletions

View File

@@ -1,11 +1,62 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang=""> <html lang="fr">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico"> <meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title> <title>Memorium — AlexisNP</title>
<meta property="og:title" content="Memorium — AlexisNP" />
<meta name="description" content="Cartographie de mes souvenirs, voyages et de mes nombreuses opinions." />
<meta property="og:description" content="Cartographie de mes souvenirs, voyages et de mes nombreuses opinions." />
<meta name="twitter:description" content="Cartographie de mes souvenirs, voyages et de mes nombreuses opinions." />
<meta property="author" content="Alexis Pelé" />
<meta property="og:author" content="Alexis Pelé" />
<meta property="og:author:username" content="AlexisNP" />
<link rel="apple-touch-icon" sizes="57x57" href="/favicon/light/apple-icon-57x57.png" media="(prefers-color-scheme: light)">
<link rel="apple-touch-icon" sizes="60x60" href="/favicon/light/apple-icon-60x60.png" media="(prefers-color-scheme: light)">
<link rel="apple-touch-icon" sizes="72x72" href="/favicon/light/apple-icon-72x72.png" media="(prefers-color-scheme: light)">
<link rel="apple-touch-icon" sizes="76x76" href="/favicon/light/apple-icon-76x76.png" media="(prefers-color-scheme: light)">
<link rel="apple-touch-icon" sizes="114x114" href="/favicon/light/apple-icon-114x114.png" media="(prefers-color-scheme: light)">
<link rel="apple-touch-icon" sizes="120x120" href="/favicon/light/apple-icon-120x120.png" media="(prefers-color-scheme: light)">
<link rel="apple-touch-icon" sizes="144x144" href="/favicon/light/apple-icon-144x144.png" media="(prefers-color-scheme: light)">
<link rel="apple-touch-icon" sizes="152x152" href="/favicon/light/apple-icon-152x152.png" media="(prefers-color-scheme: light)">
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/light/apple-icon-180x180.png" media="(prefers-color-scheme: light)">
<link rel="icon" type="image/png" sizes="192x192" href="/favicon/light/android-icon-192x192.png" media="(prefers-color-scheme: light)">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon/light/favicon-32x32.png" media="(prefers-color-scheme: light)">
<link rel="icon" type="image/png" sizes="96x96" href="/favicon/light/favicon-96x96.png" media="(prefers-color-scheme: light)">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon/light/favicon-16x16.png" media="(prefers-color-scheme: light)">
<link rel="manifest" href="/favicon/light/manifest.json" media="(prefers-color-scheme: light)">
<meta name="msapplication-TileImage" content="/favicon/light/ms-icon-144x144.png" media="(prefers-color-scheme: light)">
<link rel="apple-touch-icon" sizes="57x57" href="/favicon/dark/apple-icon-57x57.png" media="(prefers-color-scheme: dark)">
<link rel="apple-touch-icon" sizes="60x60" href="/favicon/dark/apple-icon-60x60.png" media="(prefers-color-scheme: dark)">
<link rel="apple-touch-icon" sizes="72x72" href="/favicon/dark/apple-icon-72x72.png" media="(prefers-color-scheme: dark)">
<link rel="apple-touch-icon" sizes="76x76" href="/favicon/dark/apple-icon-76x76.png" media="(prefers-color-scheme: dark)">
<link rel="apple-touch-icon" sizes="114x114" href="/favicon/dark/apple-icon-114x114.png" media="(prefers-color-scheme: dark)">
<link rel="apple-touch-icon" sizes="120x120" href="/favicon/dark/apple-icon-120x120.png" media="(prefers-color-scheme: dark)">
<link rel="apple-touch-icon" sizes="144x144" href="/favicon/dark/apple-icon-144x144.png" media="(prefers-color-scheme: dark)">
<link rel="apple-touch-icon" sizes="152x152" href="/favicon/dark/apple-icon-152x152.png" media="(prefers-color-scheme: dark)">
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/dark/apple-icon-180x180.png" media="(prefers-color-scheme: dark)">
<link rel="icon" type="image/png" sizes="192x192" href="/favicon/dark/android-icon-192x192.png" media="(prefers-color-scheme: dark)">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon/dark/favicon-32x32.png" media="(prefers-color-scheme: dark)">
<link rel="icon" type="image/png" sizes="96x96" href="/favicon/dark/favicon-96x96.png" media="(prefers-color-scheme: dark)">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon/dark/favicon-16x16.png" media="(prefers-color-scheme: dark)">
<link rel="manifest" href="/favicon/dark/manifest.json" media="(prefers-color-scheme: dark)">
<meta name="msapplication-TileImage" content="/favicon/dark/ms-icon-144x144.png" media="(prefers-color-scheme: dark)">
<meta name="msapplication-TileColor" content="#06df72">
<meta name="theme-color" content="#06df72">
<meta name="color-scheme" content="light" />
<meta property="og:site_name" content="memorium.alexcreates.fr" />
<meta name="twitter:domain" content="memorium.alexcreates.fr" />
<meta property="og:type" content="website" />
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>
<script type="module" src="/src/main.ts"></script> <script type="module" src="/src/main.ts"></script>

View File

@@ -1,6 +1,6 @@
{ {
"name": "echoes", "name": "echoes",
"version": "0.0.0", "version": "1.0.0",
"private": true, "private": true,
"type": "module", "type": "module",
"engines": { "engines": {
@@ -18,32 +18,37 @@
"format": "prettier --write src/" "format": "prettier --write src/"
}, },
"dependencies": { "dependencies": {
"@tailwindcss/vite": "^4.1.11", "@tailwindcss/vite": "^4.1.18",
"@vue-leaflet/vue-leaflet": "^0.10.1", "@vue-leaflet/vue-leaflet": "^0.10.1",
"leaflet": "^1.9.4", "leaflet": "^1.9.4",
"pinia": "^3.0.3", "pinia": "^3.0.4",
"tailwindcss": "^4.1.11", "tailwindcss": "^4.1.18",
"vue": "^3.5.18", "vue": "^3.5.28",
"vue-router": "^4.5.1" "vue-leaflet-markercluster": "^0.6.1",
"vue-router": "^5.0.2"
}, },
"devDependencies": { "devDependencies": {
"@prettier/plugin-oxc": "^0.0.4", "@prettier/plugin-oxc": "^0.1.3",
"@tsconfig/node22": "^22.0.2", "@tsconfig/node22": "^22.0.5",
"@types/node": "^22.16.5", "@types/leaflet": "^1.9.21",
"@vitejs/plugin-vue": "^6.0.1", "@types/node": "^25.2.3",
"@vitejs/plugin-vue": "^6.0.4",
"@vue/eslint-config-prettier": "^10.2.0", "@vue/eslint-config-prettier": "^10.2.0",
"@vue/eslint-config-typescript": "^14.6.0", "@vue/eslint-config-typescript": "^14.6.0",
"@vue/tsconfig": "^0.7.0", "@vue/tsconfig": "^0.8.1",
"eslint": "^9.31.0", "clsx": "^2.1.1",
"eslint-plugin-oxlint": "~1.8.0", "eslint": "^10.0.0",
"eslint-plugin-vue": "~10.3.0", "eslint-plugin-oxlint": "~1.46.0",
"jiti": "^2.4.2", "eslint-plugin-vue": "~10.8.0",
"jiti": "^2.6.1",
"npm-run-all2": "^8.0.4", "npm-run-all2": "^8.0.4",
"oxlint": "~1.8.0", "oxlint": "~1.47.0",
"prettier": "3.6.2", "prettier": "3.8.1",
"typescript": "~5.8.0", "sass-embedded": "^1.97.3",
"vite": "npm:rolldown-vite@latest", "tailwind-merge": "^3.4.1",
"vite-plugin-vue-devtools": "^8.0.0", "typescript": "~5.9.3",
"vue-tsc": "^3.0.4" "vite": "npm:rolldown-vite@^7.3.1",
"vite-plugin-vue-devtools": "^8.0.6",
"vue-tsc": "^3.2.4"
} }
} }

3543
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig><msapplication><tile><square70x70logo src="/ms-icon-70x70.png"/><square150x150logo src="/ms-icon-150x150.png"/><square310x310logo src="/ms-icon-310x310.png"/><TileColor>#065f46</TileColor></tile></msapplication></browserconfig>

Binary file not shown.

After

Width:  |  Height:  |  Size: 833 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,46 @@
{
"name": "alexcreates.fr",
"theme_color": "#065f46",
"background_color": "#065f46",
"display": "browser",
"scope": "/",
"start_url": "https://alexcreates.fr",
"icons": [
{
"src": "\/android-icon-36x36.png",
"sizes": "36x36",
"type": "image\/png",
"density": "0.75"
},
{
"src": "\/android-icon-48x48.png",
"sizes": "48x48",
"type": "image\/png",
"density": "1.0"
},
{
"src": "\/android-icon-72x72.png",
"sizes": "72x72",
"type": "image\/png",
"density": "1.5"
},
{
"src": "\/android-icon-96x96.png",
"sizes": "96x96",
"type": "image\/png",
"density": "2.0"
},
{
"src": "\/android-icon-144x144.png",
"sizes": "144x144",
"type": "image\/png",
"density": "3.0"
},
{
"src": "\/android-icon-192x192.png",
"sizes": "192x192",
"type": "image\/png",
"density": "4.0"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig><msapplication><tile><square70x70logo src="/ms-icon-70x70.png"/><square150x150logo src="/ms-icon-150x150.png"/><square310x310logo src="/ms-icon-310x310.png"/><TileColor>#065f46</TileColor></tile></msapplication></browserconfig>

Binary file not shown.

After

Width:  |  Height:  |  Size: 822 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,46 @@
{
"name": "alexcreates.fr",
"theme_color": "#065f46",
"background_color": "#065f46",
"display": "browser",
"scope": "/",
"start_url": "https://alexcreates.fr",
"icons": [
{
"src": "\/android-icon-36x36.png",
"sizes": "36x36",
"type": "image\/png",
"density": "0.75"
},
{
"src": "\/android-icon-48x48.png",
"sizes": "48x48",
"type": "image\/png",
"density": "1.0"
},
{
"src": "\/android-icon-72x72.png",
"sizes": "72x72",
"type": "image\/png",
"density": "1.5"
},
{
"src": "\/android-icon-96x96.png",
"sizes": "96x96",
"type": "image\/png",
"density": "2.0"
},
{
"src": "\/android-icon-144x144.png",
"sizes": "144x144",
"type": "image\/png",
"density": "3.0"
},
{
"src": "\/android-icon-192x192.png",
"sizes": "192x192",
"type": "image\/png",
"density": "4.0"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
<circle fill="#fff" cx="128" cy="128" r="128" />
<path fill="#000" transform="scale(0.6)" transform-origin="center" d="M224,104h-8.37a88,88,0,0,0-175.26,0H32a8,8,0,0,0-8,8,104.35,104.35,0,0,0,56,92.28V208a16,16,0,0,0,16,16h64a16,16,0,0,0,16-16v-3.72A104.35,104.35,0,0,0,232,112,8,8,0,0,0,224,104ZM173.48,56.23q2.75,2.25,5.27,4.75a87.92,87.92,0,0,0-49.15,43H100.1A72.26,72.26,0,0,1,168,56C169.83,56,171.66,56.09,173.48,56.23ZM148.12,104a71.84,71.84,0,0,1,41.27-29.57A71.45,71.45,0,0,1,199.54,104ZM128,40a71.87,71.87,0,0,1,19,2.57A88.36,88.36,0,0,0,83.33,104H56.46A72.08,72.08,0,0,1,128,40Z"></path>
</svg>

After

Width:  |  Height:  |  Size: 676 B

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
<circle fill="#fff" cx="128" cy="128" r="128" />
<path fill="#000" transform="scale(0.6)" transform-origin="center" d="M200,40H48a40,40,0,0,0-16,76.65V200a16,16,0,0,0,16,16H200a16,16,0,0,0,16-16V116.65A40,40,0,0,0,200,40Zm-56,64a8,8,0,0,0,0,16v80H48V120a8,8,0,0,0,0-16,24,24,0,0,1,0-48h96a24,24,0,0,1,0,48Z"></path>
</svg>

After

Width:  |  Height:  |  Size: 394 B

4
public/map/icons/bar.svg Normal file
View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
<circle fill="#fff" cx="128" cy="128" r="128" />
<path fill="#000" transform="scale(0.55)" transform-origin="center" d="M237.66,45.66A8,8,0,0,0,232,32H24a8,8,0,0,0-5.66,13.66L120,147.31V208H88a8,8,0,0,0,0,16h80a8,8,0,0,0,0-16H136V147.31Zm-25,2.34-16,16H59.31l-16-16Z"></path>
</svg>

After

Width:  |  Height:  |  Size: 354 B

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
<circle fill="#fff" cx="128" cy="128" r="128" />
<path fill="#000" transform="scale(0.6)" transform-origin="center" d="M35.58,98.06a16,16,0,0,1-3.23-13.44C39.78,49.5,80,24,128,24s88.22,25.5,95.65,60.62A16,16,0,0,1,207.93,104H48.07A16,16,0,0,1,35.58,98.06Zm193.68,54.42-41.13,15L151,152.57a8,8,0,0,0-5.94,0l-37,14.81L71,152.57a8,8,0,0,0-5.7-.09l-44,16a8,8,0,0,0,5.47,15L40,178.69V184a40,40,0,0,0,40,40h96a40,40,0,0,0,40-40v-9.67l18.73-6.81a8,8,0,1,0-5.47-15ZM24,136H232a8,8,0,0,0,0-16H24a8,8,0,0,0,0,16Z"></path>
</svg>

After

Width:  |  Height:  |  Size: 590 B

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
<circle fill="#fff" cx="128" cy="128" r="128" />
<path fill="#000" transform="scale(0.6)" transform-origin="center" d="M208,80H32a8,8,0,0,0-8,8v48a96.3,96.3,0,0,0,32.54,72H32a8,8,0,0,0,0,16H208a8,8,0,0,0,0-16H183.46a96.59,96.59,0,0,0,27-40.09A40,40,0,0,0,248,128v-8A40,40,0,0,0,208,80Zm24,48a24,24,0,0,1-17.2,23,95.78,95.78,0,0,0,1.2-15V97.38A24,24,0,0,1,232,120ZM112,56V24a8,8,0,0,1,16,0V56a8,8,0,0,1-16,0Zm32,0V24a8,8,0,0,1,16,0V56a8,8,0,0,1-16,0ZM80,56V24a8,8,0,0,1,16,0V56a8,8,0,0,1-16,0Z"></path>
</svg>

After

Width:  |  Height:  |  Size: 580 B

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" color="#000000" fill="none">
<circle fill="#fff" cx="12" cy="12" r="12" />
<path fill="#000" transform="scale(0.6)" transform-origin="center" d="M11.829,1.25 L12.171,1.25 L12.214,1.25 C12.608,1.25 12.973,1.25 13.271,1.288 C13.598,1.331 13.955,1.431 14.252,1.717 C14.554,2.008 14.663,2.362 14.709,2.691 C14.75,2.983 14.75,3.339 14.75,3.716 L14.75,6.925 L15.283,5.96 L15.304,5.921 C15.505,5.557 15.69,5.222 15.876,4.969 C16.08,4.693 16.354,4.419 16.768,4.303 C17.186,4.186 17.562,4.281 17.878,4.417 C18.163,4.539 18.486,4.735 18.833,4.944 L18.872,4.967 L19.069,5.087 L19.109,5.11 C19.477,5.333 19.818,5.539 20.072,5.745 C20.354,5.974 20.617,6.271 20.714,6.705 C20.81,7.135 20.702,7.516 20.55,7.846 C20.412,8.146 20.195,8.486 19.959,8.859 L19.934,8.897 L19.709,9.251 L20.596,9.254 L20.638,9.259 C21.336,9.34 21.849,9.982 21.735,10.696 L21.728,10.741 L19.492,18.56 L19.48,18.604 C19.239,19.444 19.04,20.138 18.812,20.681 C18.572,21.253 18.271,21.732 17.784,22.094 C17.298,22.456 16.75,22.61 16.129,22.682 C15.537,22.75 14.805,22.75 13.915,22.75 L10.086,22.75 C9.195,22.75 8.463,22.75 7.871,22.682 C7.25,22.61 6.703,22.456 6.217,22.094 C5.73,21.732 5.428,21.253 5.188,20.681 C4.96,20.138 4.761,19.444 4.521,18.604 L2.273,10.741 L2.266,10.696 C2.152,9.982 2.665,9.34 3.362,9.259 L3.405,9.254 L4.84,9.25 C4.989,9.25 5.138,9.257 5.285,9.27 L3.946,6.863 L3.925,6.825 C3.717,6.452 3.526,6.11 3.407,5.811 C3.277,5.482 3.191,5.107 3.299,4.693 C3.406,4.277 3.664,3.992 3.941,3.771 C4.191,3.572 4.523,3.374 4.882,3.159 L4.882,3.159 L4.92,3.136 L5.141,3.004 L5.181,2.98 L5.181,2.98 C5.559,2.755 5.906,2.547 6.211,2.418 C6.546,2.276 6.943,2.18 7.378,2.314 C7.811,2.447 8.087,2.747 8.29,3.049 C8.475,3.326 8.656,3.695 8.854,4.098 L8.854,4.098 L8.874,4.139 L9.25,4.905 L9.25,3.76 L9.25,3.716 L9.25,3.716 C9.25,3.339 9.25,2.983 9.291,2.691 C9.337,2.362 9.446,2.008 9.748,1.717 C10.045,1.431 10.402,1.331 10.729,1.288 C11.027,1.25 11.392,1.25 11.786,1.25 Z M4.841,10.75 L3.837,10.752 L5.95,18.147 C6.207,19.042 6.382,19.649 6.571,20.101 C6.753,20.533 6.918,20.746 7.112,20.891 C7.308,21.037 7.566,21.136 8.043,21.191 C8.539,21.249 9.184,21.25 10.13,21.25 L13.871,21.25 C14.816,21.25 15.461,21.249 15.958,21.191 C16.435,21.136 16.692,21.037 16.888,20.891 C17.083,20.746 17.248,20.533 17.429,20.101 C17.619,19.649 17.794,19.042 18.05,18.148 L20.164,10.752 L19.161,10.75 C17.659,10.75 16.351,11.728 15.944,13.126 C15.749,13.799 15.128,14.25 14.437,14.25 L9.564,14.25 C8.872,14.25 8.252,13.799 8.056,13.126 C7.649,11.728 6.342,10.75 4.841,10.75 Z M10.75,8.115 C10.75,8.128 10.75,8.14 10.75,8.153 L10.75,12.75 L13.25,12.75 L13.25,3.76 C13.25,3.323 13.248,3.074 13.224,2.898 C13.217,2.85 13.21,2.819 13.205,2.801 C13.183,2.794 13.144,2.784 13.078,2.776 C12.889,2.751 12.623,2.75 12.171,2.75 L11.829,2.75 C11.377,2.75 11.111,2.751 10.922,2.776 C10.856,2.784 10.817,2.794 10.795,2.801 C10.79,2.819 10.783,2.85 10.776,2.898 C10.752,3.074 10.75,3.323 10.75,3.76 Z M7.528,4.8 C7.303,4.342 7.166,4.067 7.043,3.884 C6.991,3.806 6.956,3.768 6.938,3.752 C6.916,3.756 6.871,3.768 6.794,3.8 C6.598,3.883 6.342,4.034 5.91,4.292 L5.69,4.424 C5.279,4.669 5.037,4.815 4.877,4.943 C4.804,5.001 4.772,5.038 4.759,5.055 C4.753,5.063 4.751,5.067 4.751,5.067 L4.751,5.069 L4.75,5.073 C4.75,5.073 4.75,5.08 4.751,5.091 C4.755,5.117 4.766,5.167 4.801,5.258 C4.879,5.454 5.02,5.708 5.256,6.133 L7.386,9.963 C8.191,10.453 8.847,11.172 9.25,12.047 L9.25,8.308 Z M14.75,10.028 L14.75,12.048 C15.339,10.769 16.468,9.822 17.813,9.438 L18.669,8.092 C18.937,7.669 19.097,7.415 19.188,7.217 C19.23,7.126 19.244,7.076 19.248,7.051 L19.25,7.034 L19.25,7.033 L19.25,7.032 C19.249,7.031 19.248,7.028 19.244,7.023 C19.232,7.006 19.201,6.969 19.126,6.909 C18.964,6.777 18.715,6.625 18.294,6.371 L18.097,6.251 C17.697,6.01 17.464,5.871 17.286,5.795 C17.23,5.771 17.194,5.76 17.173,5.754 C17.155,5.771 17.126,5.802 17.083,5.86 C16.963,6.023 16.826,6.269 16.596,6.685 Z M13.008,17 C13.008,17.552 12.56,18 12.008,18 L11.999,18 C11.446,18 10.999,17.552 10.999,17 C10.999,16.448 11.446,16 11.999,16 L12.008,16 C12.56,16 13.008,16.448 13.008,17 Z M6.957,3.75 C6.957,3.75 6.955,3.75 6.949,3.75 C6.954,3.751 6.957,3.75 6.957,3.75 Z M6.93,3.745 C6.925,3.741 6.923,3.741 6.923,3.741 C6.923,3.741 6.925,3.743 6.93,3.745 Z M17.154,5.751 C17.149,5.75 17.147,5.75 17.147,5.75 C17.147,5.75 17.15,5.751 17.154,5.751 Z M17.192,5.739 L17.193,5.738 C17.193,5.738 17.191,5.739 17.187,5.742 C17.19,5.741 17.191,5.74 17.192,5.739 Z M13.198,2.781 C13.197,2.777 13.196,2.775 13.195,2.776 Z M10.805,2.776 L10.802,2.781 C10.804,2.778 10.805,2.776 10.805,2.776 Z M10.777,2.807 C10.773,2.809 10.771,2.81 10.771,2.81 Z M13.229,2.81 L13.223,2.807 C13.226,2.809 13.228,2.81 13.229,2.81 Z" />
</svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
<circle fill="#fff" cx="128" cy="128" r="128" />
<path fill="#45556c" transform="scale(0.6)" transform-origin="center" d="M112,116a12,12,0,1,1-12-12A12,12,0,0,1,112,116Zm44-12a12,12,0,1,0,12,12A12,12,0,0,0,156,104Zm68,16v96a8,8,0,0,1-13.07,6.19l-24.26-19.85L162.4,222.19a8,8,0,0,1-10.13,0L128,202.34l-24.27,19.85a8,8,0,0,1-10.13,0L69.33,202.34,45.07,222.19A8,8,0,0,1,32,216V120a96,96,0,0,1,192,0Zm-16,0a80,80,0,0,0-160,0v79.12l16.27-13.31a8,8,0,0,1,10.13,0l24.27,19.85,24.26-19.85a8,8,0,0,1,10.14,0l24.26,19.85,24.27-19.85a8,8,0,0,1,10.13,0L208,199.12Z"></path>
</svg>

After

Width:  |  Height:  |  Size: 640 B

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
<circle fill="#fff" cx="128" cy="128" r="128" />
<path fill="#000" transform="scale(0.6)" transform-origin="center" d="M208,97.37V96A80,80,0,0,0,48,96v1.37A24,24,0,0,0,56,144h3.29l54.82,95.94a16,16,0,0,0,27.78,0L196.71,144H200a24,24,0,0,0,8-46.63ZM146.89,198.94,115.5,144h19.29l21.75,38.06ZM77.71,144H97.07l40.61,71.06L128,232Zm88,21.94L153.21,144h25.08Z"></path>
</svg>

After

Width:  |  Height:  |  Size: 442 B

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
<circle fill="#fff" cx="128" cy="128" r="128" />
<path fill="#000" transform="scale(0.6)" transform-origin="center" d="M239.54,63a15.91,15.91,0,0,0-7.25-9.9,201.49,201.49,0,0,0-208.58,0,16,16,0,0,0-5.37,22l96,157.27a16,16,0,0,0,27.36,0l96-157.27A15.82,15.82,0,0,0,239.54,63Zm-55.1,68.53a40,40,0,0,0-41.38,67.77L128,224,96.5,172.43a40,40,0,1,0-41.35-67.76L48.8,94.26a152,152,0,0,1,158.39,0Z"></path>
</svg>

After

Width:  |  Height:  |  Size: 477 B

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
<circle fill="#fff" cx="128" cy="128" r="128" />
<path fill="#000" transform="scale(0.6)" transform-origin="center" d="M216,40V224a8,8,0,0,1-16,0V176H152a8,8,0,0,1-8-8,268.75,268.75,0,0,1,7.22-56.88c9.78-40.49,28.32-67.63,53.63-78.47A8,8,0,0,1,216,40Zm-96.11-1.31a8,8,0,1,0-15.78,2.63L111.89,88H88V40a8,8,0,0,0-16,0V88H48.11l7.78-46.68a8,8,0,1,0-15.78-2.63l-8,48A8.17,8.17,0,0,0,32,88a48.07,48.07,0,0,0,40,47.32V224a8,8,0,0,0,16,0V135.32A48.07,48.07,0,0,0,128,88a8.17,8.17,0,0,0-.11-1.31Z"></path>
</svg>

After

Width:  |  Height:  |  Size: 576 B

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
<circle fill="#fff" cx="128" cy="128" r="128" />
<path fill="#000" transform="scale(0.6)" transform-origin="center" d="M168,76a12,12,0,1,1-12-12A12,12,0,0,1,168,76Zm48.72,67.64c-19.37,34.9-55.44,53.76-107.24,56.1l-22,51.41A8,8,0,0,1,80.1,256l-.51,0a8,8,0,0,1-7.19-5.78L57.6,198.39,5.8,183.56a8,8,0,0,1-1-15.05l51.41-22c2.35-51.78,21.21-87.84,56.09-107.22,24.75-13.74,52.74-15.84,71.88-15.18,18.64.64,36,4.27,38.86,6a8,8,0,0,1,2.83,2.83c1.69,2.85,5.33,20.21,6,38.85C232.55,90.89,230.46,118.89,216.72,143.64Zm-4.3-100.07c-14.15-3-64.1-11-100.3,14.75a81.21,81.21,0,0,0-16,15.07,36,36,0,0,0,39.35,38.44,8,8,0,0,1,8.73,8.73,36,36,0,0,0,38.47,39.34,80.81,80.81,0,0,0,15-16C223.42,107.73,215.42,57.74,212.42,43.57Z"></path>
</svg>

After

Width:  |  Height:  |  Size: 795 B

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
<circle fill="#fff" cx="128" cy="128" r="128" />
<path fill="#000" transform="scale(0.6)" transform-origin="center" d="M112,136V72h19.47a16.09,16.09,0,0,1,13.72,7.77L165.72,114a16.06,16.06,0,0,1,2.28,8.24V216a16,16,0,0,1-16,16H56a16,16,0,0,1-16-16V122.22A16.06,16.06,0,0,1,42.28,114L62.81,79.77A16.09,16.09,0,0,1,76.53,72H96v64a8,8,0,0,0,16,0Zm112,24a16,16,0,0,1-16-16V64A56,56,0,0,0,96,64v8h16V64a40,40,0,0,1,80,0v80a32,32,0,0,0,32,32,8,8,0,0,0,0-16Z"></path>
</svg>

After

Width:  |  Height:  |  Size: 539 B

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
<path fill="#fff" transform="scale(0.6)" transform-origin="center" d="M254.07,106.79,208.53,53.73A16,16,0,0,0,196.26,48H32A16,16,0,0,0,16,64V176a16,16,0,0,0,16,16H49a32,32,0,0,0,62,0h50a32,32,0,0,0,62,0h17a16,16,0,0,0,16-16V112A8,8,0,0,0,254.07,106.79ZM32,104V64H88v40Zm48,96a16,16,0,1,1,16-16A16,16,0,0,1,80,200Zm80-96H104V64h56Zm32,96a16,16,0,1,1,16-16A16,16,0,0,1,192,200Zm-16-96V64h20.26l34.33,40Z"></path>
</svg>

After

Width:  |  Height:  |  Size: 485 B

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256">
<circle fill="#fff" cx="128" cy="128" r="128" />
<path fill="#000" transform="scale(0.6)" transform-origin="center" d="M232,80H199.44a64,64,0,0,1-10.19,77.26c-8.52,8.69-19.61,16.92-31.85,24.51a4,4,0,0,1-4.91-.59l-34.84-34.84a8,8,0,0,0-11.49.18,8.23,8.23,0,0,0,.41,11.38l29.88,29.88a4,4,0,0,1-1,6.39C95.74,214.79,53,228.54,46.78,230.48a16,16,0,0,1-21.26-21.26c2.73-8.71,29-90.27,64.86-133.35a4,4,0,0,1,5.9-.26l42.05,42.06a8,8,0,0,0,11.71-.43,8.19,8.19,0,0,0-.6-11.1L108.08,64.78a4,4,0,0,1,.63-6.18,64,64,0,0,1,67.28-2V24a8,8,0,0,1,8.54-8A8.18,8.18,0,0,1,192,24.28V52.69l26.34-26.35a8,8,0,0,1,11.32,11.32L203.31,64h28.41A8.18,8.18,0,0,1,240,71.47,8,8,0,0,1,232,80Z"></path>
</svg>

After

Width:  |  Height:  |  Size: 750 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

49
public/robots.txt Normal file
View File

@@ -0,0 +1,49 @@
User-agent: GPTBot
Disallow: /
User-agent: ChatGPT-User
Disallow: /
User-agent: Google-Extended
Disallow: /
User-agent: PerplexityBot
Disallow: /
User-agent: Amazonbot
Disallow: /
User-agent: ClaudeBot
Disallow: /
User-agent: Omgilibot
Disallow: /
User-Agent: FacebookBot
Disallow: /
User-Agent: Applebot
Disallow: /
User-agent: anthropic-ai
Disallow: /
User-agent: Bytespider
Disallow: /
User-agent: Claude-Web
Disallow: /
User-agent: Diffbot
Disallow: /
User-agent: ImagesiftBot
Disallow: /
User-agent: Omgilibot
Disallow: /
User-agent: Omgili
Disallow: /
User-agent: YouBot
Disallow: /
User-agent: AhrefsBot
Disallow: /
User-agent: AhrefsSiteAudit
Disallow: /
User-agent: SemrushBot
Disallow: /
User-agent: YandexMarket
Disallow: /
User-agent: YandexBot
Disallow: /
User-agent: DataForSeoBot
Disallow: /
Sitemap: https://alexcreates.fr/sitemap-index.xml

View File

@@ -1,27 +1,112 @@
<script setup lang="ts"> <script setup lang="ts">
import 'leaflet/dist/leaflet.css' import 'leaflet/dist/leaflet.css'
import { LMap, LTileLayer } from '@vue-leaflet/vue-leaflet' import 'vue-leaflet-markercluster/dist/style.css'
import { ref } from 'vue'
const zoom = ref(6) import L from 'leaflet'
const center = ref([38, 139.69]) globalThis.L = L
import { LMap, LTileLayer, LControlZoom, LLayerGroup } from '@vue-leaflet/vue-leaflet'
import { LMarkerClusterGroup } from 'vue-leaflet-markercluster'
import ReviewMarker from './components/map/ReviewMarker.vue'
import TokenMarker from './components/map/TokenMarker.vue'
import { storeToRefs } from 'pinia'
import { useReviewStore } from './stores/reviews'
import { useParisTokensStore } from './stores/parisTokens'
import { useMap } from './stores/map'
import MapSidebar from './components/map/MapSidebar.vue'
const { zoom, minZoom, center } = useMap()
const { markers: reviews } = useReviewStore()
const { markers: parisTokens } = useParisTokensStore()
const { activeLayers } = storeToRefs(useMap())
</script> </script>
<template> <template>
<main> <main>
<LMap ref="map" v-model:zoom="zoom" v-model:center="center" :useGlobalLeaflet="false"> <LMap
ref="map"
:min-zoom
v-model:zoom="zoom"
v-model:center="center"
:options="{ zoomControl: false }"
:useGlobalLeaflet="true"
>
<LControlZoom position="bottomright" />
<LTileLayer <LTileLayer
url="https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/{z}/{x}/{y}{r}.png" url="https://tiles.stadiamaps.com/tiles/alidade_smooth/{z}/{x}/{y}{r}.png"
layer-type="base" layer-type="base"
name="Stadia Maps Basemap"
/> />
<!-- "Monnaie de Paris" CSGroup -->
<LLayerGroup v-if="activeLayers.tokens && parisTokens.length > 0" :max-cluster-radius="18" :disable-clustering-at-zoom="14">
<TokenMarker v-once v-for="marker in parisTokens" :key="marker.title" :marker />
</LLayerGroup>
<!-- Review CSGroup -->
<LMarkerClusterGroup v-if="activeLayers.food && reviews.length > 0" :max-cluster-radius="18" :disable-clustering-at-zoom="14">
<ReviewMarker v-once v-for="marker in reviews" :key="marker.title" :marker />
</LMarkerClusterGroup>
</LMap> </LMap>
</main> </main>
<MapSidebar />
</template> </template>
<style scoped> <style lang="scss">
main { main {
height: 100vh; height: 100vh;
width: 100vw; width: 100vw;
position: relative;
z-index: 1;
}
.leaflet-marker-icon:not(.marker-cluster) {
border-radius: 50%;
box-shadow: 0 0 5px 3px color-mix(in srgb, var(--color-neutral-400) 66%, transparent);
}
.leaflet-popup-content-wrapper {
border-radius: 5px;
.leaflet-popup-content {
margin: 10px 20px 10px 15px;
p {
margin-bottom: 0;
}
}
}
.marker-cluster span {
font-weight: var(--font-weight-medium);
}
.marker-cluster-small {
background-color: color-mix(in srgb, var(--color-green-500) 25%, transparent);
div {
background-color: color-mix(in srgb, var(--color-green-500) 33%, transparent);
}
}
.marker-cluster-medium {
background-color: color-mix(in srgb, var(--color-yellow-400) 25%, transparent);
div {
background-color: color-mix(in srgb, var(--color-yellow-400) 33%, transparent);
}
}
.marker-cluster-large {
background-color: color-mix(in srgb, var(--color-rose-400) 25%, transparent);
div {
background-color: color-mix(in srgb, var(--color-rose-400) 33%, transparent);
}
} }
</style> </style>

View File

@@ -1,7 +1,31 @@
@import 'tailwindcss'; @import 'tailwindcss';
@custom-variant dark (&:where(.dark, .dark *));
@theme {
--color-foreground: var(--color-slate-950);
--color-background: var(--color-slate-100);
--color-border: var(--color-slate-200);
}
@layer theme {
.dark {
--color-foreground: var(--color-slate-100);
--color-background: var(--color-slate-900);
--color-border: var(--color-slate-800);
}
}
:root {
--body-padding: 1rem;
}
html, html,
body { body {
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
.spacing > * + * {
margin: .5em 0 0 !important;
}

View File

@@ -0,0 +1,83 @@
<script lang="ts" setup>
import { useMap } from '@/stores/map';
import { useParisTokensStore } from '@/stores/parisTokens';
import { useReviewStore } from '@/stores/reviews';
import { storeToRefs } from 'pinia';
const { activeLayers } = storeToRefs(useMap())
const { markers: restaurants } = useReviewStore()
const { markers: tokens } = useParisTokensStore()
function handleTokenClick() {
activeLayers.value.tokens = !activeLayers.value.tokens
}
function handleFoodClick() {
activeLayers.value.food = !activeLayers.value.food
}
</script>
<template>
<aside class="rounded bg-background border border-border shadow-sm">
<header class="py-1.5 px-2 text-[.8em] font-medium border-b border-border">
<h2>
Calques
</h2>
</header>
<menu class="first:pt-0.5 last:pb-0.5">
<li>
<button
class="w-full pl-2 pr-3 py-1.5 text-xs cursor-pointer flex items-start gap-1 hover:bg-foreground/10"
:class="{
'text-foreground *:fill-foreground': !activeLayers.food,
'text-emerald-600 *:fill-emerald-600': activeLayers.food
}"
@click="handleFoodClick"
>
<svg v-if="activeLayers.food" xmlns="http://www.w3.org/2000/svg" width="1.2em" height="1.2em" viewBox="0 0 256 256">
<path d="M208,32H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32Zm-34.34,77.66-56,56a8,8,0,0,1-11.32,0l-24-24a8,8,0,0,1,11.32-11.32L112,148.69l50.34-50.35a8,8,0,0,1,11.32,11.32Z" />
</svg>
<svg v-else xmlns="http://www.w3.org/2000/svg" width="1.2em" height="1.2em" viewBox="0 0 256 256">
<path d="M216,40V224a8,8,0,0,1-16,0V176H152a8,8,0,0,1-8-8,268.75,268.75,0,0,1,7.22-56.88c9.78-40.49,28.32-67.63,53.63-78.47A8,8,0,0,1,216,40Zm-96.11-1.31a8,8,0,1,0-15.78,2.63L111.89,88H88V40a8,8,0,0,0-16,0V88H48.11l7.78-46.68a8,8,0,1,0-15.78-2.63l-8,48A8.17,8.17,0,0,0,32,88a48.07,48.07,0,0,0,40,47.32V224a8,8,0,0,0,16,0V135.32A48.07,48.07,0,0,0,128,88a8.17,8.17,0,0,0-.11-1.31Z" />
</svg>
<span>
Restaurants <small>({{ restaurants.length }})</small>
</span>
</button>
</li>
<li>
<button
class="pl-2 pr-3 py-1.5 text-xs cursor-pointer flex items-start gap-1 hover:bg-foreground/10"
:class="{
'text-foreground *:fill-foreground': !activeLayers.tokens,
'text-emerald-600 *:fill-emerald-600': activeLayers.tokens
}"
@click="handleTokenClick"
>
<svg v-if="activeLayers.tokens" xmlns="http://www.w3.org/2000/svg" width="1.2em" height="1.2em" viewBox="0 0 256 256">
<path d="M208,32H48A16,16,0,0,0,32,48V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V48A16,16,0,0,0,208,32Zm-34.34,77.66-56,56a8,8,0,0,1-11.32,0l-24-24a8,8,0,0,1,11.32-11.32L112,148.69l50.34-50.35a8,8,0,0,1,11.32,11.32Z" />
</svg>
<svg v-else xmlns="http://www.w3.org/2000/svg" width="1.2em" height="1.2em" viewBox="0 0 256 256">
<path d="M198.51,56.09C186.44,35.4,169.92,24,152,24H104C86.08,24,69.56,35.4,57.49,56.09,46.21,75.42,40,101,40,128s6.21,52.58,17.49,71.91C69.56,220.6,86.08,232,104,232h48c17.92,0,34.44-11.4,46.51-32.09C209.79,180.58,216,155,216,128S209.79,75.42,198.51,56.09ZM199.79,120h-32a152.78,152.78,0,0,0-9.68-48H188.7C194.82,85.38,198.86,102,199.79,120Zm-20.6-64H150.46a83.13,83.13,0,0,0-12-16H152C162,40,171.4,46,179.19,56ZM152,216H138.49a83.13,83.13,0,0,0,12-16h28.73C171.4,210,162,216,152,216Zm36.7-32H158.12a152.78,152.78,0,0,0,9.68-48h32C198.86,154,194.82,170.62,188.7,184Z" />
</svg>
<span>
Monnaie de Paris <small>({{ tokens.length }})</small>
</span>
</button>
</li>
</menu>
</aside>
</template>
<style lang="scss" scoped>
aside {
position: fixed;
top: var(--body-padding);
left: var(--body-padding);
z-index: 100;
}
</style>

View File

@@ -0,0 +1,107 @@
<script setup lang="ts">
import type { ReviewMarker } from '@/models/Markers';
import { LMarker, LPopup, LIcon } from '@vue-leaflet/vue-leaflet'
import type { PointTuple } from 'leaflet';
import { computed, ref } from 'vue';
import { cn } from '@/lib/cn';
const props = defineProps<{
marker: ReviewMarker
}>()
const normalIconSize: PointTuple = [30, 30]
const tinyIconSize: PointTuple = [25, 25]
const iconSize = ref<PointTuple>(props.marker.closed ? tinyIconSize : normalIconSize)
const iconAnchor = computed<PointTuple>(() => [iconSize.value[0] / 2, iconSize.value[1]])
const popupOffset = [0, iconSize.value[0] * -0.66]
</script>
<template>
<LMarker :lat-lng="marker.coords">
<LPopup :options="{ offset: popupOffset, maxWidth: 380, minWidth: 180 }">
<div class="spacing">
<h2 class="font-bold text-[1.2em] leading-5">
{{ marker.title }}
</h2>
<p v-html="marker.reviews?.[0]!!.text" />
</div>
</LPopup>
<LIcon
:icon-size
:icon-anchor
:class-name="cn(
{ 'grayscale': marker.closed }
)"
>
<img v-if="marker.closed" src="/map/icons/ghost.svg" />
<template v-else>
<img v-if="marker.type === 'bar'" src="/map/icons/bar.svg" />
<img v-else-if="marker.type === 'bakery'" src="/map/icons/bakery.svg" />
<img v-else-if="marker.type === 'tea-shop'" src="/map/icons/tea-shop.svg" />
<img v-else-if="marker.type === 'coffee-shop'" src="/map/icons/coffee-shop.svg" />
<img v-else-if="marker.type === 'ice-cream'" src="/map/icons/ice-cream.svg" />
<img v-else-if="marker.type === 'food-truck'" src="/map/icons/truck.svg" />
<template v-else-if="marker.type === 'restaurant'">
<img v-if="marker.food === 'asian'" src="/map/icons/asian.svg" />
<img v-else-if="marker.food === 'burgers'" src="/map/icons/burgers.svg" />
<!-- <img v-else-if="marker.food === 'creperie'" src="/map/icons/creperie.svg" /> -->
<!-- <img v-else-if="marker.food === 'eastern'" src="/map/icons/eastern.svg" /> -->
<img v-else-if="marker.food === 'fast-food'" src="/map/icons/fast-food.svg" />
<img v-else-if="marker.food === 'italian'" src="/map/icons/italian.svg" />
<img v-else-if="marker.food === 'seafood'" src="/map/icons/seafood.svg" />
<!-- <img v-else-if="marker.food === 'street-food'" src="/map/icons/street-food.svg" /> -->
<img v-else-if="marker.food === 'vegetarian'" src="/map/icons/vegetarian.svg" />
<img v-else src="/map/icons/restaurant.svg" />
</template>
</template>
<div
class="absolute -top-2 -right-2 size-5 text-center grid place-items-center rounded-full text-[0.65rem] font-bold tracking-[-0.075em]"
:class="cn(
{
'text-white bg-red-500': marker.reviews?.[0]!.grade! <= 1.5,
'text-black bg-amber-400': marker.reviews?.[0]!.grade! > 1.5 && marker.reviews?.[0]!.grade! <= 2.5,
'text-black bg-lime-400': marker.reviews?.[0]!.grade! > 2.5 && marker.reviews?.[0]!.grade! < 4.0,
'text-black bg-green-400': marker.reviews?.[0]!.grade! > 2.5 && marker.reviews?.[0]!.grade! < 4.5,
'text-black bg-sky-400': marker.reviews?.[0]!.grade! >= 4.5,
},
marker.type === 'food-truck' && {
'bg-red-600': marker.reviews?.[0]!.grade! <= 1.5,
'bg-amber-500': marker.reviews?.[0]!.grade! > 1.5 && marker.reviews?.[0]!.grade! <= 2.5,
'bg-lime-500': marker.reviews?.[0]!.grade! > 2.5 && marker.reviews?.[0]!.grade! < 4.0,
'bg-green-500': marker.reviews?.[0]!.grade! > 2.5 && marker.reviews?.[0]!.grade! < 4.5,
'bg-sky-400': marker.reviews?.[0]!.grade! >= 4.5,
}
)"
>
{{ marker.reviews?.[0]!.grade }}
</div>
<div
class="absolute -z-10 -inset-0.5 rounded-full"
:class="cn(
{
'bg-red-500': marker.reviews?.[0]!.grade! <= 1.5,
'bg-amber-400': marker.reviews?.[0]!.grade! > 1.5 && marker.reviews?.[0]!.grade! <= 2.5,
'bg-lime-400': marker.reviews?.[0]!.grade! > 2.5 && marker.reviews?.[0]!.grade! < 4.0,
'bg-green-400': marker.reviews?.[0]!.grade! > 2.5 && marker.reviews?.[0]!.grade! < 4.5,
'bg-sky-400': marker.reviews?.[0]!.grade! >= 4.5,
'bg-slate-800': marker.type === 'food-truck'
},
marker.type === 'food-truck' && {
'border-2 border-red-700': marker.reviews?.[0]!.grade! <= 1.5,
'border-2 border-amber-600': marker.reviews?.[0]!.grade! > 1.5 && marker.reviews?.[0]!.grade! <= 2.5,
'border-2 border-lime-600': marker.reviews?.[0]!.grade! > 2.5 && marker.reviews?.[0]!.grade! < 4.0,
'border-2 border-green-600': marker.reviews?.[0]!.grade! > 2.5 && marker.reviews?.[0]!.grade! < 4.5,
'border-2 border-sky-500': marker.reviews?.[0]!.grade! >= 4.5,
}
)"
/>
</LIcon>
</LMarker>
</template>

View File

@@ -0,0 +1,45 @@
<script setup lang="ts">
import type { TokenMarker } from '@/models/Markers';
import { LMarker, LPopup, LIcon } from '@vue-leaflet/vue-leaflet'
import type { PointTuple } from 'leaflet';
import { computed, ref } from 'vue';
import { cn } from '@/lib/cn';
defineProps<{
marker: TokenMarker
}>()
const iconSize = ref<PointTuple>([38, 38])
const iconAnchor = computed<PointTuple>(() => [iconSize.value[0] / 2, iconSize.value[1]])
const popupOffset = [0, iconSize.value[0] * -0.66]
</script>
<template>
<LMarker :lat-lng="marker.coords">
<LPopup :options="{ offset: popupOffset, maxWidth: 380, minWidth: 180 }">
<div class="spacing">
<h2 class="font-bold text-[1.2em] leading-5">
{{ marker.title }}
</h2>
<p v-html="marker.reviews?.[0]!!.text" />
</div>
</LPopup>
<LIcon
:icon-size
:icon-anchor
:class-name="cn(
{ 'grayscale': marker.bootleg }
)"
>
<img src="/map/monnaie-de-paris.png" width="40" height="40" />
<div
class="absolute -top-2 -right-2 size-5 text-center grid place-items-center rounded-full text-[0.65rem] font-bold tracking-[-0.075em]"
>
{{ marker.reviews?.[0]!.grade }}
</div>
</LIcon>
</LMarker>
</template>

4
src/lib/cn.ts Normal file
View File

@@ -0,0 +1,4 @@
import { clsx, type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'
export const cn = (...inputs: ClassValue[]) => twMerge(clsx(inputs))

29
src/models/Markers.ts Normal file
View File

@@ -0,0 +1,29 @@
import type { PointTuple } from "leaflet"
export type ReviewType = "restaurant" | "bar" | "bakery" | "tea-shop" | "coffee-shop" | "ice-cream" | "food-truck"
export type FoodType = "mixed" | "asian" | "creole" | "vegetarian" | "italian" | "fast-food" | "street-food" | "burgers" | "seafood" | "creperie" | "eastern" | "south-american"
export interface DefaultMarker {
coords: PointTuple
title?: string
}
export interface ReviewMarker extends DefaultMarker {
type?: ReviewType
food?: FoodType
reviews?: Review[]
closed?: boolean
url?: string
}
export interface TokenMarker extends DefaultMarker {
bootleg?: boolean
reviews?: Review[]
closed?: boolean
url?: string
}
export interface Review {
text?: string
grade?: number
}

View File

@@ -1,12 +0,0 @@
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
return { count, doubleCount, increment }
})

21
src/stores/map.ts Normal file
View File

@@ -0,0 +1,21 @@
import type { PointTuple } from 'leaflet'
import { defineStore } from 'pinia'
import { ref } from 'vue'
export const useMap = defineStore('map', () => {
const zoom = ref(7)
const minZoom = 4
const center = ref<PointTuple>([47.809376, -0.637207])
const activeLayers = ref({
tokens: false,
food: true,
})
return {
zoom,
minZoom,
center,
activeLayers
}
})

42
src/stores/parisTokens.ts Normal file
View File

@@ -0,0 +1,42 @@
import type { TokenMarker } from '@/models/Markers'
import { defineStore } from 'pinia'
export const useParisTokensStore = defineStore('paris-tokens', () => {
const markers: TokenMarker[] = [
{
coords: [48.66782350856912, -3.8571097704328814],
title: "Cairn de Barnenez"
},
{
coords: [50.40515618183852, 1.560438779852095],
title: "Berck-sur-Mer"
},
{
coords: [50.73066247214813, 1.5943634531170394],
title: "Nausicaa - Boulogne-sur-Mer"
},
{
coords: [48.11527629124499, -1.6809942217011355],
title: "Parlement de Bretagne - Rennes"
},
{
coords: [48.01889482103195, -2.1739765065268],
title: "Brocéliande, la Porte des Secrets - Paimpont"
},
{
coords: [48.12445665790851, -1.2151411880015635],
title: "Chateau de Vitré"
},
{
coords: [48.59066905927157, -2.553362074561438],
title: "Pléneuf-Val-André"
},
{
coords: [48.68378516188998, -3.9867849311824264],
title: "Saint Pol de Léon",
bootleg: true,
}
]
return { markers }
})

1494
src/stores/reviews.ts Normal file

File diff suppressed because it is too large Load Diff