add filters merge

This commit is contained in:
Tykayn 2025-04-27 22:24:09 +02:00 committed by tykayn
commit 756d997e06
15 changed files with 642 additions and 614 deletions

3
.gitignore vendored
View file

@ -82,6 +82,7 @@ web_modules/
# parcel-bundler cache (https://parceljs.org/)
.cache
.sass-cache
.parcel-cache
# Next.js build output
@ -131,4 +132,4 @@ dist
.pnp.*
#ide
.idea
.idea

View file

@ -30,7 +30,17 @@
<img class="icon-img" src="img/prise-de-courant.png" alt="prise"> Libre Charge Map
</h1>
</header>
<div class="research_display">
<div id='spinning_icon'>
<svg id='star' width='4cm' height='4cm' viewBox='0 0 700 400' xmlns='http://www.w3.org/2000/svg'
version='1.1'>
<polygon fill='red' stroke='red' stroke-width='10' points='350,75 379,161 469,161 397,215
423,301 350,250 277,301 303,215
231,161 321,161' />
</svg>
</div>
</div>
<main>
@ -42,17 +52,7 @@
<div id="zoomMessage">
Zoomez pour voir les stations de recharge
</div>
<div class="research_display">
<div id='spinning_icon'>
<svg id='star' width='4cm' height='4cm' viewBox='0 0 700 400' xmlns='http://www.w3.org/2000/svg'
version='1.1'>
<polygon fill='red' stroke='red' stroke-width='10' points='350,75 379,161 469,161 397,215
423,301 350,250 277,301 303,215
231,161 321,161' />
</svg>
</div>
</div>
<div id='count_features_fond'>
</div>
<div id='map'>
@ -72,7 +72,7 @@
<form onclick="searchLocation()">
<!-- <fieldset>-->
<input type="text" id="searchLocation" placeholder="Rechercher un lieu" class="search-input">
<button id="searchButton" class="rounded-button">🔍 Rechercher</button>
<button id="searchButton" class="rounded-button">🔍</button>
<select id="searchResults" class="search-results" size="5" style="display: none;"></select>
<!-- </fieldset>-->
</form>
@ -109,13 +109,28 @@
<div id="current_station_infos"></div>
<div id="infos_carte"></div>
<!-- <div id="infos_carte"></div> -->
<div id="filters">
<h2>
⚙️ Filtres:
</h2>
<div class="filter-group">
<p>
<!-- <input type="checkbox" id="filter_unknown_output" checked>
<label for="filter_unknown_output">
Afficher les stations avec une puissance inconnue
</label>
<br> -->
<!-- <input type="checkbox" id="filter_max_output" checked> -->
<label for="filter_max_output">
Afficher les stations avec une puissance supérieure à:
</label>
<span id="filter_max_output_display">
3 kW
</span>
</p>
<h3>Types de prises</h3>
<label>
<input type="checkbox" id="filterCableAttached">
@ -165,29 +180,12 @@
<span>❓ kW max inconnu</span>
</label>
</div>
<!--
<br>
<fieldset class="wip">
WIP:
<a href="" id="mapCompleteLink" class="external-editor">mapcomplete</a>
<a href="" id="josmLink" class="external-editor">JOSM</a>
<a href="" id="idLink" class="external-editor">id</a>
<br>
<button id="cableMissing">sans information de câble</button>
<i class="info">
<span class="i">i</span>
<span class="tooltip">mettre un marqueur aux stations qui n'ont pas d'information de
câble</span>
</i>
</fieldset>
<button id="filterChelou">les valeurs chelou</button>
-->
</div>
<br>
<!-- TODO filtrer les bornes selon la puissance -->
<input type="range" min="1" max="400" value="3" class="slider" id="filter_max_output_slider">
</div>
<br>
<!-- TODO filtrer les bornes selon la puissance -->
<div id="statsChargingStation">
@ -209,11 +207,16 @@
<a href="https://wiki.openstreetmap.org/wiki/FR:Tag:amenity%3Dcharging_station">
stations de recharge pour véhicules électriques
</a>.
<br>
Les analyses Osmose proposent l'intégration de stations de recharges issues de l'open data sur les IRVE de
Data Gouv. Vous pouvez les désactiver dans les filtres de calques. Quand les stations existantes sont
activées, seules les analyses osmoses avec un minimum de distance sont affichées.
</p>
<br>
Fait par <a href="https://mastodon.cipherbliss.com/@tykayn">Tykayn</a> - <a
href="https://www.cipherbliss.com">www.cipherbliss.com</a>.
<a href="https://forge.chapril.org/tykayn/">Sources disponibles sur la forge du Chapril.</a>
<p>
Fait par <a href="https://mastodon.cipherbliss.com/@tykayn">Tykayn</a> - <a
href="https://www.cipherbliss.com">www.cipherbliss.com</a>.
<a href="https://forge.chapril.org/tykayn/">Sources disponibles sur la forge du Chapril.</a>
<div class="icones">
<img class="icon-img" src="img/Type2_Connector_Outline.svg" alt="type2">
@ -223,40 +226,21 @@
<img class="icon-img" src="img/chademo.svg" alt="prise">
</div>
<br>
icones
câble électrique <a href="https://www.flaticon.com/fr/icones-gratuites/energie" title="energie icônes">Energie
icônes créées par rukanicon - Flaticon</a>
<span class="small">
icones
câble électrique <a href="https://www.flaticon.com/fr/icones-gratuites/energie"
title="energie icônes">Energie
icônes créées par rukanicon - Flaticon</a>
</span>
</p>
</div>
</div>
<div class="filters-box">
<button id="removeMarkers" class="rounded-button" title="Effacer les marqueurs">
🗑️
<!-- Effacer les marqueurs -->
</button>
<button id="chercherButton" class="rounded-button" title="Recharger">
🔄
<!-- Recharger -->
</button>
<button id="setRandomView" class="rounded-button" title="Une ville au hasard">
🎲
<!-- Une ville au hasard -->
</button>
<button id="sendToJOSM" class="rounded-button" title="Éditer dans JOSM">
🗺️
<!-- Éditer dans JOSM -->
</button>
<button id="shareUrl" class="rounded-button" title="Partager l'URL">
📤
<!-- Partager l'URL -->
</button>
<!-- <button id="toggle">-->
<!-- toggle : montrer les stations avec à minima 150kW de puissance dispo-->
<!-- </button>-->
</div>
<script src='js/leaflet.js'></script>
<script src='js/jquery-3.2.1.min.js'></script>
@ -271,4 +255,4 @@
</script>
</body>
</html>
</html>

