316 lines
8.8 KiB
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>
|