Compare commits

...

68 Commits

Author SHA1 Message Date
Antonio De Lucreziis 39ccb715db Merge pull request 'chore: updated calendar ids to first semester of 2024/2025' (#16) from dev into main
continuous-integration/drone/push Build is passing Details
Reviewed-on: phc/orario#16
4 months ago
Antonio De Lucreziis d929aa6cfe chore: updated calendar ids to first semester of 2024/2025 4 months ago
Antonio De Lucreziis db72898471 Merge pull request 'chore: empty commit to trigger deploy' (#15) from dev into main
continuous-integration/drone/push Build is passing Details
Reviewed-on: phc/orario#15
9 months ago
Antonio De Lucreziis 4d95a1a633 chore: empty commit to trigger deploy 9 months ago
Antonio De Lucreziis 65b800806f Merge pull request 'Fixed iOS date picker bug' (#14) from dev into main
Reviewed-on: phc/orario#14
9 months ago
Antonio De Lucreziis 935309147c cmd: prettier -w src/ 9 months ago
Antonio De Lucreziis fb551fb719 fix: safari ios showPicker() bug 9 months ago
Francesco Minnocci c731d9c8b9 Merge pull request 'chore: fix LIMCO courses' names' (#13) from dev into main
continuous-integration/drone/push Build is passing Details
Reviewed-on: phc/orario#13
10 months ago
Francesco Minnocci d9d2aaed11
chore: fix LIMCO courses' names 10 months ago
Francesco Minnocci 7bbd9ba139 Merge pull request 'chore: update calendar IDs for the 2nd semester' (#12) from dev into main
continuous-integration/drone/push Build is passing Details
Reviewed-on: phc/orario#12
10 months ago
Francesco Minnocci 62a9b80b21
chore: update calendar IDs for the 2nd semester 10 months ago
Fran314 c43bdc60e7 Merge pull request 'dev' (#11) from dev into main
continuous-integration/drone/push Build is passing Details
Reviewed-on: phc/orario#11
1 year ago
Francesco Baldino c8172ad88a Added warning messages when date outside of lecture period 1 year ago
Francesco Baldino c0b2894c22 Merge branch 'dev' of git.phc.dm.unipi.it:phc/orario into dev 1 year ago
Francesco Baldino fd0440465c Added date picker and fixed menu rendering 1 year ago
Antonio De Lucreziis bdbf031bce Merge pull request 'fix: rimosso un console.log' (#8) from dev into main
continuous-integration/drone/push Build is passing Details
Reviewed-on: phc/orario#8
1 year ago
Antonio De Lucreziis 32dc9a6104 fix: rimosso un console.log 1 year ago
Fran314 2d4a3ce664 Merge pull request 'reintrodotta visualizzazione lista rimossa nel commit precedente' (#7) from dev into main
continuous-integration/drone/push Build is passing Details
Reviewed-on: phc/orario#7
1 year ago
Francesco Baldino af41177561 reintrodotta visualizzazione lista rimossa nel commit precedente 1 year ago
Fran314 22ce830c80 Merge pull request 'dev' (#6) from dev into main
continuous-integration/drone/push Build is passing Details
Reviewed-on: phc/orario#6
1 year ago
Francesco Baldino 7efb311a61 Aggiunta trasposizione 1 year ago
Francesco Baldino a34d36257b first brutal rework and first prototype 1 year ago
Francesco Minnocci 04b6d5640d Merge pull request 'chore: update date ranges' (#5) from dev into main
continuous-integration/drone/push Build is passing Details
Reviewed-on: phc/orario#5
1 year ago
Francesco Minnocci 0caf967e14
chore: update date ranges 1 year ago
Antonio De Lucreziis 291aa72fd0 Merge branch 'dev'
continuous-integration/drone/push Build is passing Details
2 years ago
Antonio De Lucreziis 17188b17ee fix: tolto definitivamente l'effetto hover da mobile 2 years ago
Antonio De Lucreziis e9d40598eb Merge pull request 'fix: aggiornato il range di date alla settimana del 2023-03-06' (#4) from dev into main
continuous-integration/drone/push Build is passing Details
Reviewed-on: phc/orario#4
2 years ago
Antonio De Lucreziis 9a8fa0c440 fix: aggiornato il range di date alla settimana del 2023-03-06 2 years ago
Francesco Minnocci c831bb1715
WorkWeek: Add 18-20 slot, CSS seems to be fine.
continuous-integration/drone/push Build is passing Details
2 years ago
Antonio De Lucreziis ce2f76da14 drone: now it actually works
continuous-integration/drone/push Build is passing Details
2 years ago
Antonio De Lucreziis 5ebc62b844 drone: testing per branch config
continuous-integration/drone/push Build is passing Details
2 years ago
Antonio De Lucreziis d2f143133e fix: no hover on mobile
continuous-integration/drone/push Build is passing Details
2 years ago
Antonio De Lucreziis 82c21d2af9 fix: missing base url while building
continuous-integration/drone/push Build is passing Details
2 years ago
Antonio De Lucreziis d4cd070cce fix: ora forse tutto funge
continuous-integration/drone/push Build is passing Details
2 years ago
Antonio De Lucreziis bc1196f216 boh
continuous-integration/drone/push Build is passing Details
2 years ago
Antonio De Lucreziis e77b4a19e3 boh
continuous-integration/drone/push Build encountered an error Details
2 years ago
Antonio De Lucreziis 4589cda93d fix: wrong dir again
continuous-integration/drone/push Build is passing Details
2 years ago
Antonio De Lucreziis 63b73ed0b3 fix: wrong folder
continuous-integration/drone/push Build is passing Details
2 years ago
Antonio De Lucreziis 1219eeb408 fix: testing drone
continuous-integration/drone/push Build is passing Details
2 years ago
Antonio De Lucreziis 15446e3cbc fix: missing command
continuous-integration/drone/push Build is passing Details
2 years ago
Antonio De Lucreziis 0af55b4755 fix: wrong image name
continuous-integration/drone/push Build is failing Details
2 years ago
Antonio De Lucreziis 4b01e91fa7 trying out drone deploy
continuous-integration/drone Build encountered an error Details
2 years ago
Antonio De Lucreziis e7b145a02f fix: aggiunta un'altra patch per i nomi dei delle aule 2 years ago
Antonio De Lucreziis b6eb7a5ec1 fix: ehm avevo dimenticato una cosa 2 years ago
Antonio De Lucreziis 03f9db6e76 fix: aggiornati gli id dei calendari 2 years ago
Antonio De Lucreziis e7f59c4693 fix: aggiunta finalmente un'icona 2 years ago
Antonio De Lucreziis f86edb9f6c fix: Beh che dire 2 years ago
Antonio De Lucreziis 025a44472d fix: tutti gli orario ora sono nel range del secondo semestre 2023 2 years ago
Antonio De Lucreziis 9f66f40984 fix: non so perché prima c'era 22 2 years ago
Antonio De Lucreziis 9c12cbf759 chore: added new calendars 2 years ago
Antonio De Lucreziis 4bf696ea75 feat: added analytics 2 years ago
Antonio De Lucreziis e432b60b54 Fixed half-hour lessons for work-week-v 2 years ago
Antonio De Lucreziis abb98dfbc3 Fixed grid lines again 2 years ago
Antonio De Lucreziis 4af3529b6e Fixed grid lines offset 2 years ago
Antonio De Lucreziis 8f9fbb2bc5 Changed dark theme colors a bit 2 years ago
Francesco Minnocci e7f538c53c
Update Help.jsx 2 years ago
Francesco Minnocci 864a0d23da
Revamp Help popup 2 years ago
Antonio De Lucreziis 7cbbf243c4 Rimossa visualizzazione giornata dalla modalità desktop 2 years ago
Antonio De Lucreziis 7d20ccab10 Fix: corsi con più aule, prof dei corsi, patch speciale per il lab di primo anno 2 years ago
Antonio De Lucreziis 96ca0fef8f Added localstorage support 2 years ago
Antonio De Lucreziis d623df9158 Some fixes 2 years ago
Antonio De Lucreziis 142c5e1b67 Finalizzazione nuovo layout da mobile 2 years ago
Antonio De Lucreziis 5d8fbc9363 Missing conflicts 2 years ago
Antonio De Lucreziis 0b1dbaebbd Merged conflicts 2 years ago
Antonio De Lucreziis 22aa06ebf6 Some adjustments 2 years ago
Antonio De Lucreziis 41195462f1 Merge pull request 'Added optionbar for mobile' (#2) from Fran314/orario:mobile-header into dev
Reviewed-on: phc/orario#2
2 years ago
Antonio De Lucreziis 4a5994210e Formatting 2 years ago
Antonio De Lucreziis 16233adcf1 Formatting 2 years ago

@ -0,0 +1,46 @@
kind: pipeline
name: default
steps:
- name: deploy
image: node:latest
volumes:
- name: host-orario-dist
path: /drone/src/dist
environment:
BASE_URL:
from_secret: base_url
commands:
- pwd
- npm install
- npm run build
volumes:
- name: host-orario-dist
host:
path: /var/www/orario
trigger:
branch:
- main
event:
- push
---
kind: pipeline
type: exec
name: caddy-permissions
depends_on:
- default
steps:
- name: chown
commands:
- chown -R caddy:caddy /var/www/orario
trigger:
branch:
- main
event:
- push

2
.gitignore vendored

@ -6,3 +6,5 @@ node_modules/
.env .env
.env.production .env.production
.vscode/

@ -0,0 +1,9 @@
{
"printWidth": 90,
"singleQuote": true,
"quoteProps": "consistent",
"tabWidth": 4,
"semi": false,
"arrowParens": "avoid",
"proseWrap": "always"
}

@ -10,6 +10,22 @@ You need to have installed `node` and `npm` (or `pnpm`). To setup the project ju
To start the development server run `npm run dev`. To start the development server run `npm run dev`.
### Editor
È meglio se prima di fare commit il codice sia formattato con Prettier, nel caso di VSCode c'è un'estensione omonima e le opzioni da aggiungere al proprio JSON di impostazioni sono
```json
...
"prettier.printWidth": 100,
"prettier.singleQuote": true,
"prettier.quoteProps": "consistent",
"prettier.tabWidth": 4,
"prettier.semi": false,
"prettier.arrowParens": "avoid",
"editor.formatOnSave": true,
...
```
### Production ### Production
To build the ViteJS project run `npm run build`, for deployment a `.env` files can be used to set the `BASE_URL` variable. To build the ViteJS project run `npm run build`, for deployment a `.env` files can be used to set the `BASE_URL` variable.

@ -1,9 +1,9 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Orario DM Unipi</title> <title>Orario DM Unipi</title>
<meta property="og:title" content="PHC - Orario" /> <meta property="og:title" content="PHC - Orario" />
@ -11,14 +11,18 @@
<meta property="og:type" content="website" /> <meta property="og:type" content="website" />
<meta property="og:url" content="https://lab.phc.dm.unipi.it/orario" /> <meta property="og:url" content="https://lab.phc.dm.unipi.it/orario" />
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@48,400,1,0" /> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@48,400,1,0" />
<link rel="stylesheet" href="/src/styles/main.scss"> <link rel="icon" type="image/png" href="icon.png" />
</head>
<body> <link rel="stylesheet" href="/src/styles/main.scss" />
<script data-goatcounter="https://analytics.phc.dm.unipi.it/count" async src="//analytics.phc.dm.unipi.it/count.js"></script>
</head>
<body>
<script type="module" src="/src/main.jsx"></script> <script type="module" src="/src/main.jsx"></script>
</body> </body>
</html> </html>

@ -1,30 +1,40 @@
lockfileVersion: 5.4 lockfileVersion: '6.0'
specifiers: settings:
'@babel/core': ^7.18.13 autoInstallPeers: true
'@preact/preset-vite': ^2.3.0 excludeLinksFromLockfile: false
date-fns: ^2.29.2
lodash: ^4.17.21
lodash-es: ^4.17.21
preact: ^10.10.6
sass: ^1.54.8
vite: ^3.0.9
dependencies: dependencies:
date-fns: 2.29.2 date-fns:
lodash: 4.17.21 specifier: ^2.29.2
lodash-es: 4.17.21 version: 2.29.2
preact: 10.10.6 lodash:
sass: 1.54.8 specifier: ^4.17.21
vite: 3.0.9_sass@1.54.8 version: 4.17.21
lodash-es:
specifier: ^4.17.21
version: 4.17.21
preact:
specifier: ^10.10.6
version: 10.10.6
sass:
specifier: ^1.54.8
version: 1.54.8
vite:
specifier: ^3.0.9
version: 3.0.9(sass@1.54.8)
devDependencies: devDependencies:
'@babel/core': 7.18.13 '@babel/core':
'@preact/preset-vite': 2.3.0_wibdudaz52xr4lhcmpvnys3x3u specifier: ^7.18.13
version: 7.18.13
'@preact/preset-vite':
specifier: ^2.3.0
version: 2.3.0(@babel/core@7.18.13)(preact@10.10.6)(vite@3.0.9)
packages: packages:
/@ampproject/remapping/2.2.0: /@ampproject/remapping@2.2.0:
resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==} resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==}
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
dependencies: dependencies:
@ -32,26 +42,26 @@ packages:
'@jridgewell/trace-mapping': 0.3.15 '@jridgewell/trace-mapping': 0.3.15
dev: true dev: true
/@babel/code-frame/7.18.6: /@babel/code-frame@7.18.6:
resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dependencies: dependencies:
'@babel/highlight': 7.18.6 '@babel/highlight': 7.18.6
dev: true dev: true
/@babel/compat-data/7.18.13: /@babel/compat-data@7.18.13:
resolution: {integrity: sha512-5yUzC5LqyTFp2HLmDoxGQelcdYgSpP9xsnMWBphAscOdFrHSAVbLNzWiy32sVNDqJRDiJK6klfDnAgu6PAGSHw==} resolution: {integrity: sha512-5yUzC5LqyTFp2HLmDoxGQelcdYgSpP9xsnMWBphAscOdFrHSAVbLNzWiy32sVNDqJRDiJK6klfDnAgu6PAGSHw==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dev: true dev: true
/@babel/core/7.18.13: /@babel/core@7.18.13:
resolution: {integrity: sha512-ZisbOvRRusFktksHSG6pjj1CSvkPkcZq/KHD45LAkVP/oiHJkNBZWfpvlLmX8OtHDG8IuzsFlVRWo08w7Qxn0A==} resolution: {integrity: sha512-ZisbOvRRusFktksHSG6pjj1CSvkPkcZq/KHD45LAkVP/oiHJkNBZWfpvlLmX8OtHDG8IuzsFlVRWo08w7Qxn0A==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dependencies: dependencies:
'@ampproject/remapping': 2.2.0 '@ampproject/remapping': 2.2.0
'@babel/code-frame': 7.18.6 '@babel/code-frame': 7.18.6
'@babel/generator': 7.18.13 '@babel/generator': 7.18.13
'@babel/helper-compilation-targets': 7.18.9_@babel+core@7.18.13 '@babel/helper-compilation-targets': 7.18.9(@babel/core@7.18.13)
'@babel/helper-module-transforms': 7.18.9 '@babel/helper-module-transforms': 7.18.9
'@babel/helpers': 7.18.9 '@babel/helpers': 7.18.9
'@babel/parser': 7.18.13 '@babel/parser': 7.18.13
@ -67,7 +77,7 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@babel/generator/7.18.13: /@babel/generator@7.18.13:
resolution: {integrity: sha512-CkPg8ySSPuHTYPJYo7IRALdqyjM9HCbt/3uOBEFbzyGVP6Mn8bwFPB0jX6982JVNBlYzM1nnPkfjuXSOPtQeEQ==} resolution: {integrity: sha512-CkPg8ySSPuHTYPJYo7IRALdqyjM9HCbt/3uOBEFbzyGVP6Mn8bwFPB0jX6982JVNBlYzM1nnPkfjuXSOPtQeEQ==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dependencies: dependencies:
@ -76,14 +86,14 @@ packages:
jsesc: 2.5.2 jsesc: 2.5.2
dev: true dev: true
/@babel/helper-annotate-as-pure/7.18.6: /@babel/helper-annotate-as-pure@7.18.6:
resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==} resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dependencies: dependencies:
'@babel/types': 7.18.13 '@babel/types': 7.18.13
dev: true dev: true
/@babel/helper-compilation-targets/7.18.9_@babel+core@7.18.13: /@babel/helper-compilation-targets@7.18.9(@babel/core@7.18.13):
resolution: {integrity: sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==} resolution: {integrity: sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
peerDependencies: peerDependencies:
@ -96,12 +106,12 @@ packages:
semver: 6.3.0 semver: 6.3.0
dev: true dev: true
/@babel/helper-environment-visitor/7.18.9: /@babel/helper-environment-visitor@7.18.9:
resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==} resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dev: true dev: true
/@babel/helper-function-name/7.18.9: /@babel/helper-function-name@7.18.9:
resolution: {integrity: sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==} resolution: {integrity: sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dependencies: dependencies:
@ -109,21 +119,21 @@ packages:
'@babel/types': 7.18.13 '@babel/types': 7.18.13
dev: true dev: true
/@babel/helper-hoist-variables/7.18.6: /@babel/helper-hoist-variables@7.18.6:
resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dependencies: dependencies:
'@babel/types': 7.18.13 '@babel/types': 7.18.13
dev: true dev: true
/@babel/helper-module-imports/7.18.6: /@babel/helper-module-imports@7.18.6:
resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dependencies: dependencies:
'@babel/types': 7.18.13 '@babel/types': 7.18.13
dev: true dev: true
/@babel/helper-module-transforms/7.18.9: /@babel/helper-module-transforms@7.18.9:
resolution: {integrity: sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==} resolution: {integrity: sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dependencies: dependencies:
@ -139,41 +149,41 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@babel/helper-plugin-utils/7.18.9: /@babel/helper-plugin-utils@7.18.9:
resolution: {integrity: sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==} resolution: {integrity: sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dev: true dev: true
/@babel/helper-simple-access/7.18.6: /@babel/helper-simple-access@7.18.6:
resolution: {integrity: sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==} resolution: {integrity: sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dependencies: dependencies:
'@babel/types': 7.18.13 '@babel/types': 7.18.13
dev: true dev: true
/@babel/helper-split-export-declaration/7.18.6: /@babel/helper-split-export-declaration@7.18.6:
resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dependencies: dependencies:
'@babel/types': 7.18.13 '@babel/types': 7.18.13
dev: true dev: true
/@babel/helper-string-parser/7.18.10: /@babel/helper-string-parser@7.18.10:
resolution: {integrity: sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==} resolution: {integrity: sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dev: true dev: true
/@babel/helper-validator-identifier/7.18.6: /@babel/helper-validator-identifier@7.18.6:
resolution: {integrity: sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==} resolution: {integrity: sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dev: true dev: true
/@babel/helper-validator-option/7.18.6: /@babel/helper-validator-option@7.18.6:
resolution: {integrity: sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==} resolution: {integrity: sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dev: true dev: true
/@babel/helpers/7.18.9: /@babel/helpers@7.18.9:
resolution: {integrity: sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==} resolution: {integrity: sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dependencies: dependencies:
@ -184,7 +194,7 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@babel/highlight/7.18.6: /@babel/highlight@7.18.6:
resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dependencies: dependencies:
@ -193,7 +203,7 @@ packages:
js-tokens: 4.0.0 js-tokens: 4.0.0
dev: true dev: true
/@babel/parser/7.18.13: /@babel/parser@7.18.13:
resolution: {integrity: sha512-dgXcIfMuQ0kgzLB2b9tRZs7TTFFaGM2AbtA4fJgUUYukzGH4jwsS7hzQHEGs67jdehpm22vkgKwvbU+aEflgwg==} resolution: {integrity: sha512-dgXcIfMuQ0kgzLB2b9tRZs7TTFFaGM2AbtA4fJgUUYukzGH4jwsS7hzQHEGs67jdehpm22vkgKwvbU+aEflgwg==}
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
hasBin: true hasBin: true
@ -201,7 +211,7 @@ packages:
'@babel/types': 7.18.13 '@babel/types': 7.18.13
dev: true dev: true
/@babel/plugin-syntax-jsx/7.18.6_@babel+core@7.18.13: /@babel/plugin-syntax-jsx@7.18.6(@babel/core@7.18.13):
resolution: {integrity: sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==} resolution: {integrity: sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
peerDependencies: peerDependencies:
@ -211,17 +221,17 @@ packages:
'@babel/helper-plugin-utils': 7.18.9 '@babel/helper-plugin-utils': 7.18.9
dev: true dev: true
/@babel/plugin-transform-react-jsx-development/7.18.6_@babel+core@7.18.13: /@babel/plugin-transform-react-jsx-development@7.18.6(@babel/core@7.18.13):
resolution: {integrity: sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==} resolution: {integrity: sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
peerDependencies: peerDependencies:
'@babel/core': ^7.0.0-0 '@babel/core': ^7.0.0-0
dependencies: dependencies:
'@babel/core': 7.18.13 '@babel/core': 7.18.13
'@babel/plugin-transform-react-jsx': 7.18.10_@babel+core@7.18.13 '@babel/plugin-transform-react-jsx': 7.18.10(@babel/core@7.18.13)
dev: true dev: true
/@babel/plugin-transform-react-jsx/7.18.10_@babel+core@7.18.13: /@babel/plugin-transform-react-jsx@7.18.10(@babel/core@7.18.13):
resolution: {integrity: sha512-gCy7Iikrpu3IZjYZolFE4M1Sm+nrh1/6za2Ewj77Z+XirT4TsbJcvOFOyF+fRPwU6AKKK136CZxx6L8AbSFG6A==} resolution: {integrity: sha512-gCy7Iikrpu3IZjYZolFE4M1Sm+nrh1/6za2Ewj77Z+XirT4TsbJcvOFOyF+fRPwU6AKKK136CZxx6L8AbSFG6A==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
peerDependencies: peerDependencies:
@ -231,11 +241,11 @@ packages:
'@babel/helper-annotate-as-pure': 7.18.6 '@babel/helper-annotate-as-pure': 7.18.6
'@babel/helper-module-imports': 7.18.6 '@babel/helper-module-imports': 7.18.6
'@babel/helper-plugin-utils': 7.18.9 '@babel/helper-plugin-utils': 7.18.9
'@babel/plugin-syntax-jsx': 7.18.6_@babel+core@7.18.13 '@babel/plugin-syntax-jsx': 7.18.6(@babel/core@7.18.13)
'@babel/types': 7.18.13 '@babel/types': 7.18.13
dev: true dev: true
/@babel/template/7.18.10: /@babel/template@7.18.10:
resolution: {integrity: sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==} resolution: {integrity: sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dependencies: dependencies:
@ -244,7 +254,7 @@ packages:
'@babel/types': 7.18.13 '@babel/types': 7.18.13
dev: true dev: true
/@babel/traverse/7.18.13: /@babel/traverse@7.18.13:
resolution: {integrity: sha512-N6kt9X1jRMLPxxxPYWi7tgvJRH/rtoU+dbKAPDM44RFHiMH8igdsaSBgFeskhSl/kLWLDUvIh1RXCrTmg0/zvA==} resolution: {integrity: sha512-N6kt9X1jRMLPxxxPYWi7tgvJRH/rtoU+dbKAPDM44RFHiMH8igdsaSBgFeskhSl/kLWLDUvIh1RXCrTmg0/zvA==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dependencies: dependencies:
@ -262,7 +272,7 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@babel/types/7.18.13: /@babel/types@7.18.13:
resolution: {integrity: sha512-ePqfTihzW0W6XAU+aMw2ykilisStJfDnsejDCXRchCcMJ4O0+8DhPXf2YUbZ6wjBlsEmZwLK/sPweWtu8hcJYQ==} resolution: {integrity: sha512-ePqfTihzW0W6XAU+aMw2ykilisStJfDnsejDCXRchCcMJ4O0+8DhPXf2YUbZ6wjBlsEmZwLK/sPweWtu8hcJYQ==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dependencies: dependencies:
@ -271,7 +281,7 @@ packages:
to-fast-properties: 2.0.0 to-fast-properties: 2.0.0
dev: true dev: true
/@esbuild/linux-loong64/0.14.54: /@esbuild/linux-loong64@0.14.54:
resolution: {integrity: sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==} resolution: {integrity: sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==}
engines: {node: '>=12'} engines: {node: '>=12'}
cpu: [loong64] cpu: [loong64]
@ -279,7 +289,7 @@ packages:
requiresBuild: true requiresBuild: true
optional: true optional: true
/@jridgewell/gen-mapping/0.1.1: /@jridgewell/gen-mapping@0.1.1:
resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==} resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==}
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
dependencies: dependencies:
@ -287,7 +297,7 @@ packages:
'@jridgewell/sourcemap-codec': 1.4.14 '@jridgewell/sourcemap-codec': 1.4.14
dev: true dev: true
/@jridgewell/gen-mapping/0.3.2: /@jridgewell/gen-mapping@0.3.2:
resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==} resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==}
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
dependencies: dependencies:
@ -296,53 +306,53 @@ packages:
'@jridgewell/trace-mapping': 0.3.15 '@jridgewell/trace-mapping': 0.3.15
dev: true dev: true
/@jridgewell/resolve-uri/3.1.0: /@jridgewell/resolve-uri@3.1.0:
resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==}
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
dev: true dev: true
/@jridgewell/set-array/1.1.2: /@jridgewell/set-array@1.1.2:
resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==}
engines: {node: '>=6.0.0'} engines: {node: '>=6.0.0'}
dev: true dev: true
/@jridgewell/sourcemap-codec/1.4.14: /@jridgewell/sourcemap-codec@1.4.14:
resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==}
dev: true dev: true
/@jridgewell/trace-mapping/0.3.15: /@jridgewell/trace-mapping@0.3.15:
resolution: {integrity: sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==} resolution: {integrity: sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==}
dependencies: dependencies:
'@jridgewell/resolve-uri': 3.1.0 '@jridgewell/resolve-uri': 3.1.0
'@jridgewell/sourcemap-codec': 1.4.14 '@jridgewell/sourcemap-codec': 1.4.14
dev: true dev: true
/@preact/preset-vite/2.3.0_wibdudaz52xr4lhcmpvnys3x3u: /@preact/preset-vite@2.3.0(@babel/core@7.18.13)(preact@10.10.6)(vite@3.0.9):
resolution: {integrity: sha512-0kOuz7wdrQLqrPlyI/Ypw9IWDF2++GGcOHMRBYO5T2w2+dheelaBH+XrIN/okqdsGIflzFIFNyIGubo5BC8wbQ==} resolution: {integrity: sha512-0kOuz7wdrQLqrPlyI/Ypw9IWDF2++GGcOHMRBYO5T2w2+dheelaBH+XrIN/okqdsGIflzFIFNyIGubo5BC8wbQ==}
peerDependencies: peerDependencies:
'@babel/core': 7.x '@babel/core': 7.x
vite: 2.x || 3.x vite: 2.x || 3.x
dependencies: dependencies:
'@babel/core': 7.18.13 '@babel/core': 7.18.13
'@babel/plugin-transform-react-jsx': 7.18.10_@babel+core@7.18.13 '@babel/plugin-transform-react-jsx': 7.18.10(@babel/core@7.18.13)
'@babel/plugin-transform-react-jsx-development': 7.18.6_@babel+core@7.18.13 '@babel/plugin-transform-react-jsx-development': 7.18.6(@babel/core@7.18.13)
'@prefresh/vite': 2.2.8_preact@10.10.6+vite@3.0.9 '@prefresh/vite': 2.2.8(preact@10.10.6)(vite@3.0.9)
'@rollup/pluginutils': 4.2.1 '@rollup/pluginutils': 4.2.1
babel-plugin-transform-hook-names: 1.0.2_@babel+core@7.18.13 babel-plugin-transform-hook-names: 1.0.2(@babel/core@7.18.13)
debug: 4.3.4 debug: 4.3.4
kolorist: 1.5.1 kolorist: 1.5.1
resolve: 1.22.1 resolve: 1.22.1
vite: 3.0.9_sass@1.54.8 vite: 3.0.9(sass@1.54.8)
transitivePeerDependencies: transitivePeerDependencies:
- preact - preact
- supports-color - supports-color
dev: true dev: true
/@prefresh/babel-plugin/0.4.3: /@prefresh/babel-plugin@0.4.3:
resolution: {integrity: sha512-fYAWbU1WDSLn108kKY4eDaaeUcnszFqXjgaGKYXNZ5NLulpRTpsrY+Sbfo9q8LDpWrBpqIgzjrwNnvglWI1xNQ==} resolution: {integrity: sha512-fYAWbU1WDSLn108kKY4eDaaeUcnszFqXjgaGKYXNZ5NLulpRTpsrY+Sbfo9q8LDpWrBpqIgzjrwNnvglWI1xNQ==}
dev: true dev: true
/@prefresh/core/1.3.4_preact@10.10.6: /@prefresh/core@1.3.4(preact@10.10.6):
resolution: {integrity: sha512-s7iNsnyJ3lZEUrYIgmVIB/hKtp4U6mdD91a31Zg7Q8M49O0x2KThrbrMQYraoDDrs4STdFB8Zv6bceUguOoX1A==} resolution: {integrity: sha512-s7iNsnyJ3lZEUrYIgmVIB/hKtp4U6mdD91a31Zg7Q8M49O0x2KThrbrMQYraoDDrs4STdFB8Zv6bceUguOoX1A==}
peerDependencies: peerDependencies:
preact: ^10.0.0 preact: ^10.0.0
@ -350,11 +360,11 @@ packages:
preact: 10.10.6 preact: 10.10.6
dev: true dev: true
/@prefresh/utils/1.1.3: /@prefresh/utils@1.1.3:
resolution: {integrity: sha512-Mb9abhJTOV4yCfkXrMrcgFiFT7MfNOw8sDa+XyZBdq/Ai2p4Zyxqsb3EgHLOEdHpMj6J9aiZ54W8H6FTam1u+A==} resolution: {integrity: sha512-Mb9abhJTOV4yCfkXrMrcgFiFT7MfNOw8sDa+XyZBdq/Ai2p4Zyxqsb3EgHLOEdHpMj6J9aiZ54W8H6FTam1u+A==}
dev: true dev: true
/@prefresh/vite/2.2.8_preact@10.10.6+vite@3.0.9: /@prefresh/vite@2.2.8(preact@10.10.6)(vite@3.0.9):
resolution: {integrity: sha512-yGGa+PKPYPTzMlxgQ8aBgxw9K69I8X4iQ0E6KOcIvls96WKqKLLOYZW9SUgCve446jpUXvc9udviPBZjCeZIIQ==} resolution: {integrity: sha512-yGGa+PKPYPTzMlxgQ8aBgxw9K69I8X4iQ0E6KOcIvls96WKqKLLOYZW9SUgCve446jpUXvc9udviPBZjCeZIIQ==}
peerDependencies: peerDependencies:
preact: ^10.4.0 preact: ^10.4.0
@ -362,16 +372,16 @@ packages:
dependencies: dependencies:
'@babel/core': 7.18.13 '@babel/core': 7.18.13
'@prefresh/babel-plugin': 0.4.3 '@prefresh/babel-plugin': 0.4.3
'@prefresh/core': 1.3.4_preact@10.10.6 '@prefresh/core': 1.3.4(preact@10.10.6)
'@prefresh/utils': 1.1.3 '@prefresh/utils': 1.1.3
'@rollup/pluginutils': 4.2.1 '@rollup/pluginutils': 4.2.1
preact: 10.10.6 preact: 10.10.6
vite: 3.0.9_sass@1.54.8 vite: 3.0.9(sass@1.54.8)
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
dev: true dev: true
/@rollup/pluginutils/4.2.1: /@rollup/pluginutils@4.2.1:
resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==}
engines: {node: '>= 8.0.0'} engines: {node: '>= 8.0.0'}
dependencies: dependencies:
@ -379,21 +389,21 @@ packages:
picomatch: 2.3.1 picomatch: 2.3.1
dev: true dev: true
/ansi-styles/3.2.1: /ansi-styles@3.2.1:
resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
engines: {node: '>=4'} engines: {node: '>=4'}
dependencies: dependencies:
color-convert: 1.9.3 color-convert: 1.9.3
dev: true dev: true
/anymatch/3.1.2: /anymatch@3.1.2:
resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==} resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
dependencies: dependencies:
normalize-path: 3.0.0 normalize-path: 3.0.0
picomatch: 2.3.1 picomatch: 2.3.1
/babel-plugin-transform-hook-names/1.0.2_@babel+core@7.18.13: /babel-plugin-transform-hook-names@1.0.2(@babel/core@7.18.13):
resolution: {integrity: sha512-5gafyjyyBTTdX/tQQ0hRgu4AhNHG/hqWi0ZZmg2xvs2FgRkJXzDNKBZCyoYqgFkovfDrgM8OoKg8karoUvWeCw==} resolution: {integrity: sha512-5gafyjyyBTTdX/tQQ0hRgu4AhNHG/hqWi0ZZmg2xvs2FgRkJXzDNKBZCyoYqgFkovfDrgM8OoKg8karoUvWeCw==}
peerDependencies: peerDependencies:
'@babel/core': ^7.12.10 '@babel/core': ^7.12.10
@ -401,17 +411,17 @@ packages:
'@babel/core': 7.18.13 '@babel/core': 7.18.13
dev: true dev: true
/binary-extensions/2.2.0: /binary-extensions@2.2.0:
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
engines: {node: '>=8'} engines: {node: '>=8'}
/braces/3.0.2: /braces@3.0.2:
resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
engines: {node: '>=8'} engines: {node: '>=8'}
dependencies: dependencies:
fill-range: 7.0.1 fill-range: 7.0.1
/browserslist/4.21.3: /browserslist@4.21.3:
resolution: {integrity: sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==} resolution: {integrity: sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==}
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true hasBin: true
@ -419,14 +429,14 @@ packages:
caniuse-lite: 1.0.30001388 caniuse-lite: 1.0.30001388
electron-to-chromium: 1.4.241 electron-to-chromium: 1.4.241
node-releases: 2.0.6 node-releases: 2.0.6
update-browserslist-db: 1.0.7_browserslist@4.21.3 update-browserslist-db: 1.0.7(browserslist@4.21.3)
dev: true dev: true
/caniuse-lite/1.0.30001388: /caniuse-lite@1.0.30001388:
resolution: {integrity: sha512-znVbq4OUjqgLxMxoNX2ZeeLR0d7lcDiE5uJ4eUiWdml1J1EkxbnQq6opT9jb9SMfJxB0XA16/ziHwni4u1I3GQ==} resolution: {integrity: sha512-znVbq4OUjqgLxMxoNX2ZeeLR0d7lcDiE5uJ4eUiWdml1J1EkxbnQq6opT9jb9SMfJxB0XA16/ziHwni4u1I3GQ==}
dev: true dev: true
/chalk/2.4.2: /chalk@2.4.2:
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
engines: {node: '>=4'} engines: {node: '>=4'}
dependencies: dependencies:
@ -435,7 +445,7 @@ packages:
supports-color: 5.5.0 supports-color: 5.5.0
dev: true dev: true
/chokidar/3.5.3: /chokidar@3.5.3:
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
engines: {node: '>= 8.10.0'} engines: {node: '>= 8.10.0'}
dependencies: dependencies:
@ -449,28 +459,28 @@ packages:
optionalDependencies: optionalDependencies:
fsevents: 2.3.2 fsevents: 2.3.2
/color-convert/1.9.3: /color-convert@1.9.3:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
dependencies: dependencies:
color-name: 1.1.3 color-name: 1.1.3
dev: true dev: true
/color-name/1.1.3: /color-name@1.1.3:
resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
dev: true dev: true
/convert-source-map/1.8.0: /convert-source-map@1.8.0:
resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==} resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==}
dependencies: dependencies:
safe-buffer: 5.1.2 safe-buffer: 5.1.2
dev: true dev: true
/date-fns/2.29.2: /date-fns@2.29.2:
resolution: {integrity: sha512-0VNbwmWJDS/G3ySwFSJA3ayhbURMTJLtwM2DTxf9CWondCnh6DTNlO9JgRSq6ibf4eD0lfMJNBxUdEAHHix+bA==} resolution: {integrity: sha512-0VNbwmWJDS/G3ySwFSJA3ayhbURMTJLtwM2DTxf9CWondCnh6DTNlO9JgRSq6ibf4eD0lfMJNBxUdEAHHix+bA==}
engines: {node: '>=0.11'} engines: {node: '>=0.11'}
dev: false dev: false
/debug/4.3.4: /debug@4.3.4:
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
engines: {node: '>=6.0'} engines: {node: '>=6.0'}
peerDependencies: peerDependencies:
@ -482,11 +492,11 @@ packages:
ms: 2.1.2 ms: 2.1.2
dev: true dev: true
/electron-to-chromium/1.4.241: /electron-to-chromium@1.4.241:
resolution: {integrity: sha512-e7Wsh4ilaioBZ5bMm6+F4V5c11dh56/5Jwz7Hl5Tu1J7cnB+Pqx5qIF2iC7HPpfyQMqGSvvLP5bBAIDd2gAtGw==} resolution: {integrity: sha512-e7Wsh4ilaioBZ5bMm6+F4V5c11dh56/5Jwz7Hl5Tu1J7cnB+Pqx5qIF2iC7HPpfyQMqGSvvLP5bBAIDd2gAtGw==}
dev: true dev: true
/esbuild-android-64/0.14.54: /esbuild-android-64@0.14.54:
resolution: {integrity: sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==} resolution: {integrity: sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==}
engines: {node: '>=12'} engines: {node: '>=12'}
cpu: [x64] cpu: [x64]
@ -494,7 +504,7 @@ packages:
requiresBuild: true requiresBuild: true
optional: true optional: true
/esbuild-android-arm64/0.14.54: /esbuild-android-arm64@0.14.54:
resolution: {integrity: sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==} resolution: {integrity: sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==}
engines: {node: '>=12'} engines: {node: '>=12'}
cpu: [arm64] cpu: [arm64]
@ -502,7 +512,7 @@ packages:
requiresBuild: true requiresBuild: true
optional: true optional: true
/esbuild-darwin-64/0.14.54: /esbuild-darwin-64@0.14.54:
resolution: {integrity: sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==} resolution: {integrity: sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==}
engines: {node: '>=12'} engines: {node: '>=12'}
cpu: [x64] cpu: [x64]
@ -510,7 +520,7 @@ packages:
requiresBuild: true requiresBuild: true
optional: true optional: true
/esbuild-darwin-arm64/0.14.54: /esbuild-darwin-arm64@0.14.54:
resolution: {integrity: sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==} resolution: {integrity: sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==}
engines: {node: '>=12'} engines: {node: '>=12'}
cpu: [arm64] cpu: [arm64]
@ -518,7 +528,7 @@ packages:
requiresBuild: true requiresBuild: true
optional: true optional: true
/esbuild-freebsd-64/0.14.54: /esbuild-freebsd-64@0.14.54:
resolution: {integrity: sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==} resolution: {integrity: sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==}
engines: {node: '>=12'} engines: {node: '>=12'}
cpu: [x64] cpu: [x64]
@ -526,7 +536,7 @@ packages:
requiresBuild: true requiresBuild: true
optional: true optional: true
/esbuild-freebsd-arm64/0.14.54: /esbuild-freebsd-arm64@0.14.54:
resolution: {integrity: sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==} resolution: {integrity: sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==}
engines: {node: '>=12'} engines: {node: '>=12'}
cpu: [arm64] cpu: [arm64]
@ -534,7 +544,7 @@ packages:
requiresBuild: true requiresBuild: true
optional: true optional: true
/esbuild-linux-32/0.14.54: /esbuild-linux-32@0.14.54:
resolution: {integrity: sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==} resolution: {integrity: sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==}
engines: {node: '>=12'} engines: {node: '>=12'}
cpu: [ia32] cpu: [ia32]
@ -542,7 +552,7 @@ packages:
requiresBuild: true requiresBuild: true
optional: true optional: true
/esbuild-linux-64/0.14.54: /esbuild-linux-64@0.14.54:
resolution: {integrity: sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==} resolution: {integrity: sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==}
engines: {node: '>=12'} engines: {node: '>=12'}
cpu: [x64] cpu: [x64]
@ -550,23 +560,23 @@ packages:
requiresBuild: true requiresBuild: true
optional: true optional: true
/esbuild-linux-arm/0.14.54: /esbuild-linux-arm64@0.14.54:
resolution: {integrity: sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==} resolution: {integrity: sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==}
engines: {node: '>=12'} engines: {node: '>=12'}
cpu: [arm] cpu: [arm64]
os: [linux] os: [linux]
requiresBuild: true requiresBuild: true
optional: true optional: true
/esbuild-linux-arm64/0.14.54: /esbuild-linux-arm@0.14.54:
resolution: {integrity: sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==} resolution: {integrity: sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==}
engines: {node: '>=12'} engines: {node: '>=12'}
cpu: [arm64] cpu: [arm]
os: [linux] os: [linux]
requiresBuild: true requiresBuild: true
optional: true optional: true
/esbuild-linux-mips64le/0.14.54: /esbuild-linux-mips64le@0.14.54:
resolution: {integrity: sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==} resolution: {integrity: sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==}
engines: {node: '>=12'} engines: {node: '>=12'}
cpu: [mips64el] cpu: [mips64el]
@ -574,7 +584,7 @@ packages:
requiresBuild: true requiresBuild: true
optional: true optional: true
/esbuild-linux-ppc64le/0.14.54: /esbuild-linux-ppc64le@0.14.54:
resolution: {integrity: sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==} resolution: {integrity: sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==}
engines: {node: '>=12'} engines: {node: '>=12'}
cpu: [ppc64] cpu: [ppc64]
@ -582,7 +592,7 @@ packages:
requiresBuild: true requiresBuild: true
optional: true optional: true
/esbuild-linux-riscv64/0.14.54: /esbuild-linux-riscv64@0.14.54:
resolution: {integrity: sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==} resolution: {integrity: sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==}
engines: {node: '>=12'} engines: {node: '>=12'}
cpu: [riscv64] cpu: [riscv64]
@ -590,7 +600,7 @@ packages:
requiresBuild: true requiresBuild: true
optional: true optional: true
/esbuild-linux-s390x/0.14.54: /esbuild-linux-s390x@0.14.54:
resolution: {integrity: sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==} resolution: {integrity: sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==}
engines: {node: '>=12'} engines: {node: '>=12'}
cpu: [s390x] cpu: [s390x]
@ -598,7 +608,7 @@ packages:
requiresBuild: true requiresBuild: true
optional: true optional: true
/esbuild-netbsd-64/0.14.54: /esbuild-netbsd-64@0.14.54:
resolution: {integrity: sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==} resolution: {integrity: sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==}
engines: {node: '>=12'} engines: {node: '>=12'}
cpu: [x64] cpu: [x64]
@ -606,7 +616,7 @@ packages:
requiresBuild: true requiresBuild: true
optional: true optional: true
/esbuild-openbsd-64/0.14.54: /esbuild-openbsd-64@0.14.54:
resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==} resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==}
engines: {node: '>=12'} engines: {node: '>=12'}
cpu: [x64] cpu: [x64]
@ -614,7 +624,7 @@ packages:
requiresBuild: true requiresBuild: true
optional: true optional: true
/esbuild-sunos-64/0.14.54: /esbuild-sunos-64@0.14.54:
resolution: {integrity: sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==} resolution: {integrity: sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==}
engines: {node: '>=12'} engines: {node: '>=12'}
cpu: [x64] cpu: [x64]
@ -622,7 +632,7 @@ packages:
requiresBuild: true requiresBuild: true
optional: true optional: true
/esbuild-windows-32/0.14.54: /esbuild-windows-32@0.14.54:
resolution: {integrity: sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==} resolution: {integrity: sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==}
engines: {node: '>=12'} engines: {node: '>=12'}
cpu: [ia32] cpu: [ia32]
@ -630,7 +640,7 @@ packages:
requiresBuild: true requiresBuild: true
optional: true optional: true
/esbuild-windows-64/0.14.54: /esbuild-windows-64@0.14.54:
resolution: {integrity: sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==} resolution: {integrity: sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==}
engines: {node: '>=12'} engines: {node: '>=12'}
cpu: [x64] cpu: [x64]
@ -638,7 +648,7 @@ packages:
requiresBuild: true requiresBuild: true
optional: true optional: true
/esbuild-windows-arm64/0.14.54: /esbuild-windows-arm64@0.14.54:
resolution: {integrity: sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==} resolution: {integrity: sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==}
engines: {node: '>=12'} engines: {node: '>=12'}
cpu: [arm64] cpu: [arm64]
@ -646,7 +656,7 @@ packages:
requiresBuild: true requiresBuild: true
optional: true optional: true
/esbuild/0.14.54: /esbuild@0.14.54:
resolution: {integrity: sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==} resolution: {integrity: sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==}
engines: {node: '>=12'} engines: {node: '>=12'}
hasBin: true hasBin: true
@ -674,147 +684,147 @@ packages:
esbuild-windows-64: 0.14.54 esbuild-windows-64: 0.14.54
esbuild-windows-arm64: 0.14.54 esbuild-windows-arm64: 0.14.54
/escalade/3.1.1: /escalade@3.1.1:
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
engines: {node: '>=6'} engines: {node: '>=6'}
dev: true dev: true
/escape-string-regexp/1.0.5: /escape-string-regexp@1.0.5:
resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==}
engines: {node: '>=0.8.0'} engines: {node: '>=0.8.0'}
dev: true dev: true
/estree-walker/2.0.2: /estree-walker@2.0.2:
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
dev: true dev: true
/fill-range/7.0.1: /fill-range@7.0.1:
resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
engines: {node: '>=8'} engines: {node: '>=8'}
dependencies: dependencies:
to-regex-range: 5.0.1 to-regex-range: 5.0.1
/fsevents/2.3.2: /fsevents@2.3.2:
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin] os: [darwin]
requiresBuild: true requiresBuild: true
optional: true optional: true
/function-bind/1.1.1: /function-bind@1.1.1:
resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
/gensync/1.0.0-beta.2: /gensync@1.0.0-beta.2:
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
engines: {node: '>=6.9.0'} engines: {node: '>=6.9.0'}
dev: true dev: true
/glob-parent/5.1.2: /glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
dependencies: dependencies:
is-glob: 4.0.3 is-glob: 4.0.3
/globals/11.12.0: /globals@11.12.0:
resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
engines: {node: '>=4'} engines: {node: '>=4'}
dev: true dev: true
/has-flag/3.0.0: /has-flag@3.0.0:
resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==}
engines: {node: '>=4'} engines: {node: '>=4'}
dev: true dev: true
/has/1.0.3: /has@1.0.3:
resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
engines: {node: '>= 0.4.0'} engines: {node: '>= 0.4.0'}
dependencies: dependencies:
function-bind: 1.1.1 function-bind: 1.1.1
/immutable/4.1.0: /immutable@4.1.0:
resolution: {integrity: sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==} resolution: {integrity: sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==}
/is-binary-path/2.1.0: /is-binary-path@2.1.0:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
engines: {node: '>=8'} engines: {node: '>=8'}
dependencies: dependencies:
binary-extensions: 2.2.0 binary-extensions: 2.2.0
/is-core-module/2.10.0: /is-core-module@2.10.0:
resolution: {integrity: sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==} resolution: {integrity: sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==}
dependencies: dependencies:
has: 1.0.3 has: 1.0.3
/is-extglob/2.1.1: /is-extglob@2.1.1:
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
/is-glob/4.0.3: /is-glob@4.0.3:
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
dependencies: dependencies:
is-extglob: 2.1.1 is-extglob: 2.1.1
/is-number/7.0.0: /is-number@7.0.0:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'} engines: {node: '>=0.12.0'}
/js-tokens/4.0.0: /js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
dev: true dev: true
/jsesc/2.5.2: /jsesc@2.5.2:
resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
engines: {node: '>=4'} engines: {node: '>=4'}
hasBin: true hasBin: true
dev: true dev: true
/json5/2.2.1: /json5@2.2.1:
resolution: {integrity: sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==} resolution: {integrity: sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==}
engines: {node: '>=6'} engines: {node: '>=6'}
hasBin: true hasBin: true
dev: true dev: true
/kolorist/1.5.1: /kolorist@1.5.1:
resolution: {integrity: sha512-lxpCM3HTvquGxKGzHeknB/sUjuVoUElLlfYnXZT73K8geR9jQbroGlSCFBax9/0mpGoD3kzcMLnOlGQPJJNyqQ==} resolution: {integrity: sha512-lxpCM3HTvquGxKGzHeknB/sUjuVoUElLlfYnXZT73K8geR9jQbroGlSCFBax9/0mpGoD3kzcMLnOlGQPJJNyqQ==}
dev: true dev: true
/lodash-es/4.17.21: /lodash-es@4.17.21:
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
dev: false dev: false
/lodash/4.17.21: /lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
dev: false dev: false
/ms/2.1.2: /ms@2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
dev: true dev: true
/nanoid/3.3.4: /nanoid@3.3.4:
resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true hasBin: true
/node-releases/2.0.6: /node-releases@2.0.6:
resolution: {integrity: sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==} resolution: {integrity: sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==}
dev: true dev: true
/normalize-path/3.0.0: /normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
/path-parse/1.0.7: /path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
/picocolors/1.0.0: /picocolors@1.0.0:
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
/picomatch/2.3.1: /picomatch@2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'} engines: {node: '>=8.6'}
/postcss/8.4.16: /postcss@8.4.16:
resolution: {integrity: sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==} resolution: {integrity: sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==}
engines: {node: ^10 || ^12 || >=14} engines: {node: ^10 || ^12 || >=14}
dependencies: dependencies:
@ -822,16 +832,16 @@ packages:
picocolors: 1.0.0 picocolors: 1.0.0
source-map-js: 1.0.2 source-map-js: 1.0.2
/preact/10.10.6: /preact@10.10.6:
resolution: {integrity: sha512-w0mCL5vICUAZrh1DuHEdOWBjxdO62lvcO++jbzr8UhhYcTbFkpegLH9XX+7MadjTl/y0feoqwQ/zAnzkc/EGog==} resolution: {integrity: sha512-w0mCL5vICUAZrh1DuHEdOWBjxdO62lvcO++jbzr8UhhYcTbFkpegLH9XX+7MadjTl/y0feoqwQ/zAnzkc/EGog==}
/readdirp/3.6.0: /readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'} engines: {node: '>=8.10.0'}
dependencies: dependencies:
picomatch: 2.3.1 picomatch: 2.3.1
/resolve/1.22.1: /resolve@1.22.1:
resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==}
hasBin: true hasBin: true
dependencies: dependencies:
@ -839,18 +849,18 @@ packages:
path-parse: 1.0.7 path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0 supports-preserve-symlinks-flag: 1.0.0
/rollup/2.77.3: /rollup@2.77.3:
resolution: {integrity: sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==} resolution: {integrity: sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==}
engines: {node: '>=10.0.0'} engines: {node: '>=10.0.0'}
hasBin: true hasBin: true
optionalDependencies: optionalDependencies:
fsevents: 2.3.2 fsevents: 2.3.2
/safe-buffer/5.1.2: /safe-buffer@5.1.2:
resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
dev: true dev: true
/sass/1.54.8: /sass@1.54.8:
resolution: {integrity: sha512-ib4JhLRRgbg6QVy6bsv5uJxnJMTS2soVcCp9Y88Extyy13A8vV0G1fAwujOzmNkFQbR3LvedudAMbtuNRPbQww==} resolution: {integrity: sha512-ib4JhLRRgbg6QVy6bsv5uJxnJMTS2soVcCp9Y88Extyy13A8vV0G1fAwujOzmNkFQbR3LvedudAMbtuNRPbQww==}
engines: {node: '>=12.0.0'} engines: {node: '>=12.0.0'}
hasBin: true hasBin: true
@ -859,38 +869,38 @@ packages:
immutable: 4.1.0 immutable: 4.1.0
source-map-js: 1.0.2 source-map-js: 1.0.2
/semver/6.3.0: /semver@6.3.0:
resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==}
hasBin: true hasBin: true
dev: true dev: true
/source-map-js/1.0.2: /source-map-js@1.0.2:
resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
/supports-color/5.5.0: /supports-color@5.5.0:
resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
engines: {node: '>=4'} engines: {node: '>=4'}
dependencies: dependencies:
has-flag: 3.0.0 has-flag: 3.0.0
dev: true dev: true
/supports-preserve-symlinks-flag/1.0.0: /supports-preserve-symlinks-flag@1.0.0:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
/to-fast-properties/2.0.0: /to-fast-properties@2.0.0:
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
engines: {node: '>=4'} engines: {node: '>=4'}
dev: true dev: true
/to-regex-range/5.0.1: /to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'} engines: {node: '>=8.0'}
dependencies: dependencies:
is-number: 7.0.0 is-number: 7.0.0
/update-browserslist-db/1.0.7_browserslist@4.21.3: /update-browserslist-db@1.0.7(browserslist@4.21.3):
resolution: {integrity: sha512-iN/XYesmZ2RmmWAiI4Z5rq0YqSiv0brj9Ce9CfhNE4xIW2h+MFxcgkxIzZ+ShkFPUkjU3gQ+3oypadD3RAMtrg==} resolution: {integrity: sha512-iN/XYesmZ2RmmWAiI4Z5rq0YqSiv0brj9Ce9CfhNE4xIW2h+MFxcgkxIzZ+ShkFPUkjU3gQ+3oypadD3RAMtrg==}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
@ -901,7 +911,7 @@ packages:
picocolors: 1.0.0 picocolors: 1.0.0
dev: true dev: true
/vite/3.0.9_sass@1.54.8: /vite@3.0.9(sass@1.54.8):
resolution: {integrity: sha512-waYABTM+G6DBTCpYAxvevpG50UOlZuynR0ckTK5PawNVt7ebX6X7wNXHaGIO6wYYFXSM7/WcuFuO2QzhBB6aMw==} resolution: {integrity: sha512-waYABTM+G6DBTCpYAxvevpG50UOlZuynR0ckTK5PawNVt7ebX6X7wNXHaGIO6wYYFXSM7/WcuFuO2QzhBB6aMw==}
engines: {node: ^14.18.0 || >=16.0.0} engines: {node: ^14.18.0 || >=16.0.0}
hasBin: true hasBin: true

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

@ -5,7 +5,11 @@ export const CompoundButton = ({ options, value, setValue }) => {
<div class="compound"> <div class="compound">
{options.map(option => ( {options.map(option => (
<button <button
class={withClasses(['radio', option.value === value && 'selected'])} class={withClasses([
'radio',
option.value === value && 'selected',
option.icon && 'icon',
])}
onClick={() => setValue(option.value)} onClick={() => setValue(option.value)}
> >
{option.label} {option.label}

@ -1,12 +0,0 @@
import { Icon } from './Icon.jsx'
export const ToolOverlay = ({ visibility, toggleVisibility, onClose }) => (
<div class="overlay">
<button class="icon primary" onClick={toggleVisibility}>
<Icon name={visibility ? 'visibility_off' : 'visibility'} />
</button>
<button class="icon" onClick={onClose}>
<Icon name="close" />
</button>
</div>
)

@ -0,0 +1,33 @@
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={() =>
isSafari ? input.current.focus() : input.current.showPicker()
}
>
<input
ref={input}
type="date"
value={`${year}-${month}-${day}`}
onChange={e => setDate(new Date(e.target.value).toISOString())}
/>
<div class="date-picker-render">
<div class="date">
{day}/{month}/{year}
</div>
<div class="calendar">
<Icon name="calendar_month" />
</div>
</div>
</div>
)
}

@ -1,29 +1,41 @@
import { Course } from './view/Course.jsx' import { Courses } from './view/Courses.jsx'
import { Schedule } from './view/Schedule.jsx' import { Schedule } from './view/Schedule.jsx'
import { WorkWeek } from './view/WorkWeek.jsx'
import { WorkWeekGrid } from './view/WorkWeekGrid.jsx'
import { WorkWeekTranspose } from './view/WorkWeekTranspose.jsx'
export const MODE_COURSE = 'course' export const MODE_COURSES = 'course'
export const MODE_WORKWEEK = 'work-week' export const MODE_WORKWEEK = 'work-week'
export const MODE_SCHEDULE = 'schedule' export const MODE_SCHEDULE = 'schedule'
export const MODE_WORKWEEK_GRID = 'work-week-grid' export const MODE_WORKWEEK_GRID = 'work-week-grid'
export const MODE_WORKWEEK_TRANSPOSE = 'work-week-transpose' export const MODE_WORKWEEK_TRANSPOSE = 'work-week-transpose'
const viewModeMap = { const viewModeMap = {
[MODE_COURSE]: Course, [MODE_COURSES]: Courses,
[MODE_WORKWEEK]: WorkWeek,
[MODE_WORKWEEK_GRID]: WorkWeekGrid,
[MODE_WORKWEEK_TRANSPOSE]: WorkWeekTranspose,
[MODE_SCHEDULE]: Schedule, [MODE_SCHEDULE]: Schedule,
} }
export const EventsView = ({ mode, ...viewProps }) => { // export const EventsView = ({ mode, ...viewProps }) => {
const Mode = viewModeMap[mode] // const Mode = viewModeMap[mode]
//
// return (
// <div class="events-view">
// <Mode {...viewProps} />
// </div>
// )
// }
export const EventsView = ({ mode, source, ...viewProps }) => {
// const Mode = viewModeMap[mode]
if (source === 'orario') {
return (
<div class="events-view">
<Schedule source={source} {...viewProps} />
</div>
)
} else {
return ( return (
<div class="events-view"> <div class="events-view">
<Mode {...viewProps} /> <Courses source={source} {...viewProps} />
</div> </div>
) )
}
} }

@ -1,53 +1,17 @@
import { ComboBox } from './ComboBox.jsx' import { ComboBox } from './ComboBox.jsx'
import { MODE_COURSE, MODE_SCHEDULE, MODE_WORKWEEK, MODE_WORKWEEK_GRID } from './EventsView.jsx' import {
MODE_COURSES,
MODE_SCHEDULE,
MODE_WORKWEEK,
MODE_WORKWEEK_GRID,
} from './EventsView.jsx'
import { DatePicker } from './DatePicker.jsx'
import { Help } from './Help.jsx' import { Help } from './Help.jsx'
import { Icon } from './Icon.jsx' import { Icon } from './Icon.jsx'
export const HamburgerMenu = ({ onClose, mode, setMode, source, setSource, theme, setTheme }) => { export const HamburgerMenu = ({ date, setDate, onClose, theme, setTheme }) => {
return ( return (
<div class="menu"> <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"> <div class="help">
<h2> <h2>
<Icon name="info" /> <Icon name="info" />

@ -2,38 +2,45 @@ import { Icon } from './Icon.jsx'
export const Help = ({}) => ( export const Help = ({}) => (
<> <>
<h3>Selezione Corsi</h3> <h3>Visualizzazione Corsi</h3>
<p> <p>
Per visualizzare solo una selezione dei corsi disponibili, clicca su quelli che ti Per visualizzare i corsi che ti interessano nella tabella dell'orario, devi
interessano e poi nascondi gli altri con il tasto <Icon name="visibility" /> che prima selezionarli. Puoi selezionare dei corsi cliccandoli, cercandoli nelle
comparirà in basso a destra. sezioni Primo anno (<b>I</b>), Secondo anno (<b>II</b>), Terzo anno (
<b>III</b>), Magistrale (<b>M</b>), o Tutti.
</p> </p>
<p> <p>
Per vedere l'orario settimanale, clicca su <b>Settimana</b>, che mostrerà un calendario Una volta compiuta la selezione, è possibile vedere la tabella delle lezioni
con i corsi attualmente selezionati. andando nella visualizzazione Orario (
<Icon name="calendar_view_month" />)
</p> </p>
<p> <p>
La selezione effettuata verrà preservata dalla visualizzazione <b>Corsi</b> a quella Per via di eventuali preferenze personali, è possibile cambiare l'orientazione
Settimana, permettendo di individuare eventuali sovrapposizioni di orari. della tabella Orario trasponendola, utilizzando il pulsante Trasponi (
<Icon name="switch_left" style="transform: rotate(-45deg)" />)
</p> </p>
<p> <p>
I corsi sono raggruppati per: primo, secondo, terzo anno (<b>I</b>,<b>II</b>,<b>III</b>) È anche possibile visualizzare in uno specchietto riassuntivo soltanto i corsi
e magistrale. Alternativamente, puoi scegliere fra tutti i corsi disponibili cliccando selezionati, andando nella visualizzazione Lista (
su <b>Tutti</b>. <Icon name="list" />)
</p> </p>
<h3>Stampa</h3> <h3>Stampa</h3>
<p> <p>
Da desktop puoi stampare l'orario attualmente visibile con il bottone <Icon name="print" /> (è Da desktop puoi stampare l'orario attualmente visibile con il bottone{' '}
consigliato controllare le opzioni di stampa per un risultato soddisfacente). <Icon name="print" /> (è consigliato controllare le opzioni di stampa per
ottenere un risultato soddisfacente).
</p> </p>
<h3>Bug &amp; Contatti</h3> <h3>Bug &amp; Contatti</h3>
<p> <p>
In caso di bug puoi creare una issue sulla repo git del progetto{' '} In caso di bug puoi creare una issue sulla repo git del progetto{' '}
<a href="https://git.phc.dm.unipi.it/phc/orario"> <a href="https://git.phc.dm.unipi.it/phc/orario">
https://git.phc.dm.unipi.it/phc/orario https://git.phc.dm.unipi.it/phc/orario
</a>
, contattarci all'indirizzo{' '}
<a href="mailto:macchinisti@lists.dm.unipi.it">
macchinisti@lists.dm.unipi.it
</a>{' '} </a>{' '}
oppure puoi contattarci direttamente all'indirizzo{' '} oppure passare direttamente in PHC.
<a href="mailto:macchinisti@lists.dm.unipi.it">macchinisti@lists.dm.unipi.it</a>.
</p> </p>
</> </>
) )

@ -0,0 +1,40 @@
import { CompoundButton } from './CompoundButton.jsx'
import { Icon } from './Icon.jsx'
export const OptionBar = ({ view, setView }) => {
return (
<div class="option-bar">
<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: 'Tutti' },
]}
value={view}
setValue={setView}
/>
</div>
<CompoundButton
options={[
{
value: 'orario',
label: <Icon name="calendar_view_month" />,
icon: true,
},
{
value: 'lista',
label: <Icon name="list" />,
icon: true,
},
]}
value={view}
setValue={setView}
/>
</div>
</div>
)
}

@ -1,41 +0,0 @@
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,9 +9,12 @@ export const Popup = ({ title, children, onClose }) => {
class="popup-container" class="popup-container"
ref={popupLeaveRegionRef} ref={popupLeaveRegionRef}
onClick={e => onClick={e =>
popupLeaveRegionRef.current && popupLeaveRegionRef.current === e.target && onClose() popupLeaveRegionRef.current &&
popupLeaveRegionRef.current === e.target &&
onClose()
} }
> >
<div class="popup-wrapper">
<div class="popup"> <div class="popup">
<div class="header"> <div class="header">
<div class="title">{title}</div> <div class="title">{title}</div>
@ -22,5 +25,6 @@ export const Popup = ({ title, children, onClose }) => {
<div class="content">{children}</div> <div class="content">{children}</div>
</div> </div>
</div> </div>
</div>
) )
} }

@ -0,0 +1,18 @@
import { DatePicker } from './DatePicker.jsx'
import { Icon } from './Icon.jsx'
export const SettingsBar = ({ theme, setTheme, date, setDate }) => {
return (
<div class="settings-bar">
<div class="settings-group">
<button
class="icon"
onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
>
<Icon name={theme === 'dark' ? 'dark_mode' : 'light_mode'} />
</button>
<DatePicker date={date} setDate={setDate} />
</div>
</div>
)
}

@ -0,0 +1,13 @@
import { Icon } from './Icon.jsx'
import { MODE_COURSES } from './EventsView.jsx'
export const ToolOverlay = ({ mode, toggleMode, onClose }) => (
<div class="overlay">
<button class="icon primary" onClick={toggleMode}>
<Icon name={mode === MODE_COURSES ? 'calendar_month' : 'view_list'} />
</button>
<button class="icon" onClick={onClose}>
<Icon name="close" />
</button>
</div>
)

@ -1,13 +1,14 @@
import { CompoundButton } from './CompoundButton.jsx' import { CompoundButton } from './CompoundButton.jsx'
import { MODE_COURSE, MODE_SCHEDULE, MODE_WORKWEEK, MODE_WORKWEEK_GRID } from './EventsView.jsx' import { DatePicker } from './DatePicker.jsx'
import { Icon } from './Icon.jsx' import { Icon } from './Icon.jsx'
export const Toolbar = ({ export const Toolbar = ({
mode,
setMode,
source, source,
setSource, setSource,
onShowMenu, date,
setDate,
showMobileMenu,
setShowMobileMenu,
onHelp, onHelp,
theme, theme,
setTheme, setTheme,
@ -15,8 +16,11 @@ export const Toolbar = ({
return ( return (
<div class="toolbar"> <div class="toolbar">
<div class="mobile"> <div class="mobile">
<button class="flat icon" onClick={onShowMenu}> <button
<Icon name="menu" /> class="flat icon"
onClick={() => setShowMobileMenu(!showMobileMenu)}
>
<Icon name={`${showMobileMenu ? 'close' : 'menu'}`} />
</button> </button>
</div> </div>
<div class="item logo"> <div class="item logo">
@ -36,20 +40,21 @@ export const Toolbar = ({
setValue={setSource} setValue={setSource}
/> />
</div> </div>
</div>
<div class="option-group">
<div class="item option"> <div class="item option">
<CompoundButton <CompoundButton
options={[ options={[
{ value: MODE_COURSE, label: 'Corsi' }, { value: 'orario', label: 'Orario' },
{ value: MODE_WORKWEEK, label: 'Settimana' }, { value: 'lista', label: 'Lista' },
{ value: MODE_WORKWEEK_GRID, label: 'Schema' },
{ value: MODE_SCHEDULE, label: 'Giorno' },
]} ]}
value={mode} value={source}
setValue={setMode} setValue={setSource}
/> />
</div> </div>
</div>
<div class="option-group">
<DatePicker date={date} setDate={setDate} />
</div>
<div class="option-group">
<div class="item option"> <div class="item option">
<button class="icon" onClick={() => window.print()}> <button class="icon" onClick={() => window.print()}>
<Icon name="print" /> <Icon name="print" />

@ -2,23 +2,39 @@ import { format } from 'date-fns'
import _ from 'lodash' import _ from 'lodash'
import { useEffect, useRef, useState } from 'preact/hooks' import { useEffect, useRef, useState } from 'preact/hooks'
import { normalizeCourseName, WEEK_DAYS } from '../../utils.jsx' import { prettyCourseName, WEEK_DAYS } from '../../utils.jsx'
import { Icon } from '../Icon.jsx'
export const Course = ({ events, selection, setSelection, hideOtherCourses }) => { export const Courses = ({
source,
timetables,
selection,
setSelection,
hideOtherCourses,
}) => {
const events = timetables[source]
const selectionSet = new Set(selection) const selectionSet = new Set(selection)
const visibleEvents = !hideOtherCourses ? events : events.filter(e => selectionSet.has(e.id)) const visibleEvents = hideOtherCourses
? events.filter(e => selectionSet.has(e.id))
: events
const eventsByCourse = _.groupBy(_.sortBy(visibleEvents, 'id'), 'id') const eventsByCourse = _.groupBy(_.sortBy(visibleEvents, 'id'), 'id')
const profsPerCourse = _.mapValues(eventsByCourse, events =>
_.uniq(events.flatMap(event => event.docenti))
)
const [currentlyHovered, setCurrentlyHovered] = useState(null) const [currentlyHovered, setCurrentlyHovered] = useState(null)
const element = useRef() const element = useRef()
useEffect(() => { useEffect(() => {
if (element.current) { if (element.current) {
const l = e => { const l = e => {
const isMobile = window.matchMedia('(pointer: coarse)').matches
const $course = e.target.closest('.course') const $course = e.target.closest('.course')
if ($course) { if ($course && !isMobile) {
setCurrentlyHovered($course.dataset.courseId) setCurrentlyHovered($course.dataset.courseId)
} else { } else {
setCurrentlyHovered(null) setCurrentlyHovered(null)
@ -37,6 +53,15 @@ export const Course = ({ events, selection, setSelection, hideOtherCourses }) =>
return ( return (
<div class="course-view" ref={element}> <div class="course-view" ref={element}>
{hideOtherCourses && selection.length === 0 && (
<div class="warning">
<p>Non hai ancora selezionato nessun corso.</p>
<p>
Clicca sui corsi nelle altre visuali per selezionarli e
visualizzarli nella lista
</p>
</div>
)}
<div class="wrap-container"> <div class="wrap-container">
{Object.entries(eventsByCourse).map(([id, courseEvents]) => ( {Object.entries(eventsByCourse).map(([id, courseEvents]) => (
<div <div
@ -51,14 +76,14 @@ export const Course = ({ events, selection, setSelection, hideOtherCourses }) =>
else setSelection(selection.filter(selId => selId !== id)) else setSelection(selection.filter(selId => selId !== id))
}} }}
> >
<div class="title">{normalizeCourseName(courseEvents[0].name)}</div> <div class="title">{prettyCourseName(courseEvents[0].name)}</div>
<div class="docenti">{courseEvents[0].docenti.join(', ')}</div> <div class="docenti">{profsPerCourse[id].join(', ')}</div>
<div class="events"> <div class="events">
{courseEvents.map(course => ( {courseEvents.map(course => (
<div> <div>
{WEEK_DAYS[course.start.getDay()]}{' '} {WEEK_DAYS[course.start.getDay()]}{' '}
{format(course.start, 'H:mm')} &ndash;{' '} {format(course.start, 'H:mm')}&ndash;
{format(course.end, 'H:mm')} {course.aula} {format(course.end, 'H:mm')} {course.aule.join(', ')}
</div> </div>
))} ))}
</div> </div>

@ -1,54 +1,266 @@
import { format } from 'date-fns' import { useEffect, useRef, useState } from 'preact/hooks'
import _ from 'lodash' import _ from 'lodash'
import { normalizeCourseName, WEEK_DAYS, withClasses } from '../../utils.jsx' import { differenceInMinutes, startOfDay } from 'date-fns'
export const Schedule = ({ events, selection, setSelection, hideOtherCourses }) => { import { WEEK_DAYS_SHORT, prettyCourseName, usePersistentState } from '../../utils.jsx'
const selectionSet = new Set(selection) import { layoutEvents, layoutIntervals } from '../../interval-layout.js'
import { Popup } from '../Popup.jsx'
import { Icon } from '../Icon.jsx'
const TransposePopup = ({ onClose }) => {
return (
<Popup
title={
<>
<Icon name="info" /> Attenzione! La tabella è stata trasposta!
</>
}
onClose={onClose}
>
<p>A grande richiesta popolare abbiamo trasposto la tabella dell'orario!</p>
const visibleEvents = !hideOtherCourses ? events : events.filter(e => selectionSet.has(e.id)) <p>
Assicurati quindi di leggerla correttamente (dall'alto verso il basso
invece che da sinistra verso destra).
</p>
const eventsByWeekday = _.mapValues( <p>
_.groupBy(visibleEvents, e => e.start.getDay()), Se preferisci utilizzare la versione vecchia, puoi utilizzare il pulsante
dailyEvents => _.groupBy(dailyEvents, e => e.start.getHours()) 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>
) )
}
const NoCourseWarning = () => {
return ( return (
<div class="schedule-view"> <div class="warning">
{Object.entries(eventsByWeekday).map(([index, dailyEvents]) => ( <p>Non hai ancora selezionato nessun corso.</p>
<> <p>
<div class="header giorno"> Clicca sui corsi nelle altre visuali per selezionarli e visualizzarli
<div class="inner">{WEEK_DAYS[index]}</div> nell'orario
</p>
</div> </div>
{Object.values(dailyEvents).map(events => ( )
}
const Layout = ({ layout, day, colors }) => {
return (
<> <>
<div class="header orario">{format(events[0].start, 'H:mm')}</div> {layout.map(block => (
{events.map(event => (
<div <div
class={withClasses([ class="event-block-wrapper"
'event', style={{
selectionSet.has(event.id) && 'selected', '--time-start': block.start,
])} '--time-end': block.end,
onClick={() => { '--day-position': day,
if (!selectionSet.has(event.id)) }}
setSelection([...selection, event.id]) >
else <div class="event-block">
setSelection( {block.events.map((event, index) => (
selection.filter(selId => selId !== event.id) <div
class="event-wrapper"
style={{
'--block-size': block.end - block.start,
'--size': event.end - event.start,
'--relative-start': event.start - block.start,
'--index': event.index,
'--of': block.layers,
'--color': `var(--event-${colors[event.id]})`,
}}
>
<div class="event">
{event.aule.map(aula => (
<div>{aula.replace(/^Fib /, '')}</div>
))}
</div>
</div>
))}
</div>
</div>
))}
</>
) )
}
const ScheduleGrid = ({
orientation,
setOrientation,
weekStart,
weekEnd,
dayBlocksLayout,
colors,
}) => {
return (
<div
class={`grid ${orientation}`}
style={{
'--time-slots': weekEnd - weekStart,
}} }}
> >
<div class="title">{normalizeCourseName(event.name)}</div> <div class="transpose-button">
<div class="orario"> <button
{format(event.start, 'H:mm')} &ndash;{' '} class="small"
{format(event.end, 'H:mm')} onClick={() =>
setOrientation(
orientation === 'original' ? 'transposed' : 'original'
)
}
>
<Icon name="switch_left" style="transform: rotate(-45deg)" />
</button>
</div> </div>
<div class="aula">{event.aula}</div> {[1, 2, 3, 4, 5].map(n => (
<>
<div class="day-label" style={`--position: ${n + 1}`}>
{WEEK_DAYS_SHORT[n]}
</div>
<div class="day-line" style={`--position: ${n + 1}`}></div>
</>
))}
{[9, 11, 14, 16].map(n => (
<div
class="time-label"
style={{
'--position': n * 2 - weekStart,
}}
>
{n}-{n + 2}
</div> </div>
))} ))}
<div class="time-line" style="--position: 0"></div>
{[9, 11, 13, 14, 16, 18].map(n => (
<>
{n * 2 > weekStart && n * 2 < weekEnd && (
<div
class="time-line"
style={{
'--position': n * 2 - weekStart,
}}
></div>
)}
</> </>
))} ))}
{Object.entries(dayBlocksLayout).map(([day, layout]) => (
<Layout layout={layout} day={day} colors={colors} />
))}
</div>
)
}
const ScheduleLegend = ({ courses, colors }) => {
return (
<div class="legend">
{courses.map(course => (
<>
<div
class="color"
style={{
'--color': `var(--event-${colors[course.id]})`,
}}
></div>
<div class="name">{prettyCourseName(course.name)}</div>
</> </>
))} ))}
</div> </div>
) )
} }
const ScheduleCard = ({
orientation,
setOrientation,
weekStart,
weekEnd,
dayBlocksLayout,
courses,
colors,
}) => {
return (
<div class="schedule-card">
<ScheduleGrid
orientation={orientation}
setOrientation={setOrientation}
weekStart={weekStart}
weekEnd={weekEnd}
dayBlocksLayout={dayBlocksLayout}
colors={colors}
/>
<ScheduleLegend courses={courses} colors={colors} />
</div>
)
}
export const Schedule = ({ timetables, selection }) => {
const [hasSeenTranspose, setHasSeenTranspose] = usePersistentState(
'transpose_info',
'false'
)
const [orientation, setOrientation] = usePersistentState('orientation', 'original')
const colorList = ['red', 'purple', 'blue', 'yellow', 'green', 'orange', 'lightblue']
const allEvents = timetables['tutti']
const selectionSet = new Set(selection)
const events = allEvents
.filter(e => selectionSet.has(e.id))
.map(e => ({
...e,
day: e.start.getDay(),
start: differenceInMinutes(e.start, startOfDay(e.start)),
end: differenceInMinutes(e.end, startOfDay(e.start)),
}))
const weekStart = Math.min(...events.map(e => e.start), 9 * 60) / 30
const weekEnd = Math.max(...events.map(e => e.end), 18 * 60) / 30
const relativeEvents = events.map(e => ({
...e,
start: Math.round(e.start / 30 - weekStart),
end: Math.round(e.end / 30 - weekStart),
}))
const courses = _.uniqBy(events, event => event.id)
const colors = Object.fromEntries(
courses.map((course, index) => {
return [course.id, colorList[index % colorList.length]]
})
)
const base = {
1: [],
2: [],
3: [],
4: [],
5: [],
}
const eventsByWeekday = {
...base,
..._.groupBy(relativeEvents, event => event.day),
}
const dayBlocksLayout = _.mapValues(eventsByWeekday, dayEvents =>
layoutEvents(dayEvents)
)
return (
<>
{hasSeenTranspose === 'false' && (
<TransposePopup onClose={() => setHasSeenTranspose('true')} />
)}
<div class="schedule-view">
{selection.length === 0 && <NoCourseWarning />}
<ScheduleCard
orientation={orientation}
setOrientation={setOrientation}
weekStart={weekStart}
weekEnd={weekEnd}
dayBlocksLayout={dayBlocksLayout}
courses={courses}
colors={colors}
/>
</div>
</>
)
}

@ -1,150 +0,0 @@
import { useEffect, useRef, useState } from 'preact/hooks'
import _ from 'lodash'
import { differenceInMinutes, startOfDay } from 'date-fns'
import { hashString, normalizeCourseName, WEEK_DAYS } from '../../utils.jsx'
import { layoutIntervals } from '../../interval-layout.js'
export const WorkWeek = ({ events, selection, setSelection, hideOtherCourses }) => {
const selectionSet = new Set(selection)
const eventsByWeekday = _.groupBy(
!hideOtherCourses ? events : events.filter(e => selectionSet.has(e.id)),
event => event.start.getDay()
)
// const dayIntervalLayout = _.mapValues(Object.assign(base, eventsByWeekday), events =>
const dayIntervalLayout = _.mapValues(eventsByWeekday, events =>
layoutIntervals(
events.map(e => ({
start: differenceInMinutes(e.start, startOfDay(e.start)),
end: differenceInMinutes(e.end, startOfDay(e.start)),
data: e,
}))
)
)
const [currentlyHovered, setCurrentlyHovered] = useState(null)
const element = useRef()
useEffect(() => {
if (element.current) {
const l = e => {
const $event = e.target.closest('.event')
if ($event) {
setCurrentlyHovered($event.dataset.eventId)
} else {
setCurrentlyHovered(null)
}
}
element.current.addEventListener('mousemove', l)
element.current.addEventListener('mouseleave', l)
return () => {
element.current.removeEventListener('mousemove', l)
element.current.removeEventListener('mouseleave', l)
}
}
}, [element.current])
return (
<div class="work-week-v-view" ref={element}>
<div class="pivot"></div>
<div class="left-header">
<div class="blocks">
<div
class="block skip-border"
style={{
'--start': 9 - 7,
'--size': 2,
}}
>
9:00 &ndash; 11:00
</div>
<div
class="block"
style={{
'--start': 11 - 7,
'--size': 2,
}}
>
11:00 &ndash; 13:00
</div>
<div
class="block skip-border"
style={{
'--start': 14 - 7,
'--size': 2,
}}
>
14:00 &ndash; 16:00
</div>
<div
class="block"
style={{
'--start': 16 - 7,
'--size': 2,
}}
>
16:00 &ndash; 18:00
</div>
</div>
</div>
{Object.entries(dayIntervalLayout).map(([index, layout]) => (
<div class="day" style={{ '--size': Math.max(1, layout.length) }}>
<div class="top-header">{WEEK_DAYS[parseInt(index)]}</div>
<div class="events">
{layout.map((events, stackIndex) => (
<>
{events.map(event => (
<div
class={
'event' +
(currentlyHovered === event.data.id
? ' highlight'
: '') +
(selectionSet.has(event.data.id) ? ' selected' : '')
}
data-event-id={event.data.id}
style={{
'--start': event.start / 60 - 7,
'--stack': stackIndex + 1,
'--size': (event.end - event.start) / 60,
'--hue':
(Math.abs(hashString('seed3' + event.data.id)) %
360) +
'deg',
}}
onClick={() => {
if (!selectionSet.has(event.data.id))
setSelection([...selection, event.data.id])
else
setSelection(
selection.filter(id => event.data.id !== id)
)
}}
>
<div class="title">
{normalizeCourseName(event.data.name)}
</div>
<div class="aula">{event.data.aula}</div>
</div>
))}
</>
))}
{/* Grid Tracks */}
{[1, 3, 5].map(i => (
<div class="grid-line-h" style={{ '--track': i }}></div>
))}
{[6, 8, 10].map(i => (
<div class="grid-line-h" style={{ '--track': i }}></div>
))}
</div>
</div>
))}
</div>
)
}

@ -1,200 +0,0 @@
import { useEffect, useRef, useState } from 'preact/hooks'
import _ from 'lodash'
import { differenceInMinutes, startOfDay } from 'date-fns'
import { hashString, normalizeCourseName, WEEK_DAYS } from '../../utils.jsx'
import { layoutIntervals } from '../../interval-layout.js'
export const WorkWeekGrid = ({ events, selection, setSelection, hideOtherCourses }) => {
const selectionSet = new Set(selection)
const colorList = [
'red',
'purple',
'blue',
'yellow',
'green',
'orange',
'lightblue',
];
const courses = _.uniqBy(!hideOtherCourses ? events : events.filter(e => selectionSet.has(e.id)), event => event.id);
const colors = Object.fromEntries(courses.map((course, index) => {
return [
course.id,
[
colorList[index % colorList.length],
courses.length <= colorList.length ? '' : String.fromCharCode(65 + Math.floor(index / colorList.length))
]
];
}));
const base = {
1: [],
2: [],
3: [],
4: [],
5: [],
}
const eventsByWeekday = {
... base,
... _.groupBy(
!hideOtherCourses ? events : events.filter(e => selectionSet.has(e.id)),
event => event.start.getDay()
)
}
const dayIntervalLayout = _.mapValues(eventsByWeekday, events =>
layoutIntervals(
events.map(e => ({
start: differenceInMinutes(e.start, startOfDay(e.start)),
end: differenceInMinutes(e.end, startOfDay(e.start)),
data: e,
}))
)
)
const startsAndEnds = Object.entries(dayIntervalLayout).flatMap(([index, layout]) => layout.flatMap(events => events.map(event => [event.start, event.end])));
const minStart = Math.min(...startsAndEnds.map(([s, e]) => s)) / 60;
const maxEnd = Math.max(...startsAndEnds.map(([s, e]) => e)) / 60;
// const timeStart = minStart < 9 ? 7 :
// minStart < 11 ? 9 :
// minStart < 13 ? 11 :
// minStart < 14 ? 13 :
// minStart < 16 ? 14 :
// minStart < 18 ? 16 :
// 18;
// const timeEnd = maxEnd > 18 ? 20 :
// maxEnd > 16 ? 18 :
// maxEnd > 14 ? 16 :
// maxEnd > 13 ? 14 :
// maxEnd > 11 ? 13 :
// maxEnd > 9 ? 11 :
// 9;
const timeStart = minStart < 9 ? 7 : 9;
const timeEnd = maxEnd > 18 ? 20 : 18;
const daySizes = Object.entries(dayIntervalLayout).map(([index, layout]) => Math.max(1, layout.length));
const dayOffsets = daySizes.map((v, i) => {
let sum = 0;
for(let j = 0; j < i; j++) {
sum += daySizes[j];
}
return sum;
});
const daysLength = daySizes[4] + dayOffsets[4];
const [currentlyHovered, setCurrentlyHovered] = useState(null)
const element = useRef()
useEffect(() => {
if (element.current) {
const l = e => {
const $event = e.target.closest('.event')
if ($event) {
setCurrentlyHovered($event.dataset.eventId)
} else {
setCurrentlyHovered(null)
}
}
element.current.addEventListener('mousemove', l)
element.current.addEventListener('mouseleave', l)
return () => {
element.current.removeEventListener('mousemove', l)
element.current.removeEventListener('mouseleave', l)
}
}
}, [element.current])
return (
<div class="work-week-grid-view" ref={element}>
<div class="grid" style={{'--days-length': daysLength, '--time-length': timeEnd - timeStart}}>
{[7, 9, 11, 14, 16, 18].map(n =>
<>
{n + 2 > timeStart && n < timeEnd && (
<div class="time" style={{'--offset': n - timeStart + 2}}>{n}-{n+2}</div>
)}
</>
)}
<div class="vline" style="--offset: 2"></div>
{[9, 11, 13, 14, 16, 18].map(n =>
<>
{n > timeStart && n < timeEnd && (
<div class="vline" style={{'--offset': n - timeStart + 2}}></div>
)}
</>
)}
<div class="day-name" style={{'--line': 2 + dayOffsets[0]}}>Lun</div>
<div class="day-name" style={{'--line': 2 + dayOffsets[1]}}>Mar</div>
<div class="day-name" style={{'--line': 2 + dayOffsets[2]}}>Mer</div>
<div class="day-name" style={{'--line': 2 + dayOffsets[3]}}>Gio</div>
<div class="day-name" style={{'--line': 2 + dayOffsets[4]}}>Ven</div>
<div class="hline" style={{'--line': 2 + dayOffsets[0]}}></div>
<div class="hline" style={{'--line': 2 + dayOffsets[1]}}></div>
<div class="hline" style={{'--line': 2 + dayOffsets[2]}}></div>
<div class="hline" style={{'--line': 2 + dayOffsets[3]}}></div>
<div class="hline" style={{'--line': 2 + dayOffsets[4]}}></div>
{Object.entries(dayIntervalLayout).map(([index, layout]) => (
<>
{layout.map((events, stackIndex) => (
<>
{events.map(event => (
<div class={
'event' +
(currentlyHovered === event.data.id
? ' highlight'
: '') +
(selectionSet.has(event.data.id) ? ' selected' : '')
}
data-event-id={event.data.id}
style={{
'--line': 2 + dayOffsets[index-1] + stackIndex,
'--offset': event.start / 60 - timeStart + 2,
'--length': (event.end - event.start) / 60,
'--color': `var(--bubble-${colors[event.data.id][0]})`,
'--border-color': `var(--bubble-border-${colors[event.data.id][0]})`,
'--highlight-color': `var(--bubble-highlight-${colors[event.data.id][0]})`
}}
onClick={() => {
if (!selectionSet.has(event.data.id))
setSelection([...selection, event.data.id])
else
setSelection(
selection.filter(id => event.data.id !== id)
)
}}
>
{colors[event.data.id][1] !== '' && (
<div className="distinguisher">{`(${colors[event.data.id][1]})`}</div>
)}
{event.data.aula}</div>
))}
</>
))}
</>
))}
</div>
<div class="legend">
{courses.map(course => (
<>
<div class="color"
style={{
'--color': `var(--bubble-${colors[course.id][0]})`,
'--border-color': `var(--bubble-border-${colors[course.id][0]})`
}}
>
{colors[course.id][1]}
</div>
<div class="name">{normalizeCourseName(course.name)}</div>
</>
))}
</div>
</div>
)
}

@ -1,104 +0,0 @@
import { useEffect, useRef } from 'preact/hooks'
import _ from 'lodash'
import { differenceInMinutes, startOfDay } from 'date-fns'
import { hashString, normalizeCourseName, WEEK_DAYS } from '../../utils.jsx'
import { layoutIntervals } from '../../interval-layout.js'
export const WorkWeekTranspose = ({ 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,
}))
)
)
return (
<div class="work-week-h-view">
<div class="week">
{WEEK_DAYS.slice(1, 6).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.id)
) %
360) +
'deg',
}}
ref={eventRef}
>
{normalizeCourseName(event.data.name)}
</div>
)
}
return <Local />
})
)}
</div>
))}
</div>
</div>
</div>
)
}

@ -34,6 +34,55 @@ export function layoutIntervals(intervals, { tight } = {}) {
return stack.map(({ intervals }) => intervals) return stack.map(({ intervals }) => intervals)
} }
function layoutBlockEvents(events) {
events.sort((a, b) => a.start - b.start)
let result = []
for (const event of events) {
let viableIndex = 0
while (
result.filter(
e => e.index === viableIndex && e.start < event.end && event.start < e.end
).length !== 0
) {
viableIndex += 1
}
result.push({ ...event, index: viableIndex })
}
return result
}
export function layoutEvents(events) {
const overlap = (event, block) => event.start < block.end && block.start < event.end
events.sort((a, b) => a.start - b.start)
let layout = []
for (const event of events) {
const blocks = layout.filter(block => overlap(event, block))
if (blocks.length > 0) {
layout = layout.filter(block => !overlap(event, block))
layout.push({
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]),
})
} else {
layout.push({ start: event.start, end: event.end, events: [event] })
}
}
return layout.map(block => {
const events = layoutBlockEvents(block.events)
return {
...block,
layers: Math.max(...events.map(event => event.index)) + 1,
events: events,
}
})
}
// // // //
// // Testing... // // Testing...
// // // //

@ -1,35 +1,98 @@
import _ from 'lodash' import _ from 'lodash'
import { render } from 'preact' import { render } from 'preact'
import { useEffect, useState } from 'preact/hooks' import { useEffect, useState } from 'preact/hooks'
import { ToolOverlay } from './components/CourseVisibility.jsx'
import { EventsView, MODE_WORKWEEK_GRID } from './components/EventsView.jsx' // import { ToolOverlay } from './components/ToolOverlay.jsx'
//
// import {
// EventsView,
// MODE_COURSES,
// MODE_SCHEDULE,
// } from './components/EventsView.jsx'
import { Courses } from './components/view/Courses.jsx'
import { Schedule } from './components/view/Schedule.jsx'
import { HamburgerMenu } from './components/HamburgerMenu.jsx' import { HamburgerMenu } from './components/HamburgerMenu.jsx'
import { Help } from './components/Help.jsx' import { Help } from './components/Help.jsx'
import { Icon } from './components/Icon.jsx' import { Icon } from './components/Icon.jsx'
import { Popup } from './components/Popup.jsx' import { Popup } from './components/Popup.jsx'
import { Toolbar } from './components/Toolbar.jsx' import { Toolbar } from './components/Toolbar.jsx'
import { Optionbar } from './components/Optionbar.jsx' import { OptionBar } from './components/OptionBar.jsx'
import {
prettyAulaName,
prettyProfName,
clearOldPersistentStates,
usePersistentState,
} from './utils.jsx'
import { SettingsBar } from './components/SettingsBar.jsx'
// Che fanno queste due righe?
window._ = _ window._ = _
window.dataBuffer = {} window.dataBuffer = {}
const CALENDAR_IDS = { const TIMETABLE_IDS = {
'anno-1': ['6308cfcb1df5cb026699ce32'], 'anno-1': '667e88275e9623041f0e43d4',
'anno-2': ['6308e2dc09352a0208fefdd9'], 'anno-2': '667e89055e9623041f0e43d6',
'anno-3': ['6308e42a1df5cb026699ced4'], 'anno-3': '667e89fcf748ed0415a11dcc',
'magistrale': ['6308e8ea0c34e703bb1f7e85'], 'magistrale': '667ebae63379a3046517ffd4',
'tutti': [
'6308cfcb1df5cb026699ce32',
'6308e2dc09352a0208fefdd9',
'6308e42a1df5cb026699ced4',
'6308e8ea0c34e703bb1f7e85',
],
} }
async function loadEventi(ids) { // const DEFAULT_DATE_RANGE = {
const calendari = await Promise.all( // from: '2023-10-09T00:00:00.000Z',
ids.map(async id => { // to: '2023-10-14T00:00:00.000Z',
// }
// const DATE_RANGES = {
// '64a7c1c651f079001d52e9c8': DEFAULT_DATE_RANGE,
// '6308e2dc09352a0208fefdd9': DEFAULT_DATE_RANGE,
// '6308e42a1df5cb026699ced4': DEFAULT_DATE_RANGE,
// '64a7c7091ab813002c5d9ede': DEFAULT_DATE_RANGE,
// }
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'
) {
if (evento.docenti[0].nome === 'GIOVANNI') {
evento.nome += ' (A)'
}
if (evento.docenti[0].nome === 'PAOLO') {
evento.nome += ' (B)'
}
}
})
return eventi
}
function formatEvents(timetable) {
return timetable.map(({ nome, dataInizio, dataFine, docenti, aule }) => {
return {
id: nome,
name: _.split(nome, '-', 1)[0].trim(),
start: new Date(dataInizio),
end: new Date(dataFine),
docenti: docenti.map(({ nome, cognome }) => prettyProfName(nome, cognome)),
aule: aule.map(aula => prettyAulaName(aula.codice)),
}
})
}
async function loadCalendari(date) {
function getMonday(d) {
const day = d.getDay()
const diff = d.getDate() - day + (day === 0 ? -6 : 1)
const monday = new Date(d.setDate(diff))
monday.setUTCHours(0, 0, 0, 0)
return monday
}
const monday = getMonday(date)
const saturday = new Date(monday)
saturday.setDate(monday.getDate() + 5)
async function req(id) {
// Almost directly copy-pasted from Chrome Dev Tools // Almost directly copy-pasted from Chrome Dev Tools
const req = await fetch( const req = await fetch(
'https://apache.prod.up.cineca.it/api/Impegni/getImpegniCalendarioPubblico', 'https://apache.prod.up.cineca.it/api/Impegni/getImpegniCalendarioPubblico',
@ -46,8 +109,8 @@ async function loadEventi(ids) {
linkCalendarioId: id, linkCalendarioId: id,
clienteId: '628de8b9b63679f193b87046', clienteId: '628de8b9b63679f193b87046',
pianificazioneTemplate: false, pianificazioneTemplate: false,
dataInizio: '2022-10-02T22:00:00.000Z', dataInizio: monday.toISOString(),
dataFine: '2022-10-07T22:00:00.000Z', dataFine: saturday.toISOString(),
}), }),
method: 'POST', method: 'POST',
mode: 'cors', mode: 'cors',
@ -56,127 +119,136 @@ async function loadEventi(ids) {
) )
return await req.json() return await req.json()
}) }
)
// console.log(calendari) const requests = [
req(TIMETABLE_IDS['anno-1']),
req(TIMETABLE_IDS['anno-2']),
req(TIMETABLE_IDS['anno-3']),
req(TIMETABLE_IDS['magistrale']),
]
const results = await Promise.all(requests)
const timetablesRaw = results.map(timetable =>
specialEventPatches(_.uniqBy(timetable, 'id'))
)
const allRaw = specialEventPatches(_.concat(...results), 'id')
if (ids.length === 1) { return {
return calendari[0] 'anno-1': formatEvents(timetablesRaw[0]),
'anno-2': formatEvents(timetablesRaw[1]),
'anno-3': formatEvents(timetablesRaw[2]),
'magistrale': formatEvents(timetablesRaw[3]),
'tutti': formatEvents(allRaw),
} }
return _.uniqBy(_.concat(...calendari), 'id')
} }
const View = ({ view, selection, setSelection, timetables }) => {
if (view === 'orario') {
return <Schedule selection={selection} timetables={timetables} />
} else if (view === 'lista') {
return (
<Courses
selection={selection}
setSelection={setSelection}
source={'tutti'}
timetables={timetables}
hideOtherCourses={true}
/>
)
} else {
return (
<Courses
selection={selection}
setSelection={setSelection}
source={view}
timetables={timetables}
hideOtherCourses={false}
/>
)
}
}
const App = ({}) => { const App = ({}) => {
// Clear persistent states unless state_token corresponds to the one passed
// as the argument. Useful with breaking updates. Change this token if your
// (breaking) update needs a reset of persistent states to avoid crashes.
//
// Use any random string of your choice
// clearOldPersistentStates('e73cba02')
const [date, setDate] = useState(new Date().toISOString())
// Data Sources // Data Sources
const [source, setSource] = useState('anno-1') const [view, setView] = usePersistentState('view', 'magistrale')
const [eventi, setEventi] = useState([]) const [timetables, setTimetables] = useState(null)
useEffect(async () => {
setTimetables(await loadCalendari(new Date(date)))
}, [date])
// View Modes // View Modes
const [mode, setMode] = useState(MODE_WORKWEEK_GRID) // const [mode, setMode] = usePersistentState('orario.mode', MODE_COURSES)
// Selection // Selection
const [selectedCourses, setSelectedCourses] = useState([]) const [selectedCourses, setSelectedCourses] = usePersistentState('selection', [])
const [hideOtherCourses, setHideOtherCourses] = useState(false)
// Menus // Menus
const [helpVisible, setHelpVisible] = useState(false) const [helpVisible, setHelpVisible] = useState(false)
const [showMobileMenu, setShowMobileMenu] = useState(false) const [showMobileMenu, setShowMobileMenu] = useState(false)
useEffect(async () => { // const groupIds = new Set(eventi.map(e => e.nome))
console.log('source changed') const toolOverlayVisible = selectedCourses.length > 0
const eventi = await loadEventi(CALENDAR_IDS[source])
window.dataBuffer[source] = eventi
setEventi(eventi)
}, [source])
const groupIds = new Set(eventi.map(e => e.nome)) const [theme, setTheme] = usePersistentState(
const toolOverlayVisible = 'theme',
selectedCourses.length > 0 && selectedCourses.filter(id => groupIds.has(id)).length > 0 'light'
// window.matchMedia('(prefers-color-scheme: dark)').matches
useEffect(() => { // ? 'dark'
console.log('course length changed') // : 'light'
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') document.body.classList.toggle('dark-mode', theme === 'dark')
localStorage.setItem('theme', theme)
return ( return (
<> <>
<Toolbar <Toolbar
{...{ {...{
mode, source: view,
setMode, setSource: setView,
source, date: date,
setSource, setDate: setDate,
onShowMenu: () => setShowMobileMenu(true), showMobileMenu: showMobileMenu,
setShowMobileMenu: setShowMobileMenu,
onHelp: () => setHelpVisible(true), onHelp: () => setHelpVisible(true),
theme, theme,
setTheme, setTheme,
}} }}
/> />
<Optionbar {showMobileMenu ? (
<SettingsBar
{...{ {...{
mode, theme,
setMode, setTheme,
source, date,
setSource, setDate,
onHelp: () => setHelpVisible(true),
}} }}
/> />
<EventsView ) : (
mode={mode} <OptionBar
selection={selectedCourses} {...{
setSelection={setSelectedCourses} view: view,
hideOtherCourses={hideOtherCourses} setView: setView,
start={new Date(2022, 10, 3)} onHelp: () => setHelpVisible(true),
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)
}} }}
orizzontale
/> />
)} )}
{showMobileMenu && (
<div class="content">
{timetables &&
(showMobileMenu ? (
<HamburgerMenu <HamburgerMenu
{...{ {...{
mode, date,
setMode, setDate,
source,
setSource,
theme, theme,
setTheme, setTheme,
onClose: () => { onClose: () => {
@ -184,7 +256,33 @@ const App = ({}) => {
}, },
}} }}
/> />
)} ) : timetables['tutti'].length === 0 ? (
<div class="warning">
<p>
Non esistono corsi per la settimana selezionata: buone
vacanze! 🎉
</p>
<p>
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 (
<Icon name="menu" />)
</p>
</div>
) : (
<View
selection={selectedCourses}
setSelection={setSelectedCourses}
view={view}
timetables={timetables}
/>
))}
</div>
{/* showMobileMenu && (
) */}
{helpVisible && ( {helpVisible && (
<Popup <Popup
title={ title={

File diff suppressed because it is too large Load Diff

@ -1,5 +1,7 @@
// Calendar // Calendar
import { useEffect, useState } from 'preact/hooks'
export const WEEK_DAYS = [ export const WEEK_DAYS = [
'Domenica', 'Domenica',
'Lunedì', 'Lunedì',
@ -10,6 +12,8 @@ export const WEEK_DAYS = [
'Sabato', 'Sabato',
] ]
export const WEEK_DAYS_SHORT = ['Dom', 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab']
// Hashing // Hashing
export function hashString(str, seed = 0) { export function hashString(str, seed = 0) {
@ -27,7 +31,7 @@ export function hashString(str, seed = 0) {
// Courses // Courses
export function normalizeCourseName(name) { export function prettyCourseName(name) {
return name return name
.split(' ') .split(' ')
.map(word => word.toLowerCase()) .map(word => word.toLowerCase())
@ -40,8 +44,24 @@ export function normalizeCourseName(name) {
}) })
.join(' ') .join(' ')
.replaceAll('Ii', 'II') .replaceAll('Ii', 'II')
.replaceAll('IIi', 'III')
.replaceAll('Iii', 'III') .replaceAll('Iii', 'III')
.replaceAll(/'(.)/g, ({}, letter) => "'" + letter.toUpperCase()) .replaceAll(/'(.)/g, ({}, letter) => "'" + letter.toUpperCase())
.replaceAll(/\((a|b)\)/g, ({}, letter) => '(' + letter.toUpperCase() + ')')
}
export function prettyAulaName(name) {
return name
.replace('FIB', 'Fib')
.replace('RIUNIONI', 'Riunioni')
.replace(/([A-Z0-9])\-LAB/, 'Lab $1')
}
export function prettyProfName(nome, cognome) {
return (nome + ' ' + cognome)
.split(/\b/)
.map(word => _.capitalize(word))
.join('')
} }
// JSX // JSX
@ -53,3 +73,30 @@ export const withClasses = classes =>
.filter(([, value]) => value) .filter(([, value]) => value)
.map(([key]) => key) .map(([key]) => key)
.join(' ') .join(' ')
// LocalStorage stuff
export const clearOldPersistentStates = stateToken => {
const lastStateToken = localStorage.getItem('orario.state_token')
if (lastStateToken === null || lastStateToken !== stateToken) {
localStorage.clear()
localStorage.setItem('orario.state_token', stateToken)
}
}
// Hooks
export const usePersistentState = (key, initialValue) => {
const previousValue = localStorage.getItem(`orario.${key}`)
const [value, setValue] = useState(
previousValue !== null ? JSON.parse(previousValue) : initialValue
)
useEffect(() => {
localStorage.setItem(`orario.${key}`, JSON.stringify(value))
}, [value])
return [value, setValue]
}

Loading…
Cancel
Save