Initial prototype
This commit is contained in:
@@ -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 – 11:00
|
||||
</div>
|
||||
<div class="label" style={{ 'grid-column': '4 / span 2' }}>
|
||||
11:00 – 13:00
|
||||
</div>
|
||||
<div class="label" style={{ 'grid-column': '7 / span 2' }}>
|
||||
14:00 – 16:00
|
||||
</div>
|
||||
<div class="label" style={{ 'grid-column': '9 / span 2' }}>
|
||||
16:00 – 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')} –
|
||||
{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>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export const Icon = ({ name }) => <span class="material-symbols-outlined">{name}</span>
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user