Added optionbar for mobile

pull/2/head
Francesco Baldino 2 years ago
parent 66b04ea7be
commit 19389dbee2

@ -4,57 +4,57 @@ import { Help } from './Help.jsx'
import { Icon } from './Icon.jsx'
export const HamburgerMenu = ({ onClose, mode, setMode, source, setSource, theme, setTheme }) => {
return (
<div class="menu">
<div class="header">
<div class="option-group">
<button class="flat icon" onClick={onClose}>
<Icon name="close" />
</button>
<button
class="icon"
onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
>
<Icon name={theme === 'dark' ? 'dark_mode' : 'light_mode'} />
</button>
</div>
<div class="item logo">
<img src="logo-circuit-board.svg" alt="logo" /> / <span>Orario</span>
</div>
</div>
<div class="options">
<div class="label">Gruppo Corsi</div>
<ComboBox
value={source}
setValue={setSource}
options={[
{ value: 'anno-1', label: 'I' },
{ value: 'anno-2', label: 'II' },
{ value: 'anno-3', label: 'III' },
{ value: 'magistrale', label: 'Magistrale' },
{ value: 'tutti', label: 'Tutti' },
]}
/>
<div class="label">Visualizzazione</div>
<ComboBox
value={mode}
setValue={setMode}
options={[
{ value: MODE_COURSE, label: 'Corsi' },
{ value: MODE_SCHEDULE, label: 'Giornaliera' },
{ value: MODE_WORKWEEK, label: 'Settimana' },
return (
<div class="menu">
<div class="header">
<div class="option-group">
<button class="flat icon" onClick={onClose}>
<Icon name="close" />
</button>
<button
class="icon"
onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
>
<Icon name={theme === 'dark' ? 'dark_mode' : 'light_mode'} />
</button>
</div>
<div class="item logo">
<img src="logo-circuit-board.svg" alt="logo" /> / <span>Orario</span>
</div>
</div>
{/* <div class="options">
<div class="label">Gruppo Corsi</div>
<ComboBox
value={source}
setValue={setSource}
options={[
{ value: 'anno-1', label: 'I' },
{ value: 'anno-2', label: 'II' },
{ value: 'anno-3', label: 'III' },
{ value: 'magistrale', label: 'Magistrale' },
{ value: 'tutti', label: 'Tutti' },
]}
/>
<div class="label">Visualizzazione</div>
<ComboBox
value={mode}
setValue={setMode}
options={[
{ value: MODE_COURSE, label: 'Corsi' },
{ value: MODE_SCHEDULE, label: 'Giornaliera' },
{ value: MODE_WORKWEEK, label: 'Settimana' },
{ value: MODE_WORKWEEK_GRID, label: 'Schema' },
]}
/>
</div>
<hr />
<div class="help">
<h2>
<Icon name="info" />
Guida
</h2>
<Help />
</div>
</div>
)
]}
/>
</div>
<hr /> */}
<div class="help">
<h2>
<Icon name="info" />
Guida
</h2>
<Help />
</div>
</div>
)
}

@ -0,0 +1,41 @@
import { CompoundButton } from './CompoundButton.jsx'
import { MODE_COURSE, MODE_SCHEDULE, MODE_WORKWEEK, MODE_WORKWEEK_GRID } from './EventsView.jsx'
import { Icon } from './Icon.jsx'
export const Optionbar = ({ mode, setMode, source, setSource, onHelp }) => {
return (
<div class="optionbar">
<div class="option-group">
<div class="item option">
<CompoundButton
options={[
{ value: 'anno-1', label: 'I' },
{ value: 'anno-2', label: 'II' },
{ value: 'anno-3', label: 'III' },
{ value: 'magistrale', label: 'M' },
{ value: 'tutti', label: <Icon name="apps" /> },
]}
value={source}
setValue={setSource}
/>
</div>
</div>
<div class="option-group">
<div class="item option">
<CompoundButton
options={[
{ value: MODE_COURSE, label: <Icon name="list" /> },
{
value: MODE_WORKWEEK_GRID,
label: <Icon name="calendar_view_month" />,
},
{ value: MODE_SCHEDULE, label: <Icon name="calendar_view_day" /> },
]}
value={mode}
setValue={setMode}
/>
</div>
</div>
</div>
)
}

@ -9,186 +9,196 @@ import { Help } from './components/Help.jsx'
import { Icon } from './components/Icon.jsx'
import { Popup } from './components/Popup.jsx'
import { Toolbar } from './components/Toolbar.jsx'
import { Optionbar } from './components/Optionbar.jsx'
window._ = _
window.dataBuffer = {}
const CALENDAR_IDS = {
'anno-1': ['6308cfcb1df5cb026699ce32'],
'anno-2': ['6308e2dc09352a0208fefdd9'],
'anno-3': ['6308e42a1df5cb026699ced4'],
'magistrale': ['6308e8ea0c34e703bb1f7e85'],
'tutti': [
'6308cfcb1df5cb026699ce32',
'6308e2dc09352a0208fefdd9',
'6308e42a1df5cb026699ced4',
'6308e8ea0c34e703bb1f7e85',
],
'anno-1': ['6308cfcb1df5cb026699ce32'],
'anno-2': ['6308e2dc09352a0208fefdd9'],
'anno-3': ['6308e42a1df5cb026699ced4'],
'magistrale': ['6308e8ea0c34e703bb1f7e85'],
'tutti': [
'6308cfcb1df5cb026699ce32',
'6308e2dc09352a0208fefdd9',
'6308e42a1df5cb026699ced4',
'6308e8ea0c34e703bb1f7e85',
],
}
async function loadEventi(ids) {
const calendari = await Promise.all(
ids.map(async id => {
// Almost directly copy-pasted from Chrome Dev Tools
const req = await 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: id,
clienteId: '628de8b9b63679f193b87046',
pianificazioneTemplate: false,
dataInizio: '2022-10-02T22:00:00.000Z',
dataFine: '2022-10-07T22:00:00.000Z',
}),
method: 'POST',
mode: 'cors',
credentials: 'omit',
}
)
return await req.json()
})
)
// console.log(calendari)
if (ids.length === 1) {
return calendari[0]
}
return _.uniqBy(_.concat(...calendari), 'id')
const calendari = await Promise.all(
ids.map(async id => {
// Almost directly copy-pasted from Chrome Dev Tools
const req = await 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: id,
clienteId: '628de8b9b63679f193b87046',
pianificazioneTemplate: false,
dataInizio: '2022-10-02T22:00:00.000Z',
dataFine: '2022-10-07T22:00:00.000Z',
}),
method: 'POST',
mode: 'cors',
credentials: 'omit',
}
)
return await req.json()
})
)
// console.log(calendari)
if (ids.length === 1) {
return calendari[0]
}
return _.uniqBy(_.concat(...calendari), 'id')
}
const App = ({}) => {
// Data Sources
const [source, setSource] = useState('anno-1')
const [eventi, setEventi] = useState([])
// View Modes
const [mode, setMode] = useState(MODE_WORKWEEK_GRID)
// Selection
const [selectedCourses, setSelectedCourses] = useState([])
const [hideOtherCourses, setHideOtherCourses] = useState(false)
// Menus
const [helpVisible, setHelpVisible] = useState(false)
const [showMobileMenu, setShowMobileMenu] = useState(false)
useEffect(async () => {
console.log('source changed')
const eventi = await loadEventi(CALENDAR_IDS[source])
window.dataBuffer[source] = eventi
setEventi(eventi)
}, [source])
const groupIds = new Set(eventi.map(e => e.nome))
const toolOverlayVisible =
selectedCourses.length > 0 && selectedCourses.filter(id => groupIds.has(id)).length > 0
useEffect(() => {
console.log('course length changed')
const groupIds = new Set(eventi.map(e => e.nome))
if (
selectedCourses.length === 0 ||
selectedCourses.filter(id => groupIds.has(id)).length === 0
) {
setHideOtherCourses(false)
}
}, [eventi, selectedCourses.length])
const [theme, setTheme] = useState(
localStorage.getItem('theme') ??
(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
)
document.body.classList.toggle('dark-mode', theme === 'dark')
localStorage.setItem('theme', theme)
return (
<>
<Toolbar
{...{
mode,
setMode,
source,
setSource,
onShowMenu: () => setShowMobileMenu(true),
onHelp: () => setHelpVisible(true),
theme,
setTheme,
}}
/>
<EventsView
mode={mode}
selection={selectedCourses}
setSelection={setSelectedCourses}
hideOtherCourses={hideOtherCourses}
start={new Date(2022, 10, 3)}
events={eventi.map(({ nome, dataInizio, dataFine, docenti, aule }) => ({
id: nome,
name: _.split(nome, '-', 1)[0].trim(),
start: new Date(dataInizio),
end: new Date(dataFine),
docenti: docenti.map(({ nome, cognome }) =>
_.startCase(_.lowerCase(nome) + ' ' + _.lowerCase(cognome))
),
aula: _.startCase(aule[0].codice.toLowerCase()).replace(
/([A-Z]) ([1-9])/,
'$1$2'
),
}))}
/>
{toolOverlayVisible && (
<ToolOverlay
visibility={hideOtherCourses}
toggleVisibility={() => setHideOtherCourses(s => !s)}
onClose={() => {
setSelectedCourses([])
setHideOtherCourses(false)
}}
/>
)}
{showMobileMenu && (
<HamburgerMenu
{...{
mode,
setMode,
source,
setSource,
theme,
setTheme,
onClose: () => {
setShowMobileMenu(false)
},
}}
/>
)}
{helpVisible && (
<Popup
title={
<>
<Icon name="info" /> Guida
</>
}
onClose={() => setHelpVisible(false)}
>
<Help />
</Popup>
)}
</>
)
// Data Sources
const [source, setSource] = useState('anno-1')
const [eventi, setEventi] = useState([])
// View Modes
const [mode, setMode] = useState(MODE_WORKWEEK_GRID)
// Selection
const [selectedCourses, setSelectedCourses] = useState([])
const [hideOtherCourses, setHideOtherCourses] = useState(false)
// Menus
const [helpVisible, setHelpVisible] = useState(false)
const [showMobileMenu, setShowMobileMenu] = useState(false)
useEffect(async () => {
console.log('source changed')
const eventi = await loadEventi(CALENDAR_IDS[source])
window.dataBuffer[source] = eventi
setEventi(eventi)
}, [source])
const groupIds = new Set(eventi.map(e => e.nome))
const toolOverlayVisible =
selectedCourses.length > 0 && selectedCourses.filter(id => groupIds.has(id)).length > 0
useEffect(() => {
console.log('course length changed')
const groupIds = new Set(eventi.map(e => e.nome))
if (
selectedCourses.length === 0 ||
selectedCourses.filter(id => groupIds.has(id)).length === 0
) {
setHideOtherCourses(false)
}
}, [eventi, selectedCourses.length])
const [theme, setTheme] = useState(
localStorage.getItem('theme') ??
(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
)
document.body.classList.toggle('dark-mode', theme === 'dark')
localStorage.setItem('theme', theme)
return (
<>
<Toolbar
{...{
mode,
setMode,
source,
setSource,
onShowMenu: () => setShowMobileMenu(true),
onHelp: () => setHelpVisible(true),
theme,
setTheme,
}}
/>
<Optionbar
{...{
mode,
setMode,
source,
setSource,
onHelp: () => setHelpVisible(true),
}}
/>
<EventsView
mode={mode}
selection={selectedCourses}
setSelection={setSelectedCourses}
hideOtherCourses={hideOtherCourses}
start={new Date(2022, 10, 3)}
events={eventi.map(({ nome, dataInizio, dataFine, docenti, aule }) => ({
id: nome,
name: _.split(nome, '-', 1)[0].trim(),
start: new Date(dataInizio),
end: new Date(dataFine),
docenti: docenti.map(({ nome, cognome }) =>
_.startCase(_.lowerCase(nome) + ' ' + _.lowerCase(cognome))
),
aula: _.startCase(aule[0].codice.toLowerCase()).replace(
/([A-Z]) ([1-9])/,
'$1$2'
),
}))}
/>
{toolOverlayVisible && (
<ToolOverlay
visibility={hideOtherCourses}
toggleVisibility={() => setHideOtherCourses(s => !s)}
onClose={() => {
setSelectedCourses([])
setHideOtherCourses(false)
}}
/>
)}
{showMobileMenu && (
<HamburgerMenu
{...{
mode,
setMode,
source,
setSource,
theme,
setTheme,
onClose: () => {
setShowMobileMenu(false)
},
}}
/>
)}
{helpVisible && (
<Popup
title={
<>
<Icon name="info" /> Guida
</>
}
onClose={() => setHelpVisible(false)}
>
<Help />
</Popup>
)}
</>
)
}
render(<App />, document.body)

@ -28,35 +28,34 @@ html {
--accent-500: #6cc16c;
--accent-900: #244624;
--bubble-red: hsl(359, 100%, 92%);
--bubble-purple: hsl(274, 100%, 92%);
--bubble-blue: hsl(241, 100%, 92%);
--bubble-yellow: hsl(50, 100%, 92%);
--bubble-green: hsl(125, 100%, 92%);
--bubble-orange: hsl(25, 100%, 92%);
--bubble-lightlightblue: hsl(176, 100%, 92%);
--bubble-lightblue: hsl(198, 100%, 92%);
--bubble-highlight-red: hsl(359, 100%, 85%);
--bubble-highlight-purple: hsl(274, 100%, 85%);
--bubble-highlight-blue: hsl(241, 100%, 85%);
--bubble-highlight-yellow: hsl(50, 100%, 85%);
--bubble-highlight-green: hsl(125, 100%, 85%);
--bubble-highlight-orange: hsl(25, 100%, 85%);
--bubble-highlight-lightlightblue: hsl(176, 100%, 85%);
--bubble-highlight-lightblue: hsl(198, 100%, 85%);
--bubble-border-red: hsl(359, 75%, 51%);
--bubble-border-purple: hsl(274, 75%, 51%);
--bubble-border-blue: hsl(241, 75%, 51%);
--bubble-border-yellow: hsl(50, 75%, 51%);
--bubble-border-green: hsl(125, 75%, 51%);
--bubble-border-orange: hsl(25, 75%, 51%);
--bubble-border-lightlightblue: hsl(176, 75%, 51%);
--bubble-border-lightblue: hsl(198, 75%, 51%);
--bold-on-dark: 300;
--bubble-red: hsl(359, 100%, 92%);
--bubble-purple: hsl(274, 100%, 92%);
--bubble-blue: hsl(241, 100%, 92%);
--bubble-yellow: hsl(50, 100%, 92%);
--bubble-green: hsl(125, 100%, 92%);
--bubble-orange: hsl(25, 100%, 92%);
--bubble-lightlightblue: hsl(176, 100%, 92%);
--bubble-lightblue: hsl(198, 100%, 92%);
--bubble-highlight-red: hsl(359, 100%, 85%);
--bubble-highlight-purple: hsl(274, 100%, 85%);
--bubble-highlight-blue: hsl(241, 100%, 85%);
--bubble-highlight-yellow: hsl(50, 100%, 85%);
--bubble-highlight-green: hsl(125, 100%, 85%);
--bubble-highlight-orange: hsl(25, 100%, 85%);
--bubble-highlight-lightlightblue: hsl(176, 100%, 85%);
--bubble-highlight-lightblue: hsl(198, 100%, 85%);
--bubble-border-red: hsl(359, 75%, 51%);
--bubble-border-purple: hsl(274, 75%, 51%);
--bubble-border-blue: hsl(241, 75%, 51%);
--bubble-border-yellow: hsl(50, 75%, 51%);
--bubble-border-green: hsl(125, 75%, 51%);
--bubble-border-orange: hsl(25, 75%, 51%);
--bubble-border-lightlightblue: hsl(176, 75%, 51%);
--bubble-border-lightblue: hsl(198, 75%, 51%);
--bold-on-dark: 300;
}
body.dark-mode {
@ -74,32 +73,31 @@ body.dark-mode {
--accent-500: hsl(269, 40%, 70%);
--accent-900: hsl(269, 30%, 90%);
--bubble-red: hsl(359, 40%, 25%);
--bubble-purple: hsl(274, 40%, 25%);
--bubble-blue: hsl(241, 40%, 25%);
--bubble-yellow: hsl(50, 40%, 25%);
--bubble-green: hsl(125, 40%, 25%);
--bubble-orange: hsl(25, 40%, 25%);
--bubble-lightblue: hsl(176, 40%, 25%);
--bubble-border-red: hsl(359, 75%, 51%);
--bubble-border-purple: hsl(274, 75%, 51%);
--bubble-border-blue: hsl(241, 75%, 51%);
--bubble-border-yellow: hsl(50, 75%, 51%);
--bubble-border-green: hsl(125, 75%, 51%);
--bubble-border-orange: hsl(25, 75%, 51%);
--bubble-border-lightblue: hsl(176, 75%, 51%);
--bubble-highlight-red: hsl(359, 40%, 31%);
--bubble-highlight-purple: hsl(274, 40%, 31%);
--bubble-highlight-blue: hsl(241, 40%, 31%);
--bubble-highlight-yellow: hsl(50, 40%, 31%);
--bubble-highlight-green: hsl(125, 40%, 31%);
--bubble-highlight-orange: hsl(25, 40%, 31%);
--bubble-highlight-lightblue: hsl(176, 40%, 31%);
--bold-on-dark: 500;
--bubble-red: hsl(359, 40%, 25%);
--bubble-purple: hsl(274, 40%, 25%);
--bubble-blue: hsl(241, 40%, 25%);
--bubble-yellow: hsl(50, 40%, 25%);
--bubble-green: hsl(125, 40%, 25%);
--bubble-orange: hsl(25, 40%, 25%);
--bubble-lightblue: hsl(176, 40%, 25%);
--bubble-border-red: hsl(359, 75%, 51%);
--bubble-border-purple: hsl(274, 75%, 51%);
--bubble-border-blue: hsl(241, 75%, 51%);
--bubble-border-yellow: hsl(50, 75%, 51%);
--bubble-border-green: hsl(125, 75%, 51%);
--bubble-border-orange: hsl(25, 75%, 51%);
--bubble-border-lightblue: hsl(176, 75%, 51%);
--bubble-highlight-red: hsl(359, 40%, 31%);
--bubble-highlight-purple: hsl(274, 40%, 31%);
--bubble-highlight-blue: hsl(241, 40%, 31%);
--bubble-highlight-yellow: hsl(50, 40%, 31%);
--bubble-highlight-green: hsl(125, 40%, 31%);
--bubble-highlight-orange: hsl(25, 40%, 31%);
--bubble-highlight-lightblue: hsl(176, 40%, 31%);
--bold-on-dark: 500;
}
$device-s-width: 600px;
@ -450,9 +448,38 @@ body {
}
}
}
.optionbar {
@extend .panel;
padding: 1rem 0.75rem 1rem 1rem;
border-radius: 0;
border: none;
border-bottom: 1px solid var(--border-500);
height: 4rem;
display: none;
align-items: center;
justify-content: space-between;
@media screen and (max-width: $device-s-width), (pointer: coarse) {
display: flex;
}
.option-group {
display: flex;
align-items: center;
gap: 0.75rem;
}
}
.events-view {
height: calc(100vh - 4rem);
@media screen and (max-width: $device-s-width), (pointer: coarse) {
height: calc(100vh - 8rem);
}
.course-view {
padding: 1rem;
@ -880,109 +907,108 @@ body {
height: 100%;
overflow: scroll;
.grid {
width: 100%;
max-width: 55rem;
display: grid;
grid-template-columns: 3rem repeat(var(--time-length), 1fr);
grid-template-rows: 2rem repeat(var(--days-length), 1fr);
border: 2px solid var(--border-500);
border-radius: 10px 10px 0 0;
@media screen and (max-width: $device-s-width), (pointer: coarse) {
font-size: 12px;
}
.time {
display: flex;
align-items: center;
justify-content: center;
padding: 0.5rem;
grid-row: 1;
grid-column: var(--offset) / span 2;
}
.day-name {
display: flex;
align-items: center;
justify-content: center;
padding: 0.5rem;
grid-column: 1;
grid-row: var(--line);
}
.event {
display: flex;
flex-direction: row;
@media screen and (max-width: $device-s-width), (pointer: coarse) {
flex-direction: column;
}
gap: 0.25rem;
align-items: center;
justify-content: center;
margin: 0.25rem;
padding: 0.5rem;
grid-row: var(--line);
grid-column: var(--offset) / span var(--length);
background-color: var(--color);
border: 3px solid var(--color);
border-radius: 10px;
font-weight: var(--bold-on-dark);
text-align: center;
&.highlight {
background-color: var(--highlight-color);
border: 3px solid var(--highlight-color);
}
&.selected {
border: 3px solid var(--border-color);
}
}
.hline {
grid-column: 1 / 13;
grid-row: var(--line);
height: 0px;
border-bottom: 1px solid var(--border-500);
}
.vline {
grid-column: var(--offset);
grid-row: 1 / calc(2 + var(--days-length));
width: 0px;
border-right: 1px dashed var(--border-500);
}
}
.legend {
max-width: 55rem;
display: grid;
grid-template-columns: min-content 1fr;
border: 2px solid var(--border-500);
border-radius: 0 0 10px 10px;
border-top: none;
padding: 1rem;
gap: 0.5rem 1rem;
align-items: center;
justify-content: center;
width: 100%;
.name {
width: 100%;
}
.color {
display: flex;
justify-content: center;
align-items: center;
font-weight: 500;
width: 2rem;
height: 1.5rem;
background-color: var(--color);
border: 2px solid var(--border-color);
border-radius: 10px;
font-weight: var(--bold-on-dark);
}
}
.grid {
width: 100%;
max-width: 55rem;
display: grid;
grid-template-columns: 3rem repeat(var(--time-length), 1fr);
grid-template-rows: 2rem repeat(var(--days-length), 1fr);
border: 2px solid var(--border-500);
border-radius: 10px 10px 0 0;
@media screen and (max-width: $device-s-width), (pointer: coarse) {
font-size: 12px;
}
.time {
display: flex;
align-items: center;
justify-content: center;
padding: 0.5rem;
grid-row: 1;
grid-column: var(--offset) / span 2;
}
.day-name {
display: flex;
align-items: center;
justify-content: center;
padding: 0.5rem;
grid-column: 1;
grid-row: var(--line);
}
.event {
display: flex;
flex-direction: row;
@media screen and (max-width: $device-s-width), (pointer: coarse) {
flex-direction: column;
}
gap: 0.25rem;
align-items: center;
justify-content: center;
margin: 0.25rem;
padding: 0.5rem;
grid-row: var(--line);
grid-column: var(--offset) / span var(--length);
background-color: var(--color);
border: 3px solid var(--color);
border-radius: 10px;
font-weight: var(--bold-on-dark);
text-align: center;
&.highlight {
background-color: var(--highlight-color);
border: 3px solid var(--highlight-color);
}
&.selected {
border: 3px solid var(--border-color);
}
}
.hline {
grid-column: 1 / 13;
grid-row: var(--line);
height: 0px;
border-bottom: 1px solid var(--border-500);
}
.vline {
grid-column: var(--offset);
grid-row: 1 / calc(2 + var(--days-length));
width: 0px;
border-right: 1px dashed var(--border-500);
}
}
.legend {
max-width: 55rem;
display: grid;
grid-template-columns: min-content 1fr;
border: 2px solid var(--border-500);
border-radius: 0 0 10px 10px;
border-top: none;
padding: 1rem;
gap: 0.5rem 1rem;
align-items: center;
justify-content: center;
width: 100%;
.name {
width: 100%;
}
.color {
display: flex;
justify-content: center;
align-items: center;
font-weight: 500;
width: 2rem;
height: 1.5rem;
background-color: var(--color);
border: 2px solid var(--border-color);
border-radius: 10px;
font-weight: var(--bold-on-dark);
}
}
}
.schedule-view {

Loading…
Cancel
Save