forked from DGNum/metis
Merge pull request 'Export current view as a share link' (#34) from thubrecht/selection into master
Reviewed-on: https://git.rz.ens.wtf/Klub-RZ/metis/pulls/34
This commit is contained in:
commit
a837e7ef5d
2 changed files with 139 additions and 3 deletions
|
@ -14,6 +14,7 @@
|
||||||
import { mkSource, calendarTree, initialCalendars, getSubCalendars } from './calendar';
|
import { mkSource, calendarTree, initialCalendars, getSubCalendars } from './calendar';
|
||||||
import { debounce } from 'lodash';
|
import { debounce } from 'lodash';
|
||||||
import Help from './Help.svelte';
|
import Help from './Help.svelte';
|
||||||
|
import Share from './Share.svelte';
|
||||||
|
|
||||||
import 'bootstrap/dist/css/bootstrap.css';
|
import 'bootstrap/dist/css/bootstrap.css';
|
||||||
import 'bootstrap-icons/font/bootstrap-icons.css';
|
import 'bootstrap-icons/font/bootstrap-icons.css';
|
||||||
|
@ -36,7 +37,24 @@
|
||||||
return time.toLocaleTimeString();
|
return time.toLocaleTimeString();
|
||||||
})();
|
})();
|
||||||
|
|
||||||
const params = new URL(document.location).searchParams.getAll('c');
|
const allowedViews = [
|
||||||
|
'resourceTimelineDay',
|
||||||
|
'dayGridMonth',
|
||||||
|
'timeGridWeek',
|
||||||
|
'timeGridDay',
|
||||||
|
'listWeek'
|
||||||
|
];
|
||||||
|
|
||||||
|
let search = new URL(document.location).searchParams;
|
||||||
|
|
||||||
|
if (search.has('b64')) {
|
||||||
|
// On est dans le cas où les paramètres sont codés en base64
|
||||||
|
search = new URLSearchParams(window.atob(search.get('b64')));
|
||||||
|
}
|
||||||
|
|
||||||
|
const params = search.getAll('c');
|
||||||
|
const date = search.has('d') ? new Date(search.get('d')) : now;
|
||||||
|
const view = search.get('v');
|
||||||
|
|
||||||
const headers = mobile
|
const headers = mobile
|
||||||
? {
|
? {
|
||||||
|
@ -53,7 +71,12 @@
|
||||||
let calendar;
|
let calendar;
|
||||||
|
|
||||||
let options = writable({
|
let options = writable({
|
||||||
initialView: mobile ? 'listWeek' : 'timeGridWeek',
|
initialView: allowedViews.includes(view)
|
||||||
|
? view
|
||||||
|
: mobile
|
||||||
|
? 'listWeek'
|
||||||
|
: 'timeGridWeek',
|
||||||
|
initialDate: date.toString() === 'Invalid Date' ? now : date,
|
||||||
plugins: [
|
plugins: [
|
||||||
timeGridPlugin,
|
timeGridPlugin,
|
||||||
dayGridPlugin,
|
dayGridPlugin,
|
||||||
|
@ -67,7 +90,7 @@
|
||||||
allDayContent: '',
|
allDayContent: '',
|
||||||
headerToolbar: headers,
|
headerToolbar: headers,
|
||||||
buttonText: { resourceTimelineDay: 'Salles' },
|
buttonText: { resourceTimelineDay: 'Salles' },
|
||||||
scrollTime: "08:00:00",
|
scrollTime: '08:00:00',
|
||||||
resourceGroupField: 'building',
|
resourceGroupField: 'building',
|
||||||
resourceAreaWidth: '27%',
|
resourceAreaWidth: '27%',
|
||||||
resources: Object.entries(ENSLocations).flatMap(([building, rooms]) =>
|
resources: Object.entries(ENSLocations).flatMap(([building, rooms]) =>
|
||||||
|
@ -141,6 +164,7 @@
|
||||||
<div class="h-100 d-flex flex-column">
|
<div class="h-100 d-flex flex-column">
|
||||||
<h1 class="mt-3 title text-center">Calendrier de la vie étudiante à l'ENS</h1>
|
<h1 class="mt-3 title text-center">Calendrier de la vie étudiante à l'ENS</h1>
|
||||||
|
|
||||||
|
<Share {calendar} {selectedCalendars} />
|
||||||
<Help />
|
<Help />
|
||||||
|
|
||||||
<FilterBar {calendarTree} bind:selected={selectedCalendars} {initial} />
|
<FilterBar {calendarTree} bind:selected={selectedCalendars} {initial} />
|
||||||
|
|
112
src/Share.svelte
Normal file
112
src/Share.svelte
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
<script>
|
||||||
|
import { Modal, ModalHeader, ModalBody, ModalFooter, Icon, Toast } from 'sveltestrap';
|
||||||
|
|
||||||
|
export let calendar = null;
|
||||||
|
export let selectedCalendars = [];
|
||||||
|
|
||||||
|
let share = document.URL;
|
||||||
|
|
||||||
|
let isOpen = false;
|
||||||
|
let isToastOpen = false;
|
||||||
|
let isBinary = false;
|
||||||
|
|
||||||
|
let toastText = '';
|
||||||
|
|
||||||
|
const toggle = () => {
|
||||||
|
isOpen = !isOpen;
|
||||||
|
updateShareLink();
|
||||||
|
};
|
||||||
|
|
||||||
|
const doShare = () => {
|
||||||
|
navigator.clipboard
|
||||||
|
.writeText(share)
|
||||||
|
.then(() => (toastText = '<b>Lien de partage copié dans le presse-papier.</b>'))
|
||||||
|
.catch(() => (toastText = 'Erreur de copie automatique.'))
|
||||||
|
.finally((isToastOpen = true));
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateShareLink = () => {
|
||||||
|
const loc = document.location;
|
||||||
|
const search = new URLSearchParams();
|
||||||
|
const api = calendar.getAPI();
|
||||||
|
|
||||||
|
if (calendar !== null) {
|
||||||
|
search.append('v', api.view.type);
|
||||||
|
|
||||||
|
selectedCalendars.forEach(c => search.append('c', c));
|
||||||
|
|
||||||
|
search.append('d', api.getDate().toISOString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isBinary) {
|
||||||
|
const b64 = window.btoa(search.toString());
|
||||||
|
|
||||||
|
share = `${loc.origin}${loc.pathname}?b64=${b64}`;
|
||||||
|
} else {
|
||||||
|
share = `${loc.origin}${loc.pathname}${search.toString()}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleBinary = () => {
|
||||||
|
isBinary = !isBinary;
|
||||||
|
updateShareLink();
|
||||||
|
};
|
||||||
|
|
||||||
|
$: shareDataIcon = isBinary ? 'code-square' : 'code';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="share-toast">
|
||||||
|
<Toast autohide body isOpen={isToastOpen} on:close={() => (isToastOpen = false)}>
|
||||||
|
{@html toastText}
|
||||||
|
</Toast>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<span class="share-btn fs-4" data-bs-toggle="tooltip" title="Partager" on:click={toggle}>
|
||||||
|
<Icon name="share" />
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<Modal {isOpen} {toggle} centered scrollable>
|
||||||
|
<ModalHeader {toggle}>
|
||||||
|
<Icon name="share" class="text-success me-2" />
|
||||||
|
<b>Partage</b>
|
||||||
|
</ModalHeader>
|
||||||
|
|
||||||
|
<ModalBody>
|
||||||
|
<p>La vue actuelle du calendrier peut être partagée avec l'URL suivante :</p>
|
||||||
|
|
||||||
|
<a id="share-url" on:click={doShare}>{share}</a>
|
||||||
|
</ModalBody>
|
||||||
|
|
||||||
|
<ModalFooter>
|
||||||
|
<span on:click={toggleBinary} class="flex-grow-1" title="Partager en base64">
|
||||||
|
<Icon name={shareDataIcon} class="fs-5" />
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<Icon name="balloon-heart" class="text-danger fs-5" />
|
||||||
|
<span class="fs-7">Propulsé par le Club Réseau de l'ENS</span>
|
||||||
|
</ModalFooter>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.share-btn {
|
||||||
|
position: absolute;
|
||||||
|
top: 2.5em;
|
||||||
|
right: 1em;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#share-url {
|
||||||
|
max-width: 100%;
|
||||||
|
display: block;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share-toast {
|
||||||
|
position: absolute;
|
||||||
|
top: 1.25em;
|
||||||
|
left: 1em;
|
||||||
|
z-index: 1100;
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in a new issue