├── .github └── workflows │ └── npm-publish.yml ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── assets └── image-uploading.gif ├── package.json ├── src ├── index.css └── index.js ├── vite.config.js └── yarn.lock /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish package to NPM 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | publish-and-notify: 10 | uses: codex-team/github-workflows/.github/workflows/npm-publish-and-notify-reusable.yml@main 11 | secrets: 12 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 13 | CODEX_BOT_NOTIFY_EDITORJS_PUBLIC_CHAT: ${{ secrets.CODEX_BOT_NOTIFY_EDITORJS_PUBLIC_CHAT }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | npm-debug.log 3 | .idea/ 4 | .DS_Store 5 | dist 6 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | assets/ 3 | src/ 4 | vite.config.js 5 | yarn.lock 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 CodeX 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://badgen.net/badge/Editor.js/v2.0/blue) 2 | 3 | # Simple Image Tool 4 | 5 | Provides Image Blocks for the [Editor.js](https://editorjs.io). 6 | 7 | Works only with pasted image URLs and requires no server-side uploader. 8 | 9 | ![](assets/image-uploading.gif) 10 | 11 | ## Installation 12 | 13 | Get the package 14 | 15 | ```shell 16 | yarn add @editorjs/simple-image 17 | ``` 18 | 19 | Include module at your application 20 | 21 | ```javascript 22 | import SimpleImage from "@editorjs/simple-image"; 23 | ``` 24 | 25 | Optionally, you can load this tool from CDN [JsDelivr CDN](https://cdn.jsdelivr.net/npm/@editorjs/simple-image) 26 | 27 | 28 | ## Usage 29 | 30 | Add a new Tool to the `tools` property of the Editor.js initial config. 31 | 32 | ```javascript 33 | var editor = EditorJS({ 34 | ... 35 | 36 | tools: { 37 | ... 38 | image: SimpleImage, 39 | } 40 | 41 | ... 42 | }); 43 | ``` 44 | 45 | ## Config Params 46 | 47 | This Tool has no config params 48 | 49 | ## Tool's settings 50 | 51 | ![](https://capella.pics/c74cdeec-3405-48ac-a960-f784188cf9b4.jpg) 52 | 53 | 1. Add border 54 | 55 | 2. Stretch to full-width 56 | 57 | 3. Add background 58 | 59 | ## Output data 60 | 61 | | Field | Type | Description | 62 | | -------------- | --------- | ------------------------------- | 63 | | url | `string` | image's url | 64 | | caption | `string` | image's caption | 65 | | withBorder | `boolean` | add border to image | 66 | | withBackground | `boolean` | need to add background | 67 | | stretched | `boolean` | stretch image to screen's width | 68 | 69 | ```json 70 | { 71 | "type": "image", 72 | "data": { 73 | "url": "https://www.tesla.com/tesla_theme/assets/img/_vehicle_redesign/roadster_and_semi/roadster/hero.jpg", 74 | "caption": "Roadster // tesla.com", 75 | "withBorder": false, 76 | "withBackground": false, 77 | "stretched": true 78 | } 79 | } 80 | ``` 81 | -------------------------------------------------------------------------------- /assets/image-uploading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/editor-js/simple-image/963883520c7bbe5040366335c9a37bbdc7cf60fd/assets/image-uploading.gif -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@editorjs/simple-image", 3 | "version": "1.6.0", 4 | "keywords": [ 5 | "codex editor", 6 | "image", 7 | "server-less", 8 | "editor.js", 9 | "editorjs" 10 | ], 11 | "description": "SimpleImage Tool for Editor.js", 12 | "license": "MIT", 13 | "repository": "https://github.com/editor-js/simple-image", 14 | "files": [ 15 | "dist" 16 | ], 17 | "main": "./dist/simple-image.umd.js", 18 | "module": "./dist/simple-image.mjs", 19 | "exports": { 20 | ".": { 21 | "import": "./dist/simple-image.mjs", 22 | "require": "./dist/simple-image.umd.js" 23 | } 24 | }, 25 | "scripts": { 26 | "dev": "vite", 27 | "build": "vite build" 28 | }, 29 | "author": { 30 | "name": "CodeX", 31 | "email": "team@codex.so" 32 | }, 33 | "devDependencies": { 34 | "vite": "^4.5.0", 35 | "vite-plugin-css-injected-by-js": "^3.3.0" 36 | }, 37 | "dependencies": { 38 | "@codexteam/icons": "^0.0.6" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | .cdx-simple-image {} 2 | 3 | .cdx-simple-image .cdx-loader { 4 | min-height: 200px; 5 | } 6 | 7 | .cdx-simple-image .cdx-input { 8 | margin-top: 10px; 9 | } 10 | 11 | .cdx-simple-image img { 12 | max-width: 100%; 13 | vertical-align: bottom; 14 | } 15 | 16 | .cdx-simple-image__caption[contentEditable=true][data-placeholder]:empty::before { 17 | position: absolute; 18 | content: attr(data-placeholder); 19 | color: #707684; 20 | font-weight: normal; 21 | opacity: 0; 22 | } 23 | 24 | .cdx-simple-image__caption[contentEditable=true][data-placeholder]:empty::before { 25 | opacity: 1; 26 | } 27 | 28 | .cdx-simple-image__caption[contentEditable=true][data-placeholder]:empty:focus::before { 29 | opacity: 0; 30 | } 31 | 32 | 33 | .cdx-simple-image__picture--with-background { 34 | background: #eff2f5; 35 | padding: 10px; 36 | } 37 | 38 | .cdx-simple-image__picture--with-background img { 39 | display: block; 40 | max-width: 60%; 41 | margin: 0 auto; 42 | } 43 | 44 | .cdx-simple-image__picture--with-border { 45 | border: 1px solid #e8e8eb; 46 | padding: 1px; 47 | } 48 | 49 | .cdx-simple-image__picture--stretched img { 50 | max-width: none; 51 | width: 100%; 52 | } 53 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Build styles 3 | */ 4 | import './index.css'; 5 | 6 | import { IconAddBorder, IconStretch, IconAddBackground } from '@codexteam/icons'; 7 | 8 | /** 9 | * SimpleImage Tool for the Editor.js 10 | * Works only with pasted image URLs and requires no server-side uploader. 11 | * 12 | * @typedef {object} SimpleImageData 13 | * @description Tool's input and output data format 14 | * @property {string} url — image URL 15 | * @property {string} caption — image caption 16 | * @property {boolean} withBorder - should image be rendered with border 17 | * @property {boolean} withBackground - should image be rendered with background 18 | * @property {boolean} stretched - should image be stretched to full width of container 19 | */ 20 | export default class SimpleImage { 21 | /** 22 | * Render plugin`s main Element and fill it with saved data 23 | * 24 | * @param {{data: SimpleImageData, config: object, api: object}} 25 | * data — previously saved data 26 | * config - user config for Tool 27 | * api - Editor.js API 28 | * readOnly - read-only mode flag 29 | */ 30 | constructor({ data, config, api, readOnly }) { 31 | /** 32 | * Editor.js API 33 | */ 34 | this.api = api; 35 | this.readOnly = readOnly; 36 | 37 | /** 38 | * When block is only constructing, 39 | * current block points to previous block. 40 | * So real block index will be +1 after rendering 41 | * 42 | * @todo place it at the `rendered` event hook to get real block index without +1; 43 | * @type {number} 44 | */ 45 | this.blockIndex = this.api.blocks.getCurrentBlockIndex() + 1; 46 | 47 | /** 48 | * Styles 49 | */ 50 | this.CSS = { 51 | baseClass: this.api.styles.block, 52 | loading: this.api.styles.loader, 53 | input: this.api.styles.input, 54 | 55 | /** 56 | * Tool's classes 57 | */ 58 | wrapper: 'cdx-simple-image', 59 | imageHolder: 'cdx-simple-image__picture', 60 | caption: 'cdx-simple-image__caption', 61 | }; 62 | 63 | /** 64 | * Nodes cache 65 | */ 66 | this.nodes = { 67 | wrapper: null, 68 | imageHolder: null, 69 | image: null, 70 | caption: null, 71 | }; 72 | 73 | /** 74 | * Tool's initial data 75 | */ 76 | this.data = { 77 | url: data.url || '', 78 | caption: data.caption || '', 79 | withBorder: data.withBorder !== undefined ? data.withBorder : false, 80 | withBackground: data.withBackground !== undefined ? data.withBackground : false, 81 | stretched: data.stretched !== undefined ? data.stretched : false, 82 | }; 83 | 84 | /** 85 | * Available Image tunes 86 | */ 87 | this.tunes = [ 88 | { 89 | name: 'withBorder', 90 | label: 'Add Border', 91 | icon: IconAddBorder, 92 | }, 93 | { 94 | name: 'stretched', 95 | label: 'Stretch Image', 96 | icon: IconStretch, 97 | }, 98 | { 99 | name: 'withBackground', 100 | label: 'Add Background', 101 | icon: IconAddBackground, 102 | }, 103 | ]; 104 | } 105 | 106 | /** 107 | * Creates a Block: 108 | * 1) Show preloader 109 | * 2) Start to load an image 110 | * 3) After loading, append image and caption input 111 | * 112 | * @public 113 | */ 114 | render() { 115 | const wrapper = this._make('div', [this.CSS.baseClass, this.CSS.wrapper]), 116 | loader = this._make('div', this.CSS.loading), 117 | imageHolder = this._make('div', this.CSS.imageHolder), 118 | image = this._make('img'), 119 | caption = this._make('div', [this.CSS.input, this.CSS.caption], { 120 | contentEditable: !this.readOnly, 121 | innerHTML: this.data.caption || '', 122 | }); 123 | 124 | caption.dataset.placeholder = 'Enter a caption'; 125 | 126 | wrapper.appendChild(loader); 127 | 128 | if (this.data.url) { 129 | image.src = this.data.url; 130 | } 131 | 132 | image.onload = () => { 133 | wrapper.classList.remove(this.CSS.loading); 134 | imageHolder.appendChild(image); 135 | wrapper.appendChild(imageHolder); 136 | wrapper.appendChild(caption); 137 | loader.remove(); 138 | this._acceptTuneView(); 139 | }; 140 | 141 | image.onerror = (e) => { 142 | // @todo use api.Notifies.show() to show error notification 143 | console.log('Failed to load an image', e); 144 | }; 145 | 146 | this.nodes.imageHolder = imageHolder; 147 | this.nodes.wrapper = wrapper; 148 | this.nodes.image = image; 149 | this.nodes.caption = caption; 150 | 151 | return wrapper; 152 | } 153 | 154 | /** 155 | * @public 156 | * @param {Element} blockContent - Tool's wrapper 157 | * @returns {SimpleImageData} 158 | */ 159 | save(blockContent) { 160 | const image = blockContent.querySelector('img'), 161 | caption = blockContent.querySelector('.' + this.CSS.input); 162 | 163 | if (!image) { 164 | return this.data; 165 | } 166 | 167 | return Object.assign(this.data, { 168 | url: image.src, 169 | caption: caption.innerHTML, 170 | }); 171 | } 172 | 173 | /** 174 | * Sanitizer rules 175 | */ 176 | static get sanitize() { 177 | return { 178 | url: {}, 179 | withBorder: {}, 180 | withBackground: {}, 181 | stretched: {}, 182 | caption: { 183 | br: true, 184 | }, 185 | }; 186 | } 187 | 188 | /** 189 | * Notify core that read-only mode is suppoorted 190 | * 191 | * @returns {boolean} 192 | */ 193 | static get isReadOnlySupported() { 194 | return true; 195 | } 196 | 197 | /** 198 | * Read pasted image and convert it to base64 199 | * 200 | * @static 201 | * @param {File} file 202 | * @returns {Promise} 203 | */ 204 | onDropHandler(file) { 205 | const reader = new FileReader(); 206 | 207 | reader.readAsDataURL(file); 208 | 209 | return new Promise(resolve => { 210 | reader.onload = (event) => { 211 | resolve({ 212 | url: event.target.result, 213 | caption: file.name, 214 | }); 215 | }; 216 | }); 217 | } 218 | 219 | /** 220 | * On paste callback that is fired from Editor. 221 | * 222 | * @param {PasteEvent} event - event with pasted config 223 | */ 224 | onPaste(event) { 225 | switch (event.type) { 226 | case 'tag': { 227 | const img = event.detail.data; 228 | 229 | this.data = { 230 | url: img.src, 231 | }; 232 | break; 233 | } 234 | 235 | case 'pattern': { 236 | const { data: text } = event.detail; 237 | 238 | this.data = { 239 | url: text, 240 | }; 241 | break; 242 | } 243 | 244 | case 'file': { 245 | const { file } = event.detail; 246 | 247 | this.onDropHandler(file) 248 | .then(data => { 249 | this.data = data; 250 | }); 251 | 252 | break; 253 | } 254 | } 255 | } 256 | 257 | /** 258 | * Returns image data 259 | * 260 | * @returns {SimpleImageData} 261 | */ 262 | get data() { 263 | return this._data; 264 | } 265 | 266 | /** 267 | * Set image data and update the view 268 | * 269 | * @param {SimpleImageData} data 270 | */ 271 | set data(data) { 272 | this._data = Object.assign({}, this.data, data); 273 | 274 | if (this.nodes.image) { 275 | this.nodes.image.src = this.data.url; 276 | } 277 | 278 | if (this.nodes.caption) { 279 | this.nodes.caption.innerHTML = this.data.caption; 280 | } 281 | } 282 | 283 | /** 284 | * Specify paste substitutes 285 | * 286 | * @see {@link ../../../docs/tools.md#paste-handling} 287 | * @public 288 | */ 289 | static get pasteConfig() { 290 | return { 291 | patterns: { 292 | image: /https?:\/\/\S+\.(gif|jpe?g|tiff|png|webp)$/i, 293 | }, 294 | tags: [ 295 | { 296 | img: { src: true }, 297 | }, 298 | ], 299 | files: { 300 | mimeTypes: [ 'image/*' ], 301 | }, 302 | }; 303 | } 304 | 305 | /** 306 | * Returns image tunes config 307 | * 308 | * @returns {Array} 309 | */ 310 | renderSettings() { 311 | return this.tunes.map(tune => ({ 312 | ...tune, 313 | label: this.api.i18n.t(tune.label), 314 | toggle: true, 315 | onActivate: () => this._toggleTune(tune.name), 316 | isActive: !!this.data[tune.name], 317 | })) 318 | }; 319 | 320 | /** 321 | * Helper for making Elements with attributes 322 | * 323 | * @param {string} tagName - new Element tag name 324 | * @param {Array|string} classNames - list or name of CSS classname(s) 325 | * @param {object} attributes - any attributes 326 | * @returns {Element} 327 | */ 328 | _make(tagName, classNames = null, attributes = {}) { 329 | const el = document.createElement(tagName); 330 | 331 | if (Array.isArray(classNames)) { 332 | el.classList.add(...classNames); 333 | } else if (classNames) { 334 | el.classList.add(classNames); 335 | } 336 | 337 | for (const attrName in attributes) { 338 | el[attrName] = attributes[attrName]; 339 | } 340 | 341 | return el; 342 | } 343 | 344 | /** 345 | * Click on the Settings Button 346 | * 347 | * @private 348 | * @param tune 349 | */ 350 | _toggleTune(tune) { 351 | this.data[tune] = !this.data[tune]; 352 | this._acceptTuneView(); 353 | } 354 | 355 | /** 356 | * Add specified class corresponds with activated tunes 357 | * 358 | * @private 359 | */ 360 | _acceptTuneView() { 361 | this.tunes.forEach(tune => { 362 | this.nodes.imageHolder.classList.toggle(this.CSS.imageHolder + '--' + tune.name.replace(/([A-Z])/g, (g) => `-${g[0].toLowerCase()}`), !!this.data[tune.name]); 363 | 364 | if (tune.name === 'stretched') { 365 | this.api.blocks.stretchBlock(this.blockIndex, !!this.data.stretched); 366 | } 367 | }); 368 | } 369 | } 370 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import cssInjectedByJsPlugin from "vite-plugin-css-injected-by-js"; 3 | import * as pkg from "./package.json"; 4 | 5 | const NODE_ENV = process.argv.mode || "development"; 6 | const VERSION = pkg.version; 7 | 8 | export default { 9 | build: { 10 | copyPublicDir: false, 11 | lib: { 12 | entry: path.resolve(__dirname, "src", "index.js"), 13 | name: "SimpleImage", 14 | fileName: "simple-image", 15 | }, 16 | }, 17 | define: { 18 | NODE_ENV: JSON.stringify(NODE_ENV), 19 | VERSION: JSON.stringify(VERSION), 20 | }, 21 | 22 | plugins: [cssInjectedByJsPlugin()], 23 | }; 24 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@codexteam/icons@^0.0.6": 6 | version "0.0.6" 7 | resolved "https://registry.yarnpkg.com/@codexteam/icons/-/icons-0.0.6.tgz#5553ada48dddf5940851ccc142cfe17835c36ad3" 8 | 9 | "@esbuild/android-arm64@0.18.20": 10 | version "0.18.20" 11 | resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622" 12 | integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ== 13 | 14 | "@esbuild/android-arm@0.18.20": 15 | version "0.18.20" 16 | resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682" 17 | integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw== 18 | 19 | "@esbuild/android-x64@0.18.20": 20 | version "0.18.20" 21 | resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2" 22 | integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg== 23 | 24 | "@esbuild/darwin-arm64@0.18.20": 25 | version "0.18.20" 26 | resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1" 27 | integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA== 28 | 29 | "@esbuild/darwin-x64@0.18.20": 30 | version "0.18.20" 31 | resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d" 32 | integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ== 33 | 34 | "@esbuild/freebsd-arm64@0.18.20": 35 | version "0.18.20" 36 | resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54" 37 | integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw== 38 | 39 | "@esbuild/freebsd-x64@0.18.20": 40 | version "0.18.20" 41 | resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e" 42 | integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ== 43 | 44 | "@esbuild/linux-arm64@0.18.20": 45 | version "0.18.20" 46 | resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0" 47 | integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA== 48 | 49 | "@esbuild/linux-arm@0.18.20": 50 | version "0.18.20" 51 | resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0" 52 | integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg== 53 | 54 | "@esbuild/linux-ia32@0.18.20": 55 | version "0.18.20" 56 | resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7" 57 | integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA== 58 | 59 | "@esbuild/linux-loong64@0.18.20": 60 | version "0.18.20" 61 | resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d" 62 | integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg== 63 | 64 | "@esbuild/linux-mips64el@0.18.20": 65 | version "0.18.20" 66 | resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231" 67 | integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ== 68 | 69 | "@esbuild/linux-ppc64@0.18.20": 70 | version "0.18.20" 71 | resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb" 72 | integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA== 73 | 74 | "@esbuild/linux-riscv64@0.18.20": 75 | version "0.18.20" 76 | resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6" 77 | integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A== 78 | 79 | "@esbuild/linux-s390x@0.18.20": 80 | version "0.18.20" 81 | resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071" 82 | integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ== 83 | 84 | "@esbuild/linux-x64@0.18.20": 85 | version "0.18.20" 86 | resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338" 87 | integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w== 88 | 89 | "@esbuild/netbsd-x64@0.18.20": 90 | version "0.18.20" 91 | resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1" 92 | integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A== 93 | 94 | "@esbuild/openbsd-x64@0.18.20": 95 | version "0.18.20" 96 | resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae" 97 | integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg== 98 | 99 | "@esbuild/sunos-x64@0.18.20": 100 | version "0.18.20" 101 | resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d" 102 | integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ== 103 | 104 | "@esbuild/win32-arm64@0.18.20": 105 | version "0.18.20" 106 | resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9" 107 | integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg== 108 | 109 | "@esbuild/win32-ia32@0.18.20": 110 | version "0.18.20" 111 | resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102" 112 | integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g== 113 | 114 | "@esbuild/win32-x64@0.18.20": 115 | version "0.18.20" 116 | resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d" 117 | integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ== 118 | 119 | esbuild@^0.18.10: 120 | version "0.18.20" 121 | resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6" 122 | integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA== 123 | optionalDependencies: 124 | "@esbuild/android-arm" "0.18.20" 125 | "@esbuild/android-arm64" "0.18.20" 126 | "@esbuild/android-x64" "0.18.20" 127 | "@esbuild/darwin-arm64" "0.18.20" 128 | "@esbuild/darwin-x64" "0.18.20" 129 | "@esbuild/freebsd-arm64" "0.18.20" 130 | "@esbuild/freebsd-x64" "0.18.20" 131 | "@esbuild/linux-arm" "0.18.20" 132 | "@esbuild/linux-arm64" "0.18.20" 133 | "@esbuild/linux-ia32" "0.18.20" 134 | "@esbuild/linux-loong64" "0.18.20" 135 | "@esbuild/linux-mips64el" "0.18.20" 136 | "@esbuild/linux-ppc64" "0.18.20" 137 | "@esbuild/linux-riscv64" "0.18.20" 138 | "@esbuild/linux-s390x" "0.18.20" 139 | "@esbuild/linux-x64" "0.18.20" 140 | "@esbuild/netbsd-x64" "0.18.20" 141 | "@esbuild/openbsd-x64" "0.18.20" 142 | "@esbuild/sunos-x64" "0.18.20" 143 | "@esbuild/win32-arm64" "0.18.20" 144 | "@esbuild/win32-ia32" "0.18.20" 145 | "@esbuild/win32-x64" "0.18.20" 146 | 147 | fsevents@~2.3.2: 148 | version "2.3.3" 149 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" 150 | integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== 151 | 152 | nanoid@^3.3.6: 153 | version "3.3.6" 154 | resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" 155 | integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== 156 | 157 | picocolors@^1.0.0: 158 | version "1.0.0" 159 | resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" 160 | integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== 161 | 162 | postcss@^8.4.27: 163 | version "8.4.31" 164 | resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" 165 | integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== 166 | dependencies: 167 | nanoid "^3.3.6" 168 | picocolors "^1.0.0" 169 | source-map-js "^1.0.2" 170 | 171 | rollup@^3.27.1: 172 | version "3.29.4" 173 | resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.4.tgz#4d70c0f9834146df8705bfb69a9a19c9e1109981" 174 | integrity sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw== 175 | optionalDependencies: 176 | fsevents "~2.3.2" 177 | 178 | source-map-js@^1.0.2: 179 | version "1.0.2" 180 | resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" 181 | integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== 182 | 183 | vite-plugin-css-injected-by-js@^3.3.0: 184 | version "3.3.0" 185 | resolved "https://registry.yarnpkg.com/vite-plugin-css-injected-by-js/-/vite-plugin-css-injected-by-js-3.3.0.tgz#c19480a9e42a95c5bced976a9dde1446f9bd91ff" 186 | integrity sha512-xG+jyHNCmUqi/TXp6q88wTJGeAOrNLSyUUTp4qEQ9QZLGcHWQQsCsSSKa59rPMQr8sOzfzmWDd8enGqfH/dBew== 187 | 188 | vite@^4.5.0: 189 | version "4.5.0" 190 | resolved "https://registry.yarnpkg.com/vite/-/vite-4.5.0.tgz#ec406295b4167ac3bc23e26f9c8ff559287cff26" 191 | integrity sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw== 192 | dependencies: 193 | esbuild "^0.18.10" 194 | postcss "^8.4.27" 195 | rollup "^3.27.1" 196 | optionalDependencies: 197 | fsevents "~2.3.2" 198 | --------------------------------------------------------------------------------