Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ddf325c03 | ||
|
|
973acad17a |
+2
-1
@@ -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",
|
||||
|
||||
Generated
+8
@@ -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
|
||||
|
||||
@@ -15,6 +15,16 @@ export const SettingsBar = ({ theme, setTheme, date, setDate }) => {
|
||||
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>
|
||||
</div>
|
||||
|
||||
@@ -36,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}
|
||||
@@ -51,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">
|
||||
|
||||
@@ -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,11 +72,16 @@ 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 (isRestrictedList) return
|
||||
if (!selectionSet.has(id))
|
||||
setSelection([...selection, id])
|
||||
else
|
||||
@@ -89,9 +99,11 @@ export const Courses = ({
|
||||
<div class="events">
|
||||
{courseEvents.map(course => (
|
||||
<div>
|
||||
{WEEK_DAYS[course.start.getDay()]}{' '}
|
||||
{format(course.start, 'H:mm')}–
|
||||
{format(course.end, 'H:mm')}{' '}
|
||||
{WEEK_DAYS[course.day]} {course.start / 60}:
|
||||
{String(course.start % 60).padStart(2, '0')}
|
||||
–
|
||||
{course.end / 60}:
|
||||
{String(course.end % 60).padStart(2, '0')}{' '}
|
||||
{course.aule.join(', ')}
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
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,
|
||||
@@ -210,7 +212,7 @@ const ScheduleCard = ({
|
||||
)
|
||||
}
|
||||
|
||||
export const Schedule = ({ timetables, selection }) => {
|
||||
export const Schedule = ({ timetables, selection, custom }) => {
|
||||
const [hasSeenTranspose, setHasSeenTranspose] = usePersistentState(
|
||||
'transpose_info',
|
||||
'false'
|
||||
@@ -232,14 +234,8 @@ export const Schedule = ({ timetables, selection }) => {
|
||||
|
||||
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
|
||||
|
||||
+48
-16
@@ -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?
|
||||
@@ -67,11 +63,14 @@ 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),
|
||||
day: start.getDay(),
|
||||
start: differenceInMinutes(start, startOfDay(start)),
|
||||
end: differenceInMinutes(end, startOfDay(start)),
|
||||
docenti: docenti.map(({ nome, cognome }) =>
|
||||
prettyProfName(nome, cognome)
|
||||
),
|
||||
@@ -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,15 +214,15 @@ 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',
|
||||
[]
|
||||
)
|
||||
|
||||
// Custom Events
|
||||
const [custom, setCustom] = usePersistentState('custom', [])
|
||||
|
||||
// Menus
|
||||
const [helpVisible, setHelpVisible] = useState(false)
|
||||
const [showMobileMenu, setShowMobileMenu] = useState(false)
|
||||
@@ -281,6 +311,8 @@ const App = ({}) => {
|
||||
setSelection={setSelectedCourses}
|
||||
view={view}
|
||||
timetables={timetables}
|
||||
custom={custom}
|
||||
setCustom={setCustom}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
+24
-3
@@ -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;
|
||||
@@ -897,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 {
|
||||
|
||||
+60
-11
@@ -1,6 +1,7 @@
|
||||
// Calendar
|
||||
|
||||
import { useEffect, useState } from 'preact/hooks'
|
||||
import { parse } from 'yaml'
|
||||
|
||||
// Calendar
|
||||
|
||||
export const WEEK_DAYS = [
|
||||
'Domenica',
|
||||
@@ -12,15 +13,7 @@ export const WEEK_DAYS = [
|
||||
'Sabato',
|
||||
]
|
||||
|
||||
export const WEEK_DAYS_SHORT = [
|
||||
'Dom',
|
||||
'Lun',
|
||||
'Mar',
|
||||
'Mer',
|
||||
'Gio',
|
||||
'Ven',
|
||||
'Sab'
|
||||
]
|
||||
export const WEEK_DAYS_SHORT = ['Dom', 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab']
|
||||
|
||||
// Hashing
|
||||
|
||||
@@ -77,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 =>
|
||||
|
||||
Reference in New Issue
Block a user