This repository has been archived on 2021-06-04. You can view files and clone it, but cannot push or open issues or pull requests.
carteG1/src/App.vue

316 lines
8.8 KiB
Vue

<template>
<div id="app">
<l-map
ref="map"
id="map"
:zoom="zoom"
:center="center"
no-blocking-animations
>
<l-tile-layer :url="url"></l-tile-layer>
<v-marker-cluster ref="clusterRef">
<l-marker
v-for="(topic, i) in topics"
:key="i"
:ref="`marker-${topic.id}`"
:lat-lng="[
topic.location.geo_location.lat,
topic.location.geo_location.lon
]"
>
<l-popup
:options="{
maxWidth: 400,
minWidth: 300,
autoPanPadding: [10, 20]
}"
>
<a
target="_blank"
:href="`${baseUrl}t/${topic.slug}/${topic.id}`"
class="title font-bold leading-tight pb-2 block"
>
<h2 class="text-2xl pt-4 px-4" v-html="topic.fancy_title"></h2>
<div
v-if="topic.event"
class="text-lg text-blue-500 px-4 pt-2"
style="text-decoration: none !important;"
v-html="cleanDateEvent(topic.event)"
></div>
<img
v-if="topic.image_url"
:src="topic.image_url"
:alt="topic.fancy_title"
class="mt-3 w-full"
/>
</a>
<div class="flex items-center px-4 pb-2 text-sm">
<span class="pr-1 whitespace-no-wrap">Proposé par :</span>
<a
target="_blank"
:href="`${baseUrl}u/${topic.creator.username}`"
class="flex overflow-hidden hover:bg-blue-200 p-1"
>
<img
:src="
baseUrl +
topic.creator.avatar_template.replace(/{size}/, '20')
"
:alt="topic.creator.name"
class="mr-1 rounded-full"
/>
<span class="font-bold text-gray-800 truncate">
{{ topic.creator.name }} ({{ topic.creator.username }})
</span>
</a>
</div>
<div v-if="topic.tags.length" class="flex px-4 pb-2">
<font-awesome-icon icon="tags" size="lg" class="text-gray-500" />
<div class="flex flex-wrap">
<span
v-for="(tag, t) in topic.tags"
:key="t"
class="tag bg-gray-300 ml-1 mb-1 hover:bg-blue-300"
>
<a
target="_blank"
class="px-2 py-1"
:href="`${baseUrl}tag/${tag}`"
v-html="tag"
/>
</span>
</div>
</div>
<a
target="_blank"
:href="`${baseUrl}t/${topic.slug}/${topic.id}`"
class="flex justify-around border-t py-3 px-2"
>
<div v-if="topic.highest_post_number - 1 > 0">
<font-awesome-icon
icon="comment-alt"
size="lg"
class="text-gray-500"
/>
<span class="pl-1 font-bold text-gray-600">
{{ topic.highest_post_number - 1 }} réponses
</span>
</div>
<div v-if="topic.like_count">
<font-awesome-icon
icon="heart"
size="lg"
class="text-red-500"
/>
<span class="pl-1 font-bold text-gray-600">
{{ topic.like_count }} j'aimes
</span>
</div>
<div>
<font-awesome-icon icon="eye" size="lg" class="text-blue-500" />
<span class="pl-1 font-bold text-gray-600">
{{ topic.views }} vues
</span>
</div>
</a>
</l-popup>
</l-marker>
</v-marker-cluster>
</l-map>
</div>
</template>
<script>
import { LMap, LTileLayer, LMarker, LPopup } from "vue2-leaflet";
import Vue2LeafletMarkerCluster from "vue2-leaflet-markercluster";
export default {
name: "app",
components: {
LMap,
LTileLayer,
LMarker,
LPopup,
"v-marker-cluster": Vue2LeafletMarkerCluster
},
data() {
return {
url:
"https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png",
zoom: 6,
center: [46.227638, 2.213749], // center of France
bounds: null,
topics: [],
users: [],
baseUrl: "https://forum.monnaie-libre.fr/"
};
},
async beforeCreate() {
// check url params !BOUM don't need vue.router :)
let uri = window.location.search.substring(1);
let params = await new URLSearchParams(uri);
if (params.get("zoom")) this.zoom = Number(params.get("zoom"));
if (params.get("lat") && params.get("lon")) {
this.center = {
lat: Number(params.get("lat")),
lng: Number(params.get("lon"))
};
}
const id = params.get("id");
// get discourse data
fetch("https://forum.monnaie-libre.fr/map.json?order=default")
.then(resp => resp.json())
.then(data => {
this.users = data.users;
this.topics = data.topic_list.topics
// parse topics with geolocation and remove old topic
.filter(topic => {
let outdated = false; // allow all topics
if (topic.event) {
const eventEnd = new Date(
topic.event.start || topic.event.end
).getTime();
outdated = Date.now() > eventEnd;
}
return topic.location && topic.location.geo_location && !outdated;
})
// and feed each one with creator object
.map(topic => {
return {
...topic,
...{
creator: this.users.filter(
user => user.id === topic.posters[0].user_id
)[0]
}
};
});
// Open popup if param id provided
if (id) {
this.$nextTick(() => {
const marker = this.$refs[`marker-${id}`][0].mapObject.getLatLng();
this.$refs.map.mapObject.fitBounds(
window.L.latLngBounds([marker]),
{
maxZoom: Number(params.get("zoom")) || 12, // prevent popup in cluster
padding: [10, 10]
}
);
this.$refs[`marker-${id}`][0].mapObject.openPopup();
});
}
});
},
methods: {
cleanDateEvent(event) {
const sameDay =
event.end &&
new Date(event.start).toLocaleDateString("fr-FR") ===
new Date(event.end).toLocaleDateString("fr-FR");
let dateString = !event.end || sameDay ? "Le " : "Du ";
dateString += new Date(event.start).toLocaleDateString("fr-FR", {
weekday: "short",
year: "numeric",
month: "long",
day: "numeric",
hour: "2-digit",
minute: "2-digit"
});
if (event.end) {
if (sameDay) {
dateString =
dateString.replace(/à/, "de") +
" à" +
new Date(event.end)
.toLocaleDateString("fr-FR", {
hour: "2-digit",
minute: "2-digit"
})
.replace(/.*à/, "");
} else if (event.end) {
dateString +=
"<br>Au " +
new Date(event.end).toLocaleDateString("fr-FR", {
weekday: "short",
year: "numeric",
month: "long",
day: "numeric",
hour: "2-digit",
minute: "2-digit"
});
}
}
return dateString;
}
}
};
//
</script>
<style>
@import "~leaflet.markercluster/dist/MarkerCluster.css";
@import "~leaflet.markercluster/dist/MarkerCluster.Default.css";
#app {
font-size: 13px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
margin: 0px;
padding: 0px;
}
#map {
height: 100vh;
width: 100vw;
}
.tag a {
color: #333 !important;
}
.title:hover h2 {
text-decoration: underline;
}
.leaflet-popup-content-wrapper {
padding: 0 !important;
}
div.leaflet-container {
font-size: 13px !important;
}
div.leaflet-container a.leaflet-popup-close-button {
font-size: 2em;
right: -12px;
top: -12px;
background: gray;
height: 24px;
width: 24px;
padding: 4px 0 0;
border-radius: 100%;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
color: whitesmoke !important;
transition: all 0.3s ease;
}
div.leaflet-container a.leaflet-popup-close-button:hover {
background-color: #f56565;
transform: scale(1.2);
}
.leaflet-popup-content {
margin: 0 !important;
}
div.marker-cluster span {
font-weight: bold;
opacity: 0.5;
}
</style>