Initial prototype

This commit is contained in:
2022-09-06 11:17:58 +02:00
commit 639d5e1abe
12 changed files with 63519 additions and 0 deletions
+222
View File
@@ -0,0 +1,222 @@
//
// Modes
//
import { differenceInMinutes, format, getWeek, startOfDay } from 'date-fns'
import { it } from 'date-fns/locale'
import _ from 'lodash'
import { useEffect, useRef } from 'preact/hooks'
import { layoutIntervals } from '../interval-layout.js'
function hashString(str, seed = 0) {
let h1 = 0xdeadbeef ^ seed,
h2 = 0x41c6ce57 ^ seed
for (let i = 0, ch; i < str.length; i++) {
ch = str.charCodeAt(i)
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)
return 4294967296 * (2097151 & h2) + (h1 >>> 0)
}
const WorkWeekView = ({ events }) => {
const eventsByWeekday = _.groupBy(events, event => event.start.getDay())
// For each weekday compute the interval layout
const rowLayouts = _.mapValues(eventsByWeekday, events =>
layoutIntervals(
events.map(e => ({
start: differenceInMinutes(e.start, startOfDay(e.start)),
end: differenceInMinutes(e.end, startOfDay(e.start)),
data: e,
}))
)
)
console.log(rowLayouts)
const weekDays = ['Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì']
return (
<div class="workweek-view">
<div class="week">
{weekDays.map((label, index) => (
<div class="day" style={{ '--size': rowLayouts[index + 1]?.length ?? 0 }}>
{label}
</div>
))}
</div>
<div class="events">
<div class="header">
<div class="label" style={{ 'grid-column': '2 / span 2' }}>
9:00 &ndash; 11:00
</div>
<div class="label" style={{ 'grid-column': '4 / span 2' }}>
11:00 &ndash; 13:00
</div>
<div class="label" style={{ 'grid-column': '7 / span 2' }}>
14:00 &ndash; 16:00
</div>
<div class="label" style={{ 'grid-column': '9 / span 2' }}>
16:00 &ndash; 18:00
</div>
</div>
<div class="days">
{Object.values(rowLayouts).map(layout => (
<div class="day" style={{ '--size': layout.length }}>
{layout.map((events, rowIndex) =>
events.map(event => {
const Local = () => {
const eventRef = useRef()
const updateMinWidth = () => {
eventRef.current.style.minWidth =
eventRef.current.offsetWidth + 'px'
}
useEffect(() => {
if (eventRef.current) {
setTimeout(updateMinWidth, 100)
window.addEventListener('resize', updateMinWidth)
return () => {
window.removeEventListener(
'resize',
updateMinWidth
)
}
}
}, [eventRef.current])
return (
<div
class="event"
style={{
'--row': rowIndex + 1,
'--start': event.start / 60 - 7,
'--size': (event.end - event.start) / 60,
'--hue':
(Math.abs(
hashString('seed3' + event.data.name)
) %
360) +
'deg',
}}
ref={eventRef}
>
{_.startCase(_.lowerCase(event.data.name))
.replaceAll('Ii', 'II')
.replaceAll('Iii', 'III')
.replaceAll(/\bE\b/g, 'e')}
</div>
)
}
return <Local />
})
)}
</div>
))}
</div>
</div>
</div>
)
}
/*
{sortedKeys.map(blockStart => (
<div
class="stacked"
style={{
'--start':
differenceInMinutes(
stacked[blockStart][0].start,
startOfDay(stacked[blockStart][0].start)
) -
60 * 8,
}}
>
{stacked[blockStart].map(event => (
<Event {...event} />
))}
</div>
))}
{Object.values(eventsByWeekday).map(dayEvents => {
return (
<div class="day">
{dayEvents.map(({ name, start, end }) => {
return (
<div
class="event"
style={{
'--hue':
(Math.abs(hashString('seed3' + name)) % 360) +
'deg',
'--start':
differenceInMinutes(start, startOfDay(start)) -
60 * 8,
'--size': differenceInMinutes(end, start),
}}
>
{_.startCase(_.lowerCase(name))
.replaceAll('Ii', 'II')
.replaceAll('Iii', 'III')}
</div>
)
})}
</div>
)
})}
*/
const CourseView = ({ events }) => {
const eventsByCourse = _.groupBy(events, 'name')
return (
<div class="course-view">
<div class="wrap-container">
{Object.entries(eventsByCourse).map(([name, courseEvents]) => (
<div class="course">
<div class="title">
{_.startCase(_.lowerCase(name))
.replaceAll('Ii', 'II')
.replaceAll('Iii', 'III')}
</div>
<div class="docenti">{courseEvents[0].docenti.join(', ')}</div>
<div class="events">
{courseEvents.map(course => (
<div class="event">
{_.capitalize(format(course.start, 'EEEE', { locale: it }))}{' '}
{format(course.start, 'H:mm')} &ndash;
{format(course.end, 'H:mm')} {course.aula}
</div>
))}
</div>
</div>
))}
</div>
</div>
)
}
//
// EventsView
//
const viewModeMap = {
'work-week': WorkWeekView,
'course': CourseView,
}
export const EventsView = ({ mode, ...viewProps }) => {
const Mode = viewModeMap[mode]
return (
<div class="events-view">
<Mode {...viewProps} />
</div>
)
}
+1
View File
@@ -0,0 +1 @@
export const Icon = ({ name }) => <span class="material-symbols-outlined">{name}</span>
+28
View File
@@ -0,0 +1,28 @@
export const Toolbar = ({ mode, setMode }) => {
return (
<div class="toolbar">
<div class="item logo">PHC / Orari</div>
<div class="options">
<div class="item option">
<div class="compound">
<button
class={'radio' + (mode === 'course' ? ' selected' : '')}
onClick={() => setMode('course')}
>
Corso
</button>
<button
class={'radio' + (mode === 'work-week' ? ' selected' : '')}
onClick={() => setMode('work-week')}
>
Settimana
</button>
</div>
</div>
<div class="item option">Opzione 2</div>
<div class="item option">Opzione 3</div>
<div class="item option">Opzione 4</div>
</div>
</div>
)
}