Merge pull request 'Fixed iOS date picker bug' (#14) from dev into main
Reviewed-on: #14
This commit was merged in pull request #14.
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"printWidth": 90,
|
||||
"singleQuote": true,
|
||||
"quoteProps": "consistent",
|
||||
"tabWidth": 4,
|
||||
"semi": false,
|
||||
"arrowParens": "avoid",
|
||||
"proseWrap": "always"
|
||||
}
|
||||
@@ -1,12 +1,19 @@
|
||||
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={() => input.current.showPicker()}>
|
||||
<div
|
||||
class="date-picker"
|
||||
onClick={() =>
|
||||
isSafari ? input.current.focus() : input.current.showPicker()
|
||||
}
|
||||
>
|
||||
<input
|
||||
ref={input}
|
||||
type="date"
|
||||
|
||||
@@ -24,7 +24,6 @@ const viewModeMap = {
|
||||
|
||||
export const EventsView = ({ mode, source, ...viewProps }) => {
|
||||
// const Mode = viewModeMap[mode]
|
||||
|
||||
|
||||
if (source === 'orario') {
|
||||
return (
|
||||
|
||||
+13
-15
@@ -4,33 +4,31 @@ 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 & Contatti</h3>
|
||||
<p>
|
||||
|
||||
@@ -7,13 +7,9 @@ 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>
|
||||
<DatePicker date={date} setDate={setDate} />
|
||||
</div>
|
||||
|
||||
@@ -24,8 +24,7 @@ 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">
|
||||
@@ -64,13 +63,9 @@ 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">
|
||||
|
||||
@@ -72,27 +72,18 @@ export const Courses = ({
|
||||
}
|
||||
data-course-id={id}
|
||||
onClick={() => {
|
||||
if (!selectionSet.has(id))
|
||||
setSelection([...selection, id])
|
||||
else
|
||||
setSelection(
|
||||
selection.filter(selId => selId !== id)
|
||||
)
|
||||
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')}–
|
||||
{format(course.end, 'H:mm')}{' '}
|
||||
{course.aule.join(', ')}
|
||||
{format(course.end, 'H:mm')} {course.aule.join(', ')}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
@@ -3,11 +3,7 @@ import { useEffect, useRef, useState } from 'preact/hooks'
|
||||
import _ from 'lodash'
|
||||
import { differenceInMinutes, startOfDay } from 'date-fns'
|
||||
|
||||
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'
|
||||
@@ -17,28 +13,23 @@ 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!
|
||||
Assicurati quindi di leggerla correttamente (dall'alto verso il basso
|
||||
invece che da sinistra verso destra).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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>
|
||||
)
|
||||
@@ -49,8 +40,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>
|
||||
)
|
||||
@@ -75,13 +66,10 @@ 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">
|
||||
@@ -118,16 +106,11 @@ 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 => (
|
||||
@@ -215,20 +198,9 @@ export const Schedule = ({ timetables, selection }) => {
|
||||
'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)
|
||||
|
||||
+3
-10
@@ -42,10 +42,7 @@ 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
|
||||
@@ -57,8 +54,7 @@ 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)
|
||||
|
||||
@@ -68,10 +64,7 @@ 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]),
|
||||
})
|
||||
|
||||
+8
-15
@@ -53,8 +53,7 @@ function specialEventPatches(eventi) {
|
||||
// Il laboratorio del primo anno in realtà è in due gruppi separati
|
||||
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)'
|
||||
@@ -75,9 +74,7 @@ function formatEvents(timetable) {
|
||||
name: _.split(nome, '-', 1)[0].trim(),
|
||||
start: new Date(dataInizio),
|
||||
end: new Date(dataFine),
|
||||
docenti: docenti.map(({ nome, cognome }) =>
|
||||
prettyProfName(nome, cognome)
|
||||
),
|
||||
docenti: docenti.map(({ nome, cognome }) => prettyProfName(nome, cognome)),
|
||||
aule: aule.map(aula => prettyAulaName(aula.codice)),
|
||||
}
|
||||
})
|
||||
@@ -191,10 +188,7 @@ const App = ({}) => {
|
||||
// const [mode, setMode] = usePersistentState('orario.mode', MODE_COURSES)
|
||||
|
||||
// Selection
|
||||
const [selectedCourses, setSelectedCourses] = usePersistentState(
|
||||
'selection',
|
||||
[]
|
||||
)
|
||||
const [selectedCourses, setSelectedCourses] = usePersistentState('selection', [])
|
||||
|
||||
// Menus
|
||||
const [helpVisible, setHelpVisible] = useState(false)
|
||||
@@ -265,16 +259,15 @@ 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>
|
||||
|
||||
+8
-26
@@ -644,8 +644,7 @@ 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;
|
||||
}
|
||||
|
||||
@@ -700,10 +699,7 @@ 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 {
|
||||
@@ -730,22 +726,16 @@ 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))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -753,10 +743,7 @@ 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 {
|
||||
@@ -792,15 +779,10 @@ 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))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+5
-19
@@ -12,15 +12,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
|
||||
|
||||
@@ -32,12 +24,8 @@ 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)
|
||||
}
|
||||
|
||||
@@ -50,9 +38,7 @@ 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)
|
||||
})
|
||||
@@ -61,7 +47,7 @@ export function prettyCourseName(name) {
|
||||
.replaceAll('IIi', 'III')
|
||||
.replaceAll('Iii', 'III')
|
||||
.replaceAll(/'(.)/g, ({}, letter) => "'" + letter.toUpperCase())
|
||||
.replaceAll(/\((a|b)\)/g, ({}, letter) => "(" + letter.toUpperCase() + ")")
|
||||
.replaceAll(/\((a|b)\)/g, ({}, letter) => '(' + letter.toUpperCase() + ')')
|
||||
}
|
||||
|
||||
export function prettyAulaName(name) {
|
||||
|
||||
Reference in New Issue
Block a user