Minimal working prototype, no mobile, no printing
This commit is contained in:
+81
@@ -0,0 +1,81 @@
|
||||
[
|
||||
"ANALISI ARMONICA - ANALISI ARMONICA/a",
|
||||
"ANALISI MATEMATICA 3",
|
||||
"ASPETTI MATEMATICI NELLA COMPUTAZIONE QUANTISTICA",
|
||||
"CALCOLO SCIENTIFICO",
|
||||
"COMBINATORIA ALGEBRICA",
|
||||
"DETERMINAZIONE ORBITALE",
|
||||
"DINAMICA DEL SISTEMA SOLARE",
|
||||
"DINAMICA DEL SISTEMA SOLARE",
|
||||
"ELEMENTI DI GEOMETRIA ALGEBRICA",
|
||||
"ELEMENTI DI GEOMETRIA ALGEBRICA",
|
||||
"ELEMENTI DI GEOMETRIA ALGEBRICA",
|
||||
"ELEMENTI DI GEOMETRIA ALGEBRICA",
|
||||
"ELEMENTI DI TOPOLOGIA ALGEBRICA",
|
||||
"ELEMENTI DI TOPOLOGIA ALGEBRICA",
|
||||
"ELEMENTI DI TOPOLOGIA ALGEBRICA",
|
||||
"ELEMENTI DI TOPOLOGIA ALGEBRICA",
|
||||
"FISICA II",
|
||||
"FISICA II",
|
||||
"FISICA II",
|
||||
"FISICA II",
|
||||
"FISICA II",
|
||||
"FISICA II",
|
||||
"FISICA II",
|
||||
"FISICA II",
|
||||
"GEOMETRIA E TOPOLOGIA DIFFERENZIALE",
|
||||
"GEOMETRIA E TOPOLOGIA DIFFERENZIALE",
|
||||
"GEOMETRIA E TOPOLOGIA DIFFERENZIALE",
|
||||
"GEOMETRIA E TOPOLOGIA DIFFERENZIALE",
|
||||
"GEOMETRIA E TOPOLOGIA DIFFERENZIALE",
|
||||
"GEOMETRIA E TOPOLOGIA DIFFERENZIALE",
|
||||
"ISTITUZIONI DI ALGEBRA",
|
||||
"ISTITUZIONI DI ALGEBRA",
|
||||
"ISTITUZIONI DI ANALISI MATEMATICA",
|
||||
"ISTITUZIONI DI ANALISI MATEMATICA",
|
||||
"ISTITUZIONI DI ANALISI MATEMATICA",
|
||||
"ISTITUZIONI DI DIDATTICA DELLA MATEMATICA",
|
||||
"ISTITUZIONI DI DIDATTICA DELLA MATEMATICA",
|
||||
"ISTITUZIONI DI DIDATTICA DELLA MATEMATICA",
|
||||
"ISTITUZIONI DI FISICA MATEMATICA",
|
||||
"ISTITUZIONI DI FISICA MATEMATICA",
|
||||
"LABORATORIO COMPUTAZIONALE",
|
||||
"LOGICA MATEMATICA",
|
||||
"LOGICA MATEMATICA",
|
||||
"LOGICA MATEMATICA",
|
||||
"LOGICA MATEMATICA",
|
||||
"MECCANICA SUPERIORE - MECCANICA SUPERIORE/a",
|
||||
"MECCANICA SUPERIORE - MECCANICA SUPERIORE/a",
|
||||
"METODI NUMERICI PER CATENE DI MARKOV - METODI NUMERICI PER CATENE DI MARKOV/a",
|
||||
"METODI NUMERICI PER CATENE DI MARKOV - METODI NUMERICI PER CATENE DI MARKOV/a",
|
||||
"METODI NUMERICI PER LA GRAFICA - METODI NUMERICI PER LA GRAFICA/a",
|
||||
"METODI NUMERICI PER LA GRAFICA - METODI NUMERICI PER LA GRAFICA/a",
|
||||
"PROBABILITÀ",
|
||||
"PROBABILITÀ",
|
||||
"PROBABILITÀ",
|
||||
"PROBABILITÀ",
|
||||
"PROBABILITÀ",
|
||||
"PROBABILITÀ",
|
||||
"RICERCA OPERATIVA",
|
||||
"RICERCA OPERATIVA",
|
||||
"RICERCA OPERATIVA",
|
||||
"RICERCA OPERATIVA",
|
||||
"RICERCA OPERATIVA",
|
||||
"RICERCA OPERATIVA",
|
||||
"SISTEMI DINAMICI",
|
||||
"SISTEMI DINAMICI",
|
||||
"SISTEMI DINAMICI",
|
||||
"SISTEMI DINAMICI",
|
||||
"STORIA DELLA MATEMATICA",
|
||||
"STORIA DELLA MATEMATICA",
|
||||
"STORIA DELLA MATEMATICA",
|
||||
"STORIA DELLA MATEMATICA",
|
||||
"TECNOLOGIE PER LA DIDATTICA",
|
||||
"TECNOLOGIE PER LA DIDATTICA",
|
||||
"TEORIA ANALITICA DEI NUMERI A - TEORIA ANALITICA DEI NUMERI A/a",
|
||||
"TEORIA ANALITICA DEI NUMERI A - TEORIA ANALITICA DEI NUMERI A/a",
|
||||
"TEORIA E METODI DELL'OTTIMIZZAZIONE",
|
||||
"TEORIA E METODI DELL'OTTIMIZZAZIONE",
|
||||
"TOPOLOGIA DIFFERENZIALE - TOPOLOGIA DIFFERENZIALE/a",
|
||||
"TOPOLOGIA DIFFERENZIALE - TOPOLOGIA DIFFERENZIALE/a"
|
||||
]
|
||||
@@ -0,0 +1,25 @@
|
||||
// import { createContext } from 'preact'
|
||||
// import { toChildArray } from 'preact'
|
||||
// import { useContext, useState } from 'preact/hooks'
|
||||
|
||||
// const AnimationContext = createContext()
|
||||
|
||||
// export const useAnimation = animation => {
|
||||
// const [styles, setStyles] = useState({})
|
||||
|
||||
// const start = () => {
|
||||
// setStyles({ animation })
|
||||
// }
|
||||
|
||||
// return [
|
||||
// start,
|
||||
// {
|
||||
// styles,
|
||||
// onAnimationEnd: e => {
|
||||
// console.log('animation end')
|
||||
// },
|
||||
// },
|
||||
// ]
|
||||
// }
|
||||
|
||||
// export const Animation = ({ animation, children }) => {}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { useRef } from 'preact/hooks'
|
||||
import { Icon } from './Icon.jsx'
|
||||
|
||||
export const ComboBox = ({ selected, options }) => {
|
||||
const selectRef = useRef()
|
||||
|
||||
return (
|
||||
<div class="input-combo" onClick={() => selectRef.current?.click()}>
|
||||
<select ref={selectRef}>
|
||||
{options.map(({ label, value }) => (
|
||||
<option value={value} selected={value === selected}>
|
||||
{label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<Icon name="expand_more" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import { Icon } from './Icon.jsx'
|
||||
export const ToolOverlay = ({ visibility, toggleVisibility, onClose }) => (
|
||||
<div class="overlay">
|
||||
<button class="icon primary" onClick={toggleVisibility}>
|
||||
<Icon name={visibility ? 'visibility' : 'visibility_off'} />
|
||||
<Icon name={visibility ? 'visibility_off' : 'visibility'} />
|
||||
</button>
|
||||
<button class="icon" onClick={onClose}>
|
||||
<Icon name="close" />
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Modes
|
||||
//
|
||||
|
||||
import { differenceInMinutes, format, getWeek, startOfDay } from 'date-fns'
|
||||
import { differenceInMinutes, format, startOfDay } from 'date-fns'
|
||||
import { it } from 'date-fns/locale'
|
||||
|
||||
import _ from 'lodash'
|
||||
@@ -22,6 +22,23 @@ function hashString(str, seed = 0) {
|
||||
return 4294967296 * (2097151 & h2) + (h1 >>> 0)
|
||||
}
|
||||
|
||||
function normalizeCourseName(name) {
|
||||
return name
|
||||
.split(' ')
|
||||
.map(word => word.toLowerCase())
|
||||
.map(word => {
|
||||
if (word.trim().length === 0) return word
|
||||
|
||||
return /(^del|^nel|^di$|^dei$|^con$|^alla$|^per$|^e$|^la$)/.test(word)
|
||||
? word
|
||||
: word[0].toUpperCase() + word.slice(1)
|
||||
})
|
||||
.join(' ')
|
||||
.replaceAll('Ii', 'II')
|
||||
.replaceAll('Iii', 'III')
|
||||
.replaceAll(/'(.)/g, ({}, letter) => "'" + letter.toUpperCase())
|
||||
}
|
||||
|
||||
const WorkWeekView = ({ events }) => {
|
||||
const eventsByWeekday = _.groupBy(events, event => event.start.getDay())
|
||||
|
||||
@@ -105,10 +122,7 @@ const WorkWeekView = ({ events }) => {
|
||||
}}
|
||||
ref={eventRef}
|
||||
>
|
||||
{_.startCase(_.lowerCase(event.data.name))
|
||||
.replaceAll('Ii', 'II')
|
||||
.replaceAll('Iii', 'III')
|
||||
.replaceAll(/\bE\b/g, 'e')}
|
||||
{normalizeCourseName(event.data.name)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -159,9 +173,11 @@ const WorkWeekVerticalView = ({ events, selection, setSelection, hideOtherCourse
|
||||
}
|
||||
|
||||
element.current.addEventListener('mousemove', l)
|
||||
element.current.addEventListener('mouseleave', l)
|
||||
|
||||
return () => {
|
||||
element.current.removeEventListener('mousemove', l)
|
||||
element.current.removeEventListener('mouseleave', l)
|
||||
}
|
||||
}
|
||||
}, [element.current])
|
||||
@@ -246,10 +262,7 @@ const WorkWeekVerticalView = ({ events, selection, setSelection, hideOtherCourse
|
||||
}}
|
||||
>
|
||||
<div class="title">
|
||||
{_.startCase(_.lowerCase(event.data.name))
|
||||
.replaceAll('Ii', 'II')
|
||||
.replaceAll('Iii', 'III')
|
||||
.replaceAll(/\bE\b/g, 'e')}
|
||||
{normalizeCourseName(event.data.name)}
|
||||
</div>
|
||||
<div class="aula">{event.data.aula}</div>
|
||||
</div>
|
||||
@@ -274,10 +287,9 @@ const WorkWeekVerticalView = ({ events, selection, setSelection, hideOtherCourse
|
||||
const CourseView = ({ events, selection, setSelection, hideOtherCourses }) => {
|
||||
const selectionSet = new Set(selection)
|
||||
|
||||
const eventsByCourse = _.groupBy(
|
||||
!hideOtherCourses ? events : events.filter(e => selectionSet.has(e.name)),
|
||||
'name'
|
||||
)
|
||||
const visibleEvents = !hideOtherCourses ? events : events.filter(e => selectionSet.has(e.name))
|
||||
|
||||
const eventsByCourse = _.groupBy(_.sortBy(visibleEvents, 'name'), 'name')
|
||||
|
||||
const [currentlyHovered, setCurrentlyHovered] = useState(null)
|
||||
const element = useRef()
|
||||
@@ -294,9 +306,11 @@ const CourseView = ({ events, selection, setSelection, hideOtherCourses }) => {
|
||||
}
|
||||
|
||||
element.current.addEventListener('mousemove', l)
|
||||
element.current.addEventListener('mouseleave', l)
|
||||
|
||||
return () => {
|
||||
element.current.removeEventListener('mousemove', l)
|
||||
element.current.removeEventListener('mouseleave', l)
|
||||
}
|
||||
}
|
||||
}, [element.current])
|
||||
@@ -317,12 +331,7 @@ const CourseView = ({ events, selection, setSelection, hideOtherCourses }) => {
|
||||
else setSelection(selection.filter(n => n !== name))
|
||||
}}
|
||||
>
|
||||
<div class="title">
|
||||
{_.startCase(_.lowerCase(name))
|
||||
.replaceAll('Ii', 'II')
|
||||
.replaceAll('Iii', 'III')
|
||||
.replaceAll(/\bE\b/g, 'e')}
|
||||
</div>
|
||||
<div class="title">{normalizeCourseName(name)}</div>
|
||||
<div class="docenti">{courseEvents[0].docenti.join(', ')}</div>
|
||||
<div class="events">
|
||||
{courseEvents.map(course => (
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { ComboBox } from './ComboBox.jsx'
|
||||
import { Icon } from './Icon.jsx'
|
||||
|
||||
export const HamburgerMenu = ({ onClose }) => {
|
||||
return (
|
||||
<div class="menu">
|
||||
<div class="header">
|
||||
<button class="flat icon" onClick={onClose}>
|
||||
<Icon name="close" />
|
||||
</button>
|
||||
<div class="item logo">PHC / Orari</div>
|
||||
</div>
|
||||
<div class="options">
|
||||
<ComboBox
|
||||
selected={1}
|
||||
options={[
|
||||
{ label: 'Prova 1', value: 1 },
|
||||
{ label: 'Prova 2', value: 2 },
|
||||
{ label: 'Prova 3', value: 3 },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,10 +1,50 @@
|
||||
import { Icon } from './Icon.jsx'
|
||||
|
||||
export const Toolbar = ({ mode, setMode }) => {
|
||||
export const Toolbar = ({ mode, setMode, source, setSource, onShowMenu }) => {
|
||||
return (
|
||||
<div class="toolbar">
|
||||
<div class="mobile">
|
||||
<button class="flat icon" onClick={onShowMenu}>
|
||||
<Icon name="menu" />
|
||||
</button>
|
||||
</div>
|
||||
<div class="item logo">PHC / Orari</div>
|
||||
<div class="options">
|
||||
<div class="option-group">
|
||||
<div class="item option">
|
||||
<div class="compound">
|
||||
<button
|
||||
class={'radio' + (source === 'anno-1' ? ' selected' : '')}
|
||||
onClick={() => setSource('anno-1')}
|
||||
>
|
||||
I
|
||||
</button>
|
||||
<button
|
||||
class={'radio' + (source === 'anno-2' ? ' selected' : '')}
|
||||
onClick={() => setSource('anno-2')}
|
||||
>
|
||||
II
|
||||
</button>
|
||||
<button
|
||||
class={'radio' + (source === 'anno-3' ? ' selected' : '')}
|
||||
onClick={() => setSource('anno-3')}
|
||||
>
|
||||
III
|
||||
</button>
|
||||
<button
|
||||
class={'radio' + (source === 'magistrale' ? ' selected' : '')}
|
||||
onClick={() => setSource('magistrale')}
|
||||
>
|
||||
Magistrale
|
||||
</button>
|
||||
{/* TODO: Aggiungere il pulsante per "tutti" */}
|
||||
{/* <button
|
||||
class={'radio' + (source === 'tutti' ? ' selected' : '')}
|
||||
onClick={() => setSource('tutti')}
|
||||
>
|
||||
Tutti
|
||||
</button> */}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item option">
|
||||
<div class="compound">
|
||||
<button
|
||||
@@ -27,6 +67,8 @@ export const Toolbar = ({ mode, setMode }) => {
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="option-group">
|
||||
<div class="item option">
|
||||
<button class="icon">
|
||||
<Icon name="print" />
|
||||
|
||||
+67
-27
@@ -4,29 +4,57 @@ import { useEffect, useState } from 'preact/hooks'
|
||||
import { ToolOverlay } from './components/CourseVisibility.jsx'
|
||||
|
||||
import { EventsView } from './components/EventsView.jsx'
|
||||
import { HamburgerMenu } from './components/HamburgerMenu.jsx'
|
||||
import { Toolbar } from './components/Toolbar.jsx'
|
||||
|
||||
window._ = _
|
||||
window.dataBuffer = {}
|
||||
|
||||
const CALENDAR_IDS = {
|
||||
'anno-1': '6308cfcb1df5cb026699ce32',
|
||||
'anno-2': '6308e2dc09352a0208fefdd9',
|
||||
'anno-3': '6308e42a1df5cb026699ced4',
|
||||
'magistrale': '6308e8ea0c34e703bb1f7e85',
|
||||
}
|
||||
|
||||
const App = ({}) => {
|
||||
const [source, setSource] = useState('magistrale')
|
||||
|
||||
const [eventi, setEventi] = useState([])
|
||||
|
||||
const [selectedCourses, setSelectedCourses] = useState([])
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedCourses([])
|
||||
}, [source])
|
||||
|
||||
useEffect(() => {
|
||||
// Directly copy-pasted from chrome Dev Tools
|
||||
// const request = fetch(
|
||||
// 'https://apache.prod.up.cineca.it/api/Impegni/getImpegniCalendarioPubblico',
|
||||
// {
|
||||
// headers: {
|
||||
// 'content-type': 'application/json;charset=UTF-8',
|
||||
// 'sec-fetch-dest': 'empty',
|
||||
// 'sec-fetch-mode': 'cors',
|
||||
// 'sec-fetch-site': 'same-site',
|
||||
// },
|
||||
// body: '{"mostraImpegniAnnullati":true,"mostraIndisponibilitaTotali":false,"linkCalendarioId":"6308e8ea0c34e703bb1f7e85","clienteId":"628de8b9b63679f193b87046","pianificazioneTemplate":false,"dataInizio":"2022-10-02T22:00:00.000Z","dataFine":"2022-10-07T22:00:00.000Z"}',
|
||||
// method: 'POST',
|
||||
// mode: 'cors',
|
||||
// credentials: 'omit',
|
||||
// }
|
||||
// )
|
||||
const request = fetch(
|
||||
'https://apache.prod.up.cineca.it/api/Impegni/getImpegniCalendarioPubblico',
|
||||
{
|
||||
headers: {
|
||||
'content-type': 'application/json;charset=UTF-8',
|
||||
'sec-fetch-dest': 'empty',
|
||||
'sec-fetch-mode': 'cors',
|
||||
'sec-fetch-site': 'same-site',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
mostraImpegniAnnullati: true,
|
||||
mostraIndisponibilitaTotali: false,
|
||||
linkCalendarioId: CALENDAR_IDS[source],
|
||||
clienteId: '628de8b9b63679f193b87046',
|
||||
pianificazioneTemplate: false,
|
||||
dataInizio: '2022-10-02T22:00:00.000Z',
|
||||
dataFine: '2022-10-07T22:00:00.000Z',
|
||||
}),
|
||||
method: 'POST',
|
||||
mode: 'cors',
|
||||
credentials: 'omit',
|
||||
}
|
||||
)
|
||||
|
||||
const request = fetch('/data.json')
|
||||
// const request = fetch('/data.json')
|
||||
|
||||
console.time('loading eventi')
|
||||
|
||||
@@ -34,28 +62,33 @@ const App = ({}) => {
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
console.timeEnd('loading eventi')
|
||||
window.data = data
|
||||
window.dataBuffer[source] = data
|
||||
setEventi(data)
|
||||
})
|
||||
}, [])
|
||||
}, [source])
|
||||
|
||||
const [mode, setMode] = useState('course')
|
||||
|
||||
const [hideOtherCourses, setHideOtherCourses] = useState(false)
|
||||
|
||||
console.log(hideOtherCourses)
|
||||
// TODO: Should wrap in "useEffect"?
|
||||
if (selectedCourses.length === 0) {
|
||||
setHideOtherCourses(false)
|
||||
}
|
||||
|
||||
const [selectedCourses, setSelectedCourses] = useState([])
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedCourses.length === 0) {
|
||||
setHideOtherCourses(false)
|
||||
}
|
||||
}, [selectedCourses])
|
||||
const [showMobileMenu, setShowMobileMenu] = useState(true)
|
||||
|
||||
return (
|
||||
<>
|
||||
<Toolbar {...{ mode, setMode }} />
|
||||
<Toolbar
|
||||
{...{
|
||||
mode,
|
||||
setMode,
|
||||
source,
|
||||
setSource,
|
||||
onShowMenu: () => setShowMobileMenu(true),
|
||||
}}
|
||||
/>
|
||||
<EventsView
|
||||
mode={mode}
|
||||
selection={selectedCourses}
|
||||
@@ -85,6 +118,13 @@ const App = ({}) => {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{showMobileMenu && (
|
||||
<HamburgerMenu
|
||||
onClose={() => {
|
||||
setShowMobileMenu(false)
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
+125
-8
@@ -47,7 +47,8 @@ code {
|
||||
}
|
||||
|
||||
sup {
|
||||
padding-bottom: 0.5rem;
|
||||
display: inline-block;
|
||||
transform: translate(0, -0.25rem);
|
||||
}
|
||||
|
||||
button,
|
||||
@@ -95,6 +96,38 @@ button,
|
||||
}
|
||||
}
|
||||
|
||||
.input-combo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
height: 3rem;
|
||||
|
||||
background: var(--gray-000);
|
||||
border: 2px solid var(--gray-350);
|
||||
border-radius: 0.5rem;
|
||||
|
||||
font-weight: 400;
|
||||
|
||||
padding: 0.5rem 0.5rem 0.5rem 1rem;
|
||||
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
|
||||
position: relative;
|
||||
|
||||
gap: 0.5rem;
|
||||
|
||||
select {
|
||||
border: none;
|
||||
background: none;
|
||||
appearance: none;
|
||||
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
// Components
|
||||
|
||||
.compound {
|
||||
@@ -108,6 +141,8 @@ button,
|
||||
padding-left: 0.75rem;
|
||||
padding-right: 0.75rem;
|
||||
|
||||
height: 2.5;
|
||||
|
||||
&:first-child {
|
||||
padding-left: 1rem;
|
||||
|
||||
@@ -160,6 +195,8 @@ body {
|
||||
.toolbar {
|
||||
@extend .panel;
|
||||
|
||||
padding: 1rem 0.5rem 1rem 1rem;
|
||||
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
border-bottom: 1px solid var(--gray-500);
|
||||
@@ -170,11 +207,11 @@ body {
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.options {
|
||||
.option-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
gap: 0.5rem;
|
||||
gap: 1rem;
|
||||
|
||||
@media screen and (max-width: $device-s-width) {
|
||||
display: none;
|
||||
@@ -197,11 +234,12 @@ body {
|
||||
overflow-y: scroll;
|
||||
|
||||
.wrap-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(30ch, 1fr));
|
||||
|
||||
gap: 1rem;
|
||||
|
||||
width: 100%;
|
||||
max-width: 1200px;
|
||||
|
||||
.course {
|
||||
@@ -414,6 +452,8 @@ body {
|
||||
|
||||
overflow: scroll;
|
||||
|
||||
--event-height: 4.25rem;
|
||||
|
||||
.pivot {
|
||||
height: 3rem;
|
||||
|
||||
@@ -452,7 +492,7 @@ body {
|
||||
.blocks {
|
||||
display: grid;
|
||||
|
||||
grid-template-rows: repeat(12, 6rem);
|
||||
grid-template-rows: repeat(12, calc(var(--event-height) + 1rem));
|
||||
|
||||
.block {
|
||||
grid-row: var(--start) / span var(--size);
|
||||
@@ -472,7 +512,7 @@ body {
|
||||
}
|
||||
|
||||
&:not(.skip-border) {
|
||||
height: calc(2 * 6rem + 1px);
|
||||
height: calc(2 * (var(--event-height) + 1rem) + 1px);
|
||||
border-bottom: 1px solid var(--gray-500);
|
||||
}
|
||||
}
|
||||
@@ -516,7 +556,7 @@ body {
|
||||
|
||||
display: grid;
|
||||
grid-template-columns: repeat(var(--size), auto);
|
||||
grid-template-rows: repeat(12, 5rem);
|
||||
grid-template-rows: repeat(12, var(--event-height));
|
||||
|
||||
padding: 0.5rem;
|
||||
|
||||
@@ -613,6 +653,83 @@ body {
|
||||
|
||||
box-shadow: 0 0.25rem 0.75rem #00000033;
|
||||
}
|
||||
|
||||
animation: fade-in 150ms ease-in forwards;
|
||||
}
|
||||
|
||||
// not on mobile
|
||||
@media screen and (min-width: $device-s-width) {
|
||||
.mobile {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.menu {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
// on mobile
|
||||
@media screen and (max-width: $device-s-width) {
|
||||
.toolbar {
|
||||
padding: 0.75rem 1rem 0.75rem 0.75rem;
|
||||
}
|
||||
|
||||
button {
|
||||
&.flat {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.menu {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
|
||||
background: var(--gray-000);
|
||||
|
||||
z-index: 10;
|
||||
|
||||
.header {
|
||||
height: 4rem;
|
||||
|
||||
padding: 0.75rem 1rem 0.75rem 0.75rem;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
border-bottom: 1px solid var(--gray-500);
|
||||
}
|
||||
|
||||
.options {
|
||||
padding: 1rem;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.fade-out {
|
||||
animation: fade-out 150ms ease-in forwards;
|
||||
}
|
||||
|
||||
@keyframes fade-out {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Utilities
|
||||
|
||||
Reference in New Issue
Block a user