mirror of
https://github.com/zsviczian/obsidian-excalidraw-plugin.git
synced 2025-08-06 05:46:28 +00:00
Compare commits
58 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f0ef04ed3e | ||
|
|
8760f72a13 | ||
|
|
09602e142c | ||
|
|
c7500e9ee7 | ||
|
|
92d3363b5b | ||
|
|
30682e1b40 | ||
|
|
d89431bbde | ||
|
|
1c707db3a7 | ||
|
|
a56fda222d | ||
|
|
9fcbe5b7d7 | ||
|
|
3c6dbcc8bb | ||
|
|
25e2f3d8bb | ||
|
|
1c35e86118 | ||
|
|
61b716d8f6 | ||
|
|
2a0404fe18 | ||
|
|
4f4a80b317 | ||
|
|
0259dc579f | ||
|
|
fe84c607a6 | ||
|
|
b8178ac07c | ||
|
|
a65c6afed2 | ||
|
|
6e207350d6 | ||
|
|
d64c00f2dd | ||
|
|
25a998fc01 | ||
|
|
a212136323 | ||
|
|
e1a92695d5 | ||
|
|
370e35182b | ||
|
|
634bbc2165 | ||
|
|
a2dd13049e | ||
|
|
a64c6e5335 | ||
|
|
d57a28c36b | ||
|
|
2d32b4b71a | ||
|
|
5be455d368 | ||
|
|
c4acf24bca | ||
|
|
a13c8e0127 | ||
|
|
b048dd0ee7 | ||
|
|
f6a832b2bc | ||
|
|
ec246cbd03 | ||
|
|
cbab54e848 | ||
|
|
39085bc962 | ||
|
|
87dd8b0415 | ||
|
|
f8b8dffb94 | ||
|
|
f73bd97b1d | ||
|
|
c8ac7be912 | ||
|
|
6887d0bde8 | ||
|
|
721e8514d2 | ||
|
|
8ed2d2b3a8 | ||
|
|
ad7e07a253 | ||
|
|
f3b29aa9b8 | ||
|
|
9b4f4917d4 | ||
|
|
44f67cd3f3 | ||
|
|
a711987163 | ||
|
|
38ec3634c6 | ||
|
|
adc9c17d28 | ||
|
|
12b64710a2 | ||
|
|
f2012de41c | ||
|
|
f873ac3164 | ||
|
|
ab568abf5a | ||
|
|
274b1939f8 |
3
.babelrc
Normal file
3
.babelrc
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"presets": ["@babel/preset-env", "@babel/preset-react"]
|
||||
}
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -8,4 +8,7 @@ package-lock.json
|
||||
|
||||
# build
|
||||
main.js
|
||||
*.js.map
|
||||
*.js.map
|
||||
stats.html
|
||||
hot-reload.bat
|
||||
data.json
|
||||
|
||||
90
README.md
90
README.md
@@ -1,21 +1,81 @@
|
||||
## Obsidian-Excalidraw
|
||||
# Obsidian Excalidraw Plugin
|
||||
The Obsidian-Excalidraw plugin integrates [Excalidraw](https://excalidraw.com/), a feature rich sketching tool, into Obsidian. You can store and edit Excalidraw files in your vault and you can transclude drawings into your documents. For a showcase of Excalidraw features, please read my blog post [here](https://www.zsolt.blog/2021/03/showcasing-excalidraw.html).
|
||||
|
||||
### Key features
|
||||
- Use the Excalidraw command in the Command palette to open an existing drawing or to create a new one. You create a new one by typing its name and hitting enter.
|
||||
- Set up a default folder for your drawings in Settings.
|
||||
- You can also set up a Template, by creating a drawing, customizing it the way you like, and specifying the file as the template in settings.
|
||||
- There is a known bug when inserting images from the library, in some cases these images will be placed out of view, and you'll need to select scroll to view at the bottom of the screen. The bug was reproduced by the Excalidraw dev team, so I expect in the next update of Excalidraw it will be fixed.
|
||||
- Translusion of drawings into markdown documents is not yet working.
|
||||
- Drawings are saved to your vault as a file with the extension .excalidraw
|
||||
- If you want to see these files in your vault you need to enable the following sestting
|
||||

|
||||
**See details of the 1.0.6 release including a short video, futher below**
|
||||
|
||||
### Excalidraw in Obsidian
|
||||

|
||||

|
||||
|
||||
## Key features
|
||||
- The plugin adds the following actions to the command palette:
|
||||
- To create a new drawing
|
||||
- To find and edit existing drawings in your vault,
|
||||
- To embed (transclude) a drawing into a document, and
|
||||
- To export a drawing as PNG or SVG.
|
||||
- You can also use the file explorer in your vault to open Excalidraw files.
|
||||
- Use the ribbon button to create a new drawing, do CTRL+Click to open on a new page.
|
||||
- Open settings to set up a default folder for new drawings.
|
||||
- Set up a Template by creating a drawing, customizing it the way you like it, and specifying the file as the template in settings.
|
||||
- The plugin saves drawings to your vault as a file with the *.excalidraw* file extension.
|
||||
- You can customize the size and position of the embedded image using the [[image.excalidraw|100]], [[image.excalidraw|100x100]], [[image.excalidraw|100|left]] or [[image.excalidraw|right]], format.
|
||||
- You can setup Excalidraw to automatically export SVG and/or PNG files for your drawings, and to keep those in sync with your drawing.
|
||||
|
||||
## How to?
|
||||
Part 1: Intro to Obsidian-Excalidraw - Start a new drawing (3:12)
|
||||
|
||||
[](https://youtu.be/i-hIfY-Ecjg)
|
||||
|
||||
Part 2: Intro to Obsidian-Excalidraw - Basic features (6:06)
|
||||
|
||||
[](https://youtu.be/-dk7pvdl-H0)
|
||||
|
||||
Part 3: Intro to Obsidian-Excalidraw - Advanced features (3:26)
|
||||
|
||||
[](https://youtu.be/2cKlEwo8WU0)
|
||||
|
||||
Part 4: Intro to Obsidian-Excalidraw - Setting up a template (1:45)
|
||||
|
||||
[](https://youtu.be/oNPYZEpmuJ8)
|
||||
|
||||
Part 5: Intro to Obsidian-Excalidraw - Stencil Library (3:16)
|
||||
|
||||
[](https://youtu.be/rLx-9FvlzgI)
|
||||
|
||||
Part 6: Intro to Obsidian-Excalidraw: Embedding drawings (2:08)
|
||||
|
||||
[](https://youtu.be/JQeJ-Hh-xAI)
|
||||
|
||||
## 1.0.6 update
|
||||
[](https://youtu.be/ipZPbcP2B0M)
|
||||
|
||||
### SVG styling when embedding using a code block
|
||||
- new formatting option for the code block embedding
|
||||
- Valid values: left, right, center... but really anything after the last |.
|
||||
Here is the corresponding CSS:
|
||||
```
|
||||
.excalidraw-svg-left {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.excalidraw-svg-right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.excalidraw-svg-center {
|
||||
}
|
||||
|
||||
.excalidraw-svg {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Known bug registered with Excalidraw
|
||||

|
||||
## Known issues
|
||||
- On mobile (iOS and Android): As you draw left to right it opens left sidebar. Draw right to left, opens right sidebar. Draw down, opens commands palette. So seems open is emulating the gestures, even when drawing towards the center. I understand that the issue will be resolved in the next release of Obsidian mobile.
|
||||
- I have seen two cases when adding a stencil library did not work. In both cases the end solution was a reinstall of Obsidian. The root cause is not clear, but may be due to the incremental updates of Obsidian from an early version.
|
||||
|
||||
## Feedback, questions, ideas, problems
|
||||
By clicking [here](https://github.com/zsviczian/obsidian-excalidraw-plugin/issues) you can create an issue to report a bug, suggest an improvement for this plugin, ask a question, etc.
|
||||
|
||||
https://user-images.githubusercontent.com/14358394/115161352-84028780-a09d-11eb-90ee-7d4dad82ec98.mp4
|
||||
## Support
|
||||
If you want to support me and my work, you can donate me a little something on [https://ko-fi/zsolt](https://ko-fi.com/zsolt).
|
||||
|
||||
[<img style="float:left" src="https://user-images.githubusercontent.com/14358394/115450238-f39e8100-a21b-11eb-89d0-fa4b82cdbce8.png" width="200">](https://ko-fi.com/zsolt)
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
{"openFile":"Blog/attachements/security through obscurity.excalidraw","settings":{"folder":"excalidraw","templateFilePath":"excalidraw/Template.excalidraw"}}
|
||||
@@ -1 +0,0 @@
|
||||
{"folder":"excalidraw","templateFilePath":"","openFile":"excalidraw/new file.excalidraw","settings":{"folder":"excalidraw","templateFilePath":""}}
|
||||
10
dist/manifest.json
vendored
10
dist/manifest.json
vendored
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"id": "obsidian-excalidraw-plugin",
|
||||
"name": "Excalidraw",
|
||||
"version": "0.1.0",
|
||||
"minAppVersion": "0.0.2",
|
||||
"description": "An obsidian plugin to edit and view Excalidraw drawings",
|
||||
"author": "Zsolt Viczian",
|
||||
"authorUrl": "https://zsolt.blog",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
13
dist/styles.css
vendored
13
dist/styles.css
vendored
@@ -1,13 +0,0 @@
|
||||
.App {
|
||||
font-family: sans-serif;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.excalidraw-wrapper {
|
||||
height: 100%;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.context-menu-option__shortcut {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
3
esbuild.config.json
Normal file
3
esbuild.config.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"minify": true
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"id": "obsidian-excalidraw-plugin",
|
||||
"name": "Excalidraw",
|
||||
"version": "0.1.0",
|
||||
"minAppVersion": "0.0.2",
|
||||
"description": "An obsidian plugin to edit and view Excalidraw drawings",
|
||||
"version": "1.0.7",
|
||||
"minAppVersion": "0.11.13",
|
||||
"description": "An Obsidian plugin to edit and view Excalidraw drawings",
|
||||
"author": "Zsolt Viczian",
|
||||
"authorUrl": "https://zsolt.blog",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
}
|
||||
|
||||
15
package.json
15
package.json
@@ -11,12 +11,17 @@
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@excalidraw/excalidraw": "0.6.0",
|
||||
"react": "17.0.0",
|
||||
"react-dom": "17.0.0",
|
||||
"@excalidraw/excalidraw": "0.7.0",
|
||||
"aakansha-excalidraw": "0.7.0-draft",
|
||||
"react": "17.0.1",
|
||||
"react-dom": "17.0.1",
|
||||
"react-scripts": "4.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.3.3",
|
||||
"@babel/preset-env": "^7.3.1",
|
||||
"@babel/preset-react": "^7.0.0",
|
||||
"@rollup/plugin-babel": "5.3.0",
|
||||
"@rollup/plugin-commonjs": "^15.1.0",
|
||||
"@rollup/plugin-node-resolve": "^9.0.0",
|
||||
"@rollup/plugin-typescript": "^6.0.0",
|
||||
@@ -29,7 +34,9 @@
|
||||
"rollup-plugin-copy": "3.4.0",
|
||||
"rollup-plugin-minify": "1.0.3",
|
||||
"rollup-plugin-postcss": "^4.0.0",
|
||||
"rollup-plugin-visualizer": "^5.4.1",
|
||||
"tslib": "^2.0.3",
|
||||
"typescript": "^4.0.3"
|
||||
"typescript": "^4.0.3",
|
||||
"webpack-bundle-analyzer": "^4.4.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
import typescript from '@rollup/plugin-typescript';
|
||||
import { nodeResolve } from '@rollup/plugin-node-resolve';
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
import postcss from 'rollup-plugin-postcss';
|
||||
import copy from 'rollup-plugin-copy';
|
||||
//import uglify from 'rollup-plugin-uglify';
|
||||
//import minify from "rollup-plugin-minify"
|
||||
//import copy from 'rollup-plugin-copy';
|
||||
import { env } from "process";
|
||||
import babel from '@rollup/plugin-babel';
|
||||
import replace from "@rollup/plugin-replace";
|
||||
import visualizer from "rollup-plugin-visualizer";
|
||||
|
||||
const isProd = (process.env.NODE_ENV === "production");
|
||||
|
||||
console.log(process.env.NODE_ENV);
|
||||
console.log("Is production", isProd);
|
||||
|
||||
export default {
|
||||
input: 'src/main.ts',
|
||||
output: {
|
||||
dir: isProd ? './dist' : '.',
|
||||
dir: '.',
|
||||
sourcemap: 'inline',
|
||||
format: 'cjs',
|
||||
exports: 'default'
|
||||
@@ -29,15 +26,10 @@ export default {
|
||||
preventAssignment: true,
|
||||
"process.env.NODE_ENV": JSON.stringify(env.NODE_ENV),
|
||||
}),
|
||||
babel({
|
||||
exclude: "node_modules/**"
|
||||
}),
|
||||
commonjs(),
|
||||
postcss({
|
||||
plugins: []
|
||||
}),
|
||||
copy({
|
||||
targets: [
|
||||
{ src: ['manifest.json', 'styles.css'], dest: './dist' }
|
||||
], flatten: true
|
||||
}),
|
||||
//process.env.NODE_ENV === 'production' && minify(),
|
||||
visualizer(),
|
||||
]
|
||||
};
|
||||
@@ -1,107 +1,225 @@
|
||||
import { TextFileView, WorkspaceLeaf } from "obsidian";
|
||||
import {
|
||||
TextFileView,
|
||||
WorkspaceLeaf,
|
||||
normalizePath,
|
||||
TFile,
|
||||
Menu,
|
||||
} from "obsidian";
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
import Excalidraw from "@excalidraw/excalidraw";
|
||||
import Excalidraw, {exportToSvg} from "@excalidraw/excalidraw";
|
||||
import { ExcalidrawElement } from "@excalidraw/excalidraw/types/element/types";
|
||||
import { AppState } from "@excalidraw/excalidraw/types/types";
|
||||
import {
|
||||
AppState,
|
||||
LibraryItems
|
||||
} from "@excalidraw/excalidraw/types/types";
|
||||
import {
|
||||
VIEW_TYPE_EXCALIDRAW,
|
||||
EXCALIDRAW_FILE_EXTENSION,
|
||||
ICON_NAME,
|
||||
EXCALIDRAW_LIB_HEADER,
|
||||
VIRGIL_FONT,
|
||||
CASCADIA_FONT,
|
||||
DISK_ICON_NAME,
|
||||
PNG_ICON_NAME,
|
||||
SVG_ICON_NAME
|
||||
} from './constants';
|
||||
import ExcalidrawPlugin from './main';
|
||||
|
||||
export interface ExportSettings {
|
||||
withBackground: boolean,
|
||||
withTheme: boolean
|
||||
}
|
||||
|
||||
export default class ExcalidrawView extends TextFileView {
|
||||
private getScene: any;
|
||||
private excalidrawRef: React.MutableRefObject<any>;
|
||||
private justLoaded: boolean;
|
||||
private plugin: ExcalidrawPlugin;
|
||||
|
||||
constructor(leaf: WorkspaceLeaf) {
|
||||
constructor(leaf: WorkspaceLeaf, plugin: ExcalidrawPlugin) {
|
||||
super(leaf);
|
||||
this.getScene = null;
|
||||
this.excalidrawRef = null;
|
||||
this.plugin = plugin;
|
||||
this.justLoaded = false;
|
||||
}
|
||||
|
||||
// clear the view content
|
||||
clear() {
|
||||
ReactDOM.unmountComponentAtNode(this.contentEl);
|
||||
this.getScene = null;
|
||||
public async saveSVG(data?: string) {
|
||||
if(!data) {
|
||||
if (!this.getScene) return false;
|
||||
data = this.getScene();
|
||||
}
|
||||
const filepath = this.file.path.substring(0,this.file.path.lastIndexOf('.'+EXCALIDRAW_FILE_EXTENSION)) + '.svg';
|
||||
const file = this.app.vault.getAbstractFileByPath(normalizePath(filepath));
|
||||
const exportSettings: ExportSettings = {
|
||||
withBackground: this.plugin.settings.exportWithBackground,
|
||||
withTheme: this.plugin.settings.exportWithTheme
|
||||
}
|
||||
const svg = ExcalidrawView.getSVG(data,exportSettings);
|
||||
if(!svg) return;
|
||||
//replace font references with base64 fonts
|
||||
const includesVirgil = svg.querySelector("text[font-family^='Virgil']") != null;
|
||||
const includesCascadia = svg.querySelector("text[font-family^='Cascadia']") != null;
|
||||
const defs = svg.querySelector("defs");
|
||||
if (defs && (includesCascadia || includesVirgil)) {
|
||||
defs.innerHTML = "<style>" + (includesVirgil ? VIRGIL_FONT : "") + (includesCascadia ? CASCADIA_FONT : "")+"</style>";
|
||||
}
|
||||
const svgString = svg.outerHTML;
|
||||
if(file && file instanceof TFile) await this.app.vault.modify(file,svgString);
|
||||
else await this.app.vault.create(filepath,svgString);
|
||||
}
|
||||
|
||||
public async savePNG(data?: string) {
|
||||
if(!data) {
|
||||
if (!this.getScene) return false;
|
||||
data = this.getScene();
|
||||
}
|
||||
const filepath = this.file.path.substring(0,this.file.path.lastIndexOf('.'+EXCALIDRAW_FILE_EXTENSION)) + '.png';
|
||||
const file = this.app.vault.getAbstractFileByPath(normalizePath(filepath));
|
||||
const exportSettings: ExportSettings = {
|
||||
withBackground: this.plugin.settings.exportWithBackground,
|
||||
withTheme: this.plugin.settings.exportWithTheme
|
||||
}
|
||||
const png = await ExcalidrawView.getPNG(data,exportSettings);
|
||||
if(!png) return;
|
||||
if(file && file instanceof TFile) await this.app.vault.modifyBinary(file,await png.arrayBuffer());
|
||||
else await this.app.vault.createBinary(filepath,await png.arrayBuffer());
|
||||
}
|
||||
|
||||
// get the new file content
|
||||
getViewData () {
|
||||
if(this.getScene) return this.getScene();
|
||||
else return '';
|
||||
if(this.getScene) {
|
||||
const scene = this.getScene();
|
||||
if(this.plugin.settings.autoexportSVG) this.saveSVG(scene);
|
||||
if(this.plugin.settings.autoexportPNG) this.savePNG(scene);
|
||||
return scene;
|
||||
}
|
||||
else return this.data;
|
||||
}
|
||||
|
||||
setViewData (data: string, clear: boolean) {
|
||||
if(clear) this.clear();
|
||||
const excalidrawData = JSON.parse(data);
|
||||
this.instantiateExcalidraw({
|
||||
elements: excalidrawData.elements,
|
||||
appState: excalidrawData.appState,
|
||||
scrollToContent: true,
|
||||
async onload() {
|
||||
this.addAction(DISK_ICON_NAME,"Save drawing",async (ev)=> {
|
||||
await this.save();
|
||||
this.plugin.triggerEmbedUpdates();
|
||||
});
|
||||
this.addAction(PNG_ICON_NAME,"Export as PNG",async (ev)=>this.savePNG());
|
||||
this.addAction(SVG_ICON_NAME,"Export as SVG",async (ev)=>this.saveSVG());
|
||||
}
|
||||
|
||||
async onunload() {
|
||||
if(this.excalidrawRef) await this.save();
|
||||
}
|
||||
|
||||
setViewData (data: string, clear: boolean) {
|
||||
if (this.app.workspace.layoutReady) {
|
||||
this.loadDrawing(data,clear);
|
||||
} else {
|
||||
this.registerEvent(this.app.workspace.on('layout-ready', async () => this.loadDrawing(data,clear)));
|
||||
}
|
||||
}
|
||||
|
||||
// clear the view content
|
||||
clear() {
|
||||
if(this.excalidrawRef) {
|
||||
this.excalidrawRef = null;
|
||||
this.getScene = null;
|
||||
ReactDOM.unmountComponentAtNode(this.contentEl);
|
||||
}
|
||||
}
|
||||
|
||||
private async loadDrawing (data:string, clear:boolean) {
|
||||
if(clear) this.clear();
|
||||
this.justLoaded = true; //a flag to trigger zoom to fit after the drawing has been loaded
|
||||
const excalidrawData = JSON.parse(data);
|
||||
if(this.excalidrawRef) {
|
||||
this.excalidrawRef.current.updateScene({
|
||||
elements: excalidrawData.elements,
|
||||
appState: excalidrawData.appState,
|
||||
});
|
||||
} else {
|
||||
this.instantiateExcalidraw({
|
||||
elements: excalidrawData.elements,
|
||||
appState: excalidrawData.appState,
|
||||
scrollToContent: true,
|
||||
libraryItems: await this.getLibrary(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// gets the title of the document
|
||||
getDisplayText() {
|
||||
if(this.file) return this.file.basename;
|
||||
else return "excalidraw (no file)";
|
||||
|
||||
else return "Excalidraw (no file)";
|
||||
}
|
||||
|
||||
// confirms this view can accept csv extension
|
||||
canAcceptExtension(extension: string) {
|
||||
return extension == 'excalidraw';
|
||||
return extension == EXCALIDRAW_FILE_EXTENSION;
|
||||
}
|
||||
|
||||
// the view type name
|
||||
getViewType() {
|
||||
return "excalidraw";
|
||||
return VIEW_TYPE_EXCALIDRAW;
|
||||
}
|
||||
|
||||
// icon for the view
|
||||
getIcon() {
|
||||
return "document-excalidraw";
|
||||
return ICON_NAME;
|
||||
}
|
||||
|
||||
async getLibrary() {
|
||||
const data = JSON.parse(this.plugin.settings.library);
|
||||
return data?.library ? data.library : [];
|
||||
}
|
||||
|
||||
|
||||
private instantiateExcalidraw(initdata: any) {
|
||||
ReactDOM.render(React.createElement(() => {
|
||||
let previousSceneVersion = 0;
|
||||
const reactElement = React.createElement(() => {
|
||||
const excalidrawRef = React.useRef(null);
|
||||
const excalidrawWrapperRef = React.useRef(null);
|
||||
const [dimensions, setDimensions] = React.useState({
|
||||
width: undefined,
|
||||
height: undefined
|
||||
});
|
||||
|
||||
|
||||
this.excalidrawRef = excalidrawRef;
|
||||
React.useEffect(() => {
|
||||
setDimensions({
|
||||
width: this.contentEl.clientWidth,
|
||||
height: this.contentEl.clientHeight,
|
||||
});
|
||||
|
||||
const onResize = () => {
|
||||
try {
|
||||
setDimensions({
|
||||
width: this.contentEl.clientWidth,
|
||||
height: this.contentEl.clientHeight,
|
||||
});
|
||||
} catch(err) {console.log ("onResize ",err)}
|
||||
} catch(err) {console.log ("Excalidraw React-Wrapper, onResize ",err)}
|
||||
};
|
||||
window.addEventListener("resize", onResize);
|
||||
return () => window.removeEventListener("resize", onResize);
|
||||
}, [excalidrawWrapperRef]);
|
||||
|
||||
this.getScene = function() {
|
||||
|
||||
this.getScene = () => {
|
||||
if(!excalidrawRef?.current) {
|
||||
return null;
|
||||
}
|
||||
const el: ExcalidrawElement[] = excalidrawRef.current.getSceneElements();
|
||||
const st: AppState = excalidrawRef.current.getAppState();
|
||||
return JSON.stringify({
|
||||
"type": "excalidraw",
|
||||
"version": 2,
|
||||
"source": "https://excalidraw.com",
|
||||
"elements": el.filter(e => !e.isDeleted),
|
||||
"elements": el,
|
||||
"appState": {
|
||||
"theme": st.theme,
|
||||
"viewBackgroundColor": st.viewBackgroundColor,
|
||||
"gridSize": st.gridSize,
|
||||
"zenModeEnabled": st.zenModeEnabled
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
return React.createElement(
|
||||
React.Fragment,
|
||||
null,
|
||||
@@ -109,23 +227,75 @@ export default class ExcalidrawView extends TextFileView {
|
||||
"div",
|
||||
{
|
||||
className: "excalidraw-wrapper",
|
||||
ref: excalidrawWrapperRef
|
||||
ref: excalidrawWrapperRef,
|
||||
key: "abc",
|
||||
},
|
||||
React.createElement(Excalidraw.default, {
|
||||
ref: excalidrawRef,
|
||||
key: "xyz",
|
||||
width: dimensions.width,
|
||||
height: dimensions.height,
|
||||
UIOptions: {
|
||||
canvasActions: {
|
||||
loadScene: false,
|
||||
saveScene: false,
|
||||
saveAsScene: false
|
||||
saveAsScene: false,
|
||||
export: false
|
||||
},
|
||||
},
|
||||
initialData: initdata
|
||||
initialData: initdata,
|
||||
onChange: (et:ExcalidrawElement[],st:AppState) => {
|
||||
if(this.justLoaded) {
|
||||
this.justLoaded = false;
|
||||
const e = new KeyboardEvent("keydown", {bubbles : true, cancelable : true, shiftKey : true, code:"Digit1"});
|
||||
this.contentEl.querySelector("canvas")?.dispatchEvent(e);
|
||||
}
|
||||
},
|
||||
onLibraryChange: (items:LibraryItems) => {
|
||||
(async () => {
|
||||
this.plugin.settings.library = EXCALIDRAW_LIB_HEADER+JSON.stringify(items)+'}';
|
||||
await this.plugin.saveSettings();
|
||||
})();
|
||||
}
|
||||
})
|
||||
)
|
||||
);
|
||||
}),(this as any).contentEl);
|
||||
});
|
||||
ReactDOM.render(reactElement,(this as any).contentEl);
|
||||
}
|
||||
|
||||
public static getSVG(data:string, exportSettings:ExportSettings):SVGSVGElement {
|
||||
try {
|
||||
const excalidrawData = JSON.parse(data);
|
||||
return exportToSvg({
|
||||
elements: excalidrawData.elements,
|
||||
appState: {
|
||||
exportBackground: exportSettings.withBackground,
|
||||
exportWithDarkMode: exportSettings.withTheme ? (excalidrawData.appState?.theme=="light" ? false : true) : false,
|
||||
... excalidrawData.appState,},
|
||||
exportPadding:10,
|
||||
metadata: "Generated by Excalidraw-Obsidian plugin",
|
||||
});
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static async getPNG(data:string, exportSettings:ExportSettings) {
|
||||
try {
|
||||
const excalidrawData = JSON.parse(data);
|
||||
return await Excalidraw.exportToBlob({
|
||||
elements: excalidrawData.elements,
|
||||
appState: {
|
||||
exportBackground: exportSettings.withBackground,
|
||||
exportWithDarkMode: exportSettings.withTheme ? (excalidrawData.appState?.theme=="light" ? false : true) : false,
|
||||
... excalidrawData.appState,},
|
||||
mimeType: "image/png",
|
||||
exportWithDarkMode: "true",
|
||||
metadata: "Generated by Excalidraw-Obsidian plugin",
|
||||
});
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
354
src/main.ts
354
src/main.ts
@@ -1,109 +1,309 @@
|
||||
import {
|
||||
TFile,
|
||||
TFolder,
|
||||
Plugin,
|
||||
WorkspaceLeaf,
|
||||
addIcon,
|
||||
App,
|
||||
PluginManifest,
|
||||
EventRef,
|
||||
Menu,
|
||||
TAbstractFile
|
||||
TFile,
|
||||
TFolder,
|
||||
Plugin,
|
||||
WorkspaceLeaf,
|
||||
addIcon,
|
||||
App,
|
||||
PluginManifest,
|
||||
MarkdownView,
|
||||
normalizePath,
|
||||
MarkdownPostProcessorContext,
|
||||
} from 'obsidian';
|
||||
import { BLANK_DRAWING, VIEW_TYPE_EXCALIDRAW, PALETTE_ICON } from './constants';
|
||||
import ExcalidrawView from './ExcalidrawView';
|
||||
import {
|
||||
BLANK_DRAWING,
|
||||
VIEW_TYPE_EXCALIDRAW,
|
||||
EXCALIDRAW_ICON,
|
||||
ICON_NAME,
|
||||
EXCALIDRAW_FILE_EXTENSION,
|
||||
CODEBLOCK_EXCALIDRAW,
|
||||
DISK_ICON,
|
||||
DISK_ICON_NAME,
|
||||
PNG_ICON,
|
||||
PNG_ICON_NAME,
|
||||
SVG_ICON,
|
||||
SVG_ICON_NAME,
|
||||
RERENDER_EVENT
|
||||
} from './constants';
|
||||
import ExcalidrawView, {ExportSettings} from './ExcalidrawView';
|
||||
import {
|
||||
ExcalidrawSettings,
|
||||
DEFAULT_SETTINGS,
|
||||
ExcalidrawSettingTab
|
||||
ExcalidrawSettings,
|
||||
DEFAULT_SETTINGS,
|
||||
ExcalidrawSettingTab
|
||||
} from './settings';
|
||||
import {OpenFileDialog} from './openDrawing';
|
||||
import {getDateString} from './utils'
|
||||
import {
|
||||
openDialogAction,
|
||||
OpenFileDialog
|
||||
} from './openDrawing';
|
||||
|
||||
|
||||
export default class ExcalidrawPlugin extends Plugin {
|
||||
public settings: ExcalidrawSettings;
|
||||
public view: ExcalidrawView;
|
||||
private openDialog: OpenFileDialog;
|
||||
private activeDrawing: TFile;
|
||||
private activeDrawingFilename: string;
|
||||
|
||||
public settings: ExcalidrawSettings;
|
||||
private openDialog: OpenFileDialog;
|
||||
|
||||
constructor(app: App, manifest: PluginManifest) {
|
||||
constructor(app: App, manifest: PluginManifest) {
|
||||
super(app, manifest);
|
||||
this.activeDrawing = null;
|
||||
this.activeDrawingFilename = '';
|
||||
}
|
||||
|
||||
async onload() {
|
||||
addIcon("excalidraw", PALETTE_ICON);
|
||||
async onload() {
|
||||
addIcon(ICON_NAME, EXCALIDRAW_ICON);
|
||||
addIcon(DISK_ICON_NAME,DISK_ICON);
|
||||
addIcon(PNG_ICON_NAME,PNG_ICON);
|
||||
addIcon(SVG_ICON_NAME,SVG_ICON);
|
||||
|
||||
this.registerView(
|
||||
VIEW_TYPE_EXCALIDRAW,
|
||||
(leaf: WorkspaceLeaf) => (this.view = new ExcalidrawView(leaf))
|
||||
(leaf: WorkspaceLeaf) => new ExcalidrawView(leaf, this)
|
||||
);
|
||||
|
||||
this.registerExtensions(["excalidraw"],"excalidraw");
|
||||
this.registerExtensions([EXCALIDRAW_FILE_EXTENSION],VIEW_TYPE_EXCALIDRAW);
|
||||
|
||||
await this.loadSettings();
|
||||
this.addSettingTab(new ExcalidrawSettingTab(this.app, this));
|
||||
this.registerMarkdownCodeBlockProcessor(CODEBLOCK_EXCALIDRAW, async (source,el,ctx) => {
|
||||
el.addEventListener(RERENDER_EVENT,async (e) => {
|
||||
e.stopPropagation();
|
||||
el.empty();
|
||||
this.codeblockProcessor(source,el,ctx,this);
|
||||
});
|
||||
this.codeblockProcessor(source,el,ctx,this);
|
||||
});
|
||||
|
||||
this.openDialog = new OpenFileDialog(this.app, this);
|
||||
this.addRibbonIcon('excalidraw', 'Excalidraw', async () => {
|
||||
this.openDialog.start();
|
||||
});
|
||||
await this.loadSettings();
|
||||
this.addSettingTab(new ExcalidrawSettingTab(this.app, this));
|
||||
|
||||
this.addCommand({
|
||||
id: "excalidraw-open",
|
||||
name: "Open existing drawing or create new one",
|
||||
callback: () => {
|
||||
this.openDialog.start();
|
||||
},
|
||||
});
|
||||
this.openDialog = new OpenFileDialog(this.app, this);
|
||||
this.addRibbonIcon(ICON_NAME, 'Create a new drawing in Excalidraw', async (e) => {
|
||||
this.createDrawing(this.getNextDefaultFilename(), e.ctrlKey);
|
||||
});
|
||||
|
||||
this.addCommand({
|
||||
id: "excalidraw-autocreate",
|
||||
name: "Create a new drawing",
|
||||
callback: () => {
|
||||
this.createDrawing(this.getNextDefaultFilename());
|
||||
},
|
||||
});
|
||||
}
|
||||
id: "excalidraw-open",
|
||||
name: "Open an existing drawing - IN A NEW PANE",
|
||||
callback: () => {
|
||||
this.openDialog.start(openDialogAction.openFile, true);
|
||||
},
|
||||
});
|
||||
|
||||
private async loadSettings() {
|
||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||
}
|
||||
|
||||
async saveSettings() {
|
||||
await this.saveData(this.settings);
|
||||
}
|
||||
this.addCommand({
|
||||
id: "excalidraw-open-on-current",
|
||||
name: "Open an existing drawing - IN THE CURRENT ACTIVE PANE",
|
||||
callback: () => {
|
||||
this.openDialog.start(openDialogAction.openFile, false);
|
||||
},
|
||||
});
|
||||
|
||||
this.addCommand({
|
||||
id: "excalidraw-insert-transclusion",
|
||||
name: "Transclude (embed) an ."+EXCALIDRAW_FILE_EXTENSION+" drawing",
|
||||
checkCallback: (checking: boolean) => {
|
||||
if (checking) {
|
||||
return this.app.workspace.activeLeaf.view.getViewType() == "markdown";
|
||||
} else {
|
||||
this.openDialog.start(openDialogAction.insertLink, false);
|
||||
return true;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
this.addCommand({
|
||||
id: "excalidraw-autocreate",
|
||||
name: "Create a new drawing - IN A NEW PANE",
|
||||
callback: () => {
|
||||
this.createDrawing(this.getNextDefaultFilename(), true);
|
||||
},
|
||||
});
|
||||
|
||||
this.addCommand({
|
||||
id: "excalidraw-autocreate-on-current",
|
||||
name: "Create a new drawing - IN THE CURRENT ACTIVE PANE",
|
||||
callback: () => {
|
||||
this.createDrawing(this.getNextDefaultFilename(), false);
|
||||
},
|
||||
});
|
||||
|
||||
this.addCommand({
|
||||
id: 'export-svg',
|
||||
name: 'Export SVG. Save it next to the current file',
|
||||
checkCallback: (checking: boolean) => {
|
||||
if (checking) {
|
||||
return this.app.workspace.activeLeaf.view.getViewType() == VIEW_TYPE_EXCALIDRAW;
|
||||
} else {
|
||||
const view = this.app.workspace.activeLeaf.view;
|
||||
if(view.getViewType() == VIEW_TYPE_EXCALIDRAW) {
|
||||
(this.app.workspace.activeLeaf.view as ExcalidrawView).saveSVG();
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
this.addCommand({
|
||||
id: 'export-png',
|
||||
name: 'Export PNG. Save it next to the current file',
|
||||
checkCallback: (checking: boolean) => {
|
||||
if (checking) {
|
||||
return this.app.workspace.activeLeaf.view.getViewType() == VIEW_TYPE_EXCALIDRAW;
|
||||
} else {
|
||||
const view = this.app.workspace.activeLeaf.view;
|
||||
if(view.getViewType() == VIEW_TYPE_EXCALIDRAW) {
|
||||
(this.app.workspace.activeLeaf.view as ExcalidrawView).savePNG();
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
},
|
||||
});
|
||||
//watch filename change to rename .svg
|
||||
this.app.vault.on('rename',async (file,oldPath) => {
|
||||
if (!(this.settings.keepInSync && file instanceof TFile)) return;
|
||||
if (file.extension != EXCALIDRAW_FILE_EXTENSION) return;
|
||||
const oldSVGpath = oldPath.substring(0,oldPath.lastIndexOf('.'+EXCALIDRAW_FILE_EXTENSION)) + '.svg';
|
||||
const svgFile = this.app.vault.getAbstractFileByPath(normalizePath(oldSVGpath));
|
||||
if(svgFile && svgFile instanceof TFile) {
|
||||
const newSVGpath = file.path.substring(0,file.path.lastIndexOf('.'+EXCALIDRAW_FILE_EXTENSION)) + '.svg';
|
||||
await this.app.vault.rename(svgFile,newSVGpath);
|
||||
}
|
||||
});
|
||||
|
||||
//watch file delete and delete corresponding .svg
|
||||
this.app.vault.on('delete',async (file:TFile) => {
|
||||
if (!(this.settings.keepInSync && file instanceof TFile)) return;
|
||||
if (file.extension != EXCALIDRAW_FILE_EXTENSION) return;
|
||||
const svgPath = file.path.substring(0,file.path.lastIndexOf('.'+EXCALIDRAW_FILE_EXTENSION)) + '.svg';
|
||||
const svgFile = this.app.vault.getAbstractFileByPath(normalizePath(svgPath));
|
||||
if(svgFile && svgFile instanceof TFile) {
|
||||
await this.app.vault.delete(svgFile);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async codeblockProcessor(source: string, el: HTMLElement, ctx: MarkdownPostProcessorContext, plugin: ExcalidrawPlugin) {
|
||||
const parseError = (message: string) => {
|
||||
el.createDiv("excalidraw-error",(el)=> {
|
||||
el.createEl("p","Please provide a link to an excalidraw file: [[file."+EXCALIDRAW_FILE_EXTENSION+"]]");
|
||||
el.createEl("p",message);
|
||||
el.createEl("p",source);
|
||||
})
|
||||
}
|
||||
|
||||
const parts = source.match(/\[{2}([^|]*)\|?(\d*)x?(\d*)\|?(.*)\]{2}/m);
|
||||
if(!parts) {
|
||||
parseError("No link to file found in codeblock.");
|
||||
return;
|
||||
}
|
||||
const fname = parts[1];
|
||||
const fwidth = parts[2]? parts[2] : plugin.settings.width;
|
||||
const fheight = parts[3];
|
||||
const style = "excalidraw-svg" + (parts[4] ? "-" + parts[4] : "");
|
||||
|
||||
if(!fname) {
|
||||
parseError("No link to file found in codeblock.");
|
||||
return;
|
||||
}
|
||||
|
||||
const file = plugin.app.vault.getAbstractFileByPath(fname);
|
||||
if(!(file && file instanceof TFile)) {
|
||||
parseError("File does not exist. " + fname);
|
||||
return;
|
||||
}
|
||||
|
||||
if(file.extension != EXCALIDRAW_FILE_EXTENSION) {
|
||||
parseError("Not an excalidraw file. Must have extension " + EXCALIDRAW_FILE_EXTENSION);
|
||||
return;
|
||||
}
|
||||
|
||||
const content = await plugin.app.vault.read(file);
|
||||
const exportSettings: ExportSettings = {
|
||||
withBackground: plugin.settings.exportWithBackground,
|
||||
withTheme: plugin.settings.exportWithTheme
|
||||
}
|
||||
const svg = ExcalidrawView.getSVG(content,exportSettings);
|
||||
if(!svg) {
|
||||
parseError("Parse error. Not a valid Excalidraw file.");
|
||||
return;
|
||||
}
|
||||
el.createDiv(style,(el)=> {
|
||||
svg.removeAttribute('width');
|
||||
svg.removeAttribute('height');
|
||||
svg.style.setProperty('width',fwidth);
|
||||
if(fheight) svg.style.setProperty('height',fheight);
|
||||
svg.addClass(style);
|
||||
el.appendChild(svg);
|
||||
});
|
||||
}
|
||||
|
||||
public insertCodeblock(data:string) {
|
||||
const activeView = this.app.workspace.getActiveViewOfType(MarkdownView);
|
||||
if(activeView) {
|
||||
const editor = activeView.editor;
|
||||
editor.replaceSelection(
|
||||
String.fromCharCode(96,96,96) +
|
||||
CODEBLOCK_EXCALIDRAW +
|
||||
"\n[["+data+"]]\n" +
|
||||
String.fromCharCode(96,96,96));
|
||||
editor.focus();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private async loadSettings() {
|
||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||
}
|
||||
|
||||
async saveSettings() {
|
||||
await this.saveData(this.settings);
|
||||
}
|
||||
|
||||
public triggerEmbedUpdates(){
|
||||
const e = document.createEvent("Event")
|
||||
e.initEvent(RERENDER_EVENT,true,false);
|
||||
document
|
||||
.querySelectorAll("svg[class^='excalidraw-svg']")
|
||||
.forEach((el) => el.dispatchEvent(e));
|
||||
}
|
||||
|
||||
public async openDrawing(drawingFile: TFile, onNewPane: boolean) {
|
||||
const leafs = this.app.workspace.getLeavesOfType(VIEW_TYPE_EXCALIDRAW);
|
||||
let leaf:WorkspaceLeaf = null;
|
||||
|
||||
if (leafs?.length > 0) {
|
||||
leaf = leafs[0];
|
||||
}
|
||||
if(!leaf) {
|
||||
leaf = this.app.workspace.activeLeaf;
|
||||
}
|
||||
|
||||
if(!leaf) {
|
||||
leaf = this.app.workspace.getLeaf();
|
||||
}
|
||||
|
||||
if(onNewPane) {
|
||||
leaf = this.app.workspace.createLeafBySplit(leaf);
|
||||
}
|
||||
|
||||
public async openDrawing(drawingFile: TFile) {
|
||||
this.activeDrawing = drawingFile;
|
||||
this.saveSettings();
|
||||
const leaf = this.view ? this.view.leaf : this.app.workspace.activeLeaf;
|
||||
leaf.setViewState({
|
||||
type: VIEW_TYPE_EXCALIDRAW,
|
||||
state: {file: drawingFile.path}}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private getNextDefaultFilename():string {
|
||||
return this.settings.folder+'/Drawing ' + getDateString('yyyy-MM-dd HH.mm.ss')+'.excalidraw';
|
||||
}
|
||||
private getNextDefaultFilename():string {
|
||||
return this.settings.folder+'/Drawing ' + window.moment().format('YYYY-MM-DD HH.mm.ss')+'.'+EXCALIDRAW_FILE_EXTENSION;
|
||||
}
|
||||
|
||||
public async createDrawing(filename: string) {
|
||||
if(!(this.app.vault.getAbstractFileByPath(this.settings.folder) as TFile)) {
|
||||
this.app.vault.createFolder(this.settings.folder);
|
||||
}
|
||||
public async createDrawing(filename: string, onNewPane: boolean) {
|
||||
const folder = this.app.vault.getAbstractFileByPath(normalizePath(this.settings.folder));
|
||||
if (!(folder && folder instanceof TFolder)) {
|
||||
await this.app.vault.createFolder(this.settings.folder);
|
||||
}
|
||||
|
||||
const file = (this.app.vault.getAbstractFileByPath(this.settings.templateFilePath) as TFile);
|
||||
if(file) {
|
||||
this.app.vault.read(file).then(async (content: string) => {
|
||||
this.openDrawing(await this.app.vault.create(filename,content==''?BLANK_DRAWING:content))
|
||||
});
|
||||
} else {
|
||||
this.openDrawing(await this.app.vault.create(filename,BLANK_DRAWING));
|
||||
}
|
||||
}
|
||||
const file = this.app.vault.getAbstractFileByPath(normalizePath(this.settings.templateFilePath));
|
||||
if(file && file instanceof TFile) {
|
||||
const content = await this.app.vault.read(file);
|
||||
this.openDrawing(await this.app.vault.create(filename,content==''?BLANK_DRAWING:content), onNewPane);
|
||||
} else {
|
||||
this.openDrawing(await this.app.vault.create(filename,BLANK_DRAWING), onNewPane);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,40 @@
|
||||
import { App, FuzzySuggestModal, TFile, TFolder, normalizePath, Vault, TAbstractFile, Instruction } from "obsidian";
|
||||
import {
|
||||
App,
|
||||
FuzzySuggestModal,
|
||||
TFile
|
||||
} from "obsidian";
|
||||
import ExcalidrawPlugin from './main';
|
||||
import ExcalidrawView from './view';
|
||||
import {
|
||||
EMPTY_MESSAGE,
|
||||
EXCALIDRAW_FILE_EXTENSION
|
||||
} from './constants';
|
||||
|
||||
export enum openDialogAction {
|
||||
openFile,
|
||||
insertLink,
|
||||
}
|
||||
|
||||
export class OpenFileDialog extends FuzzySuggestModal<TFile> {
|
||||
public app: App;
|
||||
private plugin: ExcalidrawPlugin;
|
||||
|
||||
private action: openDialogAction;
|
||||
private onNewPane: boolean;
|
||||
|
||||
constructor(app: App, plugin: ExcalidrawPlugin) {
|
||||
super(app);
|
||||
this.app = app;
|
||||
this.action = openDialogAction.openFile;
|
||||
this.plugin = plugin;
|
||||
const EMPTY_MESSAGE = "Hit enter to create a new drawing";
|
||||
this.emptyStateText = EMPTY_MESSAGE;
|
||||
this.onNewPane = false;
|
||||
this.setInstructions([{
|
||||
command: "Select an existing drawing or type title for your new drawing, then hit enter.",
|
||||
purpose: "The new drawing will be created in the default Excalidraw folder specified in Settings.",
|
||||
command: "Type name of drawing to select.",
|
||||
purpose: "",
|
||||
}]);
|
||||
|
||||
this.inputEl.onkeyup = (e) => {
|
||||
if(e.key=="Enter") {
|
||||
if(e.key=="Enter" && this.action == openDialogAction.openFile) {
|
||||
if (this.containerEl.innerText.includes(EMPTY_MESSAGE)) {
|
||||
this.plugin.createDrawing(this.plugin.settings.folder+'/'+this.inputEl.value+'.excalidraw');
|
||||
this.plugin.createDrawing(this.plugin.settings.folder+'/'+this.inputEl.value+'.'+EXCALIDRAW_FILE_EXTENSION, this.onNewPane);
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
@@ -28,9 +42,8 @@ export class OpenFileDialog extends FuzzySuggestModal<TFile> {
|
||||
}
|
||||
|
||||
getItems(): TFile[] {
|
||||
let excalidrawFiles: TFile[] = [];
|
||||
excalidrawFiles = this.app.vault.getFiles();
|
||||
return excalidrawFiles.filter((f:TFile) => (f.extension=='excalidraw'));
|
||||
const excalidrawFiles = this.app.vault.getFiles();
|
||||
return (excalidrawFiles || []).filter((f:TFile) => (f.extension==EXCALIDRAW_FILE_EXTENSION));
|
||||
}
|
||||
|
||||
getItemText(item: TFile): string {
|
||||
@@ -38,17 +51,30 @@ export class OpenFileDialog extends FuzzySuggestModal<TFile> {
|
||||
}
|
||||
|
||||
onChooseItem(item: TFile, _evt: MouseEvent | KeyboardEvent): void {
|
||||
this.plugin.openDrawing(item);
|
||||
switch(this.action) {
|
||||
case(openDialogAction.openFile):
|
||||
this.plugin.openDrawing(item, this.onNewPane);
|
||||
break;
|
||||
case(openDialogAction.insertLink):
|
||||
this.plugin.insertCodeblock(item.path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
start(): void {
|
||||
try {
|
||||
let files = this.getItems();
|
||||
this.open();
|
||||
}
|
||||
catch(error) {
|
||||
console.log(error);
|
||||
start(action:openDialogAction, onNewPane: boolean): void {
|
||||
this.action = action;
|
||||
this.onNewPane = onNewPane;
|
||||
switch(action) {
|
||||
case (openDialogAction.openFile):
|
||||
this.emptyStateText = EMPTY_MESSAGE;
|
||||
this.setPlaceholder("Select existing drawing or type name of new and hit enter.");
|
||||
break;
|
||||
case (openDialogAction.insertLink):
|
||||
this.emptyStateText = "No file matches your query.";
|
||||
this.setPlaceholder("Select existing drawing to insert into document.");
|
||||
break;
|
||||
}
|
||||
this.open();
|
||||
}
|
||||
|
||||
}
|
||||
165
src/settings.ts
165
src/settings.ts
@@ -1,51 +1,144 @@
|
||||
import {App, PluginSettingTab, Setting} from 'obsidian';
|
||||
import {
|
||||
App,
|
||||
parseFrontMatterAliases,
|
||||
PluginSettingTab,
|
||||
Setting
|
||||
} from 'obsidian';
|
||||
import type ExcalidrawPlugin from "./main";
|
||||
|
||||
export interface ExcalidrawSettings {
|
||||
folder: string,
|
||||
templateFilePath: string,
|
||||
folder: string,
|
||||
templateFilePath: string,
|
||||
width: string,
|
||||
exportWithTheme: boolean,
|
||||
exportWithBackground: boolean,
|
||||
autoexportSVG: boolean,
|
||||
autoexportPNG: boolean,
|
||||
keepInSync: boolean,
|
||||
library: string,
|
||||
}
|
||||
|
||||
export const DEFAULT_SETTINGS: ExcalidrawSettings = {
|
||||
folder: 'excalidraw',
|
||||
templateFilePath: '',
|
||||
folder: 'Excalidraw',
|
||||
templateFilePath: 'Excalidraw/Template.excalidraw',
|
||||
width: '400',
|
||||
exportWithTheme: true,
|
||||
exportWithBackground: true,
|
||||
autoexportSVG: false,
|
||||
autoexportPNG: false,
|
||||
keepInSync: false,
|
||||
library: `{"type":"excalidrawlib","version":1,"library":[]}`,
|
||||
}
|
||||
|
||||
export class ExcalidrawSettingTab extends PluginSettingTab {
|
||||
plugin: ExcalidrawPlugin;
|
||||
plugin: ExcalidrawPlugin;
|
||||
|
||||
constructor(app: App, plugin: ExcalidrawPlugin) {
|
||||
super(app, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
constructor(app: App, plugin: ExcalidrawPlugin) {
|
||||
super(app, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
display(): void {
|
||||
let {containerEl} = this;
|
||||
display(): void {
|
||||
let {containerEl} = this;
|
||||
this.containerEl.empty();
|
||||
|
||||
this.containerEl.empty();
|
||||
new Setting(containerEl)
|
||||
.setName('Excalidraw folder')
|
||||
.setDesc('Default location for your Excalidraw drawings. Leaving this empty means drawings will be created in the Vault root.')
|
||||
.addText(text => text
|
||||
.setPlaceholder('Excalidraw')
|
||||
.setValue(this.plugin.settings.folder)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.folder = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Excalidraw folder')
|
||||
.setDesc('Default location for Excalidraw drawings. Leaving this empty means drawings will be saved to the Vault root.')
|
||||
.addText(text => text
|
||||
.setPlaceholder('excalidraw')
|
||||
.setValue(this.plugin.settings.folder)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.folder = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Excalidraw template file')
|
||||
.setDesc('Full path to file containing the file you want to use as the template for new Excalidraw drawings. '+
|
||||
'Note that Excalidraw files will have an extension of ".excalidraw" ' +
|
||||
'Assuming your template is in the default excalidraw folder, the setting would be: excalidraw/Template.excalidraw')
|
||||
.addText(text => text
|
||||
.setPlaceholder('excalidraw')
|
||||
new Setting(containerEl)
|
||||
.setName('Excalidraw template file')
|
||||
.setDesc('Full path to file containing the file you want to use as the template for new Excalidraw drawings. '+
|
||||
'Note that Excalidraw files will have the extension ".excalidraw". ' +
|
||||
'Assuming your template is in the default Excalidraw folder, the setting would be: Excalidraw/Template.excalidraw')
|
||||
.addText(text => text
|
||||
.setPlaceholder('Excalidraw/Template.excalidraw')
|
||||
.setValue(this.plugin.settings.templateFilePath)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.templateFilePath = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
}
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.templateFilePath = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Default width of embedded (transcluded) image')
|
||||
.setDesc('The default width of an embedded drawing. You can specify a different ' +
|
||||
'width when embedding an image using the [[drawing.excalidraw|100]] or ' +
|
||||
'[[drawing.excalidraw|100x100]] format.')
|
||||
.addText(text => text
|
||||
.setPlaceholder('400')
|
||||
.setValue(this.plugin.settings.width)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.width = value;
|
||||
await this.plugin.saveSettings();
|
||||
this.plugin.triggerEmbedUpdates();
|
||||
}));
|
||||
|
||||
this.containerEl.createEl('h1', {text: 'Embedded image settings'});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Export image with background')
|
||||
.setDesc('If turned off, the exported image will be transparent.')
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.exportWithBackground)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.exportWithBackground = value;
|
||||
await this.plugin.saveSettings();
|
||||
this.plugin.triggerEmbedUpdates();
|
||||
}));
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Export image with theme')
|
||||
.setDesc('Export the image matching the dark/light theme setting used for your drawing in Excalidraw. If turned off, ' +
|
||||
'drawings created in drak mode will appear as they would in light mode.')
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.exportWithTheme)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.exportWithTheme = value;
|
||||
await this.plugin.saveSettings();
|
||||
this.plugin.triggerEmbedUpdates();
|
||||
}));
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Auto-export SVG')
|
||||
.setDesc('Automatically create an SVG export of your drawing matching the title of your "my drawing.excalidraw" file. ' +
|
||||
'The plugin will save the .SVG file in the same folder as the drawing. '+
|
||||
'You can use this file ("my drawing.svg") to embed your drawing into documents in a platform independent way. ' +
|
||||
'While the auto export switch is on, this file will get updated every time you edit the excalidraw drawing with the matching name.')
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.autoexportSVG)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.autoexportSVG = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Auto-export PNG')
|
||||
.setDesc('Same as the auto-export SVG, but for PNG.')
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.autoexportPNG)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.autoexportPNG = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Keep the .SVG and/or .PNG filenames in sync with the .excalidraw file')
|
||||
.setDesc('When turned on, the plugin will automaticaly update the filename of the .SVG and/or .PNG files when the .excalidraw file in the same folder (and same name) is renamed. ' +
|
||||
'The plugin will also automatically delete the .SVG and/or .PNG files when the .excalidraw file in the same folder (and same name) is deleted. ')
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.keepInSync)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.keepInSync = value;
|
||||
await this.plugin.saveSettings();
|
||||
}));
|
||||
|
||||
}
|
||||
}
|
||||
28
src/utils.ts
28
src/utils.ts
@@ -1,28 +0,0 @@
|
||||
export function getDateString(format:string):string {
|
||||
const pad2 = (n:number) => {
|
||||
return n>9? n.toString():'0'+n;
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
const M=now.getMonth()+1,H=now.getHours(),m=now.getMinutes(),d=now.getDate(),s=now.getSeconds(),yyyy=now.getFullYear();
|
||||
const n = {
|
||||
yyyy: yyyy.toString(),
|
||||
MM : pad2(M),
|
||||
dd : pad2(d),
|
||||
HH : pad2(H),
|
||||
mm : pad2(m),
|
||||
ss : pad2(s)
|
||||
};
|
||||
|
||||
return format.replace(/([a-zA-Z]+)/g,function (s:string, $1:string):string {
|
||||
switch($1) {
|
||||
case 'yyyy' : return n.yyyy;
|
||||
case 'MM' : return n.MM;
|
||||
case 'dd' : return n.dd;
|
||||
case 'HH' : return n.HH;
|
||||
case 'mm' : return n.mm;
|
||||
case 'ss' : return n.ss;
|
||||
}
|
||||
return '';
|
||||
});
|
||||
}
|
||||
146
src/view.ts
146
src/view.ts
@@ -1,146 +0,0 @@
|
||||
import { EventRef, Workspace, ItemView, WorkspaceLeaf, TFile } from "obsidian";
|
||||
import { VIEW_TYPE_EXCALIDRAW } from "./constants";
|
||||
import * as ReactDOM from "react-dom";
|
||||
import * as React from "react";
|
||||
import Excalidraw, { exportToCanvas, exportToSvg, exportToBlob } from "@excalidraw/excalidraw";
|
||||
import type SceneData from "@excalidraw/excalidraw";
|
||||
import '../styles.css';
|
||||
import Scene from "@excalidraw/excalidraw/types/scene/Scene";
|
||||
import { ExcalidrawElement } from "@excalidraw/excalidraw/types/element/types";
|
||||
import { AppState } from "@excalidraw/excalidraw/types/types";
|
||||
|
||||
export default class ExcalidrawView extends ItemView {
|
||||
getSVG: any;
|
||||
getPNG: any;
|
||||
file: TFile;
|
||||
|
||||
workspace: Workspace;
|
||||
|
||||
constructor(leaf: WorkspaceLeaf) {
|
||||
super(leaf);
|
||||
this.workspace = this.app.workspace;
|
||||
this.file = null;
|
||||
}
|
||||
|
||||
private instantiateExcalidraw(initdata: any) {
|
||||
ReactDOM.unmountComponentAtNode(this.contentEl);
|
||||
|
||||
ReactDOM.render(React.createElement(() => {
|
||||
let previousSceneVersion = 0;
|
||||
const excalidrawRef = React.useRef(null);
|
||||
const excalidrawWrapperRef = React.useRef(null);
|
||||
const [dimensions, setDimensions] = React.useState({
|
||||
width: undefined,
|
||||
height: undefined
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
setDimensions({
|
||||
width: this.contentEl.clientWidth,
|
||||
height: this.contentEl.clientHeight,
|
||||
});
|
||||
const onResize = () => {
|
||||
try {
|
||||
setDimensions({
|
||||
width: this.contentEl.clientWidth,
|
||||
height: this.contentEl.clientHeight,
|
||||
});
|
||||
} catch(err) {console.log ("onResize ",err)}
|
||||
};
|
||||
window.addEventListener("resize", onResize);
|
||||
return () => window.removeEventListener("resize", onResize);
|
||||
}, [excalidrawWrapperRef]);
|
||||
|
||||
/* this.getScene = function() {
|
||||
return {
|
||||
elements: excalidrawRef.current.getSceneElements(),
|
||||
appState: excalidrawRef.current.getAppState()
|
||||
};
|
||||
};*/
|
||||
|
||||
/* this.updateScene = function(scene: Scene) {
|
||||
sceneJustUpdated = true;
|
||||
excalidrawRef.current.updateScene(scene);
|
||||
};*/
|
||||
|
||||
return React.createElement(
|
||||
React.Fragment,
|
||||
null,
|
||||
React.createElement(
|
||||
"div",
|
||||
{
|
||||
className: "excalidraw-wrapper",
|
||||
ref: excalidrawWrapperRef
|
||||
},
|
||||
React.createElement(Excalidraw.default, {
|
||||
ref: excalidrawRef,
|
||||
width: dimensions.width,
|
||||
height: dimensions.height,
|
||||
UIOptions: {
|
||||
canvasActions: {
|
||||
loadScene: false,
|
||||
saveScene: false,
|
||||
saveAsScene: false
|
||||
},
|
||||
},
|
||||
initialData: initdata,
|
||||
onChange: (el: ExcalidrawElement[], st: AppState) => {
|
||||
if (st.editingElement == null && st.resizingElement == null &&
|
||||
st.draggingElement == null && st.editingGroupId == null &&
|
||||
st.editingLinearElement == null ) {
|
||||
const sceneVersion = Excalidraw.getSceneVersion(el);
|
||||
if(sceneVersion != previousSceneVersion) {
|
||||
previousSceneVersion = sceneVersion;
|
||||
this.saveFile(JSON.stringify({
|
||||
"type": "excalidraw",
|
||||
"version": 2,
|
||||
"source": "https://excalidraw.com",
|
||||
"elements": el.filter(e => !e.isDeleted),
|
||||
"appState": {
|
||||
"theme": st.theme,
|
||||
"viewBackgroundColor": st.viewBackgroundColor
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
)
|
||||
);
|
||||
}),(this as any).contentEl);
|
||||
}
|
||||
|
||||
private async saveFile(content: string) {
|
||||
await this.app.vault.modify(this.file, content);
|
||||
}
|
||||
|
||||
public loadDrawing(file: TFile) {
|
||||
this.file = file;
|
||||
this.app.vault.read(file).then((content: string) => {
|
||||
const data = JSON.parse(content);
|
||||
this.instantiateExcalidraw({
|
||||
elements: data.elements,
|
||||
appState: data.appState,
|
||||
scrollToContent: true,
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public getCurrentDrawingFilename() {
|
||||
return this.file == null ? '' : this.file.path;
|
||||
}
|
||||
|
||||
getDisplayText() {
|
||||
return this.file!=null ? this.file.basename : "Excalidraw";
|
||||
}
|
||||
|
||||
getIcon() {
|
||||
return "palette";
|
||||
}
|
||||
|
||||
getViewType() {
|
||||
return VIEW_TYPE_EXCALIDRAW;
|
||||
}
|
||||
|
||||
}
|
||||
29
styles.css
29
styles.css
@@ -6,8 +6,35 @@
|
||||
.excalidraw-wrapper {
|
||||
height: 100%;
|
||||
margin: 0px;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.context-menu-option__shortcut {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
}
|
||||
|
||||
.block-language-excalidraw {
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.excalidraw .github-corner {
|
||||
display: none;
|
||||
}
|
||||
|
||||
svg.excalidraw-svg-right-wrap {
|
||||
float: right;
|
||||
margin: 0px 0px 20px 20px;
|
||||
}
|
||||
|
||||
svg.excalidraw-svg-left-wrap {
|
||||
float: left;
|
||||
margin: 0px 35px 20px 0px;
|
||||
}
|
||||
|
||||
div.excalidraw-svg-right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
div.excalidraw-svg-left {
|
||||
text-align: left;
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
{
|
||||
".0.1": "0.11.13"
|
||||
}
|
||||
"1.0.7": "0.11.13",
|
||||
"1.0.6": "0.11.13",
|
||||
"1.0.5": "0.11.13"
|
||||
}
|
||||
|
||||
206
yarn.lock
206
yarn.lock
@@ -28,7 +28,7 @@
|
||||
"resolved" "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.15.tgz"
|
||||
"version" "7.13.15"
|
||||
|
||||
"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.13.0", "@babel/core@^7.4.0-0", "@babel/core@^7.7.5", "@babel/core@^7.8.4", "@babel/core@^7.9.0", "@babel/core@7 || ^7.0.0-rc.2":
|
||||
"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.13.0", "@babel/core@^7.3.3", "@babel/core@^7.4.0-0", "@babel/core@^7.7.5", "@babel/core@^7.8.4", "@babel/core@^7.9.0", "@babel/core@7 || ^7.0.0-rc.2":
|
||||
"integrity" "sha512-6GXmNYeNjS2Uz+uls5jalOemgIhnTMeaXo+yBUA72kC2uX/8VW6XyhVIo2L8/q0goKQA3EVKx0KOQpVKSeWadQ=="
|
||||
"resolved" "https://registry.npmjs.org/@babel/core/-/core-7.13.15.tgz"
|
||||
"version" "7.13.15"
|
||||
@@ -176,7 +176,7 @@
|
||||
dependencies:
|
||||
"@babel/types" "^7.13.12"
|
||||
|
||||
"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.12.1", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.13.12":
|
||||
"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.12.1", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.13.12":
|
||||
"integrity" "sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA=="
|
||||
"resolved" "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz"
|
||||
"version" "7.13.12"
|
||||
@@ -914,7 +914,7 @@
|
||||
"@babel/helper-create-regexp-features-plugin" "^7.12.13"
|
||||
"@babel/helper-plugin-utils" "^7.12.13"
|
||||
|
||||
"@babel/preset-env@^7.8.4", "@babel/preset-env@^7.9.5":
|
||||
"@babel/preset-env@^7.3.1", "@babel/preset-env@^7.8.4", "@babel/preset-env@^7.9.5":
|
||||
"integrity" "sha512-D4JAPMXcxk69PKe81jRJ21/fP/uYdcTZ3hJDF5QX2HSI9bBxxYw/dumdR6dGumhjxlprHPE4XWoPaqzZUVy2MA=="
|
||||
"resolved" "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.13.15.tgz"
|
||||
"version" "7.13.15"
|
||||
@@ -1072,7 +1072,7 @@
|
||||
"@babel/types" "^7.4.4"
|
||||
"esutils" "^2.0.2"
|
||||
|
||||
"@babel/preset-react@^7.9.4":
|
||||
"@babel/preset-react@^7.0.0", "@babel/preset-react@^7.9.4":
|
||||
"integrity" "sha512-gx+tDLIE06sRjKJkVtpZ/t3mzCDOnPG+ggHZG9lffUbX8+wC739x20YQc9V35Do6ZAxaUc/HhVHIiOzz5MvDmA=="
|
||||
"resolved" "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.13.13.tgz"
|
||||
"version" "7.13.13"
|
||||
@@ -1190,10 +1190,10 @@
|
||||
"minimatch" "^3.0.4"
|
||||
"strip-json-comments" "^3.1.1"
|
||||
|
||||
"@excalidraw/excalidraw@0.6.0":
|
||||
"integrity" "sha512-JC+Sg1T3AUJOX2xKp0/pCX7d845fta4nKc3Uw1V5Y2a5bi9AWSybjEPiuYsUxtKbCaKf1o6OaBgj/IXvPPIi4Q=="
|
||||
"resolved" "https://registry.npmjs.org/@excalidraw/excalidraw/-/excalidraw-0.6.0.tgz"
|
||||
"version" "0.6.0"
|
||||
"@excalidraw/excalidraw@0.7.0":
|
||||
"integrity" "sha512-D1yMXhOjWjCJIXT0puZD2QaGQ28QN2DNrVUQTsOouhPSELwhFoM7Exg/ulSwkLBI2l2KN7m39+2tj6QVijv4Sg=="
|
||||
"resolved" "https://registry.npmjs.org/@excalidraw/excalidraw/-/excalidraw-0.7.0.tgz"
|
||||
"version" "0.7.0"
|
||||
|
||||
"@hapi/address@2.x.x":
|
||||
"integrity" "sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ=="
|
||||
@@ -1455,6 +1455,19 @@
|
||||
"schema-utils" "^2.6.5"
|
||||
"source-map" "^0.7.3"
|
||||
|
||||
"@polka/url@^1.0.0-next.9":
|
||||
"integrity" "sha512-6RglhutqrGFMO1MNUXp95RBuYIuc8wTnMAV5MUhLmjTOy78ncwOw7RgeQ/HeymkKXRhZd0s2DNrM1rL7unk3MQ=="
|
||||
"resolved" "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.12.tgz"
|
||||
"version" "1.0.0-next.12"
|
||||
|
||||
"@rollup/plugin-babel@5.3.0":
|
||||
"integrity" "sha512-9uIC8HZOnVLrLHxayq/PTzw+uS25E14KPUBh5ktF+18Mjo5yK0ToMMx6epY0uEgkjwJw0aBW4x2horYXh8juWw=="
|
||||
"resolved" "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.0.tgz"
|
||||
"version" "5.3.0"
|
||||
dependencies:
|
||||
"@babel/helper-module-imports" "^7.10.4"
|
||||
"@rollup/pluginutils" "^3.1.0"
|
||||
|
||||
"@rollup/plugin-commonjs@^15.1.0":
|
||||
"integrity" "sha512-xCQqz4z/o0h2syQ7d9LskIMvBSH4PX5PjYdpSSvgS+pQik3WahkQVNWg3D8XJeYjZoVWnIUQYDghuEMRGrmQYQ=="
|
||||
"resolved" "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-15.1.0.tgz"
|
||||
@@ -1646,7 +1659,7 @@
|
||||
"resolved" "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz"
|
||||
"version" "1.3.1"
|
||||
|
||||
"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7":
|
||||
"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7", "@types/babel__core@^7.1.9":
|
||||
"integrity" "sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g=="
|
||||
"resolved" "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.14.tgz"
|
||||
"version" "7.1.14"
|
||||
@@ -2143,6 +2156,11 @@
|
||||
"resolved" "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz"
|
||||
"version" "4.2.2"
|
||||
|
||||
"aakansha-excalidraw@0.7.0-draft":
|
||||
"integrity" "sha512-bafyy/qQES3E+uI7YHGuMzIh2kKlTKx+NYYpHwR5QhdAdDsA+Tru56Yglo+8cLCSDncN/KyEb1ffQlYJyBqQwA=="
|
||||
"resolved" "https://registry.npmjs.org/aakansha-excalidraw/-/aakansha-excalidraw-0.7.0-draft.tgz"
|
||||
"version" "0.7.0-draft"
|
||||
|
||||
"abab@^2.0.3", "abab@^2.0.5":
|
||||
"integrity" "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q=="
|
||||
"resolved" "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz"
|
||||
@@ -2174,6 +2192,11 @@
|
||||
"resolved" "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz"
|
||||
"version" "7.2.0"
|
||||
|
||||
"acorn-walk@^8.0.0":
|
||||
"integrity" "sha512-+bpA9MJsHdZ4bgfDcpk0ozQyhhVct7rzOmO0s1IIr0AGGgKBljss8n2zp11rRP2wid5VGeh04CgeKzgat5/25A=="
|
||||
"resolved" "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.0.2.tgz"
|
||||
"version" "8.0.2"
|
||||
|
||||
"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", "acorn@^7.1.0", "acorn@^7.1.1", "acorn@^7.4.0":
|
||||
"integrity" "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A=="
|
||||
"resolved" "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz"
|
||||
@@ -2184,6 +2207,11 @@
|
||||
"resolved" "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz"
|
||||
"version" "6.4.2"
|
||||
|
||||
"acorn@^8.0.4":
|
||||
"integrity" "sha512-xYiIVjNuqtKXMxlRMDc6mZUhXehod4a3gbZ1qRlM7icK4EbxUFNLhWoPblCvFtB2Y9CIqHP3CF/rdxLItaQv8g=="
|
||||
"resolved" "https://registry.npmjs.org/acorn/-/acorn-8.1.1.tgz"
|
||||
"version" "8.1.1"
|
||||
|
||||
"acorn@^8.1.0":
|
||||
"integrity" "sha512-xYiIVjNuqtKXMxlRMDc6mZUhXehod4a3gbZ1qRlM7icK4EbxUFNLhWoPblCvFtB2Y9CIqHP3CF/rdxLItaQv8g=="
|
||||
"resolved" "https://registry.npmjs.org/acorn/-/acorn-8.1.1.tgz"
|
||||
@@ -3364,6 +3392,15 @@
|
||||
"strip-ansi" "^6.0.0"
|
||||
"wrap-ansi" "^6.2.0"
|
||||
|
||||
"cliui@^7.0.2":
|
||||
"integrity" "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ=="
|
||||
"resolved" "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz"
|
||||
"version" "7.0.4"
|
||||
dependencies:
|
||||
"string-width" "^4.2.0"
|
||||
"strip-ansi" "^6.0.0"
|
||||
"wrap-ansi" "^7.0.0"
|
||||
|
||||
"clone-deep@^4.0.1":
|
||||
"integrity" "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ=="
|
||||
"resolved" "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz"
|
||||
@@ -3469,6 +3506,11 @@
|
||||
"resolved" "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz"
|
||||
"version" "4.1.1"
|
||||
|
||||
"commander@^6.2.0":
|
||||
"integrity" "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA=="
|
||||
"resolved" "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz"
|
||||
"version" "6.2.1"
|
||||
|
||||
"common-tags@^1.8.0":
|
||||
"integrity" "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw=="
|
||||
"resolved" "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz"
|
||||
@@ -3749,6 +3791,11 @@
|
||||
"resolved" "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz"
|
||||
"version" "1.0.0"
|
||||
|
||||
"cyclist@^1.0.1":
|
||||
"integrity" "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk="
|
||||
"resolved" "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz"
|
||||
"version" "1.0.1"
|
||||
|
||||
"css-blank-pseudo@^0.1.4":
|
||||
"integrity" "sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w=="
|
||||
"resolved" "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz"
|
||||
@@ -3960,11 +4007,6 @@
|
||||
"resolved" "https://registry.npmjs.org/csstype/-/csstype-3.0.6.tgz"
|
||||
"version" "3.0.6"
|
||||
|
||||
"cyclist@^1.0.1":
|
||||
"integrity" "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk="
|
||||
"resolved" "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz"
|
||||
"version" "1.0.1"
|
||||
|
||||
"d@^1.0.1", "d@1":
|
||||
"integrity" "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA=="
|
||||
"resolved" "https://registry.npmjs.org/d/-/d-1.0.1.tgz"
|
||||
@@ -4323,7 +4365,7 @@
|
||||
"resolved" "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz"
|
||||
"version" "8.2.0"
|
||||
|
||||
"duplexer@^0.1.1":
|
||||
"duplexer@^0.1.1", "duplexer@^0.1.2":
|
||||
"integrity" "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg=="
|
||||
"resolved" "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz"
|
||||
"version" "0.1.2"
|
||||
@@ -5333,7 +5375,7 @@
|
||||
"resolved" "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz"
|
||||
"version" "1.0.0-beta.2"
|
||||
|
||||
"get-caller-file@^2.0.1":
|
||||
"get-caller-file@^2.0.1", "get-caller-file@^2.0.5":
|
||||
"integrity" "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
|
||||
"resolved" "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz"
|
||||
"version" "2.0.5"
|
||||
@@ -5504,6 +5546,13 @@
|
||||
"resolved" "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz"
|
||||
"version" "1.3.0"
|
||||
|
||||
"gzip-size@^6.0.0":
|
||||
"integrity" "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q=="
|
||||
"resolved" "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz"
|
||||
"version" "6.0.0"
|
||||
dependencies:
|
||||
"duplexer" "^0.1.2"
|
||||
|
||||
"gzip-size@5.1.1":
|
||||
"integrity" "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA=="
|
||||
"resolved" "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz"
|
||||
@@ -7427,6 +7476,11 @@
|
||||
dependencies:
|
||||
"mime-db" "1.47.0"
|
||||
|
||||
"mime@^2.3.1":
|
||||
"integrity" "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg=="
|
||||
"resolved" "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz"
|
||||
"version" "2.5.2"
|
||||
|
||||
"mime@^2.4.4":
|
||||
"integrity" "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg=="
|
||||
"resolved" "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz"
|
||||
@@ -7596,10 +7650,10 @@
|
||||
"dns-packet" "^1.3.1"
|
||||
"thunky" "^1.0.2"
|
||||
|
||||
"nanoid@^3.1.20":
|
||||
"integrity" "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw=="
|
||||
"resolved" "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz"
|
||||
"version" "3.1.20"
|
||||
"nanoid@^3.1.20", "nanoid@^3.1.22":
|
||||
"integrity" "sha512-/2ZUaJX2ANuLtTvqTlgqBQNJoQO398KyJgZloL0PZkC0dpysjncRUPsFe3DUPzz/y3h+u7C46np8RMuvF3jsSQ=="
|
||||
"resolved" "https://registry.npmjs.org/nanoid/-/nanoid-3.1.22.tgz"
|
||||
"version" "3.1.22"
|
||||
|
||||
"nanomatch@^1.2.9":
|
||||
"integrity" "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA=="
|
||||
@@ -7932,7 +7986,7 @@
|
||||
dependencies:
|
||||
"mimic-fn" "^2.1.0"
|
||||
|
||||
"open@^7.0.2":
|
||||
"open@^7.0.2", "open@^7.4.2":
|
||||
"integrity" "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q=="
|
||||
"resolved" "https://registry.npmjs.org/open/-/open-7.4.2.tgz"
|
||||
"version" "7.4.2"
|
||||
@@ -7940,6 +7994,11 @@
|
||||
"is-docker" "^2.0.0"
|
||||
"is-wsl" "^2.1.1"
|
||||
|
||||
"opener@^1.5.2":
|
||||
"integrity" "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A=="
|
||||
"resolved" "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz"
|
||||
"version" "1.5.2"
|
||||
|
||||
"opn@^5.5.0":
|
||||
"integrity" "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA=="
|
||||
"resolved" "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz"
|
||||
@@ -9424,14 +9483,14 @@
|
||||
"strip-ansi" "6.0.0"
|
||||
"text-table" "0.2.0"
|
||||
|
||||
"react-dom@^17.0.1", "react-dom@17.0.0":
|
||||
"integrity" "sha512-OGnFbxCjI2TMAZYMVxi4hqheJiN8rCEVVrL7XIGzCB6beNc4Am8M47HtkvxODZw9QgjmAPKpLba9FTu4fC1byA=="
|
||||
"resolved" "https://registry.npmjs.org/react-dom/-/react-dom-17.0.0.tgz"
|
||||
"version" "17.0.0"
|
||||
"react-dom@^17.0.1", "react-dom@17.0.1":
|
||||
"integrity" "sha512-6eV150oJZ9U2t9svnsspTMrWNyHc6chX0KzDeAOXftRa8bNeOKTTfCJ7KorIwenkHd2xqVTBTCZd79yk/lx/Ug=="
|
||||
"resolved" "https://registry.npmjs.org/react-dom/-/react-dom-17.0.1.tgz"
|
||||
"version" "17.0.1"
|
||||
dependencies:
|
||||
"loose-envify" "^1.1.0"
|
||||
"object-assign" "^4.1.1"
|
||||
"scheduler" "^0.20.0"
|
||||
"scheduler" "^0.20.1"
|
||||
|
||||
"react-error-overlay@^6.0.9":
|
||||
"integrity" "sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew=="
|
||||
@@ -9519,10 +9578,10 @@
|
||||
optionalDependencies:
|
||||
"fsevents" "^2.1.3"
|
||||
|
||||
"react@^17.0.1", "react@17.0.0":
|
||||
"integrity" "sha512-rG9bqS3LMuetoSUKHN8G3fMNuQOePKDThK6+2yXFWtoeTDLVNh/QCaxT+Jr+rNf4lwNXpx+atdn3Aa0oi8/6eQ=="
|
||||
"resolved" "https://registry.npmjs.org/react/-/react-17.0.0.tgz"
|
||||
"version" "17.0.0"
|
||||
"react@^17.0.1", "react@17.0.1":
|
||||
"integrity" "sha512-lG9c9UuMHdcAexXtigOZLX8exLWkW0Ku29qPRU8uhF2R9BN96dLCt0psvzPLlHc5OWkgymP3qwTRgbnw5BKx3w=="
|
||||
"resolved" "https://registry.npmjs.org/react/-/react-17.0.1.tgz"
|
||||
"version" "17.0.1"
|
||||
dependencies:
|
||||
"loose-envify" "^1.1.0"
|
||||
"object-assign" "^4.1.1"
|
||||
@@ -10088,6 +10147,16 @@
|
||||
"serialize-javascript" "^4.0.0"
|
||||
"terser" "^4.6.2"
|
||||
|
||||
"rollup-plugin-visualizer@^5.4.1":
|
||||
"integrity" "sha512-mwrUIfOamkCw3dCtLvgnn/H0rvNSDA1RAe0sO9uHBpmdf86j/xOX/2yeCrVh2Ia/gCGLG846JB00MW0chq8CHQ=="
|
||||
"resolved" "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.4.1.tgz"
|
||||
"version" "5.4.1"
|
||||
dependencies:
|
||||
"nanoid" "^3.1.22"
|
||||
"open" "^7.4.2"
|
||||
"source-map" "^0.7.3"
|
||||
"yargs" "^16.2.0"
|
||||
|
||||
"rollup-pluginutils@^2.8.1", "rollup-pluginutils@^2.8.2":
|
||||
"integrity" "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ=="
|
||||
"resolved" "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz"
|
||||
@@ -10095,7 +10164,7 @@
|
||||
dependencies:
|
||||
"estree-walker" "^0.6.1"
|
||||
|
||||
"rollup@^1.20.0 || ^2.0.0", "rollup@^1.20.0||^2.0.0", "rollup@^2.14.0", "rollup@^2.22.0", "rollup@>=0.60.0 <3", "rollup@>=0.66.0 <3", "rollup@2.45.2":
|
||||
"rollup@^1.20.0 || ^2.0.0", "rollup@^1.20.0||^2.0.0", "rollup@^2.0.0", "rollup@^2.14.0", "rollup@^2.22.0", "rollup@>=0.60.0 <3", "rollup@>=0.66.0 <3", "rollup@2.45.2":
|
||||
"integrity" "sha512-kRRU7wXzFHUzBIv0GfoFFIN3m9oteY4uAsKllIpQDId5cfnkWF2J130l+27dzDju0E6MScKiV0ZM5Bw8m4blYQ=="
|
||||
"resolved" "https://registry.npmjs.org/rollup/-/rollup-2.45.2.tgz"
|
||||
"version" "2.45.2"
|
||||
@@ -10205,7 +10274,7 @@
|
||||
dependencies:
|
||||
"xmlchars" "^2.2.0"
|
||||
|
||||
"scheduler@^0.20.0":
|
||||
"scheduler@^0.20.1":
|
||||
"integrity" "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ=="
|
||||
"resolved" "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz"
|
||||
"version" "0.20.2"
|
||||
@@ -10458,6 +10527,15 @@
|
||||
dependencies:
|
||||
"is-arrayish" "^0.3.1"
|
||||
|
||||
"sirv@^1.0.7":
|
||||
"integrity" "sha512-SR36i3/LSWja7AJNRBz4fF/Xjpn7lQFI30tZ434dIy+bitLYSP+ZEenHg36i23V2SGEz+kqjksg0uOGZ5LPiqg=="
|
||||
"resolved" "https://registry.npmjs.org/sirv/-/sirv-1.0.11.tgz"
|
||||
"version" "1.0.11"
|
||||
dependencies:
|
||||
"@polka/url" "^1.0.0-next.9"
|
||||
"mime" "^2.3.1"
|
||||
"totalist" "^1.0.0"
|
||||
|
||||
"sisteransi@^1.0.5":
|
||||
"integrity" "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="
|
||||
"resolved" "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz"
|
||||
@@ -11202,6 +11280,11 @@
|
||||
"resolved" "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz"
|
||||
"version" "1.0.0"
|
||||
|
||||
"totalist@^1.0.0":
|
||||
"integrity" "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g=="
|
||||
"resolved" "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz"
|
||||
"version" "1.1.0"
|
||||
|
||||
"tough-cookie@^2.3.3":
|
||||
"integrity" "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g=="
|
||||
"resolved" "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz"
|
||||
@@ -11271,11 +11354,6 @@
|
||||
dependencies:
|
||||
"tslib" "^1.8.1"
|
||||
|
||||
"tty-browserify@0.0.0":
|
||||
"integrity" "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY="
|
||||
"resolved" "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz"
|
||||
"version" "0.0.0"
|
||||
|
||||
"tunnel-agent@^0.6.0":
|
||||
"integrity" "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0="
|
||||
"resolved" "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz"
|
||||
@@ -11367,6 +11445,11 @@
|
||||
"resolved" "https://registry.npmjs.org/typescript/-/typescript-4.1.5.tgz"
|
||||
"version" "4.1.5"
|
||||
|
||||
"tty-browserify@0.0.0":
|
||||
"integrity" "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY="
|
||||
"resolved" "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz"
|
||||
"version" "0.0.0"
|
||||
|
||||
"uglify-js@^2.7.4":
|
||||
"integrity" "sha1-KcVzMUgFe7Th913zW3qcty5qWd0="
|
||||
"resolved" "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz"
|
||||
@@ -11690,6 +11773,21 @@
|
||||
"resolved" "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz"
|
||||
"version" "6.1.0"
|
||||
|
||||
"webpack-bundle-analyzer@^4.4.1":
|
||||
"integrity" "sha512-j5m7WgytCkiVBoOGavzNokBOqxe6Mma13X1asfVYtKWM3wxBiRRu1u1iG0Iol5+qp9WgyhkMmBAcvjEfJ2bdDw=="
|
||||
"resolved" "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.4.1.tgz"
|
||||
"version" "4.4.1"
|
||||
dependencies:
|
||||
"acorn" "^8.0.4"
|
||||
"acorn-walk" "^8.0.0"
|
||||
"chalk" "^4.1.0"
|
||||
"commander" "^6.2.0"
|
||||
"gzip-size" "^6.0.0"
|
||||
"lodash" "^4.17.20"
|
||||
"opener" "^1.5.2"
|
||||
"sirv" "^1.0.7"
|
||||
"ws" "^7.3.1"
|
||||
|
||||
"webpack-dev-middleware@^3.7.2":
|
||||
"integrity" "sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ=="
|
||||
"resolved" "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz"
|
||||
@@ -12059,6 +12157,15 @@
|
||||
"string-width" "^4.1.0"
|
||||
"strip-ansi" "^6.0.0"
|
||||
|
||||
"wrap-ansi@^7.0.0":
|
||||
"integrity" "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="
|
||||
"resolved" "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz"
|
||||
"version" "7.0.0"
|
||||
dependencies:
|
||||
"ansi-styles" "^4.0.0"
|
||||
"string-width" "^4.1.0"
|
||||
"strip-ansi" "^6.0.0"
|
||||
|
||||
"wrappy@1":
|
||||
"integrity" "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
"resolved" "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
|
||||
@@ -12081,7 +12188,7 @@
|
||||
dependencies:
|
||||
"async-limiter" "~1.0.0"
|
||||
|
||||
"ws@^7.4.4":
|
||||
"ws@^7.3.1", "ws@^7.4.4":
|
||||
"integrity" "sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw=="
|
||||
"resolved" "https://registry.npmjs.org/ws/-/ws-7.4.4.tgz"
|
||||
"version" "7.4.4"
|
||||
@@ -12106,6 +12213,11 @@
|
||||
"resolved" "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz"
|
||||
"version" "4.0.3"
|
||||
|
||||
"y18n@^5.0.5":
|
||||
"integrity" "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
|
||||
"resolved" "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz"
|
||||
"version" "5.0.8"
|
||||
|
||||
"yallist@^3.0.2":
|
||||
"integrity" "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
|
||||
"resolved" "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz"
|
||||
@@ -12147,6 +12259,11 @@
|
||||
"camelcase" "^5.0.0"
|
||||
"decamelize" "^1.2.0"
|
||||
|
||||
"yargs-parser@^20.2.2":
|
||||
"integrity" "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw=="
|
||||
"resolved" "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz"
|
||||
"version" "20.2.7"
|
||||
|
||||
"yargs@^13.3.2":
|
||||
"integrity" "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw=="
|
||||
"resolved" "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz"
|
||||
@@ -12180,6 +12297,19 @@
|
||||
"y18n" "^4.0.0"
|
||||
"yargs-parser" "^18.1.2"
|
||||
|
||||
"yargs@^16.2.0":
|
||||
"integrity" "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw=="
|
||||
"resolved" "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz"
|
||||
"version" "16.2.0"
|
||||
dependencies:
|
||||
"cliui" "^7.0.2"
|
||||
"escalade" "^3.1.1"
|
||||
"get-caller-file" "^2.0.5"
|
||||
"require-directory" "^2.1.1"
|
||||
"string-width" "^4.2.0"
|
||||
"y18n" "^5.0.5"
|
||||
"yargs-parser" "^20.2.2"
|
||||
|
||||
"yargs@~3.10.0":
|
||||
"integrity" "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E="
|
||||
"resolved" "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz"
|
||||
|
||||
Reference in New Issue
Block a user