├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── index.html ├── package.json ├── pnpm-lock.yaml ├── public ├── 61v-62r.jpg ├── 6v-13r-infrared.jpg ├── 6v-13r.jpg ├── 88v-89r.jpg ├── 92v-93r.jpg ├── favicon.svg ├── liber-floridus-2.jpg └── ultramarine.jpg ├── src ├── App.tsx ├── annotations.json ├── components │ ├── AnnotationBody.tsx │ ├── AnnotationList.tsx │ ├── AnnotationPanel.tsx │ ├── CategoryList.tsx │ ├── LayerList.tsx │ ├── MainPanel.tsx │ ├── PageNav.tsx │ ├── Panels.tsx │ └── Viewer.tsx ├── config.ts ├── data.ts ├── hooks │ └── useAnnotations.tsx ├── main.tsx ├── pages.json ├── style.css └── types │ └── global.d.ts ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "endOfLine": "lf", 3 | "semi": false, 4 | "singleQuote": false, 5 | "useTabs": true, 6 | "tabWidth": 2, 7 | "trailingComma": "es5", 8 | "arrowParens": "avoid" 9 | } 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | Copyright 2022 Bauke van der Laan 179 | 180 | Licensed under the Apache License, Version 2.0 (the "License"); 181 | you may not use this file except in compliance with the License. 182 | You may obtain a copy of the License at 183 | 184 | http://www.apache.org/licenses/LICENSE-2.0 185 | 186 | Unless required by applicable law or agreed to in writing, software 187 | distributed under the License is distributed on an "AS IS" BASIS, 188 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 189 | See the License for the specific language governing permissions and 190 | limitations under the License. 191 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Annotation demo 2 | 3 | A web application showcasing annotations in different categories in a simulated [Mirador 3](https://projectmirador.org/) environment. 4 | 5 | The app is written in TypeScript using [React](https://reactjs.org/) and [Material UI](https://mui.com/) to keep the interface as close as possible to Mirador. 6 | 7 | [Vite](https://vitejs.dev/) is used as development server and build tool. 8 | 9 | ## Installing 10 | 11 | [Node.js](https://nodejs.org/) is required to build or develop the app. 12 | 13 | Install the dependencies: 14 | 15 | ```bash 16 | npm install 17 | ``` 18 | 19 | ## Developing 20 | 21 | Start a development server: 22 | 23 | ```bash 24 | npm run dev 25 | ``` 26 | 27 | Fast refresh is disabled for now because of [this bug](https://github.com/vitejs/vite/issues/3301) in Vite. 28 | 29 | ## Building 30 | 31 | Build a production version of the app: 32 | 33 | ```bash 34 | npm run build 35 | ``` 36 | 37 | The build output can be found in `dist`. 38 | 39 | `dist/index.html` is an example of a page with the app embedded. The app will mount a `div` with `id="annotation-demo"` and needs the linked `.css` and `.js` files as seen there. 40 | 41 | > You can preview the built app with `npm run preview`. This should _not_ be used to serve the app in production. 42 | 43 | ## Structure 44 | 45 | - [`public`](public) contains static assets like the images of the Liber Floridus used in the demo. 46 | - [`src`](src) contains the sourcecode of the 47 | - [`src/main.tsx`](src/main.tsx) is the entrypoint of the React app. 48 | - [`src/config.ts`](src/config.ts) contains the available categories, their initial state and icon. 49 | - [`src/annotations.json`](src/annotations.json) contains the annotations using the [Web Annotation Data Model](https://www.w3.org/TR/annotation-model/) with an added `category` key that maps to the `id` key found in the categories in `src/config.ts` 50 | - [`src/pages.json`](src/pages.json) contains a simplified subset of an IIIF-manifest. The `body.src` in here maps to the files in `public`. The page `id` is used as target by the annotations in `src/annotations.json`. 51 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Mmmonk Annotationdemo 8 | 9 | 10 | 22 | 23 | 24 |
25 |
26 |
27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mmmonk-annotation-demo", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview", 10 | "check": "tsc --noEmit" 11 | }, 12 | "dependencies": { 13 | "@fontsource/roboto": "^4.5.8", 14 | "@material-ui/core": "^4.12.4", 15 | "@material-ui/icons": "^4.11.3", 16 | "html-react-parser": "^3.0.1", 17 | "html-to-text": "^8.2.1", 18 | "react": "^18.2.0", 19 | "react-dom": "^18.2.0", 20 | "react-rnd": "^10.3.7" 21 | }, 22 | "devDependencies": { 23 | "@types/react": "^18.0.17", 24 | "@types/react-dom": "^18.0.6", 25 | "@vitejs/plugin-react": "^2.0.1", 26 | "typescript": "^4.7.4", 27 | "vite": "^3.0.7" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: 5.4 2 | 3 | specifiers: 4 | '@fontsource/roboto': ^4.5.8 5 | '@material-ui/core': ^4.12.4 6 | '@material-ui/icons': ^4.11.3 7 | '@types/react': ^18.0.17 8 | '@types/react-dom': ^18.0.6 9 | '@vitejs/plugin-react': ^2.0.1 10 | html-react-parser: ^3.0.1 11 | html-to-text: ^8.2.1 12 | react: ^18.2.0 13 | react-dom: ^18.2.0 14 | react-rnd: ^10.3.7 15 | typescript: ^4.7.4 16 | vite: ^3.0.7 17 | 18 | dependencies: 19 | '@fontsource/roboto': 4.5.8 20 | '@material-ui/core': 4.12.4_zxljzmqdrxwnuenbkrz77w74uy 21 | '@material-ui/icons': 4.11.3_upnjamd3tbaukgopcqqdlc7jbm 22 | html-react-parser: 3.0.1_react@18.2.0 23 | html-to-text: 8.2.1 24 | react: 18.2.0 25 | react-dom: 18.2.0_react@18.2.0 26 | react-rnd: 10.3.7_biqbaboplfbrettd7655fr4n2y 27 | 28 | devDependencies: 29 | '@types/react': 18.0.17 30 | '@types/react-dom': 18.0.6 31 | '@vitejs/plugin-react': 2.0.1_vite@3.0.7 32 | typescript: 4.7.4 33 | vite: 3.0.7 34 | 35 | packages: 36 | 37 | /@ampproject/remapping/2.2.0: 38 | resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==} 39 | engines: {node: '>=6.0.0'} 40 | dependencies: 41 | '@jridgewell/gen-mapping': 0.1.1 42 | '@jridgewell/trace-mapping': 0.3.15 43 | dev: true 44 | 45 | /@babel/code-frame/7.18.6: 46 | resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} 47 | engines: {node: '>=6.9.0'} 48 | dependencies: 49 | '@babel/highlight': 7.18.6 50 | dev: true 51 | 52 | /@babel/compat-data/7.18.8: 53 | resolution: {integrity: sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==} 54 | engines: {node: '>=6.9.0'} 55 | dev: true 56 | 57 | /@babel/core/7.18.10: 58 | resolution: {integrity: sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw==} 59 | engines: {node: '>=6.9.0'} 60 | dependencies: 61 | '@ampproject/remapping': 2.2.0 62 | '@babel/code-frame': 7.18.6 63 | '@babel/generator': 7.18.12 64 | '@babel/helper-compilation-targets': 7.18.9_@babel+core@7.18.10 65 | '@babel/helper-module-transforms': 7.18.9 66 | '@babel/helpers': 7.18.9 67 | '@babel/parser': 7.18.11 68 | '@babel/template': 7.18.10 69 | '@babel/traverse': 7.18.11 70 | '@babel/types': 7.18.10 71 | convert-source-map: 1.8.0 72 | debug: 4.3.4 73 | gensync: 1.0.0-beta.2 74 | json5: 2.2.1 75 | semver: 6.3.0 76 | transitivePeerDependencies: 77 | - supports-color 78 | dev: true 79 | 80 | /@babel/generator/7.18.12: 81 | resolution: {integrity: sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==} 82 | engines: {node: '>=6.9.0'} 83 | dependencies: 84 | '@babel/types': 7.18.10 85 | '@jridgewell/gen-mapping': 0.3.2 86 | jsesc: 2.5.2 87 | dev: true 88 | 89 | /@babel/helper-annotate-as-pure/7.18.6: 90 | resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==} 91 | engines: {node: '>=6.9.0'} 92 | dependencies: 93 | '@babel/types': 7.18.10 94 | dev: true 95 | 96 | /@babel/helper-compilation-targets/7.18.9_@babel+core@7.18.10: 97 | resolution: {integrity: sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==} 98 | engines: {node: '>=6.9.0'} 99 | peerDependencies: 100 | '@babel/core': ^7.0.0 101 | dependencies: 102 | '@babel/compat-data': 7.18.8 103 | '@babel/core': 7.18.10 104 | '@babel/helper-validator-option': 7.18.6 105 | browserslist: 4.21.3 106 | semver: 6.3.0 107 | dev: true 108 | 109 | /@babel/helper-environment-visitor/7.18.9: 110 | resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==} 111 | engines: {node: '>=6.9.0'} 112 | dev: true 113 | 114 | /@babel/helper-function-name/7.18.9: 115 | resolution: {integrity: sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==} 116 | engines: {node: '>=6.9.0'} 117 | dependencies: 118 | '@babel/template': 7.18.10 119 | '@babel/types': 7.18.10 120 | dev: true 121 | 122 | /@babel/helper-hoist-variables/7.18.6: 123 | resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} 124 | engines: {node: '>=6.9.0'} 125 | dependencies: 126 | '@babel/types': 7.18.10 127 | dev: true 128 | 129 | /@babel/helper-module-imports/7.18.6: 130 | resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} 131 | engines: {node: '>=6.9.0'} 132 | dependencies: 133 | '@babel/types': 7.18.10 134 | dev: true 135 | 136 | /@babel/helper-module-transforms/7.18.9: 137 | resolution: {integrity: sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==} 138 | engines: {node: '>=6.9.0'} 139 | dependencies: 140 | '@babel/helper-environment-visitor': 7.18.9 141 | '@babel/helper-module-imports': 7.18.6 142 | '@babel/helper-simple-access': 7.18.6 143 | '@babel/helper-split-export-declaration': 7.18.6 144 | '@babel/helper-validator-identifier': 7.18.6 145 | '@babel/template': 7.18.10 146 | '@babel/traverse': 7.18.11 147 | '@babel/types': 7.18.10 148 | transitivePeerDependencies: 149 | - supports-color 150 | dev: true 151 | 152 | /@babel/helper-plugin-utils/7.18.9: 153 | resolution: {integrity: sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==} 154 | engines: {node: '>=6.9.0'} 155 | dev: true 156 | 157 | /@babel/helper-simple-access/7.18.6: 158 | resolution: {integrity: sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==} 159 | engines: {node: '>=6.9.0'} 160 | dependencies: 161 | '@babel/types': 7.18.10 162 | dev: true 163 | 164 | /@babel/helper-split-export-declaration/7.18.6: 165 | resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} 166 | engines: {node: '>=6.9.0'} 167 | dependencies: 168 | '@babel/types': 7.18.10 169 | dev: true 170 | 171 | /@babel/helper-string-parser/7.18.10: 172 | resolution: {integrity: sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==} 173 | engines: {node: '>=6.9.0'} 174 | dev: true 175 | 176 | /@babel/helper-validator-identifier/7.18.6: 177 | resolution: {integrity: sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==} 178 | engines: {node: '>=6.9.0'} 179 | dev: true 180 | 181 | /@babel/helper-validator-option/7.18.6: 182 | resolution: {integrity: sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==} 183 | engines: {node: '>=6.9.0'} 184 | dev: true 185 | 186 | /@babel/helpers/7.18.9: 187 | resolution: {integrity: sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==} 188 | engines: {node: '>=6.9.0'} 189 | dependencies: 190 | '@babel/template': 7.18.10 191 | '@babel/traverse': 7.18.11 192 | '@babel/types': 7.18.10 193 | transitivePeerDependencies: 194 | - supports-color 195 | dev: true 196 | 197 | /@babel/highlight/7.18.6: 198 | resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} 199 | engines: {node: '>=6.9.0'} 200 | dependencies: 201 | '@babel/helper-validator-identifier': 7.18.6 202 | chalk: 2.4.2 203 | js-tokens: 4.0.0 204 | dev: true 205 | 206 | /@babel/parser/7.18.11: 207 | resolution: {integrity: sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ==} 208 | engines: {node: '>=6.0.0'} 209 | hasBin: true 210 | dependencies: 211 | '@babel/types': 7.18.10 212 | dev: true 213 | 214 | /@babel/plugin-syntax-jsx/7.18.6_@babel+core@7.18.10: 215 | resolution: {integrity: sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==} 216 | engines: {node: '>=6.9.0'} 217 | peerDependencies: 218 | '@babel/core': ^7.0.0-0 219 | dependencies: 220 | '@babel/core': 7.18.10 221 | '@babel/helper-plugin-utils': 7.18.9 222 | dev: true 223 | 224 | /@babel/plugin-transform-react-jsx-development/7.18.6_@babel+core@7.18.10: 225 | resolution: {integrity: sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==} 226 | engines: {node: '>=6.9.0'} 227 | peerDependencies: 228 | '@babel/core': ^7.0.0-0 229 | dependencies: 230 | '@babel/core': 7.18.10 231 | '@babel/plugin-transform-react-jsx': 7.18.10_@babel+core@7.18.10 232 | dev: true 233 | 234 | /@babel/plugin-transform-react-jsx-self/7.18.6_@babel+core@7.18.10: 235 | resolution: {integrity: sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig==} 236 | engines: {node: '>=6.9.0'} 237 | peerDependencies: 238 | '@babel/core': ^7.0.0-0 239 | dependencies: 240 | '@babel/core': 7.18.10 241 | '@babel/helper-plugin-utils': 7.18.9 242 | dev: true 243 | 244 | /@babel/plugin-transform-react-jsx-source/7.18.6_@babel+core@7.18.10: 245 | resolution: {integrity: sha512-utZmlASneDfdaMh0m/WausbjUjEdGrQJz0vFK93d7wD3xf5wBtX219+q6IlCNZeguIcxS2f/CvLZrlLSvSHQXw==} 246 | engines: {node: '>=6.9.0'} 247 | peerDependencies: 248 | '@babel/core': ^7.0.0-0 249 | dependencies: 250 | '@babel/core': 7.18.10 251 | '@babel/helper-plugin-utils': 7.18.9 252 | dev: true 253 | 254 | /@babel/plugin-transform-react-jsx/7.18.10_@babel+core@7.18.10: 255 | resolution: {integrity: sha512-gCy7Iikrpu3IZjYZolFE4M1Sm+nrh1/6za2Ewj77Z+XirT4TsbJcvOFOyF+fRPwU6AKKK136CZxx6L8AbSFG6A==} 256 | engines: {node: '>=6.9.0'} 257 | peerDependencies: 258 | '@babel/core': ^7.0.0-0 259 | dependencies: 260 | '@babel/core': 7.18.10 261 | '@babel/helper-annotate-as-pure': 7.18.6 262 | '@babel/helper-module-imports': 7.18.6 263 | '@babel/helper-plugin-utils': 7.18.9 264 | '@babel/plugin-syntax-jsx': 7.18.6_@babel+core@7.18.10 265 | '@babel/types': 7.18.10 266 | dev: true 267 | 268 | /@babel/runtime/7.18.9: 269 | resolution: {integrity: sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==} 270 | engines: {node: '>=6.9.0'} 271 | dependencies: 272 | regenerator-runtime: 0.13.9 273 | dev: false 274 | 275 | /@babel/template/7.18.10: 276 | resolution: {integrity: sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==} 277 | engines: {node: '>=6.9.0'} 278 | dependencies: 279 | '@babel/code-frame': 7.18.6 280 | '@babel/parser': 7.18.11 281 | '@babel/types': 7.18.10 282 | dev: true 283 | 284 | /@babel/traverse/7.18.11: 285 | resolution: {integrity: sha512-TG9PiM2R/cWCAy6BPJKeHzNbu4lPzOSZpeMfeNErskGpTJx6trEvFaVCbDvpcxwy49BKWmEPwiW8mrysNiDvIQ==} 286 | engines: {node: '>=6.9.0'} 287 | dependencies: 288 | '@babel/code-frame': 7.18.6 289 | '@babel/generator': 7.18.12 290 | '@babel/helper-environment-visitor': 7.18.9 291 | '@babel/helper-function-name': 7.18.9 292 | '@babel/helper-hoist-variables': 7.18.6 293 | '@babel/helper-split-export-declaration': 7.18.6 294 | '@babel/parser': 7.18.11 295 | '@babel/types': 7.18.10 296 | debug: 4.3.4 297 | globals: 11.12.0 298 | transitivePeerDependencies: 299 | - supports-color 300 | dev: true 301 | 302 | /@babel/types/7.18.10: 303 | resolution: {integrity: sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==} 304 | engines: {node: '>=6.9.0'} 305 | dependencies: 306 | '@babel/helper-string-parser': 7.18.10 307 | '@babel/helper-validator-identifier': 7.18.6 308 | to-fast-properties: 2.0.0 309 | dev: true 310 | 311 | /@emotion/hash/0.8.0: 312 | resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==} 313 | dev: false 314 | 315 | /@esbuild/linux-loong64/0.14.54: 316 | resolution: {integrity: sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==} 317 | engines: {node: '>=12'} 318 | cpu: [loong64] 319 | os: [linux] 320 | requiresBuild: true 321 | dev: true 322 | optional: true 323 | 324 | /@fontsource/roboto/4.5.8: 325 | resolution: {integrity: sha512-CnD7zLItIzt86q4Sj3kZUiLcBk1dSk81qcqgMGaZe7SQ1P8hFNxhMl5AZthK1zrDM5m74VVhaOpuMGIL4gagaA==} 326 | dev: false 327 | 328 | /@jridgewell/gen-mapping/0.1.1: 329 | resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==} 330 | engines: {node: '>=6.0.0'} 331 | dependencies: 332 | '@jridgewell/set-array': 1.1.2 333 | '@jridgewell/sourcemap-codec': 1.4.14 334 | dev: true 335 | 336 | /@jridgewell/gen-mapping/0.3.2: 337 | resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==} 338 | engines: {node: '>=6.0.0'} 339 | dependencies: 340 | '@jridgewell/set-array': 1.1.2 341 | '@jridgewell/sourcemap-codec': 1.4.14 342 | '@jridgewell/trace-mapping': 0.3.15 343 | dev: true 344 | 345 | /@jridgewell/resolve-uri/3.1.0: 346 | resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} 347 | engines: {node: '>=6.0.0'} 348 | dev: true 349 | 350 | /@jridgewell/set-array/1.1.2: 351 | resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} 352 | engines: {node: '>=6.0.0'} 353 | dev: true 354 | 355 | /@jridgewell/sourcemap-codec/1.4.14: 356 | resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} 357 | dev: true 358 | 359 | /@jridgewell/trace-mapping/0.3.15: 360 | resolution: {integrity: sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==} 361 | dependencies: 362 | '@jridgewell/resolve-uri': 3.1.0 363 | '@jridgewell/sourcemap-codec': 1.4.14 364 | dev: true 365 | 366 | /@material-ui/core/4.12.4_zxljzmqdrxwnuenbkrz77w74uy: 367 | resolution: {integrity: sha512-tr7xekNlM9LjA6pagJmL8QCgZXaubWUwkJnoYcMKd4gw/t4XiyvnTkjdGrUVicyB2BsdaAv1tvow45bPM4sSwQ==} 368 | engines: {node: '>=8.0.0'} 369 | peerDependencies: 370 | '@types/react': ^16.8.6 || ^17.0.0 371 | react: ^16.8.0 || ^17.0.0 372 | react-dom: ^16.8.0 || ^17.0.0 373 | peerDependenciesMeta: 374 | '@types/react': 375 | optional: true 376 | dependencies: 377 | '@babel/runtime': 7.18.9 378 | '@material-ui/styles': 4.11.5_zxljzmqdrxwnuenbkrz77w74uy 379 | '@material-ui/system': 4.12.2_zxljzmqdrxwnuenbkrz77w74uy 380 | '@material-ui/types': 5.1.0_@types+react@18.0.17 381 | '@material-ui/utils': 4.11.3_biqbaboplfbrettd7655fr4n2y 382 | '@types/react': 18.0.17 383 | '@types/react-transition-group': 4.4.5 384 | clsx: 1.2.1 385 | hoist-non-react-statics: 3.3.2 386 | popper.js: 1.16.1-lts 387 | prop-types: 15.8.1 388 | react: 18.2.0 389 | react-dom: 18.2.0_react@18.2.0 390 | react-is: 17.0.2 391 | react-transition-group: 4.4.5_biqbaboplfbrettd7655fr4n2y 392 | dev: false 393 | 394 | /@material-ui/icons/4.11.3_upnjamd3tbaukgopcqqdlc7jbm: 395 | resolution: {integrity: sha512-IKHlyx6LDh8n19vzwH5RtHIOHl9Tu90aAAxcbWME6kp4dmvODM3UvOHJeMIDzUbd4muuJKHmlNoBN+mDY4XkBA==} 396 | engines: {node: '>=8.0.0'} 397 | peerDependencies: 398 | '@material-ui/core': ^4.0.0 399 | '@types/react': ^16.8.6 || ^17.0.0 400 | react: ^16.8.0 || ^17.0.0 401 | react-dom: ^16.8.0 || ^17.0.0 402 | peerDependenciesMeta: 403 | '@types/react': 404 | optional: true 405 | dependencies: 406 | '@babel/runtime': 7.18.9 407 | '@material-ui/core': 4.12.4_zxljzmqdrxwnuenbkrz77w74uy 408 | '@types/react': 18.0.17 409 | react: 18.2.0 410 | react-dom: 18.2.0_react@18.2.0 411 | dev: false 412 | 413 | /@material-ui/styles/4.11.5_zxljzmqdrxwnuenbkrz77w74uy: 414 | resolution: {integrity: sha512-o/41ot5JJiUsIETME9wVLAJrmIWL3j0R0Bj2kCOLbSfqEkKf0fmaPt+5vtblUh5eXr2S+J/8J3DaCb10+CzPGA==} 415 | engines: {node: '>=8.0.0'} 416 | peerDependencies: 417 | '@types/react': ^16.8.6 || ^17.0.0 418 | react: ^16.8.0 || ^17.0.0 419 | react-dom: ^16.8.0 || ^17.0.0 420 | peerDependenciesMeta: 421 | '@types/react': 422 | optional: true 423 | dependencies: 424 | '@babel/runtime': 7.18.9 425 | '@emotion/hash': 0.8.0 426 | '@material-ui/types': 5.1.0_@types+react@18.0.17 427 | '@material-ui/utils': 4.11.3_biqbaboplfbrettd7655fr4n2y 428 | '@types/react': 18.0.17 429 | clsx: 1.2.1 430 | csstype: 2.6.20 431 | hoist-non-react-statics: 3.3.2 432 | jss: 10.9.2 433 | jss-plugin-camel-case: 10.9.2 434 | jss-plugin-default-unit: 10.9.2 435 | jss-plugin-global: 10.9.2 436 | jss-plugin-nested: 10.9.2 437 | jss-plugin-props-sort: 10.9.2 438 | jss-plugin-rule-value-function: 10.9.2 439 | jss-plugin-vendor-prefixer: 10.9.2 440 | prop-types: 15.8.1 441 | react: 18.2.0 442 | react-dom: 18.2.0_react@18.2.0 443 | dev: false 444 | 445 | /@material-ui/system/4.12.2_zxljzmqdrxwnuenbkrz77w74uy: 446 | resolution: {integrity: sha512-6CSKu2MtmiJgcCGf6nBQpM8fLkuB9F55EKfbdTC80NND5wpTmKzwdhLYLH3zL4cLlK0gVaaltW7/wMuyTnN0Lw==} 447 | engines: {node: '>=8.0.0'} 448 | peerDependencies: 449 | '@types/react': ^16.8.6 || ^17.0.0 450 | react: ^16.8.0 || ^17.0.0 451 | react-dom: ^16.8.0 || ^17.0.0 452 | peerDependenciesMeta: 453 | '@types/react': 454 | optional: true 455 | dependencies: 456 | '@babel/runtime': 7.18.9 457 | '@material-ui/utils': 4.11.3_biqbaboplfbrettd7655fr4n2y 458 | '@types/react': 18.0.17 459 | csstype: 2.6.20 460 | prop-types: 15.8.1 461 | react: 18.2.0 462 | react-dom: 18.2.0_react@18.2.0 463 | dev: false 464 | 465 | /@material-ui/types/5.1.0_@types+react@18.0.17: 466 | resolution: {integrity: sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==} 467 | peerDependencies: 468 | '@types/react': '*' 469 | peerDependenciesMeta: 470 | '@types/react': 471 | optional: true 472 | dependencies: 473 | '@types/react': 18.0.17 474 | dev: false 475 | 476 | /@material-ui/utils/4.11.3_biqbaboplfbrettd7655fr4n2y: 477 | resolution: {integrity: sha512-ZuQPV4rBK/V1j2dIkSSEcH5uT6AaHuKWFfotADHsC0wVL1NLd2WkFCm4ZZbX33iO4ydl6V0GPngKm8HZQ2oujg==} 478 | engines: {node: '>=8.0.0'} 479 | peerDependencies: 480 | react: ^16.8.0 || ^17.0.0 481 | react-dom: ^16.8.0 || ^17.0.0 482 | dependencies: 483 | '@babel/runtime': 7.18.9 484 | prop-types: 15.8.1 485 | react: 18.2.0 486 | react-dom: 18.2.0_react@18.2.0 487 | react-is: 17.0.2 488 | dev: false 489 | 490 | /@selderee/plugin-htmlparser2/0.6.0: 491 | resolution: {integrity: sha512-J3jpy002TyBjd4N/p6s+s90eX42H2eRhK3SbsZuvTDv977/E8p2U3zikdiehyJja66do7FlxLomZLPlvl2/xaA==} 492 | dependencies: 493 | domhandler: 4.3.1 494 | selderee: 0.6.0 495 | dev: false 496 | 497 | /@types/prop-types/15.7.5: 498 | resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} 499 | 500 | /@types/react-dom/18.0.6: 501 | resolution: {integrity: sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==} 502 | dependencies: 503 | '@types/react': 18.0.17 504 | dev: true 505 | 506 | /@types/react-transition-group/4.4.5: 507 | resolution: {integrity: sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==} 508 | dependencies: 509 | '@types/react': 18.0.17 510 | dev: false 511 | 512 | /@types/react/18.0.17: 513 | resolution: {integrity: sha512-38ETy4tL+rn4uQQi7mB81G7V1g0u2ryquNmsVIOKUAEIDK+3CUjZ6rSRpdvS99dNBnkLFL83qfmtLacGOTIhwQ==} 514 | dependencies: 515 | '@types/prop-types': 15.7.5 516 | '@types/scheduler': 0.16.2 517 | csstype: 3.1.0 518 | 519 | /@types/scheduler/0.16.2: 520 | resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==} 521 | 522 | /@vitejs/plugin-react/2.0.1_vite@3.0.7: 523 | resolution: {integrity: sha512-uINzNHmjrbunlFtyVkST6lY1ewSfz/XwLufG0PIqvLGnpk2nOIOa/1CACTDNcKi1/RwaCzJLmsXwm1NsUVV/NA==} 524 | engines: {node: ^14.18.0 || >=16.0.0} 525 | peerDependencies: 526 | vite: ^3.0.0 527 | dependencies: 528 | '@babel/core': 7.18.10 529 | '@babel/plugin-transform-react-jsx': 7.18.10_@babel+core@7.18.10 530 | '@babel/plugin-transform-react-jsx-development': 7.18.6_@babel+core@7.18.10 531 | '@babel/plugin-transform-react-jsx-self': 7.18.6_@babel+core@7.18.10 532 | '@babel/plugin-transform-react-jsx-source': 7.18.6_@babel+core@7.18.10 533 | magic-string: 0.26.2 534 | react-refresh: 0.14.0 535 | vite: 3.0.7 536 | transitivePeerDependencies: 537 | - supports-color 538 | dev: true 539 | 540 | /ansi-styles/3.2.1: 541 | resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} 542 | engines: {node: '>=4'} 543 | dependencies: 544 | color-convert: 1.9.3 545 | dev: true 546 | 547 | /browserslist/4.21.3: 548 | resolution: {integrity: sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==} 549 | engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} 550 | hasBin: true 551 | dependencies: 552 | caniuse-lite: 1.0.30001375 553 | electron-to-chromium: 1.4.218 554 | node-releases: 2.0.6 555 | update-browserslist-db: 1.0.5_browserslist@4.21.3 556 | dev: true 557 | 558 | /caniuse-lite/1.0.30001375: 559 | resolution: {integrity: sha512-kWIMkNzLYxSvnjy0hL8w1NOaWNr2rn39RTAVyIwcw8juu60bZDWiF1/loOYANzjtJmy6qPgNmn38ro5Pygagdw==} 560 | dev: true 561 | 562 | /chalk/2.4.2: 563 | resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} 564 | engines: {node: '>=4'} 565 | dependencies: 566 | ansi-styles: 3.2.1 567 | escape-string-regexp: 1.0.5 568 | supports-color: 5.5.0 569 | dev: true 570 | 571 | /clsx/1.2.1: 572 | resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} 573 | engines: {node: '>=6'} 574 | dev: false 575 | 576 | /color-convert/1.9.3: 577 | resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} 578 | dependencies: 579 | color-name: 1.1.3 580 | dev: true 581 | 582 | /color-name/1.1.3: 583 | resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} 584 | dev: true 585 | 586 | /commander/2.20.3: 587 | resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} 588 | dev: false 589 | 590 | /convert-source-map/1.8.0: 591 | resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==} 592 | dependencies: 593 | safe-buffer: 5.1.2 594 | dev: true 595 | 596 | /css-vendor/2.0.8: 597 | resolution: {integrity: sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==} 598 | dependencies: 599 | '@babel/runtime': 7.18.9 600 | is-in-browser: 1.1.3 601 | dev: false 602 | 603 | /csstype/2.6.20: 604 | resolution: {integrity: sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==} 605 | dev: false 606 | 607 | /csstype/3.1.0: 608 | resolution: {integrity: sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==} 609 | 610 | /debug/4.3.4: 611 | resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} 612 | engines: {node: '>=6.0'} 613 | peerDependencies: 614 | supports-color: '*' 615 | peerDependenciesMeta: 616 | supports-color: 617 | optional: true 618 | dependencies: 619 | ms: 2.1.2 620 | dev: true 621 | 622 | /deepmerge/4.2.2: 623 | resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==} 624 | engines: {node: '>=0.10.0'} 625 | dev: false 626 | 627 | /discontinuous-range/1.0.0: 628 | resolution: {integrity: sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==} 629 | dev: false 630 | 631 | /dom-helpers/5.2.1: 632 | resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} 633 | dependencies: 634 | '@babel/runtime': 7.18.9 635 | csstype: 3.1.0 636 | dev: false 637 | 638 | /dom-serializer/1.4.1: 639 | resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} 640 | dependencies: 641 | domelementtype: 2.3.0 642 | domhandler: 4.3.1 643 | entities: 2.2.0 644 | dev: false 645 | 646 | /dom-serializer/2.0.0: 647 | resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} 648 | dependencies: 649 | domelementtype: 2.3.0 650 | domhandler: 5.0.3 651 | entities: 4.3.1 652 | dev: false 653 | 654 | /domelementtype/2.3.0: 655 | resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} 656 | dev: false 657 | 658 | /domhandler/4.3.1: 659 | resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} 660 | engines: {node: '>= 4'} 661 | dependencies: 662 | domelementtype: 2.3.0 663 | dev: false 664 | 665 | /domhandler/5.0.3: 666 | resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} 667 | engines: {node: '>= 4'} 668 | dependencies: 669 | domelementtype: 2.3.0 670 | dev: false 671 | 672 | /domutils/2.8.0: 673 | resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} 674 | dependencies: 675 | dom-serializer: 1.4.1 676 | domelementtype: 2.3.0 677 | domhandler: 4.3.1 678 | dev: false 679 | 680 | /domutils/3.0.1: 681 | resolution: {integrity: sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==} 682 | dependencies: 683 | dom-serializer: 2.0.0 684 | domelementtype: 2.3.0 685 | domhandler: 5.0.3 686 | dev: false 687 | 688 | /electron-to-chromium/1.4.218: 689 | resolution: {integrity: sha512-INDylKH//YIf2w67D+IjkfVnGVrZ/D94DAU/FPPm6T4jEPbEDQvo9r2wTj0ncFdtJH8+V8BggZTaN8Rzk5wkgw==} 690 | dev: true 691 | 692 | /entities/2.2.0: 693 | resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} 694 | dev: false 695 | 696 | /entities/4.3.1: 697 | resolution: {integrity: sha512-o4q/dYJlmyjP2zfnaWDUC6A3BQFmVTX+tZPezK7k0GLSU9QYCauscf5Y+qcEPzKL+EixVouYDgLQK5H9GrLpkg==} 698 | engines: {node: '>=0.12'} 699 | dev: false 700 | 701 | /esbuild-android-64/0.14.54: 702 | resolution: {integrity: sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==} 703 | engines: {node: '>=12'} 704 | cpu: [x64] 705 | os: [android] 706 | requiresBuild: true 707 | dev: true 708 | optional: true 709 | 710 | /esbuild-android-arm64/0.14.54: 711 | resolution: {integrity: sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==} 712 | engines: {node: '>=12'} 713 | cpu: [arm64] 714 | os: [android] 715 | requiresBuild: true 716 | dev: true 717 | optional: true 718 | 719 | /esbuild-darwin-64/0.14.54: 720 | resolution: {integrity: sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==} 721 | engines: {node: '>=12'} 722 | cpu: [x64] 723 | os: [darwin] 724 | requiresBuild: true 725 | dev: true 726 | optional: true 727 | 728 | /esbuild-darwin-arm64/0.14.54: 729 | resolution: {integrity: sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==} 730 | engines: {node: '>=12'} 731 | cpu: [arm64] 732 | os: [darwin] 733 | requiresBuild: true 734 | dev: true 735 | optional: true 736 | 737 | /esbuild-freebsd-64/0.14.54: 738 | resolution: {integrity: sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==} 739 | engines: {node: '>=12'} 740 | cpu: [x64] 741 | os: [freebsd] 742 | requiresBuild: true 743 | dev: true 744 | optional: true 745 | 746 | /esbuild-freebsd-arm64/0.14.54: 747 | resolution: {integrity: sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==} 748 | engines: {node: '>=12'} 749 | cpu: [arm64] 750 | os: [freebsd] 751 | requiresBuild: true 752 | dev: true 753 | optional: true 754 | 755 | /esbuild-linux-32/0.14.54: 756 | resolution: {integrity: sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==} 757 | engines: {node: '>=12'} 758 | cpu: [ia32] 759 | os: [linux] 760 | requiresBuild: true 761 | dev: true 762 | optional: true 763 | 764 | /esbuild-linux-64/0.14.54: 765 | resolution: {integrity: sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==} 766 | engines: {node: '>=12'} 767 | cpu: [x64] 768 | os: [linux] 769 | requiresBuild: true 770 | dev: true 771 | optional: true 772 | 773 | /esbuild-linux-arm/0.14.54: 774 | resolution: {integrity: sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==} 775 | engines: {node: '>=12'} 776 | cpu: [arm] 777 | os: [linux] 778 | requiresBuild: true 779 | dev: true 780 | optional: true 781 | 782 | /esbuild-linux-arm64/0.14.54: 783 | resolution: {integrity: sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==} 784 | engines: {node: '>=12'} 785 | cpu: [arm64] 786 | os: [linux] 787 | requiresBuild: true 788 | dev: true 789 | optional: true 790 | 791 | /esbuild-linux-mips64le/0.14.54: 792 | resolution: {integrity: sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==} 793 | engines: {node: '>=12'} 794 | cpu: [mips64el] 795 | os: [linux] 796 | requiresBuild: true 797 | dev: true 798 | optional: true 799 | 800 | /esbuild-linux-ppc64le/0.14.54: 801 | resolution: {integrity: sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==} 802 | engines: {node: '>=12'} 803 | cpu: [ppc64] 804 | os: [linux] 805 | requiresBuild: true 806 | dev: true 807 | optional: true 808 | 809 | /esbuild-linux-riscv64/0.14.54: 810 | resolution: {integrity: sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==} 811 | engines: {node: '>=12'} 812 | cpu: [riscv64] 813 | os: [linux] 814 | requiresBuild: true 815 | dev: true 816 | optional: true 817 | 818 | /esbuild-linux-s390x/0.14.54: 819 | resolution: {integrity: sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==} 820 | engines: {node: '>=12'} 821 | cpu: [s390x] 822 | os: [linux] 823 | requiresBuild: true 824 | dev: true 825 | optional: true 826 | 827 | /esbuild-netbsd-64/0.14.54: 828 | resolution: {integrity: sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==} 829 | engines: {node: '>=12'} 830 | cpu: [x64] 831 | os: [netbsd] 832 | requiresBuild: true 833 | dev: true 834 | optional: true 835 | 836 | /esbuild-openbsd-64/0.14.54: 837 | resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==} 838 | engines: {node: '>=12'} 839 | cpu: [x64] 840 | os: [openbsd] 841 | requiresBuild: true 842 | dev: true 843 | optional: true 844 | 845 | /esbuild-sunos-64/0.14.54: 846 | resolution: {integrity: sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==} 847 | engines: {node: '>=12'} 848 | cpu: [x64] 849 | os: [sunos] 850 | requiresBuild: true 851 | dev: true 852 | optional: true 853 | 854 | /esbuild-windows-32/0.14.54: 855 | resolution: {integrity: sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==} 856 | engines: {node: '>=12'} 857 | cpu: [ia32] 858 | os: [win32] 859 | requiresBuild: true 860 | dev: true 861 | optional: true 862 | 863 | /esbuild-windows-64/0.14.54: 864 | resolution: {integrity: sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==} 865 | engines: {node: '>=12'} 866 | cpu: [x64] 867 | os: [win32] 868 | requiresBuild: true 869 | dev: true 870 | optional: true 871 | 872 | /esbuild-windows-arm64/0.14.54: 873 | resolution: {integrity: sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==} 874 | engines: {node: '>=12'} 875 | cpu: [arm64] 876 | os: [win32] 877 | requiresBuild: true 878 | dev: true 879 | optional: true 880 | 881 | /esbuild/0.14.54: 882 | resolution: {integrity: sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==} 883 | engines: {node: '>=12'} 884 | hasBin: true 885 | requiresBuild: true 886 | optionalDependencies: 887 | '@esbuild/linux-loong64': 0.14.54 888 | esbuild-android-64: 0.14.54 889 | esbuild-android-arm64: 0.14.54 890 | esbuild-darwin-64: 0.14.54 891 | esbuild-darwin-arm64: 0.14.54 892 | esbuild-freebsd-64: 0.14.54 893 | esbuild-freebsd-arm64: 0.14.54 894 | esbuild-linux-32: 0.14.54 895 | esbuild-linux-64: 0.14.54 896 | esbuild-linux-arm: 0.14.54 897 | esbuild-linux-arm64: 0.14.54 898 | esbuild-linux-mips64le: 0.14.54 899 | esbuild-linux-ppc64le: 0.14.54 900 | esbuild-linux-riscv64: 0.14.54 901 | esbuild-linux-s390x: 0.14.54 902 | esbuild-netbsd-64: 0.14.54 903 | esbuild-openbsd-64: 0.14.54 904 | esbuild-sunos-64: 0.14.54 905 | esbuild-windows-32: 0.14.54 906 | esbuild-windows-64: 0.14.54 907 | esbuild-windows-arm64: 0.14.54 908 | dev: true 909 | 910 | /escalade/3.1.1: 911 | resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} 912 | engines: {node: '>=6'} 913 | dev: true 914 | 915 | /escape-string-regexp/1.0.5: 916 | resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} 917 | engines: {node: '>=0.8.0'} 918 | dev: true 919 | 920 | /fast-memoize/2.5.2: 921 | resolution: {integrity: sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==} 922 | dev: false 923 | 924 | /fsevents/2.3.2: 925 | resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} 926 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 927 | os: [darwin] 928 | requiresBuild: true 929 | dev: true 930 | optional: true 931 | 932 | /function-bind/1.1.1: 933 | resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} 934 | dev: true 935 | 936 | /gensync/1.0.0-beta.2: 937 | resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} 938 | engines: {node: '>=6.9.0'} 939 | dev: true 940 | 941 | /globals/11.12.0: 942 | resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} 943 | engines: {node: '>=4'} 944 | dev: true 945 | 946 | /has-flag/3.0.0: 947 | resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} 948 | engines: {node: '>=4'} 949 | dev: true 950 | 951 | /has/1.0.3: 952 | resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} 953 | engines: {node: '>= 0.4.0'} 954 | dependencies: 955 | function-bind: 1.1.1 956 | dev: true 957 | 958 | /he/1.2.0: 959 | resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} 960 | hasBin: true 961 | dev: false 962 | 963 | /hoist-non-react-statics/3.3.2: 964 | resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} 965 | dependencies: 966 | react-is: 16.13.1 967 | dev: false 968 | 969 | /html-dom-parser/3.0.1: 970 | resolution: {integrity: sha512-BtPGWyE2XGbqQFdZE+0/YMVppz319jvvkNGcMwLRmt1Mw0tLHzZOMs1TqbxtcCdVSZwS5pEOXasaD7HHD5iwkQ==} 971 | dependencies: 972 | domhandler: 5.0.3 973 | htmlparser2: 8.0.1 974 | dev: false 975 | 976 | /html-react-parser/3.0.1_react@18.2.0: 977 | resolution: {integrity: sha512-TsCwwmpqN8F2JA0EqWK/8U/cN07BfZU7agH3FY5G+RQqLs6HT2z2RNlFZI+Jp8e/nIXIsgYDvt8vqu8Dv9lr6w==} 978 | peerDependencies: 979 | react: 0.14 || 15 || 16 || 17 || 18 980 | dependencies: 981 | domhandler: 5.0.3 982 | html-dom-parser: 3.0.1 983 | react: 18.2.0 984 | react-property: 2.0.0 985 | style-to-js: 1.1.1 986 | dev: false 987 | 988 | /html-to-text/8.2.1: 989 | resolution: {integrity: sha512-aN/3JvAk8qFsWVeE9InWAWueLXrbkoVZy0TkzaGhoRBC2gCFEeRLDDJN3/ijIGHohy6H+SZzUQWN/hcYtaPK8w==} 990 | engines: {node: '>=10.23.2'} 991 | hasBin: true 992 | dependencies: 993 | '@selderee/plugin-htmlparser2': 0.6.0 994 | deepmerge: 4.2.2 995 | he: 1.2.0 996 | htmlparser2: 6.1.0 997 | minimist: 1.2.6 998 | selderee: 0.6.0 999 | dev: false 1000 | 1001 | /htmlparser2/6.1.0: 1002 | resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==} 1003 | dependencies: 1004 | domelementtype: 2.3.0 1005 | domhandler: 4.3.1 1006 | domutils: 2.8.0 1007 | entities: 2.2.0 1008 | dev: false 1009 | 1010 | /htmlparser2/8.0.1: 1011 | resolution: {integrity: sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==} 1012 | dependencies: 1013 | domelementtype: 2.3.0 1014 | domhandler: 5.0.3 1015 | domutils: 3.0.1 1016 | entities: 4.3.1 1017 | dev: false 1018 | 1019 | /hyphenate-style-name/1.0.4: 1020 | resolution: {integrity: sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==} 1021 | dev: false 1022 | 1023 | /inline-style-parser/0.1.1: 1024 | resolution: {integrity: sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==} 1025 | dev: false 1026 | 1027 | /is-core-module/2.10.0: 1028 | resolution: {integrity: sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==} 1029 | dependencies: 1030 | has: 1.0.3 1031 | dev: true 1032 | 1033 | /is-in-browser/1.1.3: 1034 | resolution: {integrity: sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g==} 1035 | dev: false 1036 | 1037 | /js-tokens/4.0.0: 1038 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} 1039 | 1040 | /jsesc/2.5.2: 1041 | resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} 1042 | engines: {node: '>=4'} 1043 | hasBin: true 1044 | dev: true 1045 | 1046 | /json5/2.2.1: 1047 | resolution: {integrity: sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==} 1048 | engines: {node: '>=6'} 1049 | hasBin: true 1050 | dev: true 1051 | 1052 | /jss-plugin-camel-case/10.9.2: 1053 | resolution: {integrity: sha512-wgBPlL3WS0WDJ1lPJcgjux/SHnDuu7opmgQKSraKs4z8dCCyYMx9IDPFKBXQ8Q5dVYij1FFV0WdxyhuOOAXuTg==} 1054 | dependencies: 1055 | '@babel/runtime': 7.18.9 1056 | hyphenate-style-name: 1.0.4 1057 | jss: 10.9.2 1058 | dev: false 1059 | 1060 | /jss-plugin-default-unit/10.9.2: 1061 | resolution: {integrity: sha512-pYg0QX3bBEFtTnmeSI3l7ad1vtHU42YEEpgW7pmIh+9pkWNWb5dwS/4onSfAaI0kq+dOZHzz4dWe+8vWnanoSg==} 1062 | dependencies: 1063 | '@babel/runtime': 7.18.9 1064 | jss: 10.9.2 1065 | dev: false 1066 | 1067 | /jss-plugin-global/10.9.2: 1068 | resolution: {integrity: sha512-GcX0aE8Ef6AtlasVrafg1DItlL/tWHoC4cGir4r3gegbWwF5ZOBYhx04gurPvWHC8F873aEGqge7C17xpwmp2g==} 1069 | dependencies: 1070 | '@babel/runtime': 7.18.9 1071 | jss: 10.9.2 1072 | dev: false 1073 | 1074 | /jss-plugin-nested/10.9.2: 1075 | resolution: {integrity: sha512-VgiOWIC6bvgDaAL97XCxGD0BxOKM0K0zeB/ECyNaVF6FqvdGB9KBBWRdy2STYAss4VVA7i5TbxFZN+WSX1kfQA==} 1076 | dependencies: 1077 | '@babel/runtime': 7.18.9 1078 | jss: 10.9.2 1079 | tiny-warning: 1.0.3 1080 | dev: false 1081 | 1082 | /jss-plugin-props-sort/10.9.2: 1083 | resolution: {integrity: sha512-AP1AyUTbi2szylgr+O0OB7gkIxEGzySLITZ2GpsaoX72YMCGI2jYAc+WUhPfvUnZYiauF4zTnN4V4TGuvFjJlw==} 1084 | dependencies: 1085 | '@babel/runtime': 7.18.9 1086 | jss: 10.9.2 1087 | dev: false 1088 | 1089 | /jss-plugin-rule-value-function/10.9.2: 1090 | resolution: {integrity: sha512-vf5ms8zvLFMub6swbNxvzsurHfUZ5Shy5aJB2gIpY6WNA3uLinEcxYyraQXItRHi5ivXGqYciFDRM2ZoVoRZ4Q==} 1091 | dependencies: 1092 | '@babel/runtime': 7.18.9 1093 | jss: 10.9.2 1094 | tiny-warning: 1.0.3 1095 | dev: false 1096 | 1097 | /jss-plugin-vendor-prefixer/10.9.2: 1098 | resolution: {integrity: sha512-SxcEoH+Rttf9fEv6KkiPzLdXRmI6waOTcMkbbEFgdZLDYNIP9UKNHFy6thhbRKqv0XMQZdrEsbDyV464zE/dUA==} 1099 | dependencies: 1100 | '@babel/runtime': 7.18.9 1101 | css-vendor: 2.0.8 1102 | jss: 10.9.2 1103 | dev: false 1104 | 1105 | /jss/10.9.2: 1106 | resolution: {integrity: sha512-b8G6rWpYLR4teTUbGd4I4EsnWjg7MN0Q5bSsjKhVkJVjhQDy2KzkbD2AW3TuT0RYZVmZZHKIrXDn6kjU14qkUg==} 1107 | dependencies: 1108 | '@babel/runtime': 7.18.9 1109 | csstype: 3.1.0 1110 | is-in-browser: 1.1.3 1111 | tiny-warning: 1.0.3 1112 | dev: false 1113 | 1114 | /loose-envify/1.4.0: 1115 | resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} 1116 | hasBin: true 1117 | dependencies: 1118 | js-tokens: 4.0.0 1119 | dev: false 1120 | 1121 | /magic-string/0.26.2: 1122 | resolution: {integrity: sha512-NzzlXpclt5zAbmo6h6jNc8zl2gNRGHvmsZW4IvZhTC4W7k4OlLP+S5YLussa/r3ixNT66KOQfNORlXHSOy/X4A==} 1123 | engines: {node: '>=12'} 1124 | dependencies: 1125 | sourcemap-codec: 1.4.8 1126 | dev: true 1127 | 1128 | /minimist/1.2.6: 1129 | resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} 1130 | dev: false 1131 | 1132 | /moo/0.5.1: 1133 | resolution: {integrity: sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w==} 1134 | dev: false 1135 | 1136 | /ms/2.1.2: 1137 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 1138 | dev: true 1139 | 1140 | /nanoid/3.3.4: 1141 | resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} 1142 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 1143 | hasBin: true 1144 | dev: true 1145 | 1146 | /nearley/2.20.1: 1147 | resolution: {integrity: sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==} 1148 | hasBin: true 1149 | dependencies: 1150 | commander: 2.20.3 1151 | moo: 0.5.1 1152 | railroad-diagrams: 1.0.0 1153 | randexp: 0.4.6 1154 | dev: false 1155 | 1156 | /node-releases/2.0.6: 1157 | resolution: {integrity: sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==} 1158 | dev: true 1159 | 1160 | /object-assign/4.1.1: 1161 | resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} 1162 | engines: {node: '>=0.10.0'} 1163 | dev: false 1164 | 1165 | /parseley/0.7.0: 1166 | resolution: {integrity: sha512-xyOytsdDu077M3/46Am+2cGXEKM9U9QclBDv7fimY7e+BBlxh2JcBp2mgNsmkyA9uvgyTjVzDi7cP1v4hcFxbw==} 1167 | dependencies: 1168 | moo: 0.5.1 1169 | nearley: 2.20.1 1170 | dev: false 1171 | 1172 | /path-parse/1.0.7: 1173 | resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} 1174 | dev: true 1175 | 1176 | /picocolors/1.0.0: 1177 | resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} 1178 | dev: true 1179 | 1180 | /popper.js/1.16.1-lts: 1181 | resolution: {integrity: sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==} 1182 | dev: false 1183 | 1184 | /postcss/8.4.16: 1185 | resolution: {integrity: sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==} 1186 | engines: {node: ^10 || ^12 || >=14} 1187 | dependencies: 1188 | nanoid: 3.3.4 1189 | picocolors: 1.0.0 1190 | source-map-js: 1.0.2 1191 | dev: true 1192 | 1193 | /prop-types/15.8.1: 1194 | resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} 1195 | dependencies: 1196 | loose-envify: 1.4.0 1197 | object-assign: 4.1.1 1198 | react-is: 16.13.1 1199 | dev: false 1200 | 1201 | /railroad-diagrams/1.0.0: 1202 | resolution: {integrity: sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==} 1203 | dev: false 1204 | 1205 | /randexp/0.4.6: 1206 | resolution: {integrity: sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==} 1207 | engines: {node: '>=0.12'} 1208 | dependencies: 1209 | discontinuous-range: 1.0.0 1210 | ret: 0.1.15 1211 | dev: false 1212 | 1213 | /re-resizable/6.9.6_biqbaboplfbrettd7655fr4n2y: 1214 | resolution: {integrity: sha512-0xYKS5+Z0zk+vICQlcZW+g54CcJTTmHluA7JUUgvERDxnKAnytylcyPsA+BSFi759s5hPlHmBRegFrwXs2FuBQ==} 1215 | peerDependencies: 1216 | react: ^16.13.1 || ^17.0.0 || ^18.0.0 1217 | react-dom: ^16.13.1 || ^17.0.0 || ^18.0.0 1218 | dependencies: 1219 | fast-memoize: 2.5.2 1220 | react: 18.2.0 1221 | react-dom: 18.2.0_react@18.2.0 1222 | dev: false 1223 | 1224 | /react-dom/18.2.0_react@18.2.0: 1225 | resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} 1226 | peerDependencies: 1227 | react: ^18.2.0 1228 | dependencies: 1229 | loose-envify: 1.4.0 1230 | react: 18.2.0 1231 | scheduler: 0.23.0 1232 | dev: false 1233 | 1234 | /react-draggable/4.4.4_biqbaboplfbrettd7655fr4n2y: 1235 | resolution: {integrity: sha512-6e0WdcNLwpBx/YIDpoyd2Xb04PB0elrDrulKUgdrIlwuYvxh5Ok9M+F8cljm8kPXXs43PmMzek9RrB1b7mLMqA==} 1236 | peerDependencies: 1237 | react: '>= 16.3.0' 1238 | react-dom: '>= 16.3.0' 1239 | dependencies: 1240 | clsx: 1.2.1 1241 | prop-types: 15.8.1 1242 | react: 18.2.0 1243 | react-dom: 18.2.0_react@18.2.0 1244 | dev: false 1245 | 1246 | /react-is/16.13.1: 1247 | resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} 1248 | dev: false 1249 | 1250 | /react-is/17.0.2: 1251 | resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} 1252 | dev: false 1253 | 1254 | /react-property/2.0.0: 1255 | resolution: {integrity: sha512-kzmNjIgU32mO4mmH5+iUyrqlpFQhF8K2k7eZ4fdLSOPFrD1XgEuSBv9LDEgxRXTMBqMd8ppT0x6TIzqE5pdGdw==} 1256 | dev: false 1257 | 1258 | /react-refresh/0.14.0: 1259 | resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} 1260 | engines: {node: '>=0.10.0'} 1261 | dev: true 1262 | 1263 | /react-rnd/10.3.7_biqbaboplfbrettd7655fr4n2y: 1264 | resolution: {integrity: sha512-fYifqMI6xWzzajoRbxNNH2xpKagJT5o1zAY3a4eh4gKk+Eyy/9LGoBKA3eVX0yNOeD7JB+wznps4YmnU38v6Yw==} 1265 | peerDependencies: 1266 | react: '>=16.3.0' 1267 | react-dom: '>=16.3.0' 1268 | dependencies: 1269 | re-resizable: 6.9.6_biqbaboplfbrettd7655fr4n2y 1270 | react: 18.2.0 1271 | react-dom: 18.2.0_react@18.2.0 1272 | react-draggable: 4.4.4_biqbaboplfbrettd7655fr4n2y 1273 | tslib: 2.3.1 1274 | dev: false 1275 | 1276 | /react-transition-group/4.4.5_biqbaboplfbrettd7655fr4n2y: 1277 | resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} 1278 | peerDependencies: 1279 | react: '>=16.6.0' 1280 | react-dom: '>=16.6.0' 1281 | dependencies: 1282 | '@babel/runtime': 7.18.9 1283 | dom-helpers: 5.2.1 1284 | loose-envify: 1.4.0 1285 | prop-types: 15.8.1 1286 | react: 18.2.0 1287 | react-dom: 18.2.0_react@18.2.0 1288 | dev: false 1289 | 1290 | /react/18.2.0: 1291 | resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} 1292 | engines: {node: '>=0.10.0'} 1293 | dependencies: 1294 | loose-envify: 1.4.0 1295 | dev: false 1296 | 1297 | /regenerator-runtime/0.13.9: 1298 | resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==} 1299 | dev: false 1300 | 1301 | /resolve/1.22.1: 1302 | resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} 1303 | hasBin: true 1304 | dependencies: 1305 | is-core-module: 2.10.0 1306 | path-parse: 1.0.7 1307 | supports-preserve-symlinks-flag: 1.0.0 1308 | dev: true 1309 | 1310 | /ret/0.1.15: 1311 | resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==} 1312 | engines: {node: '>=0.12'} 1313 | dev: false 1314 | 1315 | /rollup/2.77.3: 1316 | resolution: {integrity: sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==} 1317 | engines: {node: '>=10.0.0'} 1318 | hasBin: true 1319 | optionalDependencies: 1320 | fsevents: 2.3.2 1321 | dev: true 1322 | 1323 | /safe-buffer/5.1.2: 1324 | resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} 1325 | dev: true 1326 | 1327 | /scheduler/0.23.0: 1328 | resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} 1329 | dependencies: 1330 | loose-envify: 1.4.0 1331 | dev: false 1332 | 1333 | /selderee/0.6.0: 1334 | resolution: {integrity: sha512-ibqWGV5aChDvfVdqNYuaJP/HnVBhlRGSRrlbttmlMpHcLuTqqbMH36QkSs9GEgj5M88JDYLI8eyP94JaQ8xRlg==} 1335 | dependencies: 1336 | parseley: 0.7.0 1337 | dev: false 1338 | 1339 | /semver/6.3.0: 1340 | resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} 1341 | hasBin: true 1342 | dev: true 1343 | 1344 | /source-map-js/1.0.2: 1345 | resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} 1346 | engines: {node: '>=0.10.0'} 1347 | dev: true 1348 | 1349 | /sourcemap-codec/1.4.8: 1350 | resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} 1351 | dev: true 1352 | 1353 | /style-to-js/1.1.1: 1354 | resolution: {integrity: sha512-RJ18Z9t2B02sYhZtfWKQq5uplVctgvjTfLWT7+Eb1zjUjIrWzX5SdlkwLGQozrqarTmEzJJ/YmdNJCUNI47elg==} 1355 | dependencies: 1356 | style-to-object: 0.3.0 1357 | dev: false 1358 | 1359 | /style-to-object/0.3.0: 1360 | resolution: {integrity: sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==} 1361 | dependencies: 1362 | inline-style-parser: 0.1.1 1363 | dev: false 1364 | 1365 | /supports-color/5.5.0: 1366 | resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} 1367 | engines: {node: '>=4'} 1368 | dependencies: 1369 | has-flag: 3.0.0 1370 | dev: true 1371 | 1372 | /supports-preserve-symlinks-flag/1.0.0: 1373 | resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} 1374 | engines: {node: '>= 0.4'} 1375 | dev: true 1376 | 1377 | /tiny-warning/1.0.3: 1378 | resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} 1379 | dev: false 1380 | 1381 | /to-fast-properties/2.0.0: 1382 | resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} 1383 | engines: {node: '>=4'} 1384 | dev: true 1385 | 1386 | /tslib/2.3.1: 1387 | resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==} 1388 | dev: false 1389 | 1390 | /typescript/4.7.4: 1391 | resolution: {integrity: sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==} 1392 | engines: {node: '>=4.2.0'} 1393 | hasBin: true 1394 | dev: true 1395 | 1396 | /update-browserslist-db/1.0.5_browserslist@4.21.3: 1397 | resolution: {integrity: sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==} 1398 | hasBin: true 1399 | peerDependencies: 1400 | browserslist: '>= 4.21.0' 1401 | dependencies: 1402 | browserslist: 4.21.3 1403 | escalade: 3.1.1 1404 | picocolors: 1.0.0 1405 | dev: true 1406 | 1407 | /vite/3.0.7: 1408 | resolution: {integrity: sha512-dILhvKba1mbP1wCezVQx/qhEK7/+jVn9ciadEcyKMMhZpsuAi/eWZfJRMkmYlkSFG7Qq9NvJbgFq4XOBxugJsA==} 1409 | engines: {node: ^14.18.0 || >=16.0.0} 1410 | hasBin: true 1411 | peerDependencies: 1412 | less: '*' 1413 | sass: '*' 1414 | stylus: '*' 1415 | terser: ^5.4.0 1416 | peerDependenciesMeta: 1417 | less: 1418 | optional: true 1419 | sass: 1420 | optional: true 1421 | stylus: 1422 | optional: true 1423 | terser: 1424 | optional: true 1425 | dependencies: 1426 | esbuild: 0.14.54 1427 | postcss: 8.4.16 1428 | resolve: 1.22.1 1429 | rollup: 2.77.3 1430 | optionalDependencies: 1431 | fsevents: 2.3.2 1432 | dev: true 1433 | -------------------------------------------------------------------------------- /public/61v-62r.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ugent-library/mmmonk-annotation-demo/baef22305a8ea5b8ee948ccabe1ecfeace895d15/public/61v-62r.jpg -------------------------------------------------------------------------------- /public/6v-13r-infrared.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ugent-library/mmmonk-annotation-demo/baef22305a8ea5b8ee948ccabe1ecfeace895d15/public/6v-13r-infrared.jpg -------------------------------------------------------------------------------- /public/6v-13r.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ugent-library/mmmonk-annotation-demo/baef22305a8ea5b8ee948ccabe1ecfeace895d15/public/6v-13r.jpg -------------------------------------------------------------------------------- /public/88v-89r.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ugent-library/mmmonk-annotation-demo/baef22305a8ea5b8ee948ccabe1ecfeace895d15/public/88v-89r.jpg -------------------------------------------------------------------------------- /public/92v-93r.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ugent-library/mmmonk-annotation-demo/baef22305a8ea5b8ee948ccabe1ecfeace895d15/public/92v-93r.jpg -------------------------------------------------------------------------------- /public/favicon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/liber-floridus-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ugent-library/mmmonk-annotation-demo/baef22305a8ea5b8ee948ccabe1ecfeace895d15/public/liber-floridus-2.jpg -------------------------------------------------------------------------------- /public/ultramarine.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ugent-library/mmmonk-annotation-demo/baef22305a8ea5b8ee948ccabe1ecfeace895d15/public/ultramarine.jpg -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import Paper from "@material-ui/core/Paper" 3 | import AppBar from "@material-ui/core/AppBar" 4 | import Toolbar from "@material-ui/core/Toolbar" 5 | import Typography from "@material-ui/core/Typography" 6 | import { createTheme, ThemeProvider } from "@material-ui/core" 7 | import { categoryModel } from "./config" 8 | import { hydratedAnnotations } from "./data" 9 | import pages from "./pages.json" 10 | import Panels from "./components/Panels" 11 | import Viewer from "./components/Viewer" 12 | import "@fontsource/roboto" 13 | 14 | type AnnotationContext = { 15 | activeAnnotations: AnnotationState 16 | setActiveAnnotations: React.Dispatch> 17 | } 18 | 19 | export const AnnotationContext = React.createContext(null!) 20 | 21 | const defaultCategories = categoryModel.map(category => ({ 22 | ...category, 23 | enabled: category.enabledByDefault, 24 | })) 25 | 26 | const defaultView = { 27 | pageIndex: 0, 28 | layerIndex: 0, 29 | } 30 | 31 | const theme = createTheme({ 32 | palette: { 33 | primary: { 34 | main: "#1976d2", 35 | }, 36 | }, 37 | }) 38 | 39 | function App() { 40 | const [activeAnnotations, setActiveAnnotations] = 41 | React.useState([]) 42 | 43 | const viewState = React.useState(defaultView) 44 | const [view] = viewState 45 | const pageId = pages.items[view.pageIndex].id 46 | 47 | const categoryState = React.useState(defaultCategories) 48 | const [enabledCategories] = categoryState 49 | 50 | const filteredAnnotations = hydratedAnnotations.filter(annotation => { 51 | const annotationIsOnCurrentCanvas = annotation.target.source === pageId 52 | const annotationIsFromEnabledCategory = enabledCategories.find( 53 | cat => cat.id === annotation.category.id 54 | )?.enabled 55 | return annotationIsOnCurrentCanvas && annotationIsFromEnabledCategory 56 | }) 57 | 58 | return ( 59 |
60 | 61 | 62 | 63 | Liber floridus 64 | 65 | 66 | 69 |
70 | 71 | 72 | 78 | 79 |
80 |
81 |
82 |
83 | ) 84 | } 85 | 86 | export default App 87 | -------------------------------------------------------------------------------- /src/components/AnnotationBody.tsx: -------------------------------------------------------------------------------- 1 | function AnnotationBody({ 2 | body, 3 | preview = false, 4 | }: { 5 | body: AnnotationBody 6 | preview?: boolean 7 | }) { 8 | const { format, value } = body 9 | switch (format) { 10 | case "text/plain": 11 | return ( 12 |
13 |

{value}

14 |
15 | ) 16 | case "text/html": 17 | const html = preview 18 | ? // Remove images, links and bibliography from preview 19 | value 20 | .replace(//g, "") 21 | .replace(/]*>|<\/a>/g, "") 22 | .replace(/
.*?<\/section>/g, "") 23 | : value 24 | return ( 25 |
29 | ) 30 | } 31 | } 32 | 33 | export default AnnotationBody 34 | -------------------------------------------------------------------------------- /src/components/AnnotationList.tsx: -------------------------------------------------------------------------------- 1 | import { Grid, Typography, Divider, SvgIcon } from "@material-ui/core" 2 | import AnnotationBody from "../components/AnnotationBody" 3 | import { useAnnotations } from "../hooks/useAnnotations" 4 | 5 | function AnnotationList({ 6 | annotations, 7 | categoryState, 8 | }: { 9 | annotations: HydratedAnnotation[] 10 | categoryState: CategoryState 11 | }) { 12 | const [enabledCategories] = categoryState 13 | const filteredAnnotations = annotations.filter( 14 | annotation => 15 | enabledCategories.find(category => category.id === annotation.category.id) 16 | ?.enabled 17 | ) 18 | return ( 19 |
    20 | {filteredAnnotations.map((annotation, i) => ( 21 | 22 | ))} 23 |
24 | ) 25 | } 26 | export default AnnotationList 27 | 28 | function AnnotationItem({ annotation }: { annotation: HydratedAnnotation }) { 29 | const { activeAnnotations, activateAnnotation } = useAnnotations() 30 | const isActive = activeAnnotations.find(anno => anno.id === annotation.id) 31 | return ( 32 | <> 33 |
  • 34 | 81 |
  • 82 | 83 | 84 | ) 85 | } 86 | -------------------------------------------------------------------------------- /src/components/AnnotationPanel.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Typography, 3 | Divider, 4 | Grid, 5 | Link, 6 | SvgIcon, 7 | IconButton, 8 | } from "@material-ui/core" 9 | import CloseIcon from "@material-ui/icons/Close" 10 | import AnnotationBody from "./AnnotationBody" 11 | import { hydratedAnnotations } from "../data" 12 | import { useAnnotations } from "../hooks/useAnnotations" 13 | 14 | function formatDate(dateString: string) { 15 | return new Date(dateString).toLocaleDateString("en-UK", { 16 | year: "numeric", 17 | month: "long", 18 | day: "numeric", 19 | }) 20 | } 21 | 22 | type AnnotationPanelProps = { 23 | annotation: HydratedAnnotation 24 | } 25 | 26 | function AnnotationPanel({ annotation }: AnnotationPanelProps) { 27 | const { activeAnnotations, closeAnnotation, togglePinAnnotation } = 28 | useAnnotations() 29 | 30 | const currentPanel = activeAnnotations.find( 31 | panel => panel.id === annotation.id 32 | ) 33 | const isPinned = currentPanel?.pinned 34 | 35 | return ( 36 |
    37 |
    38 |
    39 | 45 | 46 | 47 | 48 | 53 | 54 | 55 | 56 | {annotation.category.name} 57 | 58 | 59 | 60 | 61 | 62 | 88 | 89 | 90 |
    91 | 92 | Annotated by {annotation.creator.name} on{" "} 93 | {formatDate(annotation.created)} 94 | 95 |
    96 |
    97 |
    98 | 99 | {annotation.crossReferences?.length ? ( 100 | 101 | ) : null} 102 |
    103 |
    104 |
    105 | 106 |
    107 | 108 | 109 | 110 | 113 | 118 | 119 | 120 | 123 | 128 | 129 | 130 |
    111 | Annotated by 112 | 114 | 115 | {annotation.creator.name} 116 | 117 |
    121 | Created on 122 | 124 | 125 | {formatDate(annotation.created)} 126 | 127 |
    131 |
    132 |
    133 |
    134 | ) 135 | } 136 | 137 | export default AnnotationPanel 138 | 139 | function CrossReferences({ refs }: { refs: { id: string }[] }) { 140 | const { activateAnnotation } = useAnnotations() 141 | const hydratedRefs = refs.map(ref => 142 | hydratedAnnotations.find(anno => anno.id === ref.id) 143 | ) 144 | return ( 145 |
    146 |

    See also

    147 |
      148 | {hydratedRefs.map(ref => { 149 | if (ref === undefined) { 150 | throw new Error("Cross-reference does not exist in annotations") 151 | } else { 152 | return ( 153 |
    • 154 | 176 |
    • 177 | ) 178 | } 179 | })} 180 |
    181 |
    182 | ) 183 | } 184 | -------------------------------------------------------------------------------- /src/components/CategoryList.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Grid, 3 | Checkbox, 4 | Typography, 5 | SvgIcon, 6 | FormControl, 7 | FormLabel, 8 | FormGroup, 9 | FormControlLabel, 10 | } from "@material-ui/core" 11 | import { categoryModel } from "../config" 12 | import { hydratedAnnotations as allAnnotations } from "../data" 13 | 14 | type CategoryItem = Category & { 15 | occurencesInManifest: number 16 | occurencesOnPage: number 17 | } 18 | 19 | type CategoryListProps = { 20 | pageId: string 21 | categoryState: CategoryState 22 | } 23 | 24 | function CategoryList({ pageId, categoryState }: CategoryListProps) { 25 | const categories: CategoryItem[] = categoryModel.map(category => { 26 | const inManifest = allAnnotations.filter( 27 | annotation => annotation.category.id === category.id 28 | ) 29 | 30 | const onPage = inManifest.filter(annotation => { 31 | return annotation.target.source === pageId 32 | }) 33 | 34 | return { 35 | ...category, 36 | occurencesInManifest: inManifest.length, 37 | occurencesOnPage: onPage.length, 38 | } 39 | }) 40 | 41 | const [enabledCategories, setEnabledCategories] = categoryState 42 | 43 | function toggleAllCategories() { 44 | setEnabledCategories(prev => 45 | prev.map(category => ({ 46 | ...category, 47 | enabled: allCategoriesState !== "all", 48 | })) 49 | ) 50 | } 51 | 52 | function calculateAllCategoriesState() { 53 | if (enabledCategories.every(category => !category.enabled)) { 54 | return "none" 55 | } else if (enabledCategories.every(category => category.enabled)) { 56 | return "all" 57 | } else { 58 | return "some" 59 | } 60 | } 61 | 62 | const allCategoriesState = calculateAllCategoriesState() 63 | 64 | return ( 65 |
    66 | 67 | 70 | 71 | 80 | } 81 | label="All categories" 82 | /> 83 | {categories.map(category => ( 84 | 89 | ))} 90 | 91 | 92 |
    93 | ) 94 | } 95 | 96 | export default CategoryList 97 | 98 | type ItemProps = { 99 | category: CategoryItem 100 | categoryState: CategoryState 101 | } 102 | 103 | function Item({ category, categoryState }: ItemProps) { 104 | const [enabledCategories, setEnabledCategories] = categoryState 105 | 106 | const isEnabled = enabledCategories.find( 107 | ({ id }) => id === category.id 108 | )?.enabled 109 | 110 | function toggleCategory() { 111 | setEnabledCategories(existingEnabledCategories => 112 | existingEnabledCategories.map(cat => 113 | cat.id === category.id ? { ...cat, enabled: !isEnabled } : cat 114 | ) 115 | ) 116 | } 117 | 118 | return ( 119 | 127 | } 128 | label={ 129 | 130 | 131 | 136 | 137 | 138 | 139 | 140 | {category.name} 141 | 142 | 143 | 144 | {category.occurencesOnPage}{" "} 145 | 146 | / {category.occurencesInManifest} 147 | 148 | 149 | 150 | 151 | 152 | 153 | } 154 | /> 155 | ) 156 | } 157 | -------------------------------------------------------------------------------- /src/components/LayerList.tsx: -------------------------------------------------------------------------------- 1 | import Radio from "@material-ui/core/Radio" 2 | import RadioGroup from "@material-ui/core/RadioGroup" 3 | import FormControlLabel from "@material-ui/core/FormControlLabel" 4 | import FormControl from "@material-ui/core/FormControl" 5 | import pages from "../pages.json" 6 | 7 | type LayerListProps = { 8 | viewState: ViewState 9 | } 10 | 11 | function LayerList({ viewState }: LayerListProps) { 12 | const [view, setView] = viewState 13 | const layersOnThisPage = pages.items[view.pageIndex].body?.items || [] 14 | 15 | if (layersOnThisPage.length) { 16 | function handleChange(value: string) { 17 | setView(prev => ({ 18 | ...prev, 19 | layerIndex: parseInt(value), 20 | })) 21 | } 22 | 23 | return ( 24 |
    25 | 26 | handleChange(e.target.value)} 31 | > 32 | {layersOnThisPage.length ? ( 33 | layersOnThisPage.map((layer, i) => ( 34 | } 37 | label={layer.label.en[0]} 38 | key={layer.label.en[0]} 39 | /> 40 | )) 41 | ) : ( 42 | } 45 | label="Default" 46 | /> 47 | )} 48 | 49 | 50 |
    51 | ) 52 | } else { 53 | return ( 54 |
    55 | 56 | 57 | } 60 | label="Default" 61 | /> 62 | 63 | 64 |
    65 | ) 66 | } 67 | } 68 | 69 | export default LayerList 70 | -------------------------------------------------------------------------------- /src/components/MainPanel.tsx: -------------------------------------------------------------------------------- 1 | import { ReactNode, useState } from "react" 2 | import LayerList from "./LayerList" 3 | import CategoryList from "./CategoryList" 4 | import AnnotationList from "./AnnotationList" 5 | import ExpandMoreIcon from "@material-ui/icons/ExpandMore" 6 | import { withStyles } from "@material-ui/core/styles" 7 | import { Typography } from "@material-ui/core" 8 | import MuiAccordion from "@material-ui/core/Accordion" 9 | import MuiAccordionSummary from "@material-ui/core/AccordionSummary" 10 | import AccordionDetails from "@material-ui/core/AccordionDetails" 11 | 12 | type MainPanelProps = { 13 | annotations: HydratedAnnotation[] 14 | pageId: string 15 | categoryState: CategoryState 16 | viewState: ViewState 17 | } 18 | 19 | function MainPanel({ 20 | annotations, 21 | pageId, 22 | categoryState, 23 | viewState, 24 | }: MainPanelProps) { 25 | return ( 26 | <> 27 |
    28 | 29 |
    30 |
    31 | 32 |
    33 |
    34 | 38 |
    39 | 40 | ) 41 | } 42 | 43 | export default MainPanel 44 | 45 | type SectionProps = { 46 | heading: string 47 | children: ReactNode 48 | closedByDefault?: boolean 49 | } 50 | 51 | function Section({ heading, children, closedByDefault = false }: SectionProps) { 52 | const [expanded, setExpanded] = useState(!closedByDefault) 53 | return ( 54 | 55 | } 57 | onClick={() => setExpanded(!expanded)} 58 | > 59 | {heading} 60 | 61 | 62 | {children} 63 | 64 | 65 | ) 66 | } 67 | 68 | const Accordion = withStyles({ 69 | root: { 70 | border: "none", 71 | borderRadius: 0, 72 | boxShadow: "none", 73 | "&:not(:last-child)": { 74 | borderBottom: "1px solid rgba(0, 0, 0, .38)", 75 | }, 76 | "&$expanded": { 77 | margin: "auto", 78 | }, 79 | }, 80 | expanded: {}, 81 | })(MuiAccordion) 82 | 83 | const AccordionSummary = withStyles({ 84 | root: { 85 | margin: 0, 86 | minHeight: 56, 87 | "&$expanded": { 88 | margin: 0, 89 | minHeight: 56, 90 | }, 91 | }, 92 | content: { 93 | "&$expanded": { 94 | margin: "0", 95 | }, 96 | }, 97 | expanded: {}, 98 | })(MuiAccordionSummary) 99 | -------------------------------------------------------------------------------- /src/components/PageNav.tsx: -------------------------------------------------------------------------------- 1 | import { SvgIcon, IconButton, Typography } from "@material-ui/core" 2 | import { useAnnotations } from "../hooks/useAnnotations" 3 | import pages from "../pages.json" 4 | 5 | const total = pages.items.length 6 | 7 | type PageNavProps = { 8 | viewState: ViewState 9 | } 10 | 11 | function PageNav({ viewState }: PageNavProps) { 12 | const [view, setView] = viewState 13 | const { pageIndex } = view 14 | 15 | const { closeAllExceptPinnedAnnotations } = useAnnotations() 16 | 17 | function preloadImg(src: string) { 18 | const img = new Image() 19 | img.src = src 20 | } 21 | 22 | function handleHover() { 23 | if (pageIndex + 1 < total) { 24 | const nextPage = pages.items[pageIndex + 1] 25 | const { src } = nextPage.body.items 26 | ? nextPage.body.items[view.layerIndex] 27 | : nextPage.body 28 | preloadImg(src) 29 | } 30 | } 31 | 32 | function next() { 33 | closeAllExceptPinnedAnnotations() 34 | if (pageIndex + 1 < total) 35 | setView(prev => ({ 36 | pageIndex: prev.pageIndex + 1, 37 | layerIndex: 0, 38 | })) 39 | } 40 | function prev() { 41 | closeAllExceptPinnedAnnotations() 42 | if (pageIndex > 0) 43 | setView(prev => ({ 44 | pageIndex: prev.pageIndex - 1, 45 | layerIndex: 0, 46 | })) 47 | } 48 | return ( 49 | 75 | ) 76 | } 77 | 78 | export default PageNav 79 | -------------------------------------------------------------------------------- /src/components/Panels.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { Rnd } from "react-rnd" 3 | import MainPanel from "./MainPanel" 4 | import AnnotationPanel from "./AnnotationPanel" 5 | import { hydratedAnnotations } from "../data" 6 | import { useAnnotations } from "../hooks/useAnnotations" 7 | 8 | type PanelsProps = { 9 | annotations: HydratedAnnotation[] 10 | pageId: string 11 | categoryState: CategoryState 12 | viewState: ViewState 13 | } 14 | 15 | function Panels({ 16 | annotations, 17 | pageId, 18 | categoryState, 19 | viewState, 20 | }: PanelsProps) { 21 | const { activeAnnotations } = useAnnotations() 22 | 23 | return ( 24 | 25 | 31 | {activeAnnotations.map(activeAnnotation => { 32 | const hydratedAnnotation = hydratedAnnotations.find( 33 | ({ id }) => id === activeAnnotation.id 34 | ) 35 | return hydratedAnnotation ? ( 36 | 40 | ) : null 41 | })} 42 | 43 | ) 44 | } 45 | 46 | function PanelArea({ children }: { children: React.ReactNode }) { 47 | const arrayChildren = React.Children.toArray(children) 48 | return ( 49 |
    50 | {React.Children.map(arrayChildren, child => ( 51 | 52 | {React.cloneElement(child as React.ReactElement)} 53 | 54 | ))} 55 |
    56 | ) 57 | } 58 | 59 | export default Panels 60 | 61 | function ResizablePanel({ children }: { children: React.ReactNode }) { 62 | return ( 63 | 74 | {children} 75 | 76 | ) 77 | } 78 | -------------------------------------------------------------------------------- /src/components/Viewer.tsx: -------------------------------------------------------------------------------- 1 | import parse, { domToReact, attributesToProps } from "html-react-parser" 2 | import pages from "../pages.json" 3 | import { useAnnotations } from "../hooks/useAnnotations" 4 | import PageNav from "./PageNav" 5 | 6 | type ViewerProps = { 7 | viewState: ViewState 8 | annotations: HydratedAnnotation[] 9 | } 10 | 11 | function Viewer({ viewState, annotations }: ViewerProps) { 12 | const [view] = viewState 13 | const page = pages.items[view.pageIndex] 14 | const { src, width, height } = page.body.items 15 | ? page.body.items[view.layerIndex] 16 | : page.body 17 | 18 | return ( 19 |
    20 | 28 | 29 | 30 | 31 | 32 |
    33 | ) 34 | } 35 | export default Viewer 36 | 37 | type TargetsProps = { 38 | annotations: HydratedAnnotation[] 39 | } 40 | 41 | function Targets({ annotations }: TargetsProps) { 42 | const targets = annotations.map(function (annotation) { 43 | if (annotation.target.selector.type === "SvgSelector") { 44 | return 45 | } 46 | }) 47 | 48 | return <>{targets} 49 | } 50 | 51 | type TargetProps = { 52 | annotation: HydratedAnnotation 53 | } 54 | 55 | function Target({ annotation }: TargetProps) { 56 | if (annotation.target) { 57 | const { activateAnnotation, activeAnnotations } = useAnnotations() 58 | const isActive = activeAnnotations.find(anno => anno.id === annotation.id) 59 | const options = { 60 | replace: (domNode: any) => { 61 | const isValidNode = domNode.name === "svg" && domNode.children.length 62 | if (isValidNode) { 63 | const props = attributesToProps(domNode.attribs) 64 | return ( 65 | !isActive && activateAnnotation(annotation.id)} 69 | > 70 | {domToReact(domNode.children)} 71 | 72 | ) 73 | } 74 | }, 75 | } 76 | return <>{parse(annotation.target.selector.value, options)} 77 | } else return null 78 | } 79 | -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | import PaletteIcon from "@material-ui/icons/PaletteSharp" 2 | import ImageIcon from "@material-ui/icons/ImageSharp" 3 | import TextFieldsIcon from "@material-ui/icons/TextFieldsSharp" 4 | import LayersIcon from "@material-ui/icons/LayersSharp" 5 | import TranslateIcon from "@material-ui/icons/Translate" 6 | 7 | export const categoryModel = [ 8 | { 9 | id: "iconography", 10 | name: "Iconography", 11 | icon: ImageIcon, 12 | enabledByDefault: true, 13 | }, 14 | { 15 | id: "pigments", 16 | name: "Pigments", 17 | icon: PaletteIcon, 18 | enabledByDefault: true, 19 | }, 20 | { 21 | id: "transcriptions", 22 | name: "Transcriptions", 23 | icon: TextFieldsIcon, 24 | enabledByDefault: true, 25 | }, 26 | { 27 | id: "translations", 28 | name: "Translations", 29 | icon: TranslateIcon, 30 | enabledByDefault: true, 31 | }, 32 | { 33 | id: "material", 34 | name: "Material technical information", 35 | icon: LayersIcon, 36 | enabledByDefault: true, 37 | }, 38 | ] as const 39 | -------------------------------------------------------------------------------- /src/data.ts: -------------------------------------------------------------------------------- 1 | import annotationPage from "./annotations.json" 2 | import { categoryModel } from "./config" 3 | 4 | const annotations = annotationPage.items as Annotation[] 5 | 6 | export const hydratedAnnotations: HydratedAnnotation[] = annotations.map( 7 | annotation => ({ 8 | ...annotation, 9 | category: categoryModel.find(cat => cat.id === annotation.category)!, 10 | }) 11 | ) 12 | -------------------------------------------------------------------------------- /src/hooks/useAnnotations.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { AnnotationContext } from "../App" 3 | 4 | function useAnnotations() { 5 | const context = React.useContext(AnnotationContext) 6 | 7 | if (!context) { 8 | throw new Error("useAnnotations must be used within a AnnotationProvider") 9 | } 10 | 11 | const { activeAnnotations, setActiveAnnotations } = context 12 | 13 | function activateAnnotation(id: string, scrollToCard: boolean = true): void { 14 | if (scrollToCard) { 15 | const card = document.querySelector(`[data-annotation-id="${id}"]`) 16 | card?.scrollIntoView({ block: "center" }) 17 | } 18 | setActiveAnnotations(prev => { 19 | const pinnedPanels = prev.filter(annotation => annotation.pinned) 20 | const newPanel = { 21 | id, 22 | pinned: false, 23 | } 24 | return [...pinnedPanels, newPanel] 25 | }) 26 | } 27 | 28 | function closeAnnotation(id: string): void { 29 | setActiveAnnotations(prev => { 30 | const newActiveAnnotations = prev.filter( 31 | annotation => annotation.id !== id 32 | ) 33 | return newActiveAnnotations 34 | }) 35 | } 36 | 37 | function closeAllExceptPinnedAnnotations(): void { 38 | setActiveAnnotations(prev => { 39 | return prev.filter(annotation => annotation.pinned) 40 | }) 41 | } 42 | 43 | function togglePinAnnotation(id: string): void { 44 | const current = activeAnnotations.find(annotation => annotation.id === id) 45 | const isPinned = current?.pinned 46 | setActiveAnnotations(prev => { 47 | return prev.map(annotation => { 48 | return annotation.id === id 49 | ? { ...annotation, pinned: !isPinned } 50 | : annotation 51 | }) 52 | }) 53 | } 54 | 55 | return { 56 | activeAnnotations, 57 | activateAnnotation, 58 | closeAnnotation, 59 | closeAllExceptPinnedAnnotations, 60 | togglePinAnnotation, 61 | } 62 | } 63 | 64 | export { useAnnotations } 65 | -------------------------------------------------------------------------------- /src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import ReactDOM from "react-dom/client" 3 | import App from "./App" 4 | 5 | ReactDOM.createRoot( 6 | document.getElementById("annotation-demo") as HTMLElement 7 | ).render( 8 | 9 | 10 | 11 | ) 12 | -------------------------------------------------------------------------------- /src/pages.json: -------------------------------------------------------------------------------- 1 | { 2 | "items": [ 3 | { 4 | "id": "folio-1", 5 | "body": { 6 | "type": "Choice", 7 | "items": [ 8 | { 9 | "id": "folio-1-natural", 10 | "type": "Image", 11 | "src": "6v-13r.jpg", 12 | "height": 2760, 13 | "width": 3999, 14 | "label": { 15 | "en": ["Natural light"] 16 | } 17 | }, 18 | { 19 | "id": "folio-1-infrared", 20 | "type": "Image", 21 | "src": "6v-13r-infrared.jpg", 22 | "height": 2760, 23 | "width": 3999, 24 | "label": { 25 | "en": ["Infrared"] 26 | } 27 | } 28 | ] 29 | } 30 | }, 31 | { 32 | "id": "folio-2", 33 | "body": { 34 | "type": "Image", 35 | "src": "61v-62r.jpg", 36 | "height": 2760, 37 | "width": 4000 38 | } 39 | }, 40 | { 41 | "id": "folio-3", 42 | "body": { 43 | "type": "Image", 44 | "src": "88v-89r.jpg", 45 | "height": 2760, 46 | "width": 4000 47 | } 48 | }, 49 | { 50 | "id": "folio-4", 51 | "body": { 52 | "type": "Image", 53 | "src": "92v-93r.jpg", 54 | "height": 3246, 55 | "width": 4000 56 | } 57 | } 58 | ] 59 | } 60 | -------------------------------------------------------------------------------- /src/style.css: -------------------------------------------------------------------------------- 1 | #annotation-demo { 2 | width: 100%; 3 | height: 100%; 4 | } 5 | 6 | .app { 7 | --app-padding: 6px; 8 | --color-selector-rgb: 255, 245, 0; 9 | --color-muted: rgba(0, 0, 0, 0.4); 10 | --color-main: #1967d2; 11 | --color-focus: #e8f0ff; 12 | --window-background: #000; 13 | box-sizing: border-box; 14 | background: rgb(220, 220, 220); 15 | padding: var(--app-padding); 16 | height: 100%; 17 | } 18 | 19 | .window { 20 | background: var(--window-background) !important; 21 | height: 100% !important; 22 | } 23 | 24 | .window-content { 25 | display: flex; 26 | height: calc(100% - 50px); 27 | } 28 | 29 | .top-toolbar { 30 | border-top: 2px solid var(--color-main); 31 | background-color: #fff; 32 | } 33 | 34 | .viewport { 35 | position: relative; 36 | width: 100%; 37 | height: 100%; 38 | } 39 | 40 | .panel-area { 41 | height: 100%; 42 | background: white; 43 | display: flex; 44 | flex-direction: row-reverse; 45 | } 46 | 47 | .panel { 48 | position: relative; 49 | height: 100%; 50 | overflow: auto; 51 | border-left: 1px solid #21212114; 52 | } 53 | 54 | .anno-overline { 55 | letter-spacing: 1.5px !important; 56 | font-size: 10.5px !important; 57 | color: var(--color-muted); 58 | } 59 | 60 | .anno-icon { 61 | color: var(--color-muted); 62 | } 63 | 64 | .anno-cards { 65 | list-style: none; 66 | padding-inline: 0; 67 | padding-block: 0.5rem; 68 | margin: 0; 69 | } 70 | 71 | .anno-card { 72 | all: unset; 73 | --card-bg: white; 74 | background-color: var(--card-bg); 75 | box-sizing: border-box; 76 | width: 100%; 77 | display: flex; 78 | padding-block: 0.5rem; 79 | padding-inline: 1rem; 80 | cursor: pointer; 81 | } 82 | 83 | .anno-card:hover { 84 | --card-bg: #f7f7f7; 85 | } 86 | 87 | .anno-card-closed { 88 | border-left: 2px solid transparent; 89 | } 90 | 91 | .anno-card-open, 92 | .anno-card-open:hover { 93 | --card-bg: var(--color-focus); 94 | border-left: 2px solid var(--color-main); 95 | } 96 | 97 | .anno-card .format-html h1 { 98 | font-weight: 400; 99 | font-size: 1rem; 100 | } 101 | 102 | .anno-card .format-html p { 103 | margin: 0; 104 | } 105 | 106 | .anno-card main { 107 | max-height: 10rem; 108 | overflow: hidden; 109 | position: relative; 110 | } 111 | 112 | .anno-card main:before { 113 | content: ""; 114 | width: 100%; 115 | height: 100%; 116 | position: absolute; 117 | left: 0; 118 | top: 0; 119 | background: linear-gradient(transparent 2rem, var(--card-bg) 10rem); 120 | } 121 | 122 | .anno-panel-article { 123 | display: flex; 124 | row-gap: 1rem; 125 | height: 100%; 126 | flex-direction: column; 127 | justify-content: space-between; 128 | } 129 | 130 | .anno-panel-meta { 131 | padding: 1rem; 132 | } 133 | 134 | .anno-panel-meta table { 135 | /* table-layout: fixed; */ 136 | width: 100%; 137 | border-collapse: collapse; 138 | } 139 | 140 | .anno-panel-meta th { 141 | text-align: left; 142 | } 143 | 144 | .anno-panel-meta td { 145 | padding-block: 0.25rem; 146 | } 147 | 148 | .anno-panel-top { 149 | padding: 1rem; 150 | padding-top: 0.25rem; 151 | } 152 | 153 | .anno-panel .format-html h1 { 154 | font-weight: 400; 155 | font-size: 2rem; 156 | margin-bottom: 4rem; 157 | } 158 | 159 | .anno-panel section[role="doc-bibliography"], 160 | .cross-references { 161 | border-top: 1px solid var(--color-muted); 162 | margin-top: 4rem; 163 | padding-top: 0.5rem; 164 | } 165 | 166 | .anno-panel section[role="doc-bibliography"] h2, 167 | .cross-references h2 { 168 | font-size: 0.9rem; 169 | margin: 0; 170 | } 171 | 172 | .anno-panel section[role="doc-bibliography"] ul { 173 | font-size: 0.75rem; 174 | list-style: none; 175 | padding: 0; 176 | } 177 | 178 | .color-muted { 179 | color: var(--color-muted); 180 | } 181 | 182 | .layer-list, 183 | .category-list { 184 | padding: 1rem; 185 | padding-top: 0; 186 | } 187 | 188 | .canvas path, 189 | .canvas polygon, 190 | .canvas ellipse, 191 | .canvas circle, 192 | .canvas rect { 193 | pointer-events: all; 194 | transition: fill 0.15s; 195 | fill: transparent; 196 | stroke: rgb(var(--color-selector-rgb)); 197 | stroke-width: 2; 198 | vector-effect: non-scaling-stroke; 199 | } 200 | 201 | .selector.highlight path, 202 | .selector.highlight polygon, 203 | .selector.highlight circle, 204 | .selector.highlight rect, 205 | .selector.highlight ellipse, 206 | .selector:hover path, 207 | .selector:hover polygon, 208 | .selector:hover circle, 209 | .selector:hover rect, 210 | .selector:hover ellipse { 211 | fill: rgba(var(--color-selector-rgb), 0.3); 212 | cursor: pointer; 213 | } 214 | 215 | @keyframes highlight { 216 | from { 217 | stroke-width: 5; 218 | } 219 | to { 220 | stroke-width: 2; 221 | } 222 | } 223 | 224 | .selector.highlight path, 225 | .selector.highlight polygon, 226 | .selector.highlight circle, 227 | .selector.highlight rect, 228 | .selector.highlight ellipse { 229 | animation: highlight 1s; 230 | } 231 | 232 | .folio-nav { 233 | width: 100%; 234 | height: 5rem; 235 | background-color: rgba(255, 255, 255, 0.5); 236 | position: absolute; 237 | bottom: 0; 238 | left: 0; 239 | display: flex; 240 | flex-direction: column; 241 | align-items: center; 242 | } 243 | 244 | .format-plain p, 245 | .format-html { 246 | font-family: "Georgia", serif; 247 | font-size: 1rem; 248 | font-weight: 400; 249 | line-height: 1.5; 250 | letter-spacing: 0.00938em; 251 | } 252 | 253 | .format-html img { 254 | max-width: 100%; 255 | } 256 | 257 | .format-html a { 258 | color: var(--color-main); 259 | } 260 | 261 | .format-plain p { 262 | margin: 0; 263 | } 264 | 265 | .format-html h1, 266 | section[role="doc-bibliography"] h2, 267 | .cross-references h2 { 268 | font-style: inherit; 269 | font-family: "Roboto", "Helvetica", "Arial", sans-serif; 270 | font-weight: 400; 271 | margin: 0; 272 | } 273 | 274 | .anno-top-meta { 275 | margin-top: 4rem; 276 | } 277 | 278 | .anno-top-meta p { 279 | font-size: 0.8rem; 280 | } 281 | 282 | .cross-references ul { 283 | list-style: none; 284 | padding-inline: 0; 285 | } 286 | 287 | .cross-references button { 288 | all: unset; 289 | --card-bg: white; 290 | background-color: var(--card-bg); 291 | box-sizing: border-box; 292 | width: 100%; 293 | display: flex; 294 | cursor: pointer; 295 | color: var(--color-main); 296 | } 297 | -------------------------------------------------------------------------------- /src/types/global.d.ts: -------------------------------------------------------------------------------- 1 | import { categoryModel } from "../config" 2 | 3 | declare global { 4 | type View = { 5 | pageIndex: number 6 | layerIndex: number 7 | } 8 | type ViewState = [View, React.Dispatch>] 9 | 10 | type CategoryId = typeof categoryModel[number]["id"] 11 | type Category = { 12 | id: CategoryId 13 | enabled?: boolean 14 | name: string 15 | icon: any 16 | enabledByDefault: boolean 17 | } 18 | type CategoryState = [ 19 | Category[], 20 | React.Dispatch> 21 | ] 22 | 23 | type AnnotationState = { 24 | id: string 25 | pinned: boolean 26 | }[] 27 | 28 | type AnnotationBody = { 29 | type: string 30 | language: string 31 | format: "text/plain" | "text/html" 32 | value: string 33 | } 34 | 35 | type Annotation = { 36 | "@context": string 37 | id: string 38 | type: "Annotation" 39 | motivation: string 40 | category: CategoryId 41 | target: { 42 | source: string 43 | selector: { 44 | type: "SvgSelector" 45 | value: string 46 | } 47 | } 48 | body: AnnotationBody 49 | created: "2015-10-13T13:00:00Z" 50 | creator: { 51 | id: string 52 | type: "Person" | "Organization" 53 | name: string 54 | } 55 | crossReferences?: { id: string }[] 56 | } 57 | 58 | type HydratedAnnotation = Omit & { 59 | category: Category 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"], 20 | "references": [{ "path": "./tsconfig.node.json" }] 21 | } -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite" 2 | import react from "@vitejs/plugin-react" 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | build: { 7 | assetsDir: "annotation-demo-assets", 8 | }, 9 | plugins: [ 10 | react({ 11 | fastRefresh: false, 12 | }), 13 | ], 14 | }) 15 | --------------------------------------------------------------------------------