View file

@ -4,9 +4,15 @@ const lcm_config = {
overrideQuery: true,
initialZoom: 12,
hide_osmose_markers_if_close_to_existing_charging_stations: true,
hide_osmose_markers_if_close_to_existing_charging_stations_distance: 5, // meters
hide_osmose_markers_if_close_to_existing_charging_stations_distance: 10, // meters
max_possible_station_output: 400,
filter_max_output: true,
filter_max_output_min: 0,
filter_max_output_max: 499,
filter_max_output_default_value: 1,
filter_unknown_output: true,
max_possible_station_output: 499,
// Filtres pour les prises
filterCableAttached: false,
filterCCS: false,
@ -20,7 +26,7 @@ const lcm_config = {
filterConfigs: {
'filterUnknownOutput': true,
'filterCableAttached': true,
'filterCCS': true,
'filterCCS': true,
'filterType2': true,
'filterQuality': true,
'filterDomestic': true,

View file

@ -342,6 +342,12 @@ function calculerPourcentage(partie, total, reduc) {
return ((partie / total) * 100 * coef_reduction).toFixed(1)
}
// Ajouter une variable globale pour stocker le nombre d'issues Osmose
let osmoseIssuesCount = 0;
// Ajouter une variable globale pour stocker le nombre de stations affichées
let displayedStationsCount = 0;
function displayStatsFromGeoJson(resultAsGeojson, stats) {
let count = resultAsGeojson.features.length;
let count_station_output = 0;
@ -361,7 +367,7 @@ function displayStatsFromGeoJson(resultAsGeojson, stats) {
Object.keys(lcm_config.filterConfigs).forEach(filterId => {
if (!lcm_config.filterConfigs[filterId]) disabledFilters++;
});
$('#count_features_fond').html('⚡' + count + ' stations' + (disabledFilters > 0 ? ` (${disabledFilters} filtre${disabledFilters > 1 ? 's' : ''} désactivé${disabledFilters > 1 ? 's' : ''}, ${stats.count_hidden_by_filters} masqué${stats.count_hidden_by_filters > 1 ? 's' : ''})` : ''));
resultAsGeojson.features.map(feature => {
@ -464,6 +470,17 @@ function displayStatsFromGeoJson(resultAsGeojson, stats) {
$('#found_charging_stations').html(stats_content);
$('#bars_power').html(bar_powers);
// Remplacer la ligne existante par un appel à updateCounters
updateCounters();
}
// Ajouter une fonction pour mettre à jour les compteurs
function updateCounters() {
const stationsCount = geojsondata ? geojsondata.features.length : 0;
const osmoseText = osmoseIssuesCount > 0 ? ` <span class="osmose-counter">(+ ${osmoseIssuesCount} ?)</span>` : '';
$('#count_features_fond').html(`${stationsCount}${osmoseText} stations`);
}
// Modifier bindEventsOnJosmRemote pour cibler les boutons dans un contexte (la popup)
@ -472,10 +489,10 @@ function bindEventsOnJosmRemote(popupElement) {
$(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
event.preventDefault();
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) {
@ -500,6 +517,10 @@ function displayPointsFromApi(points, convert_to_osm_json) {
geojsondata = osmtogeojson(points);
}
// Réinitialiser le compteur avant d'afficher les points
displayedStationsCount = 0;
displayStatsFromGeoJson(geojsondata);
let stats = {
count_hidden_by_filters: 0
};
@ -526,10 +547,11 @@ function displayPointsFromApi(points, convert_to_osm_json) {
supprimerMarqueurs();
displayPointsFromApi();
},
onEachFeature: function(feature, layer) {
eachFeature(feature, layer, stats);
},
onEachFeature: eachFeature,
});
// Mettre à jour le compteur de stations filtrées
updateFilteredStationsCount();
}
function makePopupOfFeature(feature) {
@ -575,13 +597,29 @@ function makePopupOfFeature(feature) {
* @param layer
*/
function eachFeature(feature, layer, stats) {
let outPowerGuessed = lcm_utils.guessOutputPowerFromFeature(feature);
const maxPowerFilter = parseInt($('#filter_max_output').val()) || lcm_config.filter_max_output_default_value;
// Filtrage par puissance
if (outPowerGuessed === 0 || outPowerGuessed === null) {
if (display_unknown_max_power_station === 'hide') {
return;
}
} else {
// Filtrer les stations dont la puissance dépasse le maximum défini
if (outPowerGuessed < maxPowerFilter) {
return;
}
}
// Incrémenter le compteur de stations affichées
displayedStationsCount++;
let link_josm = createJOSMEditLink(feature);
let popupContent = makePopupOfFeature(feature);
layer.bindPopup(popupContent);
let outPowerGuessed = lcm_utils.guessOutputPowerFromFeature(feature);
let color = lcm_color_utils.getColor(feature);
let displayOutPowerGuessed = '? kW';
// Vérifier les filtres activés
@ -631,7 +669,7 @@ function eachFeature(feature, layer, stats) {
if (lcm_config.filterQuality) {
// Vérifier si les informations minimales de qualité sont présentes
let hasQualityInfo = feature.properties.tags['operator'] ||
let hasQualityInfo = feature.properties.tags['operator'] ||
feature.properties.tags['authentication:none'] ||
feature.properties.tags['payment:none'] ||
feature.properties.tags['opening_hours'];
@ -670,7 +708,7 @@ function eachFeature(feature, layer, stats) {
<a class="edit-button josm" data-href="${link_josm}" href="#">JOSM</a>
<a href="${panoramaxLink}" target="_blank" class="panoramax-link" title="Voir sur Panoramax">
<img src="styles/images/panoramax.ico" alt="icone"></a>
<span class="color-indication" style="background-color: ${color};">${displayOutPowerGuessed}</span>
<span class="color-indication" style="background-color: ${lcm_color_utils.getColor(feature)};">${displayOutPowerGuessed}</span>
<button class="edit-button" id="fullDetails" >détails</button>
<span class="popup-content">${popupContent}</span>`;
@ -758,8 +796,8 @@ function eachFeature(feature, layer, stats) {
* affichage des marqueurs de stations de recharge
*/
let circle = L.circle(layer._latlng, {
color: color,
fillColor: color,
color: lcm_color_utils.getColor(feature),
fillColor: lcm_color_utils.getColor(feature),
fillOpacity: opacity,
colorOpacity: opacity,
radius: radius
@ -768,7 +806,7 @@ function eachFeature(feature, layer, stats) {
if (zoom > 15) {
let circle_center = L.circle(layer._latlng, {
color: 'black',
fillColor: color,
fillColor: lcm_color_utils.getColor(feature),
fillOpacity: 1,
radius: 0.1
}).addTo(all_stations_markers);
@ -820,49 +858,6 @@ function bindFullDetails(feature) {
${content}`
})
}
function makeCssClassFromTags(tags) {
let tagKeys = Object.keys(tags)
if (!tags) {
return ''
}
let listOfClasses = []
tagKeys.forEach((element) => {
listOfClasses.push('tag-' + element + '_' + tags[element].replace(':', '--').replace(' ', '-'))
})
return listOfClasses.join(' ')
}
function getIconFromTags(tags) {
let iconFileName = ''
// let iconFileName = 'icon_restaurant.png';
if (tags['man_made']) {
iconFileName = 'fountain.png'
}
return iconFileName
}
function toggleMinPower(showHighPower) {
showHighPower = !showHighPower;
addFilteredMarkers(showHighPower);
this.textContent = showHighPower ? 'Montrer puissance haute' : 'Montrer puissance normale';
}
function addFilteredMarkers(showHighPower) {
allMarkers.clearLayers();
let counter = 0;
geojsondata.features.forEach(function (feature) {
if (feature.properties.puissance_haute === showHighPower) {
counter++;
let marker = L.marker(feature.geometry.coordinates).bindPopup(feature.properties.puissance_haute ? 'Puissance haute' : 'Puissance normale');
allMarkers.addLayer(marker);
}
});
}
let isLoading = false
function loadOverpassQuery() {
@ -885,7 +880,12 @@ function loadOverpassQuery() {
function refreshDisplay(convert_points_to_osm = false) {
supprimerMarqueurs();
count_hidden_by_filters = 0; // Réinitialiser le compteur
displayPointsFromApi(geojsondata, convert_points_to_osm);
if (geojsondata) {
displayPointsFromApi(geojsondata, convert_points_to_osm);
updateCounters();
updateFilteredStationsCount();
}
// Mettre à jour le compteur dans la popup
let count = geojsondata.features.length;
let disabledFilters = 0;
@ -935,7 +935,7 @@ function onMapMoveEnd() {
console.log("Zoom actuel:", map.getZoom());
if (map.getZoom() >= 12) {
console.log("Recherche des issues Osmose...");
// console.log("Recherche des issues Osmose...");
searchOsmoseIssues(map);
} else {
console.log("Zoom trop faible pour les issues Osmose");
@ -1010,6 +1010,7 @@ $('#toggle-stats').on('click', function () {
}
});
// Ajouter ces variables avec les autres déclarations globales
let food_places_markers = L.layerGroup();
const foodIcon = L.divIcon({
@ -1088,7 +1089,6 @@ function searchOsmoseIssues(map) {
const bbox = `${bounds.getWest()}%2C${bounds.getSouth()}%2C${bounds.getEast()}%2C${bounds.getNorth()}`;
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();
// Modifier la vérification des stations existantes
@ -1117,10 +1117,13 @@ function searchOsmoseIssues(map) {
.then(data => {
if (!data || !Array.isArray(data.issues)) {
console.warn("Réponse Osmose (liste) inattendue ou pas d'issues:", data);
osmoseIssuesCount = 0;
updateCounters();
return;
}
const issuesList = data.issues;
console.log(`Nombre d'issues Osmose (liste) trouvées: ${issuesList.length}`);
osmoseIssuesCount = issuesList.length;
console.log(`Nombre d'issues Osmose (liste) trouvées: ${osmoseIssuesCount}`);
issuesList.forEach(issueInfo => {
if (issueInfo.lat == null || issueInfo.lon == null || !issueInfo.id) {
@ -1138,7 +1141,7 @@ function searchOsmoseIssues(map) {
});
if (tooClose) {
// console.log(`Marqueur Osmose ignoré car trop proche d'une station existante: ${lat},${lon}`);
// console.log(`Marqueur Osmose ignoré car trop proche d'une station existante: ${lat},${lon}`);
return;
}
}
@ -1216,9 +1219,13 @@ function searchOsmoseIssues(map) {
osmose_markers.addLayer(osmoseMarker);
});
updateCounters(); // Mettre à jour l'affichage après le traitement
})
.catch(error => {
console.error('Erreur détaillée lors de la recherche de la liste des issues Osmose:', error);
osmoseIssuesCount = 0;
updateCounters();
});
}
@ -1255,133 +1262,130 @@ function handleMarkerClick(marker, map) {
// Ajouter un écouteur d'événements pour le changement de visibilité des calques
function init() {
bindEventsOnJosmRemote();
onMapMoveEnd();
map.on('moveend', onMapMoveEnd);
$('#spinning_icon').hide();
$(document).ready(function () {
bindEventsOnJosmRemote();
onMapMoveEnd();
map.on('moveend', onMapMoveEnd);
$('#spinning_icon').hide();
/**
* boutons de changement de filtres et de rechargement des bornes à l'affichage
*/
$('#removeMarkers').on('click', function () {
supprimerMarqueurs();
});
$('#load').on('click', function () {
loadOverpassQuery();
});
$('#toggleSidePanel').on('click', function () {
$('body').toggleClass('side-panel-open');
});
$('#chercherButton').on('click', function () {
supprimerMarqueurs();
loadOverpassQuery();
});
$('#setRandomView').on('click', function () {
setRandomView();
loadOverpassQuery();
});
$('#filterUnkown').on('click', function () {
display_unknown_max_power_station = cycleVariableState(display_unknown_max_power_station, '#filterUnkown');
showActiveFilter(display_unknown_max_power_station, '#filterUnkown');
refreshDisplay();
});
/**
* toggle des alertes de tags décrivant la présence de cable
*/
$('#cableMissing').on('click', function () {
display_alert_cable_missing = !display_alert_cable_missing;
showActiveFilter(display_alert_cable_missing, '#cableMissing');
refreshDisplay();
});
showActiveFilter(display_unknown_max_power_station, '#filterUnkown');
$('#shareUrl').on('click', copyCurrentUrl);
// Initialisation des états des checkboxes des filtres selon les valeurs de configuration
Object.keys(lcm_config.filterConfigs).forEach(filterId => {
console.log("checbox ", $(`#${filterId}`) , lcm_config.filterConfigs[filterId] , lcm_config)
$(`#${filterId}`).prop('checked', lcm_config.filterConfigs[filterId]);
});
// Écouteurs pour les filtres
Object.keys(lcm_config.filterConfigs).forEach(filterId => {
$(`#${filterId}`).on('change', function() {
lcm_config[lcm_config.filterConfigs[filterId]] = this.checked;
/**
* boutons de changement de filtres et de rechargement des bornes à l'affichage
*/
$('#removeMarkers').on('click', function () {
supprimerMarqueurs();
});
$('#load').on('click', function () {
loadOverpassQuery();
});
$('#toggleSidePanel').on('click', function () {
$('body').toggleClass('side-panel-open');
});
$('#chercherButton').on('click', function () {
supprimerMarqueurs();
loadOverpassQuery();
});
$('#setRandomView').on('click', function () {
setRandomView();
loadOverpassQuery();
});
$('#filterUnkown').on('click', function () {
display_unknown_max_power_station = cycleVariableState(display_unknown_max_power_station, '#filterUnkown');
showActiveFilter(display_unknown_max_power_station, '#filterUnkown');
refreshDisplay();
});
});
food_places_markers.addTo(map);
$('#found_charging_stations').hide();
/**
* toggle des alertes de tags décrivant la présence de cable
*/
$('#cableMissing').on('click', function () {
display_alert_cable_missing = !display_alert_cable_missing;
showActiveFilter(display_alert_cable_missing, '#cableMissing');
refreshDisplay();
});
showActiveFilter(display_unknown_max_power_station, '#filterUnkown');
// Mettre à jour le contrôle des calques
const overlayMaps = {
"Stations de recharge": all_stations_markers,
"Restaurants et cafés": food_places_markers,
"Bornes potentielles (Osmose)": osmose_markers
};
$('#shareUrl').on('click', copyCurrentUrl);
// Créer deux contrôles de couches séparés
// const baseLayerControl = L.control.layers(baseLayers, null, {
// collapsed: true,
// className: 'leaflet-control-layers base-layers',
// id: 'base-layers-control'
// }).addTo(map);
const overlayControl = L.control.layers(null, overlayMaps, {
collapsed: true,
className: 'leaflet-control-layers overlay-layers',
id: 'overlay-layers-control'
}).addTo(map);
$('#sendToJOSM').on('click', () => {
sendToJOSM(map, geojsondata)
.then(() => {
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');
// Initialisation des états des checkboxes des filtres selon les valeurs de configuration
Object.keys(lcm_config.filterConfigs).forEach(filterId => {
console.log("checbox ", $(`#${filterId}`) , lcm_config.filterConfigs[filterId] , lcm_config)
$(`#${filterId}`).prop('checked', lcm_config.filterConfigs[filterId]);
});
// Écouteurs pour les filtres
Object.keys(lcm_config.filterConfigs).forEach(filterId => {
$(`#${filterId}`).on('change', function() {
lcm_config[lcm_config.filterConfigs[filterId]] = this.checked;
refreshDisplay();
});
});
$('#josmLink').on('click', () => {
sendToJOSM(map, geojsondata)
.then(() => {
console.log('Données envoyées à JOSM avec succès !');
})
.catch(() => {
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 () {
const selectedIndex = $(this).val();
if (selectedIndex !== null) {
const selectedPlace = $(this).find('option:selected').data('place');
moveToLocation(selectedPlace);
}
});
food_places_markers.addTo(map);
$('#found_charging_stations').hide();
osmose_markers.addTo(map);
// Mettre à jour le contrôle des calques
const overlayMaps = {
"Stations de recharge": all_stations_markers,
"Restaurants et cafés": food_places_markers,
"Bornes potentielles (Osmose)": osmose_markers
};
// Ajouter le contrôle de source de recherche
const searchControl = `
<div class="search-source-control">
<label>
<input type="checkbox" id="useAddok" checked>
Utiliser Addok (France)
</label>
</div>
`;
$('#searchLocation').after(searchControl);
// const baseLayersControl = L.control.layers(baseLayers, null, {
// collapsed: true,
// className: 'leaflet-control-layers base-layers',
// id: 'base-layers-control'
// }).addTo(map);
// Mettre à jour les marqueurs Osmose quand la visibilité des stations change
map.on('overlayremove overlayadd', function (e) {
if (e.name === "Stations de recharge" && map.getZoom() > 12) {
searchOsmoseIssues(map);
}
const overlayControl = L.control.layers(null, overlayMaps, {
collapsed: true,
className: 'leaflet-control-layers overlay-layers',
id: 'overlay-layers-control'
}).addTo(map);
$('#sendToJOSM').on('click', () => {
sendToJOSM(map, geojsondata)
.then(() => {
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');
});
});
$('#josmLink').on('click', () => {
sendToJOSM(map, geojsondata)
.then(() => {
console.log('Données envoyées à JOSM avec succès !');
})
.catch(() => {
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);
$('#filter_max_output').on('input', function () {
const value = $(this).val();
console.log('filter_max_output', value, $(this));
$('#filter_max_output_display').text(value + ' kW');
refreshDisplay();
});
$('#filter_max_output_slider').on('input', function () {
const value = $(this).val();
lcm_config.filter_max_output_default_value = value;
$('#filter_max_output_display').text(value + ' kW');
refreshDisplay();
});
$('#searchResults').on('change', function () {
const selectedIndex = $(this).eq(0).val();
if (selectedIndex !== null) {
const selectedPlace = $(this).find('option:selected').data('place');
moveToLocation(selectedPlace);
}
});
osmose_markers.addTo(map);
});
}
@ -1404,4 +1408,18 @@ init()
// Créer un nouveau pane pour les marqueurs Osmose avec un zIndex plus élevé
map.createPane('osmosePane');
map.getPane('osmosePane').style.zIndex = 1000;
map.getPane('osmosePane').style.zIndex = 1000;
// Ajouter une nouvelle fonction pour mettre à jour le compteur de stations filtrées
function updateFilteredStationsCount() {
const totalStations = geojsondata ? geojsondata.features.length : 0;
const filterStats = `<div class="filter-stats">${displayedStationsCount} stations sur ${totalStations} trouvées</div>`;
// Mettre à jour ou créer l'élément après le slider
let existingStats = $('.filter-stats');
if (existingStats.length) {
existingStats.replaceWith(filterStats);
} else {
$('#filter_max_output_display').after(filterStats);
}
}

1
nohup.out Normal file
View file

@ -0,0 +1 @@
bash: /home/cipherbliss/Téléchargements/WebStorm-232.10335.13/bin/bin/webstorm.sh: Aucun fichier ou dossier de ce nom

41
styles/_animations.scss Normal file
View file

@ -0,0 +1,41 @@
@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;
}
}
@keyframes bounce {
0%,
100% {
transform: rotate(-45deg) translateY(0);
}
50% {
transform: rotate(-45deg) translateY(-5px);
}
}

View file

@ -1,3 +1,14 @@
#filter_max_output_slider {
width: 100%;
height: 10px;
background: #ccc;
border-radius: 5px;
}
.filter-stats {
font-size: 0.8rem;
color: #666;
}
// Variables
$primary-color: #28a745;
$border-color: #6c757d;
@ -120,4 +131,4 @@ $disabled-color: #adb5bd;
0% { transform: scale(1); }
50% { transform: scale(1.1); }
100% { transform: scale(1); }
}
}

80
styles/_mobile.scss Normal file
View file

@ -0,0 +1,80 @@
/* Style pour mobile ---------------------------------- */
@media (max-width: 700px) {
header h1 {
width: 100vw;
font-size: 1.5rem;
}
#searchButton {
margin-top: 0rem;
}
#bars_power {
position: absolute;
top: 59.1vh;
width: 117%;
}
#toggleSidePanel {
position: fixed;
top: 0.6rem;
right: 0.6rem;
z-index: 10;
background: #a9a9a9;
padding: 0.2rem 1rem;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, .2);
border: 0;
font-size: 2rem;
}
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: 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;
}
.filters-box {
position: static;
}
.close-results-button {
border: 0;
border-radius: 3px;
background: var(--button-border);
margin: 0;
position: relative;
top: -4.9rem;
right: 1.4rem;
height: 2.6rem;
}
}
#count_features_fond {
border: solid 1px grey;
}

61
styles/_osmose.scss Normal file
View file

@ -0,0 +1,61 @@
.osmose-marker-drop:hover .osmose-marker-inner {
animation: bounce 0.5s ease infinite;
background-color: #9F2BFF;
}
.osmose-counter {
font-size: 0.85rem;
color: #999;
}
.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;
tr:nth-child(even) {
background-color: #ffffff;
}
td {
padding: 2px 5px;
font-size: 12px;
}
td:first-child {
font-weight: bold;
color: #666;
}
}
.action-buttons {
margin-top: 10px;
display: flex;
flex-direction: column;
gap: 5px;
a {
padding: 5px 10px;
text-decoration: none;
border-radius: 4px;
text-align: center;
&:hover {
opacity: 0.9;
}
}
.edit-button.josm {
background-color: #4CAF50;
color: white;
}
}

92
styles/_overrides.scss Normal file
View file

@ -0,0 +1,92 @@
/**
overrides leaflet
*/
.leaflet-left .leaflet-control {
margin-left: 2rem;
}
.leaflet-interactive {
border: solid 3px white;
}
.leaflet-control-layers {
&.leaflet-control-layers-toggle {
background: url('img/burger.png');
}
}
/* Styles pour les contrôles de couches */
.leaflet-control-layers {
&.base-layers {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M2 9l10-5 10 5-10 5-10-5zm0 6l10 5 10-5M2 12l10 5 10-5"/></svg>');
background-size: 16px;
background-position: 6px center;
background-repeat: no-repeat;
padding-left: 28px !important;
.leaflet-control-layers-toggle {
background-image: none;
width: auto;
padding-right: 10px;
}
&::after {
content: "Fonds";
margin-left: 5px;
font-size: 12px;
}
}
&.overlay-layers {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/></svg>');
background-size: 16px;
background-position: 6px center;
background-repeat: no-repeat;
padding-left: 28px !important;
.leaflet-control-layers-toggle {
background-image: none;
width: auto;
padding-right: 10px;
}
&::after {
content: "Calques";
margin-left: 5px;
font-size: 12px;
}
}
}
// Styles pour les contrôles de calques
.leaflet-control-layers {
&.base-layers {
.leaflet-control-layers-toggle {
background-image: url('../img/burger.png') !important;
background-size: 20px 20px !important;
background-position: center !important;
background-repeat: no-repeat !important;
width: 30px !important;
height: 30px !important;
}
}
&.overlay-layers {
.leaflet-control-layers-toggle {
background-image: url('../img/pizza.png') !important;
background-size: 20px 20px !important;
background-position: center !important;
background-repeat: no-repeat !important;
background-color: #3f74aa !important;
width: 30px !important;
height: 30px !important;
}
}
// Style commun pour le conteneur
background: white;
padding: 5px;
border-radius: 4px;
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.4);
}

62
styles/_recherche.scss Normal file
View file

@ -0,0 +1,62 @@
#searchLocation {
width: 88%;
padding: 10px;
margin-bottom: 10px;
border: 1px solid var(--button-border);
border-radius: 5px;
}
#removeMarkers {
margin-right: 1rem;
margin-left: 1rem;
}
#searchResults {
width: 100%;
border-color: var(--button-border);
}
#searchButton {
margin-left: -1rem;
margin-top: 0;
z-index: 2;
position: absolute;
background: var(--link-color);
border-radius: 3px;
}
#count_features_fond {
position: fixed;
bottom: 1rem;
right: 1rem;
z-index: 10;
background: white;
padding: 1rem;
border-radius: 8px;
}
.search-source-control {
margin: 5px 0;
font-size: 0.9em;
label {
display: flex;
align-items: center;
gap: 5px;
}
input[type="checkbox"] {
margin: 0;
}
}
.close-results-button {
border: 0;
border-radius: 3px;
}

0
styles/_responsive.scss Normal file
View file

View file

@ -29,7 +29,8 @@ html {
}
body {
height: 100%;
height: 100vh;
overflow: auto;
width: 100%;
background: var(--background-color);
padding: 0;
@ -45,8 +46,7 @@ html {
p {
font-family: Calibri, Roboto, Arial, "Ubuntu Mono";
font-size: 1rem;
font-size: 1rem;
font-size: 0.75rem;
}
#map {
@ -104,6 +104,7 @@ table {
h2 {
font-weight: normal;
font-size: 1.25rem;
}
#overpass-api-controls {
@ -221,13 +222,14 @@ a {
svg {
position: fixed;
top: 0.5rem;
right: 3rem;
top: 0.45rem;
left: 1.5rem;
background: white;
border-radius: 100%;
width: 3rem;
height: 3rem;
animation: spin 2s linear infinite;
opacity: 0.3;
}
}
@ -253,7 +255,7 @@ a {
}
.popup-key {
width: 50%;
width: 57%;
display: inline-block;
}
@ -371,8 +373,8 @@ button {
}
.icon-img {
width: 3rem;
height: 3rem;
width: 2rem;
height: 2rem;
fill: #000;
}
@ -388,9 +390,6 @@ button {
padding: 0.25rem;
}
.leaflet-interactive {
border: solid 3px white;
}
#infos_carte {
padding: 1rem 0;
@ -406,6 +405,7 @@ button+button {
#round_power_legend {
font-size: 0.8rem;
margin-top: 4rem;
}
.side-panel {
@ -422,7 +422,7 @@ button+button {
padding-bottom: 15rem;
z-index: 1000;
visibility: hidden;
top: 5.7rem;
top: 4.5rem;
width: 26vw;
}
@ -452,8 +452,10 @@ header {
#map {
margin-left: 28.8vw;
top: 5.55rem;
top: 4.5rem;
width: 71.2vw;
border: 0;
height: 92.9vh;
}
}
@ -482,8 +484,9 @@ header {
width: 20vw;
h1 {
width: 100vw;
line-height: 3rem;
color: white;
line-height: 2rem;
font-size: 0.8rem;
}
img {
@ -514,30 +517,8 @@ header {
}
}
.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 {
position: absolute;
position: fixed;
bottom: 0.7rem;
right: 25vw;
z-index: 100;
@ -548,9 +529,6 @@ header {
}
}
#searchButton {
margin-right: 1rem;
}
.info {
@ -577,7 +555,7 @@ header {
}
.leaflet-popup-content {
max-height: 400px;
max-height: 30vh;
overflow: auto;
}
@ -623,225 +601,23 @@ header {
}
#bars_power {
position: absolute;
bottom: -16.7px;
width: 122.4%;
position: fixed;
top: 4.3rem;
width: 126vw;
z-index: 10000;
margin: 1rem 0;
height: 0.4rem;
margin: 0;
height: .4rem;
overflow: hidden;
}
/* Animation au survol plus visible */
.osmose-marker-drop:hover .osmose-marker-inner {
animation: bounce 0.5s ease infinite;
background-color: #9F2BFF;
.small {
font-size: 0.8rem;
}
.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;
}
#searchResults {
width: 100%;
}
.search-source-control {
margin: 5px 0;
font-size: 0.9em;
}
.search-source-control label {
display: flex;
align-items: center;
gap: 5px;
}
.search-source-control input[type="checkbox"] {
margin: 0;
}
@keyframes bounce {
0%,
100% {
transform: rotate(-45deg) translateY(0);
}
50% {
transform: rotate(-45deg) translateY(-5px);
}
}
/**
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;
}
}
/* Styles pour les contrôles de couches */
.leaflet-control-layers {
&.base-layers {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M2 9l10-5 10 5-10 5-10-5zm0 6l10 5 10-5M2 12l10 5 10-5"/></svg>');
background-size: 16px;
background-position: 6px center;
background-repeat: no-repeat;
padding-left: 28px !important;
.leaflet-control-layers-toggle {
background-image: none;
width: auto;
padding-right: 10px;
}
&::after {
content: "Fonds";
margin-left: 5px;
font-size: 12px;
}
}
&.overlay-layers {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/></svg>');
background-size: 16px;
background-position: 6px center;
background-repeat: no-repeat;
padding-left: 28px !important;
.leaflet-control-layers-toggle {
background-image: none;
width: auto;
padding-right: 10px;
}
&::after {
content: "Calques";
margin-left: 5px;
font-size: 12px;
}
}
}
@import '_osmose.scss';
@import '_recherche.scss';
@import '_filters.scss';
@import '_mobile.scss';
@import '_overrides.scss';
@import '_responsive.scss';
@import '_animations.scss';

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
{"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,cACA,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,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,kBACA,aACA,WACA,YAEA,6BACE,mBACA,oBAIJ,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,sBAMA,8BACE,YACA,wBACA,WACA,eACA,uCACA,iBAIJ,YACE,kBACA,eACA,aACA,cACA,cACA,aACA,gBAKF,+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,WAGF,eACE,WAGF,uBACE,aACA,eAGF,6BACE,aACA,mBACA,QAGF,4CACE,SAGF,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,uBAMF,oCACE,wOACA,qBACA,+BACA,4BACA,6BAEA,mEACE,sBACA,WACA,mBAGF,2CACE,gBACA,gBACA,eAIJ,uCACE,yOACA,qBACA,+BACA,4BACA,6BAEA,sEACE,sBACA,WACA,mBAGF,8CACE,kBACA,gBACA","file":"style.css"}
{"version":3,"sourceRoot":"","sources":["main.scss","_osmose.scss","_recherche.scss","_filters.scss","_mobile.scss","_overrides.scss","_animations.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,aACA,cACA,WACA,mCACA,UACA,SACA,UACA,SAGF,KACE,+CACA,eAGF,EACE,+CACA,iBAGF,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,mBACA,kBAGF,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,cACA,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,WACA,YACA,gBACA,mBACA,WACA,YACA,kCACA,WAIJ,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,KACE,WACA,iBACA,oCACA,WAGF,YACE,gBACA,cACA,WACA,cAGF,UACE,WACA,YACA,UAGF,cACE,kBAGF,gBACE,mBACA,gBACA,qBACA,mBACA,eAIF,aACE,eAGF,cACE,iBAGF,+BACE,wBAGF,oBACE,gBACA,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,WACA,aACA,SACA,cAIJ,aACE,WAGF,aACE,eACA,YACA,SACA,2BACA,0CACA,kBACA,kBACA,oCACA,kBACA,WACA,iDACA,4CAGF,OACE,gBACA,eACA,WAEA,UACE,WACA,iBACA,gBAGF,WACE,WACA,kBAIJ,KACE,UACA,YAGF,iBACE,iBAGF,gBACE,oBACA,mBACA,uBACA,eACA,eACA,gCAEA,sBACE,yBAIJ,aACE,eACA,aACA,WACA,YAEA,6BACE,mBACA,oBAOF,SACE,mBACA,mBACA,YACA,UACA,gBACA,qBACA,kBAGF,eACE,UAIA,qBACE,UACA,mCAKN,uBACE,gBACA,cAGF,eACE,eACA,kBACA,iBACA,oCACA,kBACA,yBAGF,oBACE,kBACA,aAGF,qBACE,kBACA,WACA,YACA,yBACA,4BACA,yBACA,aACA,mBACA,uBACA,kCACA,sBAMA,8BACE,YACA,wBACA,WACA,eACA,uCACA,iBAIJ,YACE,eACA,WACA,YACA,cACA,SACA,aACA,gBAGF,OACE,gBCrmBF,+CACE,mCACA,yBAGF,gBACE,iBACA,WAGF,yBACE,iBACA,gBACA,cACA,YACA,yBACA,kBAGF,eACE,WACA,yBAEA,kCACE,sBAGF,kBACE,gBACA,eAGF,8BACE,iBACA,WAKJ,gBACE,gBACA,aACA,sBACA,QAEA,kBACE,iBACA,qBACA,kBACA,kBAEA,wBACE,WAIJ,kCACE,yBACA,WC1DJ,gBACE,UAEA,aACA,mBACA,sCACA,kBAGF,eACE,kBACA,iBAGF,eACE,WACA,kCAGF,cACE,kBACA,aACA,UACA,kBACA,6BACA,kBAGF,qBACE,eACA,YACA,WACA,WACA,gBACA,aACA,kBAGF,uBACE,aACA,eAEA,6BACE,aACA,mBACA,QAGF,4CACE,SASJ,sBACE,SACA,kBC5DF,0BACE,WACA,YACA,gBACA,kBAGF,cACE,gBACA,WAoBF,cACE,cACA,aACA,mBACA,kBACA,oCAEA,iBACE,mBACA,MAvBS,QAwBT,eAGF,oBAtBA,aACA,mBAuBE,cACA,eApBF,wBAsBE,kBACA,aAEA,0BACE,WArCK,QAyCT,mCACE,kBACA,UACA,eACA,SACA,QAGF,+BACE,kBACA,qBACA,WACA,YACA,gBACA,yBACA,kBACA,kBA9CF,wBAiDE,2CACE,4DAIJ,4DACE,WApEY,QAqEZ,aArEY,QAsEZ,+BAEA,mEACE,WACA,kBACA,SACA,QACA,UACA,YACA,kBACA,yBACA,wBAIJ,iBACE,cACA,SACA,WACA,mBAGF,mBACE,eACA,MA3FS,QAUX,0BAqFA,+BACE,kCAIA,6DACE,WAtGK,QAuGL,aArGW,QAsGX,mBAGF,kEACE,MA1GW,QA2GX,mBAMN,uBACE,sBACA,yBACA,yBCnIF,yBACE,UACE,YACA,iBAGF,cACE,gBAGF,YACE,kBACA,WACA,WAGF,iBACE,eACA,UACA,YACA,WACA,mBACA,mBACA,kBACA,oCACA,SACA,eAOF,6BACE,gBACA,eACA,qCACA,SACA,YAGF,mBACE,eAGF,2BAEE,SACA,OACA,MACA,YACA,YACA,YAIF,OACE,gBAGF,aACE,gBAGF,sBACE,SACA,kBACA,gCACA,SACA,kBACA,YACA,aACA,eAIJ,qBACE,sBC1EF,+BACE,iBAGF,qBACE,sBAIA,sDACE,iCAMF,oCACE,wOACA,qBACA,+BACA,4BACA,6BAEA,mEACE,sBACA,WACA,mBAGF,2CACE,gBACA,gBACA,eAIJ,uCACE,yOACA,qBACA,+BACA,4BACA,6BAEA,sEACE,sBACA,WACA,mBAGF,8CACE,kBACA,gBACA,eAMN,wBAyBE,gBACA,YACA,kBACA,oCA1BE,mEACE,qDACA,qCACA,sCACA,uCACA,sBACA,uBAKF,sEACE,oDACA,qCACA,sCACA,uCACA,oCACA,sBACA,uBClFN,0BACE,GACE,sBAGF,IACE,0BAGF,IACE,uBAGF,IACE,uBAGF,IACE,uBAGF,IACE,0BAGF,KACE,uBAIJ,kBAEE,QAEE,uCAGF,IACE","file":"style.css"}