From a34d36257bf87adc42d445fb3763b1934187ae2e Mon Sep 17 00:00:00 2001 From: Francesco Baldino Date: Sat, 19 Aug 2023 03:57:46 +0200 Subject: [PATCH 1/2] first brutal rework and first prototype --- pnpm-lock.yaml | 320 +++++++++--------- src/components/CourseVisibility.jsx | 7 +- src/components/EventsView.jsx | 14 +- src/components/HamburgerMenu.jsx | 2 +- src/components/OptionBar.jsx | 28 +- src/components/Toolbar.jsx | 15 - .../view/{Course.jsx => Courses.jsx} | 7 +- src/components/view/Schedule.jsx | 5 +- src/components/view/WorkWeekGrid.jsx | 23 +- src/main.jsx | 175 +++++----- src/styles/main.scss | 2 +- 11 files changed, 287 insertions(+), 311 deletions(-) rename src/components/view/{Course.jsx => Courses.jsx} (91%) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a0c038f..43b5c75 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,30 +1,40 @@ -lockfileVersion: 5.4 - -specifiers: - '@babel/core': ^7.18.13 - '@preact/preset-vite': ^2.3.0 - 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 +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false dependencies: - 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_sass@1.54.8 + date-fns: + specifier: ^2.29.2 + version: 2.29.2 + lodash: + specifier: ^4.17.21 + 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: - '@babel/core': 7.18.13 - '@preact/preset-vite': 2.3.0_wibdudaz52xr4lhcmpvnys3x3u + '@babel/core': + 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: - /@ampproject/remapping/2.2.0: + /@ampproject/remapping@2.2.0: resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==} engines: {node: '>=6.0.0'} dependencies: @@ -32,26 +42,26 @@ packages: '@jridgewell/trace-mapping': 0.3.15 dev: true - /@babel/code-frame/7.18.6: + /@babel/code-frame@7.18.6: resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} engines: {node: '>=6.9.0'} dependencies: '@babel/highlight': 7.18.6 dev: true - /@babel/compat-data/7.18.13: + /@babel/compat-data@7.18.13: resolution: {integrity: sha512-5yUzC5LqyTFp2HLmDoxGQelcdYgSpP9xsnMWBphAscOdFrHSAVbLNzWiy32sVNDqJRDiJK6klfDnAgu6PAGSHw==} engines: {node: '>=6.9.0'} dev: true - /@babel/core/7.18.13: + /@babel/core@7.18.13: resolution: {integrity: sha512-ZisbOvRRusFktksHSG6pjj1CSvkPkcZq/KHD45LAkVP/oiHJkNBZWfpvlLmX8OtHDG8IuzsFlVRWo08w7Qxn0A==} engines: {node: '>=6.9.0'} dependencies: '@ampproject/remapping': 2.2.0 '@babel/code-frame': 7.18.6 '@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/helpers': 7.18.9 '@babel/parser': 7.18.13 @@ -67,7 +77,7 @@ packages: - supports-color dev: true - /@babel/generator/7.18.13: + /@babel/generator@7.18.13: resolution: {integrity: sha512-CkPg8ySSPuHTYPJYo7IRALdqyjM9HCbt/3uOBEFbzyGVP6Mn8bwFPB0jX6982JVNBlYzM1nnPkfjuXSOPtQeEQ==} engines: {node: '>=6.9.0'} dependencies: @@ -76,14 +86,14 @@ packages: jsesc: 2.5.2 dev: true - /@babel/helper-annotate-as-pure/7.18.6: + /@babel/helper-annotate-as-pure@7.18.6: resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.18.13 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==} engines: {node: '>=6.9.0'} peerDependencies: @@ -96,12 +106,12 @@ packages: semver: 6.3.0 dev: true - /@babel/helper-environment-visitor/7.18.9: + /@babel/helper-environment-visitor@7.18.9: resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-function-name/7.18.9: + /@babel/helper-function-name@7.18.9: resolution: {integrity: sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==} engines: {node: '>=6.9.0'} dependencies: @@ -109,21 +119,21 @@ packages: '@babel/types': 7.18.13 dev: true - /@babel/helper-hoist-variables/7.18.6: + /@babel/helper-hoist-variables@7.18.6: resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.18.13 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==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.18.13 dev: true - /@babel/helper-module-transforms/7.18.9: + /@babel/helper-module-transforms@7.18.9: resolution: {integrity: sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==} engines: {node: '>=6.9.0'} dependencies: @@ -139,41 +149,41 @@ packages: - supports-color dev: true - /@babel/helper-plugin-utils/7.18.9: + /@babel/helper-plugin-utils@7.18.9: resolution: {integrity: sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-simple-access/7.18.6: + /@babel/helper-simple-access@7.18.6: resolution: {integrity: sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.18.13 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==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.18.13 dev: true - /@babel/helper-string-parser/7.18.10: + /@babel/helper-string-parser@7.18.10: resolution: {integrity: sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-validator-identifier/7.18.6: + /@babel/helper-validator-identifier@7.18.6: resolution: {integrity: sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-validator-option/7.18.6: + /@babel/helper-validator-option@7.18.6: resolution: {integrity: sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==} engines: {node: '>=6.9.0'} dev: true - /@babel/helpers/7.18.9: + /@babel/helpers@7.18.9: resolution: {integrity: sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==} engines: {node: '>=6.9.0'} dependencies: @@ -184,7 +194,7 @@ packages: - supports-color dev: true - /@babel/highlight/7.18.6: + /@babel/highlight@7.18.6: resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} engines: {node: '>=6.9.0'} dependencies: @@ -193,7 +203,7 @@ packages: js-tokens: 4.0.0 dev: true - /@babel/parser/7.18.13: + /@babel/parser@7.18.13: resolution: {integrity: sha512-dgXcIfMuQ0kgzLB2b9tRZs7TTFFaGM2AbtA4fJgUUYukzGH4jwsS7hzQHEGs67jdehpm22vkgKwvbU+aEflgwg==} engines: {node: '>=6.0.0'} hasBin: true @@ -201,7 +211,7 @@ packages: '@babel/types': 7.18.13 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==} engines: {node: '>=6.9.0'} peerDependencies: @@ -211,17 +221,17 @@ packages: '@babel/helper-plugin-utils': 7.18.9 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==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: '@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 - /@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==} engines: {node: '>=6.9.0'} peerDependencies: @@ -231,11 +241,11 @@ packages: '@babel/helper-annotate-as-pure': 7.18.6 '@babel/helper-module-imports': 7.18.6 '@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 dev: true - /@babel/template/7.18.10: + /@babel/template@7.18.10: resolution: {integrity: sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==} engines: {node: '>=6.9.0'} dependencies: @@ -244,7 +254,7 @@ packages: '@babel/types': 7.18.13 dev: true - /@babel/traverse/7.18.13: + /@babel/traverse@7.18.13: resolution: {integrity: sha512-N6kt9X1jRMLPxxxPYWi7tgvJRH/rtoU+dbKAPDM44RFHiMH8igdsaSBgFeskhSl/kLWLDUvIh1RXCrTmg0/zvA==} engines: {node: '>=6.9.0'} dependencies: @@ -262,7 +272,7 @@ packages: - supports-color dev: true - /@babel/types/7.18.13: + /@babel/types@7.18.13: resolution: {integrity: sha512-ePqfTihzW0W6XAU+aMw2ykilisStJfDnsejDCXRchCcMJ4O0+8DhPXf2YUbZ6wjBlsEmZwLK/sPweWtu8hcJYQ==} engines: {node: '>=6.9.0'} dependencies: @@ -271,7 +281,7 @@ packages: to-fast-properties: 2.0.0 dev: true - /@esbuild/linux-loong64/0.14.54: + /@esbuild/linux-loong64@0.14.54: resolution: {integrity: sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==} engines: {node: '>=12'} cpu: [loong64] @@ -279,7 +289,7 @@ packages: requiresBuild: true optional: true - /@jridgewell/gen-mapping/0.1.1: + /@jridgewell/gen-mapping@0.1.1: resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==} engines: {node: '>=6.0.0'} dependencies: @@ -287,7 +297,7 @@ packages: '@jridgewell/sourcemap-codec': 1.4.14 dev: true - /@jridgewell/gen-mapping/0.3.2: + /@jridgewell/gen-mapping@0.3.2: resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==} engines: {node: '>=6.0.0'} dependencies: @@ -296,53 +306,53 @@ packages: '@jridgewell/trace-mapping': 0.3.15 dev: true - /@jridgewell/resolve-uri/3.1.0: + /@jridgewell/resolve-uri@3.1.0: resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} engines: {node: '>=6.0.0'} dev: true - /@jridgewell/set-array/1.1.2: + /@jridgewell/set-array@1.1.2: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} engines: {node: '>=6.0.0'} dev: true - /@jridgewell/sourcemap-codec/1.4.14: + /@jridgewell/sourcemap-codec@1.4.14: resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} dev: true - /@jridgewell/trace-mapping/0.3.15: + /@jridgewell/trace-mapping@0.3.15: resolution: {integrity: sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==} dependencies: '@jridgewell/resolve-uri': 3.1.0 '@jridgewell/sourcemap-codec': 1.4.14 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==} peerDependencies: '@babel/core': 7.x vite: 2.x || 3.x dependencies: '@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 - '@prefresh/vite': 2.2.8_preact@10.10.6+vite@3.0.9 + '@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) + '@prefresh/vite': 2.2.8(preact@10.10.6)(vite@3.0.9) '@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 kolorist: 1.5.1 resolve: 1.22.1 - vite: 3.0.9_sass@1.54.8 + vite: 3.0.9(sass@1.54.8) transitivePeerDependencies: - preact - supports-color dev: true - /@prefresh/babel-plugin/0.4.3: + /@prefresh/babel-plugin@0.4.3: resolution: {integrity: sha512-fYAWbU1WDSLn108kKY4eDaaeUcnszFqXjgaGKYXNZ5NLulpRTpsrY+Sbfo9q8LDpWrBpqIgzjrwNnvglWI1xNQ==} 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==} peerDependencies: preact: ^10.0.0 @@ -350,11 +360,11 @@ packages: preact: 10.10.6 dev: true - /@prefresh/utils/1.1.3: + /@prefresh/utils@1.1.3: resolution: {integrity: sha512-Mb9abhJTOV4yCfkXrMrcgFiFT7MfNOw8sDa+XyZBdq/Ai2p4Zyxqsb3EgHLOEdHpMj6J9aiZ54W8H6FTam1u+A==} 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==} peerDependencies: preact: ^10.4.0 @@ -362,16 +372,16 @@ packages: dependencies: '@babel/core': 7.18.13 '@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 '@rollup/pluginutils': 4.2.1 preact: 10.10.6 - vite: 3.0.9_sass@1.54.8 + vite: 3.0.9(sass@1.54.8) transitivePeerDependencies: - supports-color dev: true - /@rollup/pluginutils/4.2.1: + /@rollup/pluginutils@4.2.1: resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} engines: {node: '>= 8.0.0'} dependencies: @@ -379,21 +389,21 @@ packages: picomatch: 2.3.1 dev: true - /ansi-styles/3.2.1: + /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} dependencies: color-convert: 1.9.3 dev: true - /anymatch/3.1.2: + /anymatch@3.1.2: resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==} engines: {node: '>= 8'} dependencies: normalize-path: 3.0.0 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==} peerDependencies: '@babel/core': ^7.12.10 @@ -401,17 +411,17 @@ packages: '@babel/core': 7.18.13 dev: true - /binary-extensions/2.2.0: + /binary-extensions@2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} - /braces/3.0.2: + /braces@3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} dependencies: fill-range: 7.0.1 - /browserslist/4.21.3: + /browserslist@4.21.3: resolution: {integrity: sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -419,14 +429,14 @@ packages: caniuse-lite: 1.0.30001388 electron-to-chromium: 1.4.241 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 - /caniuse-lite/1.0.30001388: + /caniuse-lite@1.0.30001388: resolution: {integrity: sha512-znVbq4OUjqgLxMxoNX2ZeeLR0d7lcDiE5uJ4eUiWdml1J1EkxbnQq6opT9jb9SMfJxB0XA16/ziHwni4u1I3GQ==} dev: true - /chalk/2.4.2: + /chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} dependencies: @@ -435,7 +445,7 @@ packages: supports-color: 5.5.0 dev: true - /chokidar/3.5.3: + /chokidar@3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} dependencies: @@ -449,28 +459,28 @@ packages: optionalDependencies: fsevents: 2.3.2 - /color-convert/1.9.3: + /color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: color-name: 1.1.3 dev: true - /color-name/1.1.3: + /color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} dev: true - /convert-source-map/1.8.0: + /convert-source-map@1.8.0: resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==} dependencies: safe-buffer: 5.1.2 dev: true - /date-fns/2.29.2: + /date-fns@2.29.2: resolution: {integrity: sha512-0VNbwmWJDS/G3ySwFSJA3ayhbURMTJLtwM2DTxf9CWondCnh6DTNlO9JgRSq6ibf4eD0lfMJNBxUdEAHHix+bA==} engines: {node: '>=0.11'} dev: false - /debug/4.3.4: + /debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} peerDependencies: @@ -482,11 +492,11 @@ packages: ms: 2.1.2 dev: true - /electron-to-chromium/1.4.241: + /electron-to-chromium@1.4.241: resolution: {integrity: sha512-e7Wsh4ilaioBZ5bMm6+F4V5c11dh56/5Jwz7Hl5Tu1J7cnB+Pqx5qIF2iC7HPpfyQMqGSvvLP5bBAIDd2gAtGw==} dev: true - /esbuild-android-64/0.14.54: + /esbuild-android-64@0.14.54: resolution: {integrity: sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==} engines: {node: '>=12'} cpu: [x64] @@ -494,7 +504,7 @@ packages: requiresBuild: true optional: true - /esbuild-android-arm64/0.14.54: + /esbuild-android-arm64@0.14.54: resolution: {integrity: sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==} engines: {node: '>=12'} cpu: [arm64] @@ -502,7 +512,7 @@ packages: requiresBuild: true optional: true - /esbuild-darwin-64/0.14.54: + /esbuild-darwin-64@0.14.54: resolution: {integrity: sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==} engines: {node: '>=12'} cpu: [x64] @@ -510,7 +520,7 @@ packages: requiresBuild: true optional: true - /esbuild-darwin-arm64/0.14.54: + /esbuild-darwin-arm64@0.14.54: resolution: {integrity: sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==} engines: {node: '>=12'} cpu: [arm64] @@ -518,7 +528,7 @@ packages: requiresBuild: true optional: true - /esbuild-freebsd-64/0.14.54: + /esbuild-freebsd-64@0.14.54: resolution: {integrity: sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==} engines: {node: '>=12'} cpu: [x64] @@ -526,7 +536,7 @@ packages: requiresBuild: true optional: true - /esbuild-freebsd-arm64/0.14.54: + /esbuild-freebsd-arm64@0.14.54: resolution: {integrity: sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==} engines: {node: '>=12'} cpu: [arm64] @@ -534,7 +544,7 @@ packages: requiresBuild: true optional: true - /esbuild-linux-32/0.14.54: + /esbuild-linux-32@0.14.54: resolution: {integrity: sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==} engines: {node: '>=12'} cpu: [ia32] @@ -542,7 +552,7 @@ packages: requiresBuild: true optional: true - /esbuild-linux-64/0.14.54: + /esbuild-linux-64@0.14.54: resolution: {integrity: sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==} engines: {node: '>=12'} cpu: [x64] @@ -550,23 +560,23 @@ packages: requiresBuild: true optional: true - /esbuild-linux-arm/0.14.54: - resolution: {integrity: sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==} + /esbuild-linux-arm64@0.14.54: + resolution: {integrity: sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==} engines: {node: '>=12'} - cpu: [arm] + cpu: [arm64] os: [linux] requiresBuild: true optional: true - /esbuild-linux-arm64/0.14.54: - resolution: {integrity: sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==} + /esbuild-linux-arm@0.14.54: + resolution: {integrity: sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==} engines: {node: '>=12'} - cpu: [arm64] + cpu: [arm] os: [linux] requiresBuild: true optional: true - /esbuild-linux-mips64le/0.14.54: + /esbuild-linux-mips64le@0.14.54: resolution: {integrity: sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==} engines: {node: '>=12'} cpu: [mips64el] @@ -574,7 +584,7 @@ packages: requiresBuild: true optional: true - /esbuild-linux-ppc64le/0.14.54: + /esbuild-linux-ppc64le@0.14.54: resolution: {integrity: sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==} engines: {node: '>=12'} cpu: [ppc64] @@ -582,7 +592,7 @@ packages: requiresBuild: true optional: true - /esbuild-linux-riscv64/0.14.54: + /esbuild-linux-riscv64@0.14.54: resolution: {integrity: sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==} engines: {node: '>=12'} cpu: [riscv64] @@ -590,7 +600,7 @@ packages: requiresBuild: true optional: true - /esbuild-linux-s390x/0.14.54: + /esbuild-linux-s390x@0.14.54: resolution: {integrity: sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==} engines: {node: '>=12'} cpu: [s390x] @@ -598,7 +608,7 @@ packages: requiresBuild: true optional: true - /esbuild-netbsd-64/0.14.54: + /esbuild-netbsd-64@0.14.54: resolution: {integrity: sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==} engines: {node: '>=12'} cpu: [x64] @@ -606,7 +616,7 @@ packages: requiresBuild: true optional: true - /esbuild-openbsd-64/0.14.54: + /esbuild-openbsd-64@0.14.54: resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==} engines: {node: '>=12'} cpu: [x64] @@ -614,7 +624,7 @@ packages: requiresBuild: true optional: true - /esbuild-sunos-64/0.14.54: + /esbuild-sunos-64@0.14.54: resolution: {integrity: sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==} engines: {node: '>=12'} cpu: [x64] @@ -622,7 +632,7 @@ packages: requiresBuild: true optional: true - /esbuild-windows-32/0.14.54: + /esbuild-windows-32@0.14.54: resolution: {integrity: sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==} engines: {node: '>=12'} cpu: [ia32] @@ -630,7 +640,7 @@ packages: requiresBuild: true optional: true - /esbuild-windows-64/0.14.54: + /esbuild-windows-64@0.14.54: resolution: {integrity: sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==} engines: {node: '>=12'} cpu: [x64] @@ -638,7 +648,7 @@ packages: requiresBuild: true optional: true - /esbuild-windows-arm64/0.14.54: + /esbuild-windows-arm64@0.14.54: resolution: {integrity: sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==} engines: {node: '>=12'} cpu: [arm64] @@ -646,7 +656,7 @@ packages: requiresBuild: true optional: true - /esbuild/0.14.54: + /esbuild@0.14.54: resolution: {integrity: sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==} engines: {node: '>=12'} hasBin: true @@ -674,147 +684,147 @@ packages: esbuild-windows-64: 0.14.54 esbuild-windows-arm64: 0.14.54 - /escalade/3.1.1: + /escalade@3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} dev: true - /escape-string-regexp/1.0.5: + /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} dev: true - /estree-walker/2.0.2: + /estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} dev: true - /fill-range/7.0.1: + /fill-range@7.0.1: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} dependencies: to-regex-range: 5.0.1 - /fsevents/2.3.2: + /fsevents@2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] requiresBuild: true optional: true - /function-bind/1.1.1: + /function-bind@1.1.1: resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} - /gensync/1.0.0-beta.2: + /gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} dev: true - /glob-parent/5.1.2: + /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} dependencies: is-glob: 4.0.3 - /globals/11.12.0: + /globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} dev: true - /has-flag/3.0.0: + /has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} dev: true - /has/1.0.3: + /has@1.0.3: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} engines: {node: '>= 0.4.0'} dependencies: function-bind: 1.1.1 - /immutable/4.1.0: + /immutable@4.1.0: 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==} engines: {node: '>=8'} dependencies: 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==} dependencies: has: 1.0.3 - /is-extglob/2.1.1: + /is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - /is-glob/4.0.3: + /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} dependencies: is-extglob: 2.1.1 - /is-number/7.0.0: + /is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} - /js-tokens/4.0.0: + /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} dev: true - /jsesc/2.5.2: + /jsesc@2.5.2: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} engines: {node: '>=4'} hasBin: true dev: true - /json5/2.2.1: + /json5@2.2.1: resolution: {integrity: sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==} engines: {node: '>=6'} hasBin: true dev: true - /kolorist/1.5.1: + /kolorist@1.5.1: resolution: {integrity: sha512-lxpCM3HTvquGxKGzHeknB/sUjuVoUElLlfYnXZT73K8geR9jQbroGlSCFBax9/0mpGoD3kzcMLnOlGQPJJNyqQ==} dev: true - /lodash-es/4.17.21: + /lodash-es@4.17.21: resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} dev: false - /lodash/4.17.21: + /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} dev: false - /ms/2.1.2: + /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} dev: true - /nanoid/3.3.4: + /nanoid@3.3.4: resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - /node-releases/2.0.6: + /node-releases@2.0.6: resolution: {integrity: sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==} dev: true - /normalize-path/3.0.0: + /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - /path-parse/1.0.7: + /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - /picocolors/1.0.0: + /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - /picomatch/2.3.1: + /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - /postcss/8.4.16: + /postcss@8.4.16: resolution: {integrity: sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==} engines: {node: ^10 || ^12 || >=14} dependencies: @@ -822,16 +832,16 @@ packages: picocolors: 1.0.0 source-map-js: 1.0.2 - /preact/10.10.6: + /preact@10.10.6: resolution: {integrity: sha512-w0mCL5vICUAZrh1DuHEdOWBjxdO62lvcO++jbzr8UhhYcTbFkpegLH9XX+7MadjTl/y0feoqwQ/zAnzkc/EGog==} - /readdirp/3.6.0: + /readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} dependencies: picomatch: 2.3.1 - /resolve/1.22.1: + /resolve@1.22.1: resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} hasBin: true dependencies: @@ -839,18 +849,18 @@ packages: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - /rollup/2.77.3: + /rollup@2.77.3: resolution: {integrity: sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==} engines: {node: '>=10.0.0'} hasBin: true optionalDependencies: fsevents: 2.3.2 - /safe-buffer/5.1.2: + /safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} dev: true - /sass/1.54.8: + /sass@1.54.8: resolution: {integrity: sha512-ib4JhLRRgbg6QVy6bsv5uJxnJMTS2soVcCp9Y88Extyy13A8vV0G1fAwujOzmNkFQbR3LvedudAMbtuNRPbQww==} engines: {node: '>=12.0.0'} hasBin: true @@ -859,38 +869,38 @@ packages: immutable: 4.1.0 source-map-js: 1.0.2 - /semver/6.3.0: + /semver@6.3.0: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} hasBin: true dev: true - /source-map-js/1.0.2: + /source-map-js@1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} - /supports-color/5.5.0: + /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} dependencies: has-flag: 3.0.0 dev: true - /supports-preserve-symlinks-flag/1.0.0: + /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - /to-fast-properties/2.0.0: + /to-fast-properties@2.0.0: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} engines: {node: '>=4'} dev: true - /to-regex-range/5.0.1: + /to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} dependencies: 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==} hasBin: true peerDependencies: @@ -901,7 +911,7 @@ packages: picocolors: 1.0.0 dev: true - /vite/3.0.9_sass@1.54.8: + /vite@3.0.9(sass@1.54.8): resolution: {integrity: sha512-waYABTM+G6DBTCpYAxvevpG50UOlZuynR0ckTK5PawNVt7ebX6X7wNXHaGIO6wYYFXSM7/WcuFuO2QzhBB6aMw==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true diff --git a/src/components/CourseVisibility.jsx b/src/components/CourseVisibility.jsx index bbc65ac..024f758 100644 --- a/src/components/CourseVisibility.jsx +++ b/src/components/CourseVisibility.jsx @@ -1,9 +1,10 @@ import { Icon } from './Icon.jsx' +import { MODE_COURSES } from './EventsView.jsx' -export const ToolOverlay = ({ visibility, toggleVisibility, onClose }) => ( +export const ToolOverlay = ({ mode, toggleMode, onClose }) => (
-
) } diff --git a/src/components/Toolbar.jsx b/src/components/Toolbar.jsx index 522b2f8..e0dbcbf 100644 --- a/src/components/Toolbar.jsx +++ b/src/components/Toolbar.jsx @@ -1,10 +1,7 @@ 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 Toolbar = ({ - mode, - setMode, source, setSource, onShowMenu, @@ -38,18 +35,6 @@ export const Toolbar = ({
-
- -
+
) diff --git a/src/components/CourseVisibility.jsx b/src/components/ToolOverlay.jsx similarity index 81% rename from src/components/CourseVisibility.jsx rename to src/components/ToolOverlay.jsx index 024f758..2779228 100644 --- a/src/components/CourseVisibility.jsx +++ b/src/components/ToolOverlay.jsx @@ -4,7 +4,7 @@ import { MODE_COURSES } from './EventsView.jsx' export const ToolOverlay = ({ mode, toggleMode, onClose }) => (
@@ -33,6 +34,15 @@ export const Toolbar = ({ setValue={setSource} />
+
+ +
@@ -43,9 +53,13 @@ export const Toolbar = ({
diff --git a/src/components/view/Schedule.jsx b/src/components/view/Schedule.jsx index 1db8a14..fc0d32a 100644 --- a/src/components/view/Schedule.jsx +++ b/src/components/view/Schedule.jsx @@ -1,55 +1,295 @@ -import { format } from 'date-fns' +import { useEffect, useRef, useState } from 'preact/hooks' + import _ from 'lodash' -import { prettyCourseName, WEEK_DAYS, withClasses } from '../../utils.jsx' +import { differenceInMinutes, startOfDay } from 'date-fns' -export const Schedule = ({ timetables, selection, setSelection }) => { - const events = timetables['tutti'] - const selectionSet = new Set(selection) +import { + WEEK_DAYS_SHORT, + prettyCourseName, + usePersistentState, +} from '../../utils.jsx' +import { layoutEvents, layoutIntervals } from '../../interval-layout.js' +import { Popup } from '../Popup.jsx' +import { Icon } from '../Icon.jsx' + +const TransposePopup = ({ onClose }) => { + return ( + + Attenzione! La tabella è stata + trasposta! + + } + onClose={onClose} + > +

+ A grande richiesta popolare abbiamo trasposto la tabella + dell'orario! +

- const visibleEvents = events.filter(e => selectionSet.has(e.id)) +

+ Assicurati quindi di leggerla correttamente (dall'alto verso il + basso invece che da sinistra verso destra). +

+ +

+ Se preferisci utilizzare la versione vecchia, puoi utilizzare il + pulsante Trasponi{' '} + {' '} + nell'origine della tabella per trasporla. Questa scelta verrà + salvata nei cookie e verrà ricordata in futuro +

+
+ ) +} + +const NoCourseWarning = () => { + return ( +
+

Non hai ancora selezionato nessun corso.

+

+ Clicca sui corsi nelle altre visuali per selezionarli e + visualizzarli nell'orario +

+
+ ) +} - const eventsByWeekday = _.mapValues( - _.groupBy(visibleEvents, e => e.start.getDay()), - dailyEvents => _.groupBy(dailyEvents, e => e.start.getHours()) +const Layout = ({ layout, day, colors }) => { + console.log(layout) + return ( + <> + {layout.map(block => ( +
+
+ {block.events.map((event, index) => ( +
+
+ {event.aule.map(aula => ( +
{aula.replace(/^Fib /, '')}
+ ))} +
+
+ ))} +
+
+ ))} + ) +} +const ScheduleGrid = ({ + orientation, + setOrientation, + weekStart, + weekEnd, + dayBlocksLayout, + colors, +}) => { return ( -
- {Object.entries(eventsByWeekday).map(([index, dailyEvents]) => ( +
+
+ +
+ {[1, 2, 3, 4, 5].map(n => ( <> -
-
{WEEK_DAYS[index]}
+
+ {WEEK_DAYS_SHORT[n]}
- {Object.values(dailyEvents).map(events => ( - <> -
{format(events[0].start, 'H:mm')}
- {events.map(event => ( -
{ - if (!selectionSet.has(event.id)) - setSelection([...selection, event.id]) - else - setSelection( - selection.filter(selId => selId !== event.id) - ) - }} - > -
{prettyCourseName(event.name)}
-
- {format(event.start, 'H:mm')} –{' '} - {format(event.end, 'H:mm')} -
-
{event.aule.join(', ')}
-
- ))} - - ))} +
+ + ))} + + {[9, 11, 14, 16].map(n => ( +
+ {n}-{n + 2} +
+ ))} +
+ {[9, 11, 13, 14, 16, 18].map(n => ( + <> + {n * 2 > weekStart && n * 2 < weekEnd && ( +
+ )} + + ))} + + {Object.entries(dayBlocksLayout).map(([day, layout]) => ( + + ))} +
+ ) +} +const ScheduleLegend = ({ courses, colors }) => { + return ( +
+ {courses.map(course => ( + <> +
+
{prettyCourseName(course.name)}
))}
) } +const ScheduleCard = ({ + orientation, + setOrientation, + weekStart, + weekEnd, + dayBlocksLayout, + courses, + colors, +}) => { + return ( +
+ + +
+ ) +} + +export const Schedule = ({ timetables, selection, setSelection }) => { + 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' && ( + setHasSeenTranspose('true')} /> + )} +
+ {selection.length === 0 && } + +
+ + ) +} diff --git a/src/components/view/WorkWeek.jsx b/src/components/view/WorkWeek.jsx deleted file mode 100644 index 2a33f23..0000000 --- a/src/components/view/WorkWeek.jsx +++ /dev/null @@ -1,157 +0,0 @@ -import { useEffect, useRef, useState } from 'preact/hooks' - -import _ from 'lodash' -import { differenceInMinutes, startOfDay } from 'date-fns' - -import { hashString, prettyCourseName, 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 ( -
-
-
-
-
- 9:00 – 11:00 -
-
- 11:00 – 13:00 -
-
- 14:00 – 16:00 -
-
- 16:00 – 18:00 -
-
- 18:00 – 20:00 -
-
-
- {Object.entries(dayIntervalLayout).map(([index, layout]) => ( -
-
{WEEK_DAYS[parseInt(index)]}
-
- {layout.map((events, stackIndex) => ( - <> - {events.map(event => ( -
{ - if (!selectionSet.has(event.data.id)) - setSelection([...selection, event.data.id]) - else - setSelection( - selection.filter(id => event.data.id !== id) - ) - }} - > -
{prettyCourseName(event.data.name)}
-
{event.data.aule.join(', ')}
-
- ))} - - ))} - - {/* Grid Tracks */} - {[4, 8, 12].map(i => ( -
- ))} - {[14, 18, 22].map(i => ( -
- ))} -
-
- ))} -
- ) -} diff --git a/src/components/view/WorkWeekGrid.jsx b/src/components/view/WorkWeekGrid.jsx deleted file mode 100644 index 105f6ac..0000000 --- a/src/components/view/WorkWeekGrid.jsx +++ /dev/null @@ -1,227 +0,0 @@ -import { useEffect, useRef, useState } from 'preact/hooks' - -import _ from 'lodash' -import { differenceInMinutes, startOfDay } from 'date-fns' - -import { prettyCourseName } from '../../utils.jsx' -import { layoutIntervals } from '../../interval-layout.js' - -export const WorkWeekGrid = ({ timetables, selection, setSelection }) => { - const events = timetables['tutti'] - const selectionSet = new Set(selection) - - const colorList = ['red', 'purple', 'blue', 'yellow', 'green', 'orange', 'lightblue'] - - const courses = _.uniqBy( - 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( - 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 ( -
-
- {[7, 9, 11, 14, 16, 18].map(n => ( - <> - {n + 2 > timeStart && n < timeEnd && ( -
- {n}-{n + 2} -
- )} - - ))} -
- {[9, 11, 13, 14, 16, 18].map(n => ( - <> - {n > timeStart && n < timeEnd && ( -
- )} - - ))} - -
- Lun -
-
- Mar -
-
- Mer -
-
- Gio -
-
- Ven -
- -
-
-
-
-
- - {Object.entries(dayIntervalLayout).map(([index, layout]) => ( - <> - {layout.map((events, stackIndex) => ( - <> - {events.map(event => ( -
{ - // 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] !== '' && ( -
{`(${ - colors[event.data.id][1] - })`}
- )} - {event.data.aule.join(', ')} -
- ))} - - ))} - - ))} -
-
- {courses.map(course => ( - <> -
- {colors[course.id][1]} -
-
{prettyCourseName(course.name)}
- - ))} -
-
- ) -} diff --git a/src/components/view/WorkWeekTranspose.jsx b/src/components/view/WorkWeekTranspose.jsx deleted file mode 100644 index 9d0a43b..0000000 --- a/src/components/view/WorkWeekTranspose.jsx +++ /dev/null @@ -1,104 +0,0 @@ -import { useEffect, useRef } from 'preact/hooks' - -import _ from 'lodash' -import { differenceInMinutes, startOfDay } from 'date-fns' - -import { hashString, prettyCourseName, 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 ( -
-
- {WEEK_DAYS.slice(1, 6).map((label, index) => ( -
- {label} -
- ))} -
-
-
-
- 9:00 – 11:00 -
-
- 11:00 – 13:00 -
-
- 14:00 – 16:00 -
-
- 16:00 – 18:00 -
-
-
- {Object.values(rowLayouts).map(layout => ( -
- {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 ( -
- {prettyCourseName(event.data.name)} -
- ) - } - - return - }) - )} -
- ))} -
-
-
- ) -} diff --git a/src/interval-layout.js b/src/interval-layout.js index 4b09938..39b7472 100644 --- a/src/interval-layout.js +++ b/src/interval-layout.js @@ -34,6 +34,62 @@ export function layoutIntervals(intervals, { tight } = {}) { 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... // // diff --git a/src/main.jsx b/src/main.jsx index 09851f1..6da396f 100644 --- a/src/main.jsx +++ b/src/main.jsx @@ -1,43 +1,44 @@ import _ from 'lodash' import { render } from 'preact' import { useEffect, useState } from 'preact/hooks' -import { ToolOverlay } from './components/CourseVisibility.jsx' -import { EventsView, MODE_COURSES, MODE_SCHEDULE } 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 { Help } from './components/Help.jsx' import { Icon } from './components/Icon.jsx' import { Popup } from './components/Popup.jsx' import { Toolbar } from './components/Toolbar.jsx' import { OptionBar } from './components/OptionBar.jsx' -import { prettyAulaName, prettyProfName, usePersistentState } from './utils.jsx' +import { + prettyAulaName, + prettyProfName, + clearOldPersistentStates, + usePersistentState, +} from './utils.jsx' +// Che fanno queste due righe? window._ = _ window.dataBuffer = {} -const CALENDAR_IDS = { - 'anno-1': ['64a7c1c651f079001d52e9c8'], - 'anno-2': ['6308e2dc09352a0208fefdd9'], - 'anno-3': ['6308e42a1df5cb026699ced4'], - 'magistrale': ['64a7c7091ab813002c5d9ede'], - 'tutti': [ - '64a7c1c651f079001d52e9c8', - '6308e2dc09352a0208fefdd9', - '6308e42a1df5cb026699ced4', - '64a7c7091ab813002c5d9ede', - ], -} - const TIMETABLE_IDS = { - 'anno-1': '64a7c1c651f079001d52e9c8', - 'anno-2': '6308e2dc09352a0208fefdd9', - 'anno-3': '6308e42a1df5cb026699ced4', + 'anno-1': '64a7c1c651f079001d52e9c8', + 'anno-2': '6308e2dc09352a0208fefdd9', + 'anno-3': '6308e42a1df5cb026699ced4', 'magistrale': '64a7c7091ab813002c5d9ede', } const DEFAULT_DATE_RANGE = { - from: '2023-10-02T00:00:00.000Z', - to: '2023-10-07T00:00:00.000Z', + from: '2023-10-09T00:00:00.000Z', + to: '2023-10-14T00:00:00.000Z', } const DATE_RANGES = { @@ -51,7 +52,10 @@ function specialEventPatches(eventi) { // Il laboratorio del primo anno in realtà è in due canali separati let i = 1 eventi.forEach(evento => { - if (evento.nome === 'LABORATORIO DI INTRODUZIONE ALLA MATEMATICA COMPUTAZIONALE') { + if ( + evento.nome === + 'LABORATORIO DI INTRODUZIONE ALLA MATEMATICA COMPUTAZIONALE' + ) { evento.nome += ` (${i})` i++ } @@ -61,18 +65,18 @@ function specialEventPatches(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)), - } + 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() { @@ -112,31 +116,43 @@ async function loadCalendari() { req(TIMETABLE_IDS['magistrale']), ] const results = await Promise.all(requests) - const timetablesRaw = results.map(timetable => specialEventPatches(_.uniqBy(timetable, 'id'))) + const timetablesRaw = results.map(timetable => + specialEventPatches(_.uniqBy(timetable, 'id')) + ) const allRaw = specialEventPatches(_.uniqBy(_.concat(...results), 'id')) return { - 'anno-1': formatEvents(timetablesRaw[0]), - 'anno-2': formatEvents(timetablesRaw[1]), - 'anno-3': formatEvents(timetablesRaw[2]), + 'anno-1': formatEvents(timetablesRaw[0]), + 'anno-2': formatEvents(timetablesRaw[1]), + 'anno-3': formatEvents(timetablesRaw[2]), 'magistrale': formatEvents(timetablesRaw[3]), - 'tutti': formatEvents(allRaw) + 'tutti': formatEvents(allRaw), } } 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') + // Data Sources - const [source, setSource] = usePersistentState('orario.source', 'magistrale') + const [source, setSource] = usePersistentState('source', 'magistrale') const [timetables, setTimetables] = useState(null) useEffect(async () => { setTimetables(await loadCalendari()) }, []) // View Modes - const [mode, setMode] = usePersistentState('orario.mode', MODE_COURSES) + // const [mode, setMode] = usePersistentState('orario.mode', MODE_COURSES) // Selection - const [selectedCourses, setSelectedCourses] = usePersistentState('orario.selection', []) + const [selectedCourses, setSelectedCourses] = usePersistentState( + 'selection', + [] + ) // Menus const [helpVisible, setHelpVisible] = useState(false) @@ -146,8 +162,11 @@ const App = ({}) => { const toolOverlayVisible = selectedCourses.length > 0 const [theme, setTheme] = usePersistentState( - 'orario.theme', - window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' + 'theme', + 'light' + // window.matchMedia('(prefers-color-scheme: dark)').matches + // ? 'dark' + // : 'light' ) document.body.classList.toggle('dark-mode', theme === 'dark') @@ -156,8 +175,6 @@ const App = ({}) => { <> setShowMobileMenu(true), @@ -166,44 +183,53 @@ const App = ({}) => { setTheme, }} /> - {mode === MODE_COURSES && ( - setHelpVisible(true), - }}orizzontale - /> - )} + setHelpVisible(true), + }} + orizzontale + /> + {timetables && ( - +
+ {source === 'orario' ? ( + + ) : ( + + )} +
)} - {toolOverlayVisible && ( + {/* toolOverlayVisible && ( setMode(mode === MODE_COURSES ? MODE_SCHEDULE : MODE_COURSES)} + toggleMode={() => + setMode( + mode === MODE_COURSES ? MODE_SCHEDULE : MODE_COURSES + ) + } onClose={() => { setSelectedCourses([]) setMode(MODE_COURSES) }} /> - )} + ) */} {showMobileMenu && ( { diff --git a/src/styles/main.scss b/src/styles/main.scss index 69f7ad8..8ae104a 100644 --- a/src/styles/main.scss +++ b/src/styles/main.scss @@ -28,32 +28,14 @@ html { --accent-500: #6cc16c; --accent-900: #244624; - --bubble-red: hsl(359, 100%, 92%); - --bubble-purple: hsl(274, 100%, 92%); - --bubble-blue: hsl(241, 100%, 92%); - --bubble-yellow: hsl(50, 100%, 92%); - --bubble-green: hsl(125, 100%, 92%); - --bubble-orange: hsl(25, 100%, 92%); - --bubble-lightlightblue: hsl(176, 100%, 92%); - --bubble-lightblue: hsl(198, 100%, 92%); - - --bubble-highlight-red: hsl(359, 100%, 85%); - --bubble-highlight-purple: hsl(274, 100%, 85%); - --bubble-highlight-blue: hsl(241, 100%, 85%); - --bubble-highlight-yellow: hsl(50, 100%, 85%); - --bubble-highlight-green: hsl(125, 100%, 85%); - --bubble-highlight-orange: hsl(25, 100%, 85%); - --bubble-highlight-lightlightblue: hsl(176, 100%, 85%); - --bubble-highlight-lightblue: hsl(198, 100%, 85%); - - --bubble-border-red: hsl(359, 75%, 51%); - --bubble-border-purple: hsl(274, 75%, 51%); - --bubble-border-blue: hsl(241, 75%, 51%); - --bubble-border-yellow: hsl(50, 75%, 51%); - --bubble-border-green: hsl(125, 75%, 51%); - --bubble-border-orange: hsl(25, 75%, 51%); - --bubble-border-lightlightblue: hsl(176, 75%, 51%); - --bubble-border-lightblue: hsl(198, 75%, 51%); + --event-red: hsl(359, 100%, 85%); + --event-purple: hsl(274, 100%, 85%); + --event-blue: hsl(241, 100%, 85%); + --event-yellow: hsl(50, 100%, 85%); + --event-green: hsl(125, 100%, 85%); + --event-orange: hsl(25, 100%, 85%); + --event-lightlightblue: hsl(176, 100%, 85%); + --event-lightblue: hsl(198, 100%, 85%); --bold-on-dark: 300; } @@ -76,29 +58,13 @@ body.dark-mode { --accent-500: hsl(269, 40%, 70%); --accent-900: hsl(269, 30%, 90%); - --bubble-red: hsl(359, 40%, 25%); - --bubble-purple: hsl(274, 40%, 25%); - --bubble-blue: hsl(241, 40%, 25%); - --bubble-yellow: hsl(50, 40%, 25%); - --bubble-green: hsl(125, 40%, 25%); - --bubble-orange: hsl(25, 40%, 25%); - --bubble-lightblue: hsl(176, 40%, 25%); - - --bubble-border-red: hsl(359, 75%, 51%); - --bubble-border-purple: hsl(274, 75%, 51%); - --bubble-border-blue: hsl(241, 75%, 51%); - --bubble-border-yellow: hsl(50, 75%, 51%); - --bubble-border-green: hsl(125, 75%, 51%); - --bubble-border-orange: hsl(25, 75%, 51%); - --bubble-border-lightblue: hsl(176, 75%, 51%); - - --bubble-highlight-red: hsl(359, 40%, 31%); - --bubble-highlight-purple: hsl(274, 40%, 31%); - --bubble-highlight-blue: hsl(241, 40%, 31%); - --bubble-highlight-yellow: hsl(50, 40%, 31%); - --bubble-highlight-green: hsl(125, 40%, 31%); - --bubble-highlight-orange: hsl(25, 40%, 31%); - --bubble-highlight-lightblue: hsl(176, 40%, 31%); + --event-red: hsl(359, 40%, 31%); + --event-purple: hsl(274, 40%, 31%); + --event-blue: hsl(241, 40%, 31%); + --event-yellow: hsl(50, 40%, 31%); + --event-green: hsl(125, 40%, 31%); + --event-orange: hsl(25, 40%, 31%); + --event-lightblue: hsl(176, 40%, 31%); --bold-on-dark: 500; } @@ -214,6 +180,10 @@ button, &.flat { border: none; } + + &.small { + padding: 0.25rem; + } } .input-combo { @@ -294,49 +264,60 @@ button, max-width: 100%; - .popup { - @extend .panel; - + .popup-wrapper { + max-width: 100%; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); - display: flex; - flex-direction: column; - gap: 1rem; + padding: 1rem; + + .popup { + @extend .panel; - box-shadow: 0 0 1.5rem #00000033; + // position: absolute; + // top: 50%; + // left: 50%; + // transform: translate(-50%, -50%); - .header { display: flex; - align-items: center; - justify-content: space-between; + flex-direction: column; + gap: 1rem; - user-select: none; + box-shadow: 0 0 1.5rem #00000033; - .title { + .header { display: flex; align-items: center; - gap: 0.5rem; + justify-content: space-between; + + user-select: none; + + .title { + display: flex; + align-items: center; + gap: 0.5rem; - font-size: 24px; + font-size: 24px; + } } - } - .content { - @extend .text-block; + .content { + @extend .text-block; - width: 60ch; - max-width: 100%; - max-height: 60vh; + width: 60ch; + max-width: 100%; + height: fit-content; + max-height: 60vh; - overflow-y: auto; + overflow-y: auto; - padding-bottom: 3rem; - } + padding-bottom: 3rem; + } - max-width: 100%; + max-width: 100%; + } } } @@ -496,7 +477,7 @@ body { } } -.events-view { +.content { height: calc(100vh - 4rem); @media screen and (max-width: $device-s-width), (pointer: coarse) { height: calc(100vh - 8rem); @@ -568,564 +549,226 @@ body { } } - .work-week-h-view { - --header-height: 3rem; - --event-height: 2rem; - - display: grid; - grid-template-columns: auto 1fr; - grid-template-rows: var(--header-height) 1fr; + .schedule-view { + height: 100%; + width: 100%; + max-width: 57rem; + margin: auto; - overflow-y: scroll; + padding: 1rem 0.5rem; - height: 100%; + display: flex; + flex-direction: column; + align-items: center; + gap: 1rem; - .week { - grid-column: 1 / 2; - grid-row: 2 / 3; + .no-courses-warning { + width: 100%; display: flex; flex-direction: column; + gap: 1rem; + align-items: center; - .day { - box-sizing: content-box; - - // @media screen and (max-width: $device-s-width) { - // writing-mode: vertical-lr; - // } - - height: calc(var(--size) * var(--event-height) + (var(--size) - 1) * 0.25rem); - - border-top: 1px solid var(--border-500); - border-right: 1px solid var(--border-500); - padding: 0.5rem 1rem 0 0.5rem; - - font-size: 18px; - font-weight: 400; - - &:last-child { - border-bottom: 1px solid var(--border-500); - } + p { + text-align: center; } } + .schedule-card { + width: 100%; - .events { - grid-column: 2 / 3; - grid-row: 1 / 3; - - overflow-y: hidden; - overflow-x: scroll; - - // scrollbar-gutter: stable both-edges; - - display: grid; - grid-template-rows: auto 1fr; - - --hour-width: 7.5rem; - - .header { + .grid { + width: 100%; display: grid; - grid-template-columns: repeat(12, var(--hour-width)); - grid-template-rows: var(--header-height); - - gap: 0.25rem; - - .label { - display: grid; - place-content: center; - - font-size: 18px; - font-weight: 400; - border-left: 1px solid var(--border-500); + border: 1px solid var(--border-600); + border-radius: 10px 10px 0 0; - &:nth-child(2), - &:nth-child(4) { - border-right: 1px solid var(--border-500); - } + @media screen and (max-width: $device-s-width), + (pointer: coarse) { + font-size: 12px; } - } - - .days { - display: flex; - flex-direction: column; - - .day { - display: grid; - - // grid-template-columns: repeat(7, 0) repeat(12, 1fr) repeat(5, 0); - grid-template-columns: repeat(12, var(--hour-width)); - grid-template-rows: repeat(var(--size), var(--event-height)); - - gap: 0.25rem; - position: relative; - - &:hover { - z-index: 5; - } - - .event { - grid-row: var(--row) / span 1; - grid-column: var(--start) / span var(--size); - - $color: var(--bg-500); - - background: $color; - color: var(--text-500); - - border-radius: 0.25rem; - - border: 1px solid var(--border-600); + .transpose-button, + .day-label, + .time-label { + display: flex; + align-items: center; + justify-content: center; + padding: 0.5rem; + } - display: flex; - padding: 0.4rem; + .transpose-button { + width: 4rem; + height: 3rem; + } - font-size: 15px; + .event-block-wrapper { + padding: 0.125rem; + .event-block { width: 100%; - - min-height: var(--event-height); - overflow: hidden; + height: 100%; position: relative; - line-height: 1.1; - - &::after { - content: ''; + .event-wrapper { position: absolute; - inset: 0; + top: 0%; + left: 0%; - border-radius: 0.25rem; + padding: 0.125rem; - background: linear-gradient(to top, $color 0%, transparent 25%); - } + .event { + width: 100%; + height: 100%; - &:hover { - z-index: 3; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; - position: absolute; - overflow: visible; + text-align: center; - &::after { - background: none; + background: var(--color); + border-radius: 10px; + font-weight: var(--bold-on-dark); } } - - z-index: 2; - } - - border-top: 1px solid var(--border-500); - padding: 0.25rem 0; - - &:last-child { - border-bottom: 1px solid var(--border-500); } } - } - } - } - - .work-week-v-view { - position: relative; - - display: grid; - grid-template-columns: max-content repeat(5, minmax(auto, 1fr)); - - height: 100%; - - overflow: scroll; - - // --event-height: 4.75rem; - --event-height: 6rem; - - .pivot { - height: 3rem; - - grid-column: 1 / 2; - grid-row: 1 / 2; - - position: sticky; - top: 0; - left: 0; - - z-index: 2; - - background: var(--bg-500); - border-bottom: 1px solid var(--border-500); - border-right: 1px solid var(--border-500); - } - - .left-header { - grid-column: 1 / 2; - grid-row: 1 / 2; - - display: grid; - - position: sticky; - left: 0; - - border-right: 1px solid var(--border-500); - - background: var(--bg-500); - - z-index: 1; - - padding-top: 3rem; - - .blocks { - display: grid; - - grid-template-rows: repeat(24, calc(var(--event-height) / 2)); - - .block { - grid-row: var(--start) / span var(--size); - - display: grid; - place-content: center; - - padding: 0.5rem; - - font-size: 16px; - font-weight: 400; - - border-top: 1px solid var(--border-500); - - @media screen and (max-width: $device-s-width), (pointer: coarse) { - writing-mode: vertical-lr; + &.original { + grid-template-columns: auto repeat(5, 1fr); + grid-template-rows: min-content repeat( + var(--time-slots), + 1fr + ); + + .transpose-button, + .day-label { + grid-column: var(--position); + grid-row: 1; } - - &:not(.skip-border) { - height: calc(2 * var(--event-height) + 0.5px); - border-bottom: 1px solid var(--border-500); + .time-label { + min-height: 5rem; + grid-column: 1; + grid-row: calc(var(--position) + 2) / span 4; } - } - } - } - - .day { - position: relative; - - display: flex; - flex-direction: column; - - .top-header { - position: sticky; - top: 0; - height: 3rem; - - flex: 0 0 auto; - - z-index: 1; - - grid-column: span var(--size); - - display: flex; - align-items: center; - justify-content: center; - - font-size: 18px; - font-weight: 400; - - background: var(--bg-500); - border-bottom: 1px solid var(--border-500); - } - - // &:not(:last-child) { - border-right: 1px solid var(--border-500); - // } - - .events { - position: relative; - - display: grid; - grid-template-columns: repeat(var(--size), auto); - grid-template-rows: repeat(24, calc(var(--event-height) / 2)); - - padding: 0 0.25rem; - - // gap: 1rem 0.5rem; - - .event { - position: relative; - - cursor: pointer; - - grid-row: var(--start) / span var(--size); - grid-column: var(--stack) / span 1; - - background: var(--bg-500); - - border: 1px solid var(--border-600); - // border: 4px solid hsl(var(--hue), 80%, 80%); - - border-radius: 0.5rem; - - display: flex; - flex-direction: column; - - gap: 0.25rem; - - padding: 0.5rem 1rem 0.5rem 0.5rem; - margin: 0.5rem 0.25rem; - - // box-sizing: content-box; - - &.selected { - background: var(--bg-selected-500); - &::after { - content: ''; - position: absolute; - inset: -1px; - border-radius: 0.5rem; + .day-line { + grid-column: var(--position); + grid-row: 1/-1; + width: 0px; + border-right: 1px solid var(--border-500); + } + .time-line { + grid-row: calc(var(--position) + 2); + grid-column: 1/-1; + height: 0px; + border-top: 1px dashed var(--border-500); + } - border: 3px solid var(--border-selected-500); + .event-block-wrapper { + grid-row: calc(var(--time-start) + 2) / + calc(var(--time-end) + 2); + grid-column: calc(var(--day-position) + 1); + + .event-block { + .event-wrapper { + width: calc(100% / var(--of)); + height: calc( + 100% * var(--size) / var(--block-size) + ); + transform: translateX(calc(100% * var(--index))) + translateY( + calc( + 100% * var(--relative-start) / + var(--size) + ) + ); + } } } - - &.highlight { - background: var(--bg-highlight-500); - border-color: var(--border-highlight-500); + } + &.transposed { + grid-template-rows: auto repeat(5, 1fr); + grid-template-columns: min-content repeat( + var(--time-slots), + 1fr + ); + + .transpose-button, + .day-label { + grid-row: var(--position); + grid-column: 1; } - - .title { - font-size: 18px; - font-weight: 400; + .day-label { + min-height: 5rem; } - - .aula { - font-size: 16px; - font-weight: 300; + .time-label { + grid-row: 1; + grid-column: calc(var(--position) + 2) / span 4; } - } - - .grid-line-h { - grid-column: 1 / span var(--size); - grid-row: var(--track) / span 1; - - height: 0px; - border-bottom: 1px dashed var(--border-500); - - transform: translate(0, -1px); - // align-self: center; - - position: relative; - top: 0.5px; - left: -0.5rem; - width: calc(100% + 1rem); + .day-line { + grid-row: var(--position); + grid-column: 1/-1; + height: 0px; + border-top: 1px solid var(--border-500); + } + .time-line { + grid-column: calc(var(--position) + 2); + grid-row: 1/-1; + width: 0px; + border-right: 1px dashed var(--border-500); + } - z-index: -1; + .event-block-wrapper { + grid-column: calc(var(--time-start) + 2) / + calc(var(--time-end) + 2); + grid-row: calc(var(--day-position) + 1); + + .event-block { + .event-wrapper { + height: calc(100% / var(--of)); + width: calc( + 100% * var(--size) / var(--block-size) + ); + transform: translateY(calc(100% * var(--index))) + translateX( + calc( + 100% * var(--relative-start) / + var(--size) + ) + ); + } + } + } } } - } - } - - .work-week-grid-view { - position: relative; - padding: 1rem; - - display: flex; - flex-direction: column; - align-items: center; - height: 100%; - - overflow-y: auto; - - .grid { - width: 100%; - max-width: 55rem; - - display: grid; - - grid-template-columns: 3rem repeat(var(--time-length), 1fr); - grid-template-rows: 2rem repeat(var(--days-length), 1fr); - - border: 1px solid var(--border-600); - border-radius: 10px 10px 0 0; - - @media screen and (max-width: $device-s-width), (pointer: coarse) { - font-size: 12px; - } - - .time { - display: flex; - align-items: center; - justify-content: center; - padding: 0.5rem; - grid-row: 1; - grid-column: var(--offset) / span 2; - } - .day-name { - display: flex; - align-items: center; - justify-content: center; - padding: 0.5rem; - grid-column: 1; - grid-row: var(--line); - } - - .event { - display: flex; - flex-direction: row; - @media screen and (max-width: $device-s-width), (pointer: coarse) { - flex-direction: column; - } - gap: 0.25rem; + .legend { + display: grid; + grid-template-columns: min-content 1fr; + border: 1px solid var(--border-600); + border-radius: 0 0 10px 10px; + border-top: none; + padding: 1rem; + gap: 0.5rem 1rem; align-items: center; justify-content: center; - margin: 0.25rem; - padding: 0.5rem; - grid-row: var(--line); - grid-column: var(--offset) / span var(--length); - background-color: var(--color); - border: 3px solid var(--color); - border-radius: 10px; - font-weight: var(--bold-on-dark); - text-align: center; - - &.highlight { - background-color: var(--highlight-color); - border: 3px solid var(--highlight-color); - } - &.selected { - border: 3px solid var(--border-color); - } - } - - .hline { - grid-column: 1 / 13; - grid-row: var(--line); - height: 0px; - border-bottom: 1px solid var(--border-500); - } - - .vline { - grid-column: var(--offset); - grid-row: 1 / calc(2 + var(--days-length)); - width: 0px; - border-right: 1px dashed var(--border-500); - } - } - .legend { - max-width: 55rem; - display: grid; - grid-template-columns: min-content 1fr; - border: 1px solid var(--border-600); - border-radius: 0 0 10px 10px; - border-top: none; - padding: 1rem; - gap: 0.5rem 1rem; - align-items: center; - justify-content: center; - width: 100%; - - .name { width: 100%; - } - - .color { - display: flex; - justify-content: center; - align-items: center; - font-weight: 500; - width: 2rem; - height: 1.5rem; - background-color: var(--color); - border: 2px solid var(--border-color); - border-radius: 10px; - font-weight: var(--bold-on-dark); - } - } - } - - .schedule-view { - padding: 1rem; - - display: flex; - flex-direction: column; - align-items: center; - - gap: 1rem; - overflow-y: scroll; - - height: 100%; - - & > * { - max-width: 50rem; - } - - .header { - position: relative; - - width: 100%; - display: grid; - place-content: center; - - &.giorno { - font-size: 24px; - font-weight: 400; - - .inner { - background: var(--bg-500); - padding: 0 0.5rem; + .name { + width: 100%; } - &::before { - position: absolute; - - content: ''; - top: 50%; - left: 0; - right: 0; - height: 1px; - background: var(--border-600); - - z-index: -1; - } - } - - &.orario { - font-size: 18px; - font-weight: 300; - } - } - - .event { - @extend .panel; - - width: 100%; - - .title { - font-size: 22px; - } - - position: relative; - - cursor: pointer; - - @media screen and (min-width: $device-s-width), (pointer: fine) { - &:hover { - background: var(--bg-highlight-500); - border-color: var(--border-highlight-500); - } - } - - &.selected { - background: var(--bg-selected-500); - - &::after { - content: ''; - position: absolute; - inset: -1px; - border-radius: 1rem; - - border: 3px solid var(--border-selected-500); + .color { + width: 2rem; + height: 1.5rem; + background-color: var(--color); + border-radius: 10px; } } } diff --git a/src/utils.jsx b/src/utils.jsx index 8c2d7ab..925719b 100644 --- a/src/utils.jsx +++ b/src/utils.jsx @@ -12,6 +12,16 @@ export const WEEK_DAYS = [ 'Sabato', ] +export const WEEK_DAYS_SHORT = [ + 'Dom', + 'Lun', + 'Mar', + 'Mer', + 'Gio', + 'Ven', + 'Sab' +] + // Hashing export function hashString(str, seed = 0) { @@ -22,8 +32,12 @@ export function hashString(str, seed = 0) { h1 = Math.imul(h1 ^ ch, 2654435761) h2 = Math.imul(h2 ^ ch, 1597334677) } - h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909) - h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909) + h1 = + Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ + Math.imul(h2 ^ (h2 >>> 13), 3266489909) + h2 = + Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ + Math.imul(h1 ^ (h1 >>> 13), 3266489909) return 4294967296 * (2097151 & h2) + (h1 >>> 0) } @@ -36,7 +50,9 @@ export function prettyCourseName(name) { .map(word => { if (word.trim().length === 0) return word - return /(^del|^nel|^di$|^dei$|^con$|^alla$|^per$|^e$|^la$)/.test(word) + return /(^del|^nel|^di$|^dei$|^con$|^alla$|^per$|^e$|^la$)/.test( + word + ) ? word : word[0].toUpperCase() + word.slice(1) }) @@ -71,17 +87,28 @@ export const withClasses = classes => .map(([key]) => key) .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(key) + const previousValue = localStorage.getItem(`orario.${key}`) const [value, setValue] = useState( previousValue !== null ? JSON.parse(previousValue) : initialValue ) useEffect(() => { - localStorage.setItem(key, JSON.stringify(value)) + localStorage.setItem(`orario.${key}`, JSON.stringify(value)) }, [value]) return [value, setValue]