diff --git a/README.md b/README.md
index 2083844..823d599 100644
--- a/README.md
+++ b/README.md
@@ -10,8 +10,14 @@ développé par tykayn - https://www.cipherbliss.com - à partir d'un squelette
Mastodon: https://mastodon.cipherbliss.com/@tykayn
# Fonctionnalités
-Affichage des stations de recharge colorées selon leur puissance maximale délivrée sur un totem.
-Changement de fond de carte.
+- Affichage des stations de recharge colorées selon leur puissance maximale délivrée sur un totem.
+- Changement de fond de carte.
+- Voir les restaurants.
+- Recherche d'un lieu.
+- Visite d'une des villes les plus peuplées de France au hasard.
+- Affichage des bornes suggérées à l'intégration par Osmose.
+- Proposition de correction dans JOSM.
+- Voir la zone dans Panoramax.
# comment ça marche ?
Avec une lib qui affiche un fond de carte sur lequel on peut naviguer et des marqueurs, on demande poliment à un site web, Overpass Turbo, quels sont les points et polygones d'OpenStreetMap correspondant à plusieurs types de restaurants et lieux où l'on peut trouver à manger et à boire à consommer sur place ou à emporter.
@@ -32,6 +38,8 @@ Gnu Affero 3+
# servir le site localement
Ouvrir la page index.html dans votre navigateur préféré, ou utiliser le paquet npm `serve`.
+Recomplilez les styles scss avec `bash styles.sh`.
+
# Requête overpass
```javascript
diff --git a/js/lcm_main.js b/js/lcm_main.js
index 73a2ba0..3a0bcf4 100644
--- a/js/lcm_main.js
+++ b/js/lcm_main.js
@@ -7,7 +7,7 @@
import lcm_config from './lcm_config.js'
import lcm_utils from './lcm_utils.js'
import lcm_color_utils from './lcm_color_utils.js'
-import {sendToJOSM, createJOSMEditLink} from './lcm_editor.js'
+import { sendToJOSM, createJOSMEditLink } from './lcm_editor.js'
let geojsondata;
let lastLatLng;
@@ -115,7 +115,7 @@ let overlays = {
stations: all_stations_markers
}
-const layerControl = L.control.layers(baseLayers, overlays, {collapsed: true}).addTo(map)
+const layerControl = L.control.layers(baseLayers, overlays, { collapsed: true }).addTo(map)
tileGrey.addTo(map)
@@ -286,17 +286,35 @@ function displayStatsFromGeoJson(resultAsGeojson) {
$('#bars_power').html(bar_powers);
}
-function bindEventsOnJosmRemote() {
- let josm_remote_buttons = $(`#sendToJOSM`)
- $(josm_remote_buttons[0]).on('click', () => {
- let josm_link = $(josm_remote_buttons[0]).attr('data-href')
- $.get(josm_link, (res) => {
- console.log('res', res)
- })
- })
+// Modifier bindEventsOnJosmRemote pour cibler les boutons dans un contexte (la popup)
+function bindEventsOnJosmRemote(popupElement) {
+ // Cible tous les liens JOSM à l'intérieur de l'élément popup fourni
+ $(popupElement).find('.edit-button.josm').each(function () {
+ // Utiliser .off().on() pour éviter les liaisons multiples si la popup est rouverte
+ $(this).off('click').on('click', (event) => {
+ event.preventDefault(); // Empêcher le comportement par défaut du lien
+ let josm_link = $(this).attr('data-href');
+ console.log('Sending command to JOSM:', josm_link);
+ // Utiliser fetch pour la requête GET vers JOSM (plus moderne que $.get)
+ fetch(josm_link)
+ .then(response => {
+ if (!response.ok) {
+ // Gérer les erreurs de communication avec JOSM
+ console.error('JOSM remote control error:', response.status, response.statusText);
+ alert('Erreur de communication avec JOSM. Assurez-vous que JOSM est lancé et que le contrôle à distance est activé.');
+ } else {
+ console.log('JOSM command sent successfully.');
+ // Optionnel: Afficher une notification de succès
+ }
+ })
+ .catch(error => {
+ console.error('Failed to send command to JOSM:', error);
+ alert('Impossible d\'envoyer la commande à JOSM. Est-il lancé et le contrôle à distance activé ?');
+ });
+ });
+ });
}
-
function displayPointsFromApi(points, convert_to_osm_json) {
if (points && convert_to_osm_json) {
geojsondata = osmtogeojson(points);
@@ -306,7 +324,7 @@ function displayPointsFromApi(points, convert_to_osm_json) {
let resultLayer = L.geoJson(geojsondata, {
style: function (feature) {
- return {color: '#f00'};
+ return { color: '#f00' };
},
filter: function (feature, layer) {
let isPolygon = (feature.geometry) && (feature.geometry.type !== undefined) && (feature.geometry.type === 'Polygon');
@@ -475,8 +493,7 @@ function eachFeature(feature, layer) {
circle_alert.on({
mouseover: function () {
this.openPopup();
- bindEventsOnJosmRemote();
- updateExternalEditorsLinks();
+ bindEventsOnJosmRemote(this.getPopup().getElement());
bindFullDetails(feature);
},
mouseout: function () {
@@ -484,8 +501,7 @@ function eachFeature(feature, layer) {
},
click: function () {
this.openPopup();
- bindEventsOnJosmRemote();
- updateExternalEditorsLinks();
+ bindEventsOnJosmRemote(this.getPopup().getElement());
bindFullDetails(feature);
},
@@ -519,7 +535,7 @@ function eachFeature(feature, layer) {
circle.on({
mouseover: function () {
this.openPopup();
- bindEventsOnJosmRemote();
+ bindEventsOnJosmRemote(this.getPopup().getElement());
bindFullDetails(feature);
},
mouseout: function () {
@@ -527,7 +543,7 @@ function eachFeature(feature, layer) {
},
click: function () {
this.openPopup();
- bindEventsOnJosmRemote();
+ bindEventsOnJosmRemote(this.getPopup().getElement());
bindFullDetails(feature);
},
});
@@ -543,12 +559,12 @@ function bindFullDetails(feature) {
let content = '
' +
'' + ''
- let ii=0
+ let ii = 0
let keys = Object.keys(feature.properties.tags)
- keys.forEach( (elem, val) => {
- console.log('elem, val', elem, val)
- content += ''+elem+' '+feature.properties.tags[elem]+' ';
- ii++;
+ keys.forEach((elem, val) => {
+ console.log('elem, val', elem, val)
+ content += '' + elem + ' ' + feature.properties.tags[elem] + ' ';
+ ii++;
})
content += ' ' +
'
'
@@ -660,6 +676,16 @@ function onMapMoveEnd() {
}
}
+ // Ajout d'un log pour déboguer
+ console.log("Zoom actuel:", map.getZoom());
+
+ if (map.getZoom() > 12) {
+ console.log("Recherche des issues Osmose...");
+ searchOsmoseIssues(map);
+ } else {
+ console.log("Zoom trop faible pour les issues Osmose");
+ osmose_markers.clearLayers();
+ }
}
setCoordinatesOfLeafletMapFromQueryParameters()
@@ -784,12 +810,10 @@ function searchFoodPlaces(map) {
const query = `
[out:json][timeout:25];
(
- node["amenity"="restaurant"](${bbox});
- node["amenity"="cafe"](${bbox});
+ nwr["amenity"="restaurant"](${bbox});
+ nwr["amenity"="cafe"](${bbox});
);
- out body;
- >;
- out skel qt;`;
+ out center;`;
const url = `https://overpass-api.de/api/interpreter?data=${encodeURIComponent(query)}`;
@@ -798,21 +822,21 @@ function searchFoodPlaces(map) {
fetch(url)
.then(response => response.json())
.then(data => {
- const geojson = osmtogeojson(data);
- geojson.features.forEach(feature => {
- const coords = feature.geometry.coordinates;
- const properties = feature.properties;
- const name = properties.tags.name || 'Sans nom';
- const type = properties.tags.amenity;
+ data.elements.forEach(element => {
+ // Utiliser les coordonnées du centre pour les ways et relations
+ const lat = element.lat || element.center.lat;
+ const lon = element.lon || element.center.lon;
+ const name = element.tags.name || 'Sans nom';
+ const type = element.tags.amenity;
- const marker = L.marker([coords[1], coords[0]], {
+ const marker = L.marker([lat, lon], {
icon: foodIcon
});
marker.bindPopup(`
${name}
Type: ${type}
- ${properties.tags.cuisine ? 'Cuisine: ' + properties.tags.cuisine : ''}
+ ${element.tags.cuisine ? 'Cuisine: ' + element.tags.cuisine : ''}
`);
food_places_markers.addLayer(marker);
@@ -821,16 +845,150 @@ function searchFoodPlaces(map) {
.catch(error => console.error('Erreur lors de la recherche des restaurants:', error));
}
-// Modifier la fonction init pour ajouter le contrôle des couches
+// Ajouter après la déclaration des autres variables globales
+let osmose_markers = L.layerGroup();
+const osmoseIcon = L.divIcon({
+ className: 'osmose-marker-drop',
+ html: '⚡
',
+ iconSize: [30, 40],
+ iconAnchor: [15, 40]
+});
+
+// Ajouter cette nouvelle fonction
+function searchOsmoseIssues(map) {
+ const bounds = map.getBounds();
+ const zoom = map.getZoom();
+ // Construction de la bbox avec l'ordre correct : ouest,sud,est,nord
+ const bbox = `${bounds.getWest()}%2C${bounds.getSouth()}%2C${bounds.getEast()}%2C${bounds.getNorth()}`;
+
+ // URL formatée selon l'exemple fourni
+ const url = `https://osmose.openstreetmap.fr/api/0.3/issues?zoom=${zoom}&item=8410%2C8411&level=1%2C2%2C3&limit=500&bbox=${bbox}`;
+
+ console.log("Recherche des issues Osmose (liste) avec l'URL :", url);
+ osmose_markers.clearLayers();
+
+ fetch(url)
+ .then(response => {
+ if (!response.ok) {
+ return response.text().then(text => { throw new Error(`Erreur HTTP ${response.status}: ${response.statusText}. Réponse : ${text}`); });
+ }
+ return response.json();
+ })
+ .then(data => {
+ if (!data || !Array.isArray(data.issues)) {
+ console.warn("Réponse Osmose (liste) inattendue ou pas d'issues:", data);
+ return;
+ }
+ const issuesList = data.issues;
+ console.log(`Nombre d'issues Osmose (liste) trouvées: ${issuesList.length}`);
+
+ issuesList.forEach(issueInfo => {
+ // Vérifier si les coordonnées sont valides
+ if (issueInfo.lat == null || issueInfo.lon == null) {
+ console.warn("Issue Osmose sans coordonnées ignorée:", issueInfo);
+ return; // Ignorer cette issue
+ }
+
+ const lat = parseFloat(issueInfo.lat);
+ const lon = parseFloat(issueInfo.lon);
+ const issueId = issueInfo.id; // C'est l'UUID
+
+ // Vérifier si l'UUID est valide
+ if (!issueId) {
+ console.warn("Issue Osmose sans ID (UUID) ignorée:", issueInfo);
+ return;
+ }
+
+ const osmoseMarker = L.circle([lat, lon], {
+ color: "purple",
+ fillColor: "purple",
+ fillOpacity: 0.8,
+ radius: 10,
+ className: 'leaflet-osmose-layer',
+ pane: 'markerPane',
+ issueId: issueId
+ });
+
+ // Préparer une popup de chargement simple
+ osmoseMarker.bindPopup("Chargement des détails...");
+
+ osmoseMarker.on('click', function (e) {
+ const clickedMarker = e.target;
+ const storedIssueId = clickedMarker.options.issueId;
+
+ // Afficher immédiatement la popup de chargement
+ clickedMarker.openPopup();
+
+ const detailUrl = `https://osmose.openstreetmap.fr/api/0.3/issue/${storedIssueId}?langs=auto`;
+ console.log("Récupération des détails pour l'issue:", detailUrl);
+
+ fetch(detailUrl)
+ .then(response => {
+ if (!response.ok) {
+ return response.text().then(text => { throw new Error(`Erreur HTTP ${response.status}: ${response.statusText}. Réponse : ${text}`); });
+ }
+ return response.json();
+ })
+ .then(issueDetails => {
+ // Construire le contenu de la popup avec les détails
+ let popupContent = `${issueDetails.title?.auto || 'Titre non disponible'} `;
+ if (issueDetails.subtitle?.auto) {
+ popupContent += `${issueDetails.subtitle.auto}
`;
+ }
+
+ let proposedTags = '';
+ if (issueDetails.new_elems && issueDetails.new_elems[0] && issueDetails.new_elems[0].add) {
+ proposedTags = '';
+ popupContent += `
Tags proposés : ${proposedTags}`;
+ }
+
+ // Construire le lien JOSM /import
+ const josmFixUrl = `http://localhost:8111/import?url=https://osmose.openstreetmap.fr/api/0.3/issue/${storedIssueId}/fix/0`;
+
+ popupContent += `
+ `;
+
+ // Mettre à jour le contenu de la popup et s'assurer qu'elle est ouverte
+ clickedMarker.setPopupContent(popupContent);
+ clickedMarker.openPopup(); // Rouvrir pour ajuster la taille si nécessaire
+
+ // Lier l'événement au bouton JOSM DANS la popup
+ bindEventsOnJosmRemote(clickedMarker.getPopup().getElement());
+
+ })
+ .catch(error => {
+ console.error("Erreur lors de la récupération des détails de l'issue Osmose:", error);
+ clickedMarker.setPopupContent(`Erreur lors du chargement des détails.Voir sur Osmose `);
+ clickedMarker.openPopup();
+ });
+ });
+
+ osmose_markers.addLayer(osmoseMarker);
+ });
+ })
+ .catch(error => {
+ console.error('Erreur détaillée lors de la recherche de la liste des issues Osmose:', error);
+ });
+}
+
+// Modifier la fonction init pour ajouter le nouveau calque
function init() {
food_places_markers.addTo(map);
$('#found_charging_stations').hide();
- // Ajouter le contrôle des couches
+ // Mettre à jour le contrôle des calques
const overlayMaps = {
"Stations de recharge": all_stations_markers,
- "Restaurants et cafés": food_places_markers
+ "Restaurants et cafés": food_places_markers,
+ "Bornes potentielles (Osmose)": osmose_markers
};
L.control.layers(null, overlayMaps).addTo(map);
@@ -851,23 +1009,25 @@ function init() {
console.log('Données envoyées à JOSM avec succès !');
})
.catch(() => {
- alert('Erreur : JOSM doit être ouvert avec l\'option "Contrôle à distance" activée');
+ alert('Erreur : JOSM doit être ouvert avec l\'option de télécommande "Contrôle à distance" activée dans ses paramètres (accédez-y avec F12)');
});
});
$('#searchButton').on('click', searchLocation);
$('#shareUrl').on('click', copyCurrentUrl);
-
-
- $('#searchResults').on('change', function() {
+
+
+ $('#searchResults').on('change', function () {
const selectedIndex = $(this).val();
if (selectedIndex !== null) {
const selectedPlace = $(this).find('option:selected').data('place');
moveToLocation(selectedPlace);
}
});
-
+
document.getElementById('searchButton').addEventListener('click', searchLocation);
+
+ osmose_markers.addTo(map);
}
@@ -882,52 +1042,56 @@ function copyCurrentUrl() {
document.execCommand('copy');
document.body.removeChild(dummy);
}
-
-
- function searchLocation() {
- const location = $('#searchLocation').val();
- if (!location) {
- alert('Veuillez entrer un lieu à rechercher.');
- return;
- }
-
- const url = `https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(location)}`;
-
- fetch(url)
- .then(response => response.json())
- .then(data => {
- const resultsDropdown = $('#searchResults');
- resultsDropdown.empty(); // Clear previous results
-
- if (data.length === 0) {
- alert('Lieu non trouvé. Veuillez essayer un autre terme de recherche.');
- resultsDropdown.hide();
- } else if (data.length === 1) {
- const place = data[0];
- moveToLocation(place);
- resultsDropdown.hide();
- } else {
- data.forEach((place, index) => {
- const option = $(' ')
- .val(index)
- .text(`${place.display_name} (${place.lat}, ${place.lon})`);
- resultsDropdown.append(option);
- });
- resultsDropdown.show();
- }
- })
- .catch(error => {
- console.error('Erreur lors de la recherche du lieu :', error);
- alert('Erreur lors de la recherche du lieu.');
- });
- }
-
- function moveToLocation(place) {
- const lat = parseFloat(place.lat);
- const lon = parseFloat(place.lon);
- map.setView([lat, lon], 13); // Ajustez le niveau de zoom selon vos besoins
- }
-
- init()
\ No newline at end of file
+
+function searchLocation() {
+ const location = $('#searchLocation').val();
+ if (!location) {
+ alert('Veuillez entrer un lieu à rechercher.');
+ return;
+ }
+
+ const url = `https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(location)}`;
+
+ fetch(url)
+ .then(response => response.json())
+ .then(data => {
+ const resultsDropdown = $('#searchResults');
+ resultsDropdown.empty(); // Clear previous results
+
+ if (data.length === 0) {
+ alert('Lieu non trouvé. Veuillez essayer un autre terme de recherche.');
+ resultsDropdown.hide();
+ } else if (data.length === 1) {
+ const place = data[0];
+ moveToLocation(place);
+ resultsDropdown.hide();
+ } else {
+ data.forEach((place, index) => {
+ const option = $(' ')
+ .val(index)
+ .text(`${place.display_name} (${place.lat}, ${place.lon})`);
+ resultsDropdown.append(option);
+ });
+ resultsDropdown.show();
+ }
+ })
+ .catch(error => {
+ console.error('Erreur lors de la recherche du lieu :', error);
+ alert('Erreur lors de la recherche du lieu.');
+ });
+}
+
+function moveToLocation(place) {
+ const lat = parseFloat(place.lat);
+ const lon = parseFloat(place.lon);
+ map.setView([lat, lon], 13); // Ajustez le niveau de zoom selon vos besoins
+}
+
+
+init()
+
+// Créer un nouveau pane pour les marqueurs Osmose avec un zIndex plus élevé
+map.createPane('osmosePane');
+map.getPane('osmosePane').style.zIndex = 1000;
\ No newline at end of file
diff --git a/js/lcm_utils.js b/js/lcm_utils.js
index a02fd53..e2f1405 100644
--- a/js/lcm_utils.js
+++ b/js/lcm_utils.js
@@ -31,7 +31,7 @@ const lcm_utils = {
if (value && tag.toLowerCase().indexOf('output') !== -1) {
value = '' + value
if (value.indexOf(';') !== -1) {
- console.log('value output multiple', value)
+ // console.log('value output multiple', value)
let explode = value.split(';')
explode.forEach(elem => {
if (value.replace) {
@@ -56,7 +56,7 @@ const lcm_utils = {
}
}
}
-
+
feature.properties.outputPower = outputPower
return outputPower
},
@@ -65,26 +65,26 @@ const lcm_utils = {
* villes les plus peuplées de France
*/
cities: [
- {name: 'Paris', coords: [48.8566, 2.3522]},
- {name: 'Marseille', coords: [43.2965, 5.3698]},
- {name: 'Lyon', coords: [45.7640, 4.8357]},
- {name: 'Toulouse', coords: [43.6042, 1.4437]},
- {name: 'Nice', coords: [43.7101, 7.2620]},
- {name: 'Nantes', coords: [47.2184, -1.5536]},
- {name: 'Strasbourg', coords: [48.5831, 7.7521]},
- {name: 'Montpellier', coords: [43.6167, 3.8742]},
- {name: 'Bordeaux', coords: [44.8378, -0.5792]},
- {name: 'Lille', coords: [50.6293, 3.1466]},
- {name: 'Rennes', coords: [48.1120, -1.6823]},
- {name: 'Toulon', coords: [43.1230, 5.9291]},
- {name: 'Le Havre', coords: [49.4943, 0.1079]},
- {name: 'Saint-Etienne', coords: [45.4380, 4.3841]},
- {name: 'Grenoble', coords: [45.1667, 5.7295]},
- {name: 'Rouen', coords: [49.4431, 1.0820]},
- {name: 'Dijon', coords: [47.3221, 5.0446]},
- {name: 'Angers', coords: [47.4786, -0.5551]},
- {name: 'Nîmes', coords: [43.8366, 4.3623]},
- {name: 'Reims', coords: [49.2500, 4.0333]}
+ { name: 'Paris', coords: [48.8566, 2.3522] },
+ { name: 'Marseille', coords: [43.2965, 5.3698] },
+ { name: 'Lyon', coords: [45.7640, 4.8357] },
+ { name: 'Toulouse', coords: [43.6042, 1.4437] },
+ { name: 'Nice', coords: [43.7101, 7.2620] },
+ { name: 'Nantes', coords: [47.2184, -1.5536] },
+ { name: 'Strasbourg', coords: [48.5831, 7.7521] },
+ { name: 'Montpellier', coords: [43.6167, 3.8742] },
+ { name: 'Bordeaux', coords: [44.8378, -0.5792] },
+ { name: 'Lille', coords: [50.6293, 3.1466] },
+ { name: 'Rennes', coords: [48.1120, -1.6823] },
+ { name: 'Toulon', coords: [43.1230, 5.9291] },
+ { name: 'Le Havre', coords: [49.4943, 0.1079] },
+ { name: 'Saint-Etienne', coords: [45.4380, 4.3841] },
+ { name: 'Grenoble', coords: [45.1667, 5.7295] },
+ { name: 'Rouen', coords: [49.4431, 1.0820] },
+ { name: 'Dijon', coords: [47.3221, 5.0446] },
+ { name: 'Angers', coords: [47.4786, -0.5551] },
+ { name: 'Nîmes', coords: [43.8366, 4.3623] },
+ { name: 'Reims', coords: [49.2500, 4.0333] }
]
}
export default lcm_utils
diff --git a/styles.sh b/styles.sh
index b9a8291..ab88157 100644
--- a/styles.sh
+++ b/styles.sh
@@ -1,3 +1,3 @@
#!/bin/bash
-sass styles/main.scss styles/style.css
\ No newline at end of file
+sass styles/main.scss styles/style.css --style compressed
diff --git a/styles/main.css b/styles/main.css
new file mode 100644
index 0000000..5d8a4fa
--- /dev/null
+++ b/styles/main.css
@@ -0,0 +1,8 @@
+.leaflet-osmose-layer {
+ z-index: 1000 !important;
+}
+
+.leaflet-marker-icon.osmose-marker-drop,
+.leaflet-marker-shadow.osmose-marker-drop {
+ z-index: 1000 !important;
+}
\ No newline at end of file
diff --git a/styles/main.scss b/styles/main.scss
index 3bc8e5a..3d04209 100644
--- a/styles/main.scss
+++ b/styles/main.scss
@@ -130,7 +130,10 @@ img.leaflet-marker-icon.tag-socket\:type2_yes {
border-width: 3px;
}
-.rounded-button, .navigation-link, .panoramax-link, .edit-button {
+.rounded-button,
+.navigation-link,
+.panoramax-link,
+.edit-button {
background: var(--button-background);
padding: 0.5em 1em;
border-radius: 2em;
@@ -318,23 +321,28 @@ marqueurs
background: #36423d;
}
-.color-power-lesser-than-50, .map-marker-circle-demo.color-2 {
+.color-power-lesser-than-50,
+.map-marker-circle-demo.color-2 {
background: #4e8a8d;
}
-.color-power-lesser-than-100, .map-marker-circle-demo.color-3 {
+.color-power-lesser-than-100,
+.map-marker-circle-demo.color-3 {
background: #2999b3;
}
-.color-power-lesser-than-200, .map-marker-circle-demo.color-4 {
+.color-power-lesser-than-200,
+.map-marker-circle-demo.color-4 {
background: #1782dd;
}
-.color-power-lesser-than-300, .map-marker-circle-demo.color-5 {
+.color-power-lesser-than-300,
+.map-marker-circle-demo.color-5 {
background: #2900ff;
}
-.color-power-lesser-than-max, .map-marker-circle-demo.color-6 {
+.color-power-lesser-than-max,
+.map-marker-circle-demo.color-6 {
background: #8000ff;
}
@@ -393,7 +401,7 @@ button {
padding: 1rem 0;
}
-button + button {
+button+button {
margin-left: 1rem;
}
@@ -612,6 +620,119 @@ header {
}
}
+.leaflet-popup-content {
+ max-height: 400px;
+ overflow: auto;
+}
+
+.osmose-marker {
+ font-size: 20px;
+ text-align: center;
+ line-height: 20px;
+ background-color: rgba(255, 255, 255, 0.8);
+ border-radius: 50%;
+ border: 2px solid #ff6b6b;
+}
+
+.osmose-marker-drop {
+ position: relative;
+ z-index: 1000;
+}
+
+.osmose-marker-inner {
+ position: absolute;
+ width: 30px;
+ height: 40px;
+ background-color: #8B00FF;
+ border-radius: 50% 50% 50% 0;
+ transform: rotate(-45deg);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
+ border: 2px solid white;
+
+ &::before {
+ content: '⚡';
+ transform: rotate(45deg);
+ color: white;
+ font-size: 16px;
+ text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3);
+ padding-left: 1ch;
+ }
+}
+
+/* Animation au survol plus visible */
+
+.osmose-marker-drop:hover .osmose-marker-inner {
+ animation: bounce 0.5s ease infinite;
+ background-color: #9F2BFF;
+}
+
+.proposed-tags-container {
+ max-height: 200px;
+ overflow-y: auto;
+ margin: 10px 0;
+ padding: 5px;
+ background-color: #f5f5f5;
+ border-radius: 4px;
+}
+
+.proposed-tags {
+ width: 100%;
+ border-collapse: collapse;
+}
+
+.proposed-tags tr:nth-child(even) {
+ background-color: #ffffff;
+}
+
+.proposed-tags td {
+ padding: 2px 5px;
+ font-size: 12px;
+}
+
+.proposed-tags td:first-child {
+ font-weight: bold;
+ color: #666;
+}
+
+.action-buttons {
+ margin-top: 10px;
+ display: flex;
+ flex-direction: column;
+ gap: 5px;
+}
+
+.action-buttons a {
+ padding: 5px 10px;
+ text-decoration: none;
+ border-radius: 4px;
+ text-align: center;
+}
+
+.action-buttons .edit-button.josm {
+ background-color: #4CAF50;
+ color: white;
+}
+
+.action-buttons a:hover {
+ opacity: 0.9;
+}
+
+
+@keyframes bounce {
+
+ 0%,
+ 100% {
+ transform: rotate(-45deg) translateY(0);
+ }
+
+ 50% {
+ transform: rotate(-45deg) translateY(-5px);
+ }
+}
+
/**
overrides leaflet
*/
@@ -648,7 +769,8 @@ overrides leaflet
transform: none;
}
- .side-panel-open #map, #map {
+ .side-panel-open #map,
+ #map {
margin: 0;
left: 0;
top: 0;
@@ -691,4 +813,4 @@ overrides leaflet
100% {
border-left-color: #ff0000;
}
-}
+}
\ No newline at end of file
diff --git a/styles/style.css b/styles/style.css
index 8fab8a1..c3acfdb 100644
--- a/styles/style.css
+++ b/styles/style.css
@@ -1,643 +1 @@
-:root {
- --background-color: #222;
- --text-color: #ddd;
- --icon-background: white;
- --icon-border: cornflowerblue;
- --button-background: #497cd3;
- --button-hover-background: #0d377b;
- --button-border: #497cd3ff;
- --link-color: #38f;
- --popup-background: white;
- --zoom-message-background: rgba(255, 255, 255, 0.9);
- --zoom-message-border: #ff0000;
- --color-indication-background: #c0b1b1;
- --no-data-border: dodgerblue;
- --no-data-link-color: dodgerblue;
- --food-marker-color: #fff;
-}
-
-* {
- box-sizing: border-box;
-}
-
-html {
- height: 100%;
- width: 100%;
- background: var(--background-color);
- padding: 0;
- margin: 0;
-}
-
-body {
- height: 100%;
- width: 100%;
- background: var(--background-color);
- padding: 0;
- margin: 0;
- padding: 0;
- margin: 0;
-}
-
-html {
- font-family: Calibri, Roboto, Arial, "Ubuntu Mono";
- font-size: 1rem;
-}
-
-p {
- font-family: Calibri, Roboto, Arial, "Ubuntu Mono";
- font-size: 1rem;
- font-size: 1rem;
-}
-
-#map {
- height: 95vh;
- width: 100%;
- margin: 0;
- border: solid 2px;
-}
-
-.padded {
- padding: 1rem;
-}
-
-#heading {
- background: #000;
- color: var(--text-color);
- min-height: 5%;
- height: 4rem;
- width: 100%;
- padding-left: 1em;
-}
-
-.icon {
- width: 0.25rem !important;
- height: 0.25rem !important;
- display: inline-block;
- margin-right: 1rem;
- background: var(--icon-background);
- border-radius: 100%;
- padding: 0.25rem;
- margin-top: -0.5rem;
- float: left;
- border-color: var(--icon-border);
-}
-
-.title {
- margin-right: 1em;
- line-height: 1.5rem;
-}
-
-h2 {
- font-weight: normal;
-}
-
-#overpass-api-controls {
- position: fixed;
- top: -0.5rem;
- left: 4em;
- padding: 10px;
- background-color: transparent;
- border: 0;
- z-index: 10;
-}
-#overpass-api-controls a {
- display: inline;
-}
-
-.has_output_of_irve_specified {
- box-shadow: 0 0 15rem darkred;
-}
-
-img.leaflet-marker-icon.tag-socket\:type2_yes {
- box-shadow: 0 0 0.5em cornflowerblue;
- border-color: cornflowerblue;
- border-width: 3px;
-}
-
-.rounded-button, .navigation-link, .panoramax-link, .edit-button {
- background: var(--button-background);
- padding: 0.5em 1em;
- border-radius: 2em;
- color: white !important;
- border: solid 1px var(--button-border);
- float: right;
-}
-
-.panoramax-link {
- top: 7rem;
- position: absolute;
- right: 1rem;
-}
-.panoramax-link img {
- width: 1rem;
- height: 1rem;
-}
-
-.side-panel button {
- min-width: 15em;
- margin-bottom: 0.5em;
-}
-
-.navigation-link {
- background: white;
- border-radius: 0.25em;
- float: none;
- position: relative;
- top: 5em;
- right: -7.9rem;
-}
-.navigation-link:hover {
- border: black;
- background: #96b1ea;
-}
-
-button:hover {
- background: var(--button-hover-background);
- border: solid 1px #08285c;
- cursor: pointer;
-}
-
-.edit-button {
- margin-left: 1ch;
-}
-.edit-button:hover {
- background: var(--button-hover-background);
- border: solid 1px #08285c;
- cursor: pointer;
-}
-
-.pull-left {
- float: left;
-}
-
-@keyframes spin {
- 0% {
- transform: rotate(0deg);
- }
- 100% {
- transform: rotate(359deg);
- }
-}
-a {
- color: var(--link-color);
-}
-
-.leaflet-control-custom {
- padding: 1rem;
- background: var(--popup-background);
-}
-
-#spinning_icon {
- position: fixed;
- top: 0;
- left: 0;
- z-index: 10;
- background: white;
- font-size: 2rem;
-}
-#spinning_icon svg {
- position: fixed;
- top: 0.5rem;
- right: 3rem;
- background: white;
- border-radius: 100%;
- width: 3rem;
- height: 3rem;
- animation: spin 2s linear infinite;
-}
-
-#footer {
- max-width: 70ch;
- margin: 0 auto;
-}
-
-.leaflet-popup-content {
- min-width: 15rem;
- word-break: break-all;
- word-wrap: break-word;
-}
-
-.popup-content {
- width: 100%;
- display: block;
- overflow: auto;
- min-width: 10rem;
- max-width: 20rem;
- min-height: 5rem;
- max-height: 10rem;
-}
-
-.popup-key {
- width: 50%;
- display: inline-block;
-}
-
-.popup-value {
- width: 42%;
- text-align: right;
- display: inline-block;
- padding-right: 1rem;
-}
-
-.bottom-content {
- padding: 0 2rem 4rem;
-}
-
-#star {
- left: 10rem;
-}
-
-.color-indication {
- padding: 1rem;
- border-radius: 2rem;
- display: block;
- position: relative;
- top: -2rem;
- color: white;
- text-shadow: 0 0 0.5rem #222;
- clear: right;
- min-width: 7rem;
- max-width: 5rem;
- height: 3rem;
-}
-
-.no-data {
- border-left: 3px solid var(--no-data-border);
- padding: 1em 2rem;
- min-height: 4rem;
-}
-.no-data a {
- color: var(--no-data-link-color);
-}
-
-/**
-marqueurs
- */
-.marker-demo {
- margin-right: 1rem;
-}
-
-.map-marker-circle-demo {
- border-radius: 100%;
- display: inline-block;
- width: 1rem;
- height: 1rem;
- background: #fff;
-}
-
-.color-unknown {
- background: var(--color-indication-background);
-}
-
-.map-marker-circle-demo.color-1 {
- background: #36423d;
-}
-
-.color-power-lesser-than-50, .map-marker-circle-demo.color-2 {
- background: #4e8a8d;
-}
-
-.color-power-lesser-than-100, .map-marker-circle-demo.color-3 {
- background: #2999b3;
-}
-
-.color-power-lesser-than-200, .map-marker-circle-demo.color-4 {
- background: #1782dd;
-}
-
-.color-power-lesser-than-300, .map-marker-circle-demo.color-5 {
- background: #2900ff;
-}
-
-.color-power-lesser-than-max, .map-marker-circle-demo.color-6 {
- background: #8000ff;
-}
-
-#found_charging_stations {
- margin-top: 2rem;
-}
-
-button {
- cursor: pointer;
- padding: 0.5rem;
- background: white;
-}
-
-#bars_power {
- margin: 1rem 0;
- height: 3rem;
-}
-
-.bar {
- height: 2em;
- text-align: right;
- padding: 0.35rem 0.25rem 0.35rem 0.35rem;
- float: left;
-}
-
-.key-values {
- max-height: 4rem;
- overflow: auto;
- width: 100%;
- display: block;
-}
-
-.icon-img {
- width: 3rem;
- height: 3rem;
- fill: #000;
-}
-
-.sockets-list {
- margin-top: 0.25rem;
-}
-
-.socket-counter {
- background: #dedede;
- margin-top: 1rem;
- margin-left: -0.25rem;
- border-radius: 1rem;
- padding: 0.25rem;
-}
-
-.leaflet-interactive {
- border: solid 3px white;
-}
-
-#infos_carte {
- padding: 1rem 0;
-}
-
-button + button {
- margin-left: 1rem;
-}
-
-.filter-group button {
- padding: 1rem 2rem;
- border-radius: 0.25rem;
-}
-.filter-group button:after {
- position: relative;
- float: right;
- left: 1rem;
- top: 1rem;
- font-size: 0.9em;
-}
-.filter-group button.filter-state-hide:after {
- content: "cacher";
- color: grey;
-}
-.filter-group button.filter-state-show:after {
- content: "montrer";
- color: green;
-}
-.filter-group button.filter-state-showOnly:after {
- content: "montrer uniquement";
- color: orange;
-}
-.filter-group button.filter-state-hide {
- background: #fff;
-}
-.filter-group button.filter-state-show {
- color: green;
-}
-.filter-group button.filter-state-showOnly {
- color: orange;
-}
-
-.leaflet-control-layers-toggle {
- background-size: contain;
-}
-
-#round_power_legend {
- font-size: 0.8rem;
-}
-
-.side-panel {
- font-size: 1rem;
- position: fixed;
- left: 0;
- top: 0;
- width: 20vw;
- height: 74vh;
- background: white;
- box-shadow: -2px 0 5px rgba(0, 0, 0, 0.2);
- overflow-y: auto;
- padding: 1rem 2rem;
- padding-bottom: 15rem;
- z-index: 1000;
- visibility: hidden;
- top: 5.7rem;
- width: 26vw;
-}
-
-#toggleSidePanel {
- position: fixed;
- top: 1rem;
- right: 2rem;
- z-index: 10;
- background: white;
- padding: 1rem 2rem;
- border-radius: 8px;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
-}
-
-header {
- padding-left: 2rem;
- color: #666;
-}
-
-.side-panel-open .side-panel {
- visibility: visible;
- width: 29vw;
- border-right: #ccc solid 1px;
- height: 93vh;
-}
-.side-panel-open #map {
- margin-left: 28.8vw;
- top: 5.55rem;
- width: 71.2vw;
-}
-
-#infos_carte {
- clear: both;
-}
-
-#zoomMessage {
- position: fixed;
- bottom: 5rem;
- left: 50%;
- transform: translateX(-50%);
- background: var(--zoom-message-background);
- padding: 1rem 2rem;
- border-radius: 8px;
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
- text-align: center;
- z-index: 10;
- border-left: 4px solid var(--zoom-message-border);
- animation: rainbow-border 4s linear infinite;
-}
-
-header {
- background: #222;
- position: fixed;
- width: 20vw;
-}
-header h1 {
- width: 100vw;
- line-height: 3rem;
-}
-header img {
- float: left;
- margin-right: 1rem;
-}
-
-#map {
- z-index: 1;
- top: 5.55rem;
-}
-
-.side-panel #map {
- margin-left: 26vw;
-}
-
-.rounded-button {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- font-size: 1rem;
- cursor: pointer;
- transition: background-color 0.3s;
-}
-.rounded-button:hover {
- background-color: #0d377b;
-}
-
-.search-input {
- width: 100%;
- padding: 10px;
- margin-bottom: 10px;
- border: 1px solid var(--button-border);
- border-radius: 5px;
-}
-
-#count_features_fond {
- position: fixed;
- bottom: 1rem;
- right: 1rem;
- z-index: 10;
- background: white;
- padding: 1rem;
- border-radius: 8px;
-}
-
-#removeMarkers {
- margin-right: 1rem;
-}
-
-.filters-box {
- margin-top: 4rem;
- height: 10rem;
- width: auto;
-}
-.filters-box .rounded-button {
- margin-right: 1rem;
- margin-bottom: 1rem;
-}
-
-#searchButton {
- margin-right: 1rem;
-}
-
-.info .i {
- border-radius: 100%;
- background: #dedede;
- padding: 1ch;
- width: 5ch;
- margin-left: 1ch;
- display: inline-block;
- text-align: center;
-}
-.info .tooltip {
- opacity: 0;
-}
-.info:hover .tooltip {
- opacity: 1;
- transition: opacity 0.3s ease-in-out;
-}
-
-/**
-overrides leaflet
- */
-.leaflet-left .leaflet-control {
- margin-left: 2rem;
-}
-
-/* Style pour mobile */
-@media (max-width: 1200px) {
- header h1 {
- width: 100vw;
- font-size: 1.5rem;
- }
- #toggleSidePanel {
- right: 1rem;
- top: 1.3rem;
- }
- body {
- /* border: solid 3px blue; */
- }
- .side-panel-open .side-panel {
- position: static;
- transform: none;
- box-shadow: 0 -2px 5px rgba(0, 0, 0, 0.2);
- margin: 20px 0 0;
- width: 100vw;
- }
- .side-panel.active {
- transform: none;
- }
- .side-panel-open #map, #map {
- margin: 0;
- left: 0;
- top: 0;
- width: 100vw;
- height: 90vh;
- height: 55vh;
- }
- header {
- position: static;
- }
-}
-@keyframes rainbow-border {
- 0% {
- border-left-color: #ff0000;
- }
- 17% {
- border-left-color: #ff8000;
- }
- 33% {
- border-left-color: #ffff00;
- }
- 50% {
- border-left-color: #00ff00;
- }
- 67% {
- border-left-color: #0000ff;
- }
- 83% {
- border-left-color: #8000ff;
- }
- 100% {
- border-left-color: #ff0000;
- }
-}
-
-.search-results {
- width: calc(100% - 40px);
- margin-top: 10px;
- border: 1px solid var(--button-border);
- border-radius: 5px;
- display: none;
-}
-
-/*# sourceMappingURL=style.css.map */
+:root{--background-color: #222;--text-color: #ddd;--icon-background: white;--icon-border: cornflowerblue;--button-background: #497cd3;--button-hover-background: #0d377b;--button-border: #497cd3ff;--link-color: #38f;--popup-background: white;--zoom-message-background: rgba(255, 255, 255, 0.9);--zoom-message-border: #ff0000;--color-indication-background: #c0b1b1;--no-data-border: dodgerblue;--no-data-link-color: dodgerblue;--food-marker-color: #fff}*{box-sizing:border-box}html{height:100%;width:100%;background:var(--background-color);padding:0;margin:0}body{height:100%;width:100%;background:var(--background-color);padding:0;margin:0;padding:0;margin:0}html{font-family:Calibri,Roboto,Arial,"Ubuntu Mono";font-size:1rem}p{font-family:Calibri,Roboto,Arial,"Ubuntu Mono";font-size:1rem;font-size:1rem}#map{height:95vh;width:100%;margin:0;border:solid 2px}table tr td{border-bottom:#ccc 1px solid}table tr:nth-of-type(odd){background:#dedede}.padded{padding:1rem}#heading{background:#000;color:var(--text-color);min-height:5%;height:4rem;width:100%;padding-left:1em}.icon{width:.25rem !important;height:.25rem !important;display:inline-block;margin-right:1rem;background:var(--icon-background);border-radius:100%;padding:.25rem;margin-top:-0.5rem;float:left;border-color:var(--icon-border)}.title{margin-right:1em;line-height:1.5rem}h2{font-weight:normal}#overpass-api-controls{position:fixed;top:-0.5rem;left:4em;padding:10px;background-color:rgba(0,0,0,0);border:0;z-index:10}#overpass-api-controls a{display:inline}.has_output_of_irve_specified{box-shadow:0 0 15rem darkred}img.leaflet-marker-icon.tag-socket\:type2_yes{box-shadow:0 0 .5em #6495ed;border-color:#6495ed;border-width:3px}.rounded-button,.navigation-link,.panoramax-link,.edit-button{background:var(--button-background);padding:.5em 1em;border-radius:2em;color:#fff !important;border:solid 1px var(--button-border);float:right}.panoramax-link{top:7rem;position:absolute;right:1rem}.panoramax-link img{width:1rem;height:1rem}.side-panel button{min-width:15em;margin-bottom:.5em}.navigation-link{background:#fff;border-radius:.25em;float:none;position:relative;top:5em;right:-7.9rem}.navigation-link:hover{border:#000;background:#96b1ea}button:hover{background:var(--button-hover-background);border:solid 1px #08285c;cursor:pointer}.edit-button{margin-left:1ch}.edit-button:hover{background:var(--button-hover-background);border:solid 1px #08285c;cursor:pointer}.pull-left{float:left}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(359deg)}}a{color:var(--link-color)}.leaflet-control-custom{padding:1rem;background:var(--popup-background)}#spinning_icon{position:fixed;top:0;left:0;z-index:10;background:#fff;font-size:2rem}#spinning_icon svg{position:fixed;top:.5rem;right:3rem;background:#fff;border-radius:100%;width:3rem;height:3rem;animation:spin 2s linear infinite}#footer{max-width:70ch;margin:0 auto}.leaflet-popup-content{min-width:15rem;word-break:break-all;word-wrap:break-word}.popup-content{width:100%;display:block;overflow:auto;min-width:10rem;max-width:20rem;min-height:5rem;max-height:10rem}.popup-key{width:50%;display:inline-block}.popup-value{width:42%;text-align:right;display:inline-block;padding-right:1rem}.bottom-content{padding:0 2rem 4rem}#star{left:10rem}.color-indication{padding:1rem;border-radius:2rem;display:block;position:relative;top:-2rem;color:#fff;text-shadow:0 0 .5rem #222;clear:right;min-width:7rem;max-width:5rem;height:3rem}.no-data{border-left:3px solid var(--no-data-border);padding:1em 2rem;min-height:4rem}.no-data a{color:var(--no-data-link-color)}.marker-demo{margin-right:1rem}.map-marker-circle-demo{border-radius:100%;display:inline-block;width:1rem;height:1rem;background:#fff}.color-unknown{background:var(--color-indication-background)}.map-marker-circle-demo.color-1{background:#36423d}.color-power-lesser-than-50,.map-marker-circle-demo.color-2{background:#4e8a8d}.color-power-lesser-than-100,.map-marker-circle-demo.color-3{background:#2999b3}.color-power-lesser-than-200,.map-marker-circle-demo.color-4{background:#1782dd}.color-power-lesser-than-300,.map-marker-circle-demo.color-5{background:#2900ff}.color-power-lesser-than-max,.map-marker-circle-demo.color-6{background:#8000ff}#found_charging_stations{margin-top:2rem}button{cursor:pointer;padding:.5rem;background:#fff}#bars_power{margin:1rem 0;height:3rem}.bar{height:2em;text-align:right;padding:.35rem .25rem .35rem .35rem;float:left}.key-values{max-height:4rem;overflow:auto;width:100%;display:block}.icon-img{width:3rem;height:3rem;fill:#000}.sockets-list{margin-top:.25rem}.socket-counter{background:#dedede;margin-top:1rem;margin-left:-0.25rem;border-radius:1rem;padding:.25rem}.leaflet-interactive{border:solid 3px #fff}#infos_carte{padding:1rem 0}button+button{margin-left:1rem}.filter-group button{padding:1rem 2rem;border-radius:.25rem}.filter-group button:after{position:relative;float:right;left:1rem;top:1rem;font-size:.9em}.filter-group button.filter-state-hide:after{content:"cacher";color:gray}.filter-group button.filter-state-show:after{content:"montrer";color:green}.filter-group button.filter-state-showOnly:after{content:"montrer uniquement";color:orange}.filter-group button.filter-state-hide{background:#fff}.filter-group button.filter-state-show{color:green}.filter-group button.filter-state-showOnly{color:orange}.leaflet-control-layers-toggle{background-size:contain}#round_power_legend{font-size:.8rem}.side-panel{font-size:1rem;position:fixed;left:0;top:0;width:20vw;height:74vh;background:#fff;box-shadow:-2px 0 5px rgba(0,0,0,.2);overflow-y:auto;padding:1rem 2rem;padding-bottom:15rem;z-index:1000;visibility:hidden;top:5.7rem;width:26vw}#toggleSidePanel{position:fixed;top:1rem;right:2rem;z-index:10;background:#fff;padding:1rem 2rem;border-radius:8px;box-shadow:0 2px 4px rgba(0,0,0,.2)}header{padding-left:2rem;color:#666}.side-panel-open .side-panel{visibility:visible;width:29vw;border-right:#ccc solid 1px;height:93vh}.side-panel-open #map{margin-left:28.8vw;top:5.55rem;width:71.2vw}#infos_carte{clear:both}#zoomMessage{position:fixed;bottom:5rem;left:50%;transform:translateX(-50%);background:var(--zoom-message-background);padding:1rem 2rem;border-radius:8px;box-shadow:0 2px 4px rgba(0,0,0,.2);text-align:center;z-index:10;border-left:4px solid var(--zoom-message-border);animation:rainbow-border 4s linear infinite}header{background:#222;position:fixed;width:20vw}header h1{width:100vw;line-height:3rem}header img{float:left;margin-right:1rem}#map{z-index:1;top:5.55rem}.side-panel #map{margin-left:26vw}.rounded-button{display:inline-flex;align-items:center;justify-content:center;font-size:1rem;cursor:pointer;transition:background-color .3s}.rounded-button:hover{background-color:#0d377b}.search-input{width:100%;padding:10px;margin-bottom:10px;border:1px solid var(--button-border);border-radius:5px}#count_features_fond{position:fixed;bottom:1rem;right:1rem;z-index:10;background:#fff;padding:1rem;border-radius:8px}#removeMarkers{margin-right:1rem}.filters-box{margin-top:4rem;height:10rem;width:auto}.filters-box .rounded-button{margin-right:1rem;margin-bottom:1rem}#searchButton{margin-right:1rem}.info .i{border-radius:100%;background:#dedede;padding:1ch;width:5ch;margin-left:1ch;display:inline-block;text-align:center}.info .tooltip{opacity:0}.info:hover .tooltip{opacity:1;transition:opacity .3s ease-in-out}.leaflet-popup-content{max-height:400px;overflow:auto}.osmose-marker{font-size:20px;text-align:center;line-height:20px;background-color:hsla(0,0%,100%,.8);border-radius:50%;border:2px solid #ff6b6b}.osmose-marker-drop{position:relative;z-index:1000}.osmose-marker-inner{position:absolute;width:30px;height:40px;background-color:#8b00ff;border-radius:50% 50% 50% 0;transform:rotate(-45deg);display:flex;align-items:center;justify-content:center;box-shadow:0 0 5px rgba(0,0,0,.3);border:2px solid #fff}.osmose-marker-inner::before{content:"⚡";transform:rotate(45deg);color:#fff;font-size:16px;text-shadow:1px 1px 2px rgba(0,0,0,.3);padding-left:1ch}.osmose-marker-drop:hover .osmose-marker-inner{animation:bounce .5s ease infinite;background-color:#9f2bff}.proposed-tags-container{max-height:200px;overflow-y:auto;margin:10px 0;padding:5px;background-color:#f5f5f5;border-radius:4px}.proposed-tags{width:100%;border-collapse:collapse}.proposed-tags tr:nth-child(even){background-color:#fff}.proposed-tags td{padding:2px 5px;font-size:12px}.proposed-tags td:first-child{font-weight:bold;color:#666}.action-buttons{margin-top:10px;display:flex;flex-direction:column;gap:5px}.action-buttons a{padding:5px 10px;text-decoration:none;border-radius:4px;text-align:center}.action-buttons .edit-button.josm{background-color:#4caf50;color:#fff}.action-buttons a:hover{opacity:.9}@keyframes bounce{0%,100%{transform:rotate(-45deg) translateY(0)}50%{transform:rotate(-45deg) translateY(-5px)}}.leaflet-left .leaflet-control{margin-left:2rem}@media(max-width: 1200px){header h1{width:100vw;font-size:1.5rem}#toggleSidePanel{right:1rem;top:1.3rem}.side-panel-open .side-panel{position:static;transform:none;box-shadow:0 -2px 5px rgba(0,0,0,.2);margin:20px 0 0;width:100vw}.side-panel.active{transform:none}.side-panel-open #map,#map{margin:0;left:0;top:0;width:100vw;height:90vh;height:55vh}header{position:static}}@keyframes rainbow-border{0%{border-left-color:red}17%{border-left-color:#ff8000}33%{border-left-color:#ff0}50%{border-left-color:lime}67%{border-left-color:blue}83%{border-left-color:#8000ff}100%{border-left-color:red}}/*# sourceMappingURL=style.css.map */
diff --git a/styles/style.css.map b/styles/style.css.map
index 3984706..1b173f6 100644
--- a/styles/style.css.map
+++ b/styles/style.css.map
@@ -1 +1 @@
-{"version":3,"sourceRoot":"","sources":["main.scss"],"names":[],"mappings":"AAAA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;;AAIJ;EACE;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;;AAEA;EACE;EACA;;;AAIJ;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;;;AAIJ;EACE;EACA;EACA;;;AAGF;EAOE;;AANA;EACE;EACA;EACA;;;AAMJ;EACE;;;AAGF;EACE;IACE;;EAGF;IACE;;;AAIJ;EACE;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIJ;EACE;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAIF;EACE;EACA;EACA;;AAEA;EACE;;;AAIJ;AAAA;AAAA;AAIA;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;;AAEA;EACE;EACA;EACA;EACA;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA;;AAGF;EACE;EACA;;AAGF;EACE;;AAGF;EACE;;AAGF;EACE;;;AAIJ;EACE;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;;;AAIA;EACE;EACA;EACA;EACA;;AAGF;EACE;EACA;EACA;;;AAIJ;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;;AAEA;EACE;EACA;;AAGF;EACE;EACA;;;AAIJ;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;AAEA;EACE;;;AAIJ;EACE;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA;EACA;;AAEA;EACE;EACA;;;AAIJ;EACE;;;AAKA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;;AAEF;EACE;;AAIA;EACE;EACA;;;AAKN;AAAA;AAAA;AAIA;EACE;;;AAGF;AACA;EACE;IACE;IACA;;EAGF;IACE;IACA;;EAGF;AACE;;EAGF;IACE;IACA;IACA;IACA;IACA;;EAGF;IACE;;EAGF;IACE;IACA;IACA;IACA;IACA;IACA;;EAIF;IACE;;;AAIJ;EACE;IACE;;EAGF;IACE;;EAGF;IACE;;EAGF;IACE;;EAGF;IACE;;EAGF;IACE;;EAGF;IACE","file":"style.css"}
\ No newline at end of file
+{"version":3,"sourceRoot":"","sources":["main.scss"],"names":[],"mappings":"CAAA,MACE,yBACA,mBACA,yBACA,8BACA,6BACA,mCACA,2BACA,mBACA,0BACA,oDACA,+BACA,uCACA,6BACA,iCACA,0BAGF,EACE,sBAGF,KACE,YACA,WACA,mCACA,UACA,SAGF,KACE,YACA,WACA,mCACA,UACA,SACA,UACA,SAGF,KACE,+CACA,eAGF,EACE,+CACA,eACA,eAGF,KACE,YACA,WACA,SACA,iBAME,YACE,6BAKJ,0BACE,mBAKJ,QACE,aAGF,SACE,gBACA,wBACA,cACA,YACA,WACA,iBAGF,MACE,wBACA,yBACA,qBACA,kBACA,kCACA,mBACA,eACA,mBACA,WACA,gCAGF,OACE,iBACA,mBAGF,GACE,mBAGF,uBACE,eACA,YACA,SACA,aACA,+BACA,SACA,WAEA,yBACE,eAIJ,8BACE,6BAGF,8CACE,4BACA,qBACA,iBAGF,8DAIE,oCACA,iBACA,kBACA,sBACA,sCACA,YAGF,gBACE,SACA,kBACA,WAEA,oBACE,WACA,YAIJ,mBACE,eACA,mBAGF,iBACE,gBACA,oBACA,WACA,kBACA,QACA,cAEA,uBACE,YACA,mBAIJ,aACE,0CACA,yBACA,eAGF,aAOE,gBANA,mBACE,0CACA,yBACA,eAMJ,WACE,WAGF,gBACE,GACE,uBAGF,KACE,0BAIJ,EACE,wBAGF,wBACE,aACA,mCAGF,eACE,eACA,MACA,OACA,WACA,gBACA,eAEA,mBACE,eACA,UACA,WACA,gBACA,mBACA,WACA,YACA,kCAIJ,QACE,eACA,cAGF,uBACE,gBACA,qBACA,qBAGF,eACE,WACA,cACA,cACA,gBACA,gBACA,gBACA,iBAGF,WACE,UACA,qBAGF,aACE,UACA,iBACA,qBACA,mBAGF,gBACE,oBAGF,MACE,WAGF,kBACE,aACA,mBACA,cACA,kBACA,UACA,WACA,2BACA,YACA,eACA,eACA,YAIF,SACE,4CACA,iBACA,gBAEA,WACE,gCAQJ,aACE,kBAGF,wBACE,mBACA,qBACA,WACA,YACA,gBAGF,eACE,8CAGF,gCACE,mBAGF,4DAEE,mBAGF,6DAEE,mBAGF,6DAEE,mBAGF,6DAEE,mBAGF,6DAEE,mBAGF,yBACE,gBAGF,OACE,eACA,cACA,gBAGF,YACE,cACA,YAGF,KACE,WACA,iBACA,oCACA,WAGF,YACE,gBACA,cACA,WACA,cAGF,UACE,WACA,YACA,UAGF,cACE,kBAGF,gBACE,mBACA,gBACA,qBACA,mBACA,eAGF,qBACE,sBAGF,aACE,eAGF,cACE,iBAGF,qBACE,kBACA,qBAEA,2BACE,kBACA,YACA,UACA,SACA,eAGF,6CACE,iBACA,WAGF,6CACE,kBACA,YAGF,iDACE,6BACA,aAGF,uCACE,gBAGF,uCACE,YAGF,2CACE,aAIJ,+BACE,wBAGF,oBACE,gBAGF,YACE,eACA,eACA,OACA,MACA,WACA,YACA,gBACA,qCACA,gBACA,kBACA,qBACA,aACA,kBACA,WACA,WAGF,iBACE,eACA,SACA,WACA,WACA,gBACA,kBACA,kBACA,oCAGF,OACE,kBACA,WAIA,6BACE,mBACA,WACA,4BACA,YAGF,sBACE,mBACA,YACA,aAIJ,aACE,WAGF,aACE,eACA,YACA,SACA,2BACA,0CACA,kBACA,kBACA,oCACA,kBACA,WACA,iDACA,4CAGF,OACE,gBACA,eACA,WAEA,UACE,YACA,iBAGF,WACE,WACA,kBAIJ,KACE,UACA,YAGF,iBACE,iBAGF,gBACE,oBACA,mBACA,uBACA,eACA,eACA,gCAEA,sBACE,yBAIJ,cACE,WACA,aACA,mBACA,sCACA,kBAGF,qBACE,eACA,YACA,WACA,WACA,gBACA,aACA,kBAGF,eACE,kBAGF,aACE,gBACA,aACA,WAEA,6BACE,kBACA,mBAIJ,cACE,kBAKA,SACE,mBACA,mBACA,YACA,UACA,gBACA,qBACA,kBAGF,eACE,UAIA,qBACE,UACA,mCAKN,uBACE,iBACA,cAGF,eACE,eACA,kBACA,iBACA,oCACA,kBACA,yBAGF,oBACE,kBACA,aAGF,qBACE,kBACA,WACA,YACA,yBACA,4BACA,yBACA,aACA,mBACA,uBACA,kCACA,sBAEA,6BACE,YACA,wBACA,WACA,eACA,uCACA,iBAMJ,+CACE,mCACA,yBAGF,yBACE,iBACA,gBACA,cACA,YACA,yBACA,kBAGF,eACE,WACA,yBAGF,kCACE,sBAGF,kBACE,gBACA,eAGF,8BACE,iBACA,WAGF,gBACE,gBACA,aACA,sBACA,QAGF,kBACE,iBACA,qBACA,kBACA,kBAGF,kCACE,yBACA,WAGF,wBACE,WAIF,kBAEE,QAEE,uCAGF,IACE,2CAQJ,+BACE,iBAIF,0BACE,UACE,YACA,iBAGF,iBACE,WACA,WAOF,6BACE,gBACA,eACA,qCACA,gBACA,YAGF,mBACE,eAGF,2BAEE,SACA,OACA,MACA,YACA,YACA,YAIF,OACE,iBAIJ,0BACE,GACE,sBAGF,IACE,0BAGF,IACE,uBAGF,IACE,uBAGF,IACE,uBAGF,IACE,0BAGF,KACE","file":"style.css"}
\ No newline at end of file