Compare commits

..

2 Commits

Author SHA1 Message Date
Francesco Baldino 3ddf325c03 prototipo eventi custom 1 year ago
Francesco Baldino 973acad17a small fix on dynamic viewport height 1 year ago

@ -1,9 +0,0 @@
{
"printWidth": 90,
"singleQuote": true,
"quoteProps": "consistent",
"tabWidth": 4,
"semi": false,
"arrowParens": "avoid",
"proseWrap": "always"
}

@ -16,7 +16,8 @@
"lodash-es": "^4.17.21",
"preact": "^10.10.6",
"sass": "^1.54.8",
"vite": "^3.0.9"
"vite": "^3.0.9",
"yaml": "^2.3.2"
},
"devDependencies": {
"@babel/core": "^7.18.13",

@ -23,6 +23,9 @@ dependencies:
vite:
specifier: ^3.0.9
version: 3.0.9(sass@1.54.8)
yaml:
specifier: ^2.3.2
version: 2.3.2
devDependencies:
'@babel/core':
@ -937,3 +940,8 @@ packages:
sass: 1.54.8
optionalDependencies:
fsevents: 2.3.2
/yaml@2.3.2:
resolution: {integrity: sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==}
engines: {node: '>= 14'}
dev: false

@ -1,19 +1,12 @@
import { useRef } from 'preact/hooks'
import { Icon } from './Icon.jsx'
const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent)
export const DatePicker = ({ date, setDate }) => {
const input = useRef()
const [year, month, day] = date.split('T')[0].split('-')
return (
<div
class="date-picker"
onClick={() =>
isSafari ? input.current.focus() : input.current.showPicker()
}
>
<div class="date-picker" onClick={() => input.current.showPicker()}>
<input
ref={input}
type="date"

@ -24,6 +24,7 @@ const viewModeMap = {
export const EventsView = ({ mode, source, ...viewProps }) => {
// const Mode = viewModeMap[mode]
if (source === 'orario') {
return (

@ -4,31 +4,33 @@ export const Help = ({}) => (
<>
<h3>Visualizzazione Corsi</h3>
<p>
Per visualizzare i corsi che ti interessano nella tabella dell'orario, devi
prima selezionarli. Puoi selezionare dei corsi cliccandoli, cercandoli nelle
sezioni Primo anno (<b>I</b>), Secondo anno (<b>II</b>), Terzo anno (
<b>III</b>), Magistrale (<b>M</b>), o Tutti.
Per visualizzare i corsi che ti interessano nella tabella
dell'orario, devi prima selezionarli. Puoi selezionare dei corsi
cliccandoli, cercandoli nelle sezioni Primo anno (<b>I</b>), Secondo
anno (<b>II</b>), Terzo anno (<b>III</b>), Magistrale (<b>M</b>), o
Tutti.
</p>
<p>
Una volta compiuta la selezione, è possibile vedere la tabella delle lezioni
andando nella visualizzazione Orario (
Una volta compiuta la selezione, è possibile vedere la tabella delle
lezioni andando nella visualizzazione Orario (
<Icon name="calendar_view_month" />)
</p>
<p>
Per via di eventuali preferenze personali, è possibile cambiare l'orientazione
della tabella Orario trasponendola, utilizzando il pulsante Trasponi (
Per via di eventuali preferenze personali, è possibile cambiare
l'orientazione della tabella Orario trasponendola, utilizzando il
pulsante Trasponi (
<Icon name="switch_left" style="transform: rotate(-45deg)" />)
</p>
<p>
È anche possibile visualizzare in uno specchietto riassuntivo soltanto i corsi
selezionati, andando nella visualizzazione Lista (
È anche possibile visualizzare in uno specchietto riassuntivo
soltanto i corsi selezionati, andando nella visualizzazione Lista (
<Icon name="list" />)
</p>
<h3>Stampa</h3>
<p>
Da desktop puoi stampare l'orario attualmente visibile con il bottone{' '}
<Icon name="print" /> (è consigliato controllare le opzioni di stampa per
ottenere un risultato soddisfacente).
Da desktop puoi stampare l'orario attualmente visibile con il
bottone <Icon name="print" /> (è consigliato controllare le opzioni
di stampa per ottenere un risultato soddisfacente).
</p>
<h3>Bug &amp; Contatti</h3>
<p>

@ -7,9 +7,23 @@ export const SettingsBar = ({ theme, setTheme, date, setDate }) => {
<div class="settings-group">
<button
class="icon"
onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
onClick={() =>
setTheme(theme === 'dark' ? 'light' : 'dark')
}
>
<Icon name={theme === 'dark' ? 'dark_mode' : 'light_mode'} />
<Icon
name={theme === 'dark' ? 'dark_mode' : 'light_mode'}
/>
</button>
<button
class="icon"
onClick={() =>
setTheme(theme === 'dark' ? 'light' : 'dark')
}
>
<Icon
name="add"
/>
</button>
<DatePicker date={date} setDate={setDate} />
</div>

@ -24,7 +24,8 @@ export const Toolbar = ({
</button>
</div>
<div class="item logo">
<img src="logo-circuit-board.svg" alt="logo" /> / <span>Orario</span>
<img src="logo-circuit-board.svg" alt="logo" /> /{' '}
<span>Orario</span>
</div>
<div class="option-group">
<div class="item option">
@ -35,6 +36,7 @@ export const Toolbar = ({
{ value: 'anno-3', label: 'III' },
{ value: 'magistrale', label: 'Magistrale' },
{ value: 'tutti', label: 'Tutti' },
{ value: 'custom', label: 'Custom' },
]}
value={source}
setValue={setSource}
@ -50,9 +52,10 @@ export const Toolbar = ({
setValue={setSource}
/>
</div>
</div>
<div class="option-group">
<DatePicker date={date} setDate={setDate} />
<div class="empty"></div>
<div class="item option">
<DatePicker date={date} setDate={setDate} />
</div>
</div>
<div class="option-group">
<div class="item option">
@ -63,9 +66,13 @@ export const Toolbar = ({
<div class="item option">
<button
class="icon"
onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
onClick={() =>
setTheme(theme === 'dark' ? 'light' : 'dark')
}
>
<Icon name={theme === 'dark' ? 'dark_mode' : 'light_mode'} />
<Icon
name={theme === 'dark' ? 'dark_mode' : 'light_mode'}
/>
</button>
</div>
<div class="item option">

@ -2,7 +2,7 @@ import { format } from 'date-fns'
import _ from 'lodash'
import { useEffect, useRef, useState } from 'preact/hooks'
import { prettyCourseName, WEEK_DAYS } from '../../utils.jsx'
import { parseCustomEvents, prettyCourseName, WEEK_DAYS } from '../../utils.jsx'
import { Icon } from '../Icon.jsx'
export const Courses = ({
@ -10,13 +10,18 @@ export const Courses = ({
timetables,
selection,
setSelection,
hideOtherCourses,
custom,
isRestrictedList,
}) => {
const events = timetables[source]
const events = isRestrictedList ? timetables['tutti'] : timetables[source]
const selectionSet = new Set(selection)
const visibleEvents = hideOtherCourses
? events.filter(e => selectionSet.has(e.id))
console.log(events)
const visibleEvents = isRestrictedList
? events
.filter(e => selectionSet.has(e.id))
.concat(parseCustomEvents(custom))
: events
const eventsByCourse = _.groupBy(_.sortBy(visibleEvents, 'id'), 'id')
@ -53,7 +58,7 @@ export const Courses = ({
return (
<div class="course-view" ref={element}>
{hideOtherCourses && selection.length === 0 && (
{isRestrictedList && selection.length === 0 && (
<div class="warning">
<p>Non hai ancora selezionato nessun corso.</p>
<p>
@ -67,23 +72,39 @@ export const Courses = ({
<div
class={
'course' +
(currentlyHovered === id ? ' highlight' : '') +
(selectionSet.has(id) ? ' selected' : '')
(currentlyHovered === id && !isRestrictedList
? ' highlight'
: '') +
(selectionSet.has(id) && !isRestrictedList
? ' selected'
: '')
}
data-course-id={id}
onClick={() => {
if (!selectionSet.has(id)) setSelection([...selection, id])
else setSelection(selection.filter(selId => selId !== id))
if (isRestrictedList) return
if (!selectionSet.has(id))
setSelection([...selection, id])
else
setSelection(
selection.filter(selId => selId !== id)
)
}}
>
<div class="title">{prettyCourseName(courseEvents[0].name)}</div>
<div class="docenti">{profsPerCourse[id].join(', ')}</div>
<div class="title">
{prettyCourseName(courseEvents[0].name)}
</div>
<div class="docenti">
{profsPerCourse[id].join(', ')}
</div>
<div class="events">
{courseEvents.map(course => (
<div>
{WEEK_DAYS[course.start.getDay()]}{' '}
{format(course.start, 'H:mm')}&ndash;
{format(course.end, 'H:mm')} {course.aule.join(', ')}
{WEEK_DAYS[course.day]} {course.start / 60}:
{String(course.start % 60).padStart(2, '0')}
&ndash;
{course.end / 60}:
{String(course.end % 60).padStart(2, '0')}{' '}
{course.aule.join(', ')}
</div>
))}
</div>

@ -1,9 +1,15 @@
import { useEffect, useRef, useState } from 'preact/hooks'
import _ from 'lodash'
import _, { parseInt } from 'lodash'
import { differenceInMinutes, startOfDay } from 'date-fns'
import { parse } from 'yaml'
import { parseCustomEvents } from '../../utils.jsx'
import { WEEK_DAYS_SHORT, prettyCourseName, usePersistentState } from '../../utils.jsx'
import {
WEEK_DAYS_SHORT,
prettyCourseName,
usePersistentState,
} from '../../utils.jsx'
import { layoutEvents, layoutIntervals } from '../../interval-layout.js'
import { Popup } from '../Popup.jsx'
import { Icon } from '../Icon.jsx'
@ -13,23 +19,28 @@ const TransposePopup = ({ onClose }) => {
<Popup
title={
<>
<Icon name="info" /> Attenzione! La tabella è stata trasposta!
<Icon name="info" /> Attenzione! La tabella è stata
trasposta!
</>
}
onClose={onClose}
>
<p>A grande richiesta popolare abbiamo trasposto la tabella dell'orario!</p>
<p>
A grande richiesta popolare abbiamo trasposto la tabella
dell'orario!
</p>
<p>
Assicurati quindi di leggerla correttamente (dall'alto verso il basso
invece che da sinistra verso destra).
Assicurati quindi di leggerla correttamente (dall'alto verso il
basso invece che da sinistra verso destra).
</p>
<p>
Se preferisci utilizzare la versione vecchia, puoi utilizzare il pulsante
Trasponi <Icon name="switch_left" style="transform: rotate(-45deg)" />{' '}
nell'origine della tabella per trasporla. Questa scelta verrà salvata nei
cookie e verrà ricordata in futuro
Se preferisci utilizzare la versione vecchia, puoi utilizzare il
pulsante Trasponi{' '}
<Icon name="switch_left" style="transform: rotate(-45deg)" />{' '}
nell'origine della tabella per trasporla. Questa scelta verrà
salvata nei cookie e verrà ricordata in futuro
</p>
</Popup>
)
@ -40,8 +51,8 @@ const NoCourseWarning = () => {
<div class="warning">
<p>Non hai ancora selezionato nessun corso.</p>
<p>
Clicca sui corsi nelle altre visuali per selezionarli e visualizzarli
nell'orario
Clicca sui corsi nelle altre visuali per selezionarli e
visualizzarli nell'orario
</p>
</div>
)
@ -66,10 +77,13 @@ const Layout = ({ layout, day, colors }) => {
style={{
'--block-size': block.end - block.start,
'--size': event.end - event.start,
'--relative-start': event.start - block.start,
'--relative-start':
event.start - block.start,
'--index': event.index,
'--of': block.layers,
'--color': `var(--event-${colors[event.id]})`,
'--color': `var(--event-${
colors[event.id]
})`,
}}
>
<div class="event">
@ -106,11 +120,16 @@ const ScheduleGrid = ({
class="small"
onClick={() =>
setOrientation(
orientation === 'original' ? 'transposed' : 'original'
orientation === 'original'
? 'transposed'
: 'original'
)
}
>
<Icon name="switch_left" style="transform: rotate(-45deg)" />
<Icon
name="switch_left"
style="transform: rotate(-45deg)"
/>
</button>
</div>
{[1, 2, 3, 4, 5].map(n => (
@ -193,25 +212,30 @@ const ScheduleCard = ({
)
}
export const Schedule = ({ timetables, selection }) => {
export const Schedule = ({ timetables, selection, custom }) => {
const [hasSeenTranspose, setHasSeenTranspose] = usePersistentState(
'transpose_info',
'false'
)
const [orientation, setOrientation] = usePersistentState('orientation', 'original')
const [orientation, setOrientation] = usePersistentState(
'orientation',
'original'
)
const colorList = ['red', 'purple', 'blue', 'yellow', 'green', 'orange', 'lightblue']
const colorList = [
'red',
'purple',
'blue',
'yellow',
'green',
'orange',
'lightblue',
]
const allEvents = timetables['tutti']
const selectionSet = new Set(selection)
const events = allEvents
.filter(e => selectionSet.has(e.id))
.map(e => ({
...e,
day: e.start.getDay(),
start: differenceInMinutes(e.start, startOfDay(e.start)),
end: differenceInMinutes(e.end, startOfDay(e.start)),
}))
const events = allEvents.filter(e => selectionSet.has(e.id))
parseCustomEvents(custom).forEach(event => events.push(event))
const weekStart = Math.min(...events.map(e => e.start), 9 * 60) / 30
const weekEnd = Math.max(...events.map(e => e.end), 18 * 60) / 30

@ -42,7 +42,10 @@ function layoutBlockEvents(events) {
let viableIndex = 0
while (
result.filter(
e => e.index === viableIndex && e.start < event.end && event.start < e.end
e =>
e.index === viableIndex &&
e.start < event.end &&
event.start < e.end
).length !== 0
) {
viableIndex += 1
@ -54,7 +57,8 @@ function layoutBlockEvents(events) {
return result
}
export function layoutEvents(events) {
const overlap = (event, block) => event.start < block.end && block.start < event.end
const overlap = (event, block) =>
event.start < block.end && block.start < event.end
events.sort((a, b) => a.start - b.start)
@ -64,7 +68,10 @@ export function layoutEvents(events) {
if (blocks.length > 0) {
layout = layout.filter(block => !overlap(event, block))
layout.push({
start: Math.min(event.start, ...blocks.map(block => block.start)),
start: Math.min(
event.start,
...blocks.map(block => block.start)
),
end: Math.max(event.end, ...blocks.map(block => block.end)),
events: blocks.flatMap(block => block.events).concat([event]),
})

@ -1,6 +1,7 @@
import _ from 'lodash'
import { render } from 'preact'
import { useEffect, useState } from 'preact/hooks'
import { differenceInMinutes, startOfDay } from 'date-fns'
// import { ToolOverlay } from './components/ToolOverlay.jsx'
//
@ -18,12 +19,7 @@ import { Icon } from './components/Icon.jsx'
import { Popup } from './components/Popup.jsx'
import { Toolbar } from './components/Toolbar.jsx'
import { OptionBar } from './components/OptionBar.jsx'
import {
prettyAulaName,
prettyProfName,
clearOldPersistentStates,
usePersistentState,
} from './utils.jsx'
import { prettyAulaName, prettyProfName, usePersistentState } from './utils.jsx'
import { SettingsBar } from './components/SettingsBar.jsx'
// Che fanno queste due righe?
@ -31,10 +27,10 @@ window._ = _
window.dataBuffer = {}
const TIMETABLE_IDS = {
'anno-1': '667e88275e9623041f0e43d4',
'anno-2': '667e89055e9623041f0e43d6',
'anno-3': '667e89fcf748ed0415a11dcc',
'magistrale': '667ebae63379a3046517ffd4',
'anno-1': '64a7c1c651f079001d52e9c8',
'anno-2': '6308e2dc09352a0208fefdd9',
'anno-3': '6308e42a1df5cb026699ced4',
'magistrale': '64a7c7091ab813002c5d9ede',
}
// const DEFAULT_DATE_RANGE = {
@ -50,17 +46,15 @@ const TIMETABLE_IDS = {
// }
function specialEventPatches(eventi) {
// Il laboratorio del primo anno in realtà è in due gruppi separati
// Il laboratorio del primo anno in realtà è in due canali separati
let i = 1
eventi.forEach(evento => {
if (
evento.nome === 'LABORATORIO DI INTRODUZIONE ALLA MATEMATICA COMPUTAZIONALE'
evento.nome ===
'LABORATORIO DI INTRODUZIONE ALLA MATEMATICA COMPUTAZIONALE'
) {
if (evento.docenti[0].nome === 'GIOVANNI') {
evento.nome += ' (A)'
}
if (evento.docenti[0].nome === 'PAOLO') {
evento.nome += ' (B)'
}
evento.nome += ` (${i})`
i++
}
})
@ -69,12 +63,17 @@ function specialEventPatches(eventi) {
function formatEvents(timetable) {
return timetable.map(({ nome, dataInizio, dataFine, docenti, aule }) => {
const start = new Date(dataInizio)
const end = new Date(dataFine)
return {
id: nome,
name: _.split(nome, '-', 1)[0].trim(),
start: new Date(dataInizio),
end: new Date(dataFine),
docenti: docenti.map(({ nome, cognome }) => prettyProfName(nome, cognome)),
day: start.getDay(),
start: differenceInMinutes(start, startOfDay(start)),
end: differenceInMinutes(end, startOfDay(start)),
docenti: docenti.map(({ nome, cognome }) =>
prettyProfName(nome, cognome)
),
aule: aule.map(aula => prettyAulaName(aula.codice)),
}
})
@ -131,7 +130,7 @@ async function loadCalendari(date) {
const timetablesRaw = results.map(timetable =>
specialEventPatches(_.uniqBy(timetable, 'id'))
)
const allRaw = specialEventPatches(_.concat(...results), 'id')
const allRaw = specialEventPatches(_.uniqBy(_.concat(...results), 'id'))
return {
'anno-1': formatEvents(timetablesRaw[0]),
@ -142,19 +141,50 @@ async function loadCalendari(date) {
}
}
const View = ({ view, selection, setSelection, timetables }) => {
const View = ({
view,
selection,
setSelection,
timetables,
custom,
setCustom,
}) => {
if (view === 'orario') {
return <Schedule selection={selection} timetables={timetables} />
return (
<Schedule
selection={selection}
timetables={timetables}
custom={custom}
/>
)
} else if (view === 'lista') {
return (
<Courses
selection={selection}
setSelection={setSelection}
source={'tutti'}
timetables={timetables}
hideOtherCourses={true}
custom={custom}
isRestrictedList={true}
/>
)
} else if (view === 'custom') {
return (
<div class="custom-events-view">
<textarea
value={custom}
onChange={e => setCustom(e.target.value)}
/>
<p>Esempio di evento personalizzato</p>
<p>
Nome evento [label globale]:
<br />
- Lun 9-11
<br />
- Mar 9:00-11:00
<br />- Gio 8:00-12:00 [label locale]
</p>
</div>
)
} else {
return (
<Courses
@ -162,7 +192,7 @@ const View = ({ view, selection, setSelection, timetables }) => {
setSelection={setSelection}
source={view}
timetables={timetables}
hideOtherCourses={false}
isRestrictedList={false}
/>
)
}
@ -184,11 +214,14 @@ const App = ({}) => {
setTimetables(await loadCalendari(new Date(date)))
}, [date])
// View Modes
// const [mode, setMode] = usePersistentState('orario.mode', MODE_COURSES)
// Selection
const [selectedCourses, setSelectedCourses] = usePersistentState('selection', [])
const [selectedCourses, setSelectedCourses] = usePersistentState(
'selection',
[]
)
// Custom Events
const [custom, setCustom] = usePersistentState('custom', [])
// Menus
const [helpVisible, setHelpVisible] = useState(false)
@ -259,15 +292,16 @@ const App = ({}) => {
) : timetables['tutti'].length === 0 ? (
<div class="warning">
<p>
Non esistono corsi per la settimana selezionata: buone
vacanze! 🎉
Non esistono corsi per la settimana selezionata:
buone vacanze! 🎉
</p>
<p>
Per cambiare settimana puoi usare il widget Calendario (
Per cambiare settimana puoi usare il widget
Calendario (
<Icon name="calendar_month" />) in alto a destra
<br />
In versione mobile, il widget Calendario è situato dentro
il Menu (
In versione mobile, il widget Calendario è
situato dentro il Menu (
<Icon name="menu" />)
</p>
</div>
@ -277,6 +311,8 @@ const App = ({}) => {
setSelection={setSelectedCourses}
view={view}
timetables={timetables}
custom={custom}
setCustom={setCustom}
/>
))}
</div>

@ -530,9 +530,9 @@ body {
}
.content {
height: calc(100vh - 4rem);
height: calc(100dvh - 4rem);
@media screen and (max-width: $device-s-width), (pointer: coarse) {
height: calc(100vh - 8rem);
height: calc(100dvh - 8rem);
}
overflow-y: scroll;
@ -624,7 +624,7 @@ body {
.schedule-view {
min-height: 100%;
width: 100%;
max-width: 57rem;
max-width: 55rem;
margin: auto;
padding: 0rem 0.5rem;
@ -644,7 +644,8 @@ body {
border: 1px solid var(--border-600);
border-radius: 10px 10px 0 0;
@media screen and (max-width: $device-s-width), (pointer: coarse) {
@media screen and (max-width: $device-s-width),
(pointer: coarse) {
font-size: 12px;
}
@ -699,7 +700,10 @@ body {
&.original {
grid-template-columns: auto repeat(5, 1fr);
grid-template-rows: min-content repeat(var(--time-slots), 1fr);
grid-template-rows: min-content repeat(
var(--time-slots),
1fr
);
.transpose-button,
.day-label {
@ -726,16 +730,22 @@ body {
}
.event-block-wrapper {
grid-row: calc(var(--time-start) + 2) / calc(var(--time-end) + 2);
grid-row: calc(var(--time-start) + 2) /
calc(var(--time-end) + 2);
grid-column: calc(var(--day-position) + 1);
.event-block {
.event-wrapper {
width: calc(100% / var(--of));
height: calc(100% * var(--size) / var(--block-size));
height: calc(
100% * var(--size) / var(--block-size)
);
transform: translateX(calc(100% * var(--index)))
translateY(
calc(100% * var(--relative-start) / var(--size))
calc(
100% * var(--relative-start) /
var(--size)
)
);
}
}
@ -743,7 +753,10 @@ body {
}
&.transposed {
grid-template-rows: auto repeat(5, 1fr);
grid-template-columns: min-content repeat(var(--time-slots), 1fr);
grid-template-columns: min-content repeat(
var(--time-slots),
1fr
);
.transpose-button,
.day-label {
@ -779,10 +792,15 @@ body {
.event-block {
.event-wrapper {
height: calc(100% / var(--of));
width: calc(100% * var(--size) / var(--block-size));
width: calc(
100% * var(--size) / var(--block-size)
);
transform: translateY(calc(100% * var(--index)))
translateX(
calc(100% * var(--relative-start) / var(--size))
calc(
100% * var(--relative-start) /
var(--size)
)
);
}
}
@ -879,6 +897,27 @@ body {
overflow-y: scroll;
}
}
.custom-events-view {
min-height: 100%;
width: 100%;
max-width: 30rem;
margin: auto;
padding: 1rem 1rem;
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem;
textarea {
width: 100%;
min-height: 20rem;
font-size: 20px;
}
}
}
.overlay {

@ -1,6 +1,7 @@
// Calendar
import { useEffect, useState } from 'preact/hooks'
import { parse } from 'yaml'
// Calendar
export const WEEK_DAYS = [
'Domenica',
@ -24,8 +25,12 @@ export function hashString(str, seed = 0) {
h1 = Math.imul(h1 ^ ch, 2654435761)
h2 = Math.imul(h2 ^ ch, 1597334677)
}
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909)
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909)
h1 =
Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^
Math.imul(h2 ^ (h2 >>> 13), 3266489909)
h2 =
Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^
Math.imul(h1 ^ (h1 >>> 13), 3266489909)
return 4294967296 * (2097151 & h2) + (h1 >>> 0)
}
@ -38,7 +43,9 @@ export function prettyCourseName(name) {
.map(word => {
if (word.trim().length === 0) return word
return /(^del|^nel|^di$|^dei$|^con$|^alla$|^per$|^e$|^la$)/.test(word)
return /(^del|^nel|^di$|^dei$|^con$|^alla$|^per$|^e$|^la$)/.test(
word
)
? word
: word[0].toUpperCase() + word.slice(1)
})
@ -47,7 +54,6 @@ export function prettyCourseName(name) {
.replaceAll('IIi', 'III')
.replaceAll('Iii', 'III')
.replaceAll(/'(.)/g, ({}, letter) => "'" + letter.toUpperCase())
.replaceAll(/\((a|b)\)/g, ({}, letter) => '(' + letter.toUpperCase() + ')')
}
export function prettyAulaName(name) {
@ -64,6 +70,62 @@ export function prettyProfName(nome, cognome) {
.join('')
}
// Custom events
export function parseCustomEvents(customEventsString) {
try {
const customEvents = []
const parsedEvents = parse(customEventsString)
for (const customCourse in parsedEvents) {
const [_, name, teachers] = /([^\[]*)(?:\[(.*)\])?/.exec(
customCourse
)
const docenti = teachers ? teachers.split(',') : []
for (const customEvent of parsedEvents[customCourse]) {
const [_b, day, startH, startM, endH, endM, label] =
/(lun|lunedì|mar|martedì|mer|mercoledì|gio|giovedì|ven|venerdì)\s*(\d{1,2})(?:\:(\d\d))?\s*-\s*(\d{1,2})(?:\:(\d\d))?\s*(.*)?/i.exec(
customEvent
)
const dayNumber = {
lun: 1,
lunedì: 1,
mar: 2,
martedì: 2,
mer: 3,
mercoledì: 3,
gio: 4,
giovedì: 4,
ven: 5,
venerdì: 5,
}[day.toLowerCase()]
const start = startM
? parseInt(startH) * 60 + parseInt(startM)
: parseInt(startH) * 60
const end = endM
? parseInt(endH) * 60 + parseInt(endM)
: parseInt(endH) * 60
const aule = label ? label.split(',') : []
customEvents.push({
id: name,
name,
docenti,
start,
end,
day: dayNumber,
aule,
})
}
}
return customEvents
} catch (e) {
console.log('ehi', e)
return []
}
}
// JSX
export const withClasses = classes =>

Loading…
Cancel
Save