feat: rework the UI
This commit is contained in:
parent
139d7b40b1
commit
7674dc956a
4 changed files with 115 additions and 27 deletions
35
package-lock.json
generated
35
package-lock.json
generated
|
@ -43,7 +43,6 @@
|
|||
"version": "5.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@fullcalendar/common/-/common-5.10.1.tgz",
|
||||
"integrity": "sha512-EumKIJcQTvQdTs75/9dmeREFgjcRVWzqHJS1Xvlz5mNsmB+w9EINCHETRjChtAQg1WD/lTQyVj4sHsKO7vCMSw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
|
@ -80,6 +79,15 @@
|
|||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"@fullcalendar/rrule": {
|
||||
"version": "5.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@fullcalendar/rrule/-/rrule-5.10.1.tgz",
|
||||
"integrity": "sha512-K5TO8298eVkZiJ70hZrAvAAP81aTMiymgPW1nnaOkflI4bvEDJlkGdFe1MqgE07oTBZca7VU7/33ePiSTs0Pcg==",
|
||||
"requires": {
|
||||
"@fullcalendar/common": "~5.10.1",
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"@fullcalendar/timegrid": {
|
||||
"version": "5.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@fullcalendar/timegrid/-/timegrid-5.10.1.tgz",
|
||||
|
@ -1339,6 +1347,12 @@
|
|||
"yallist": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"luxon": {
|
||||
"version": "1.28.0",
|
||||
"resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz",
|
||||
"integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==",
|
||||
"optional": true
|
||||
},
|
||||
"magic-string": {
|
||||
"version": "0.25.7",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
|
||||
|
@ -2209,6 +2223,22 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"rrule": {
|
||||
"version": "2.6.8",
|
||||
"resolved": "https://registry.npmjs.org/rrule/-/rrule-2.6.8.tgz",
|
||||
"integrity": "sha512-cUaXuUPrz9d1wdyzHsBfT1hptKlGgABeCINFXFvulEPqh9Np9BnF3C3lrv9uO54IIr8VDb58tsSF3LhsW+4VRw==",
|
||||
"requires": {
|
||||
"luxon": "^1.21.3",
|
||||
"tslib": "^1.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": {
|
||||
"version": "1.14.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
|
||||
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"sade": {
|
||||
"version": "1.7.4",
|
||||
"resolved": "https://registry.npmjs.org/sade/-/sade-1.7.4.tgz",
|
||||
|
@ -2582,8 +2612,7 @@
|
|||
"tslib": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
|
||||
},
|
||||
"undici": {
|
||||
"version": "4.14.1",
|
||||
|
|
|
@ -27,8 +27,10 @@
|
|||
"svelte-fullcalendar": "^1.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fullcalendar/rrule": "^5.10.1",
|
||||
"@nextcloud/cdav-library": "^1.0.0",
|
||||
"ical.js": "^1.5.0",
|
||||
"rrule": "^2.6.8",
|
||||
"sirv-cli": "^1.0.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,18 +2,26 @@
|
|||
import { onMount } from 'svelte';
|
||||
import FullCalendar from 'svelte-fullcalendar';
|
||||
import timeGridPlugin from '@fullcalendar/timegrid';
|
||||
import rrulePlugin from '@fullcalendar/rrule';
|
||||
import dayGridPlugin from '@fullcalendar/daygrid';
|
||||
import frLocale from '@fullcalendar/core/locales/fr';
|
||||
import { refreshEvents } from './calendar';
|
||||
import { refreshEvents, calendarTree } from './calendar';
|
||||
|
||||
let options = {
|
||||
initialView: 'timeGridWeek',
|
||||
plugins: [timeGridPlugin],
|
||||
plugins: [timeGridPlugin, dayGridPlugin, rrulePlugin],
|
||||
locale: frLocale,
|
||||
height: "100%",
|
||||
schedulerLicenseKey: 'CC-Attribution-NonCommercial-NoDerivatives',
|
||||
nowIndicator: true,
|
||||
now: new Date(),
|
||||
events: []
|
||||
};
|
||||
|
||||
let selectedCalendars;
|
||||
|
||||
onMount(async () => {
|
||||
const evts = await refreshEvents();
|
||||
const evts = await refreshEvents(selectedCalendars);
|
||||
options.events = evts.flat();
|
||||
options = { ...options };
|
||||
});
|
||||
|
@ -21,15 +29,15 @@
|
|||
$: console.log(options);
|
||||
</script>
|
||||
|
||||
<div style="height:100vh">
|
||||
<FullCalendar {options} />
|
||||
<div class="app-container">
|
||||
<h1 class="title">Calendrier de la vie étudiante à l'ENS</h1>
|
||||
<div style="height: 100%;">
|
||||
<!-- <FilterBar {calendarTree} {selectedCalendars}> -->
|
||||
<FullCalendar {options} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
body {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
main {
|
||||
text-align: center;
|
||||
padding: 1em;
|
||||
|
@ -37,11 +45,14 @@
|
|||
margin: 0 auto;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #ff3e00;
|
||||
text-transform: uppercase;
|
||||
font-size: 4em;
|
||||
font-weight: 100;
|
||||
.title {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.app-container {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
|
|
|
@ -1,9 +1,24 @@
|
|||
import ICAL from 'ical.js';
|
||||
|
||||
const calendarIds = [
|
||||
"5WrcagPPARQ3BD87",
|
||||
"TFEAKjAgNFQZpNjo"
|
||||
];
|
||||
const calendars = {
|
||||
"5WrcagPPARQ3BD87": {
|
||||
name: "Club réseau",
|
||||
color: null
|
||||
},
|
||||
"TFEAKjAgNFQZpNjo": {
|
||||
name: "hackENS",
|
||||
color: null
|
||||
}
|
||||
};
|
||||
|
||||
export const calendarTree = {
|
||||
"COF": [
|
||||
"Club réseau",
|
||||
"hackENS"
|
||||
]
|
||||
};
|
||||
|
||||
const calendarIds = Object.keys(calendars);
|
||||
|
||||
function mkCalendarUrl(id) {
|
||||
return `/cal/${id}/?export&accept=jcal`;
|
||||
|
@ -14,8 +29,10 @@ function fetchCalendar(id) {
|
|||
}
|
||||
|
||||
class Calendar {
|
||||
constructor (calendar) {
|
||||
this.calName = calendar[1][3][3];
|
||||
constructor (id, calendar) {
|
||||
const metadata = calendars[id];
|
||||
this.name = metadata.name;
|
||||
this.color = metadata.color || calendar[1][4][3];
|
||||
this.events = calendar[2].filter(item => item[0] === 'vevent').map(item => this._parse_vevent(item[1]));
|
||||
}
|
||||
|
||||
|
@ -28,11 +45,39 @@ class Calendar {
|
|||
}
|
||||
}
|
||||
|
||||
function fcEventFromjCalEvent(cal) {
|
||||
return function (evt) {
|
||||
const start = new Date(evt.dtstart);
|
||||
const end = new Date(evt.dtend);
|
||||
const fcEvent = {
|
||||
title: `${cal.name}: ${evt.summary}`,
|
||||
start,
|
||||
color: cal.color,
|
||||
duration: end - start // in ms
|
||||
};
|
||||
|
||||
if (evt.description) {
|
||||
fcEvent.description = evt.description;
|
||||
}
|
||||
|
||||
if (evt.rrule) {
|
||||
const { freq, byday } = evt.rrule;
|
||||
fcEvent.rrule = {
|
||||
freq,
|
||||
byweekday: byday,
|
||||
dtstart: evt.dtstart,
|
||||
};
|
||||
}
|
||||
|
||||
return fcEvent;
|
||||
}
|
||||
}
|
||||
|
||||
function mkEventsFromCalendar(id) {
|
||||
return fetchCalendar(id).then(calendar => {
|
||||
if (calendar[0] !== 'vcalendar') return;
|
||||
const cal = new Calendar(calendar)
|
||||
return cal.events.map(evt => ({ title: evt.summary, start: new Date(evt.dtstart), end: new Date(evt.dtend) }))
|
||||
const cal = new Calendar(id, calendar)
|
||||
return cal.events.map(fcEventFromjCalEvent(cal))
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -48,6 +93,7 @@ export function mkEvent(title, start, duration, ...rest) {
|
|||
}
|
||||
}
|
||||
|
||||
export function refreshEvents() {
|
||||
return Promise.all(calendarIds.map(mkEventsFromCalendar))
|
||||
// TODO: move to FullCalendar custom fetcher to control start&end.
|
||||
export function refreshEvents(selectedCalendars) {
|
||||
return Promise.all(calendarIds.filter(id => selectedCalendars ? selectedCalendars.includes(id) : true).map(mkEventsFromCalendar))
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue