From 3d75d5dcdf2a4e4c5d30bc8b19f5a947811eb493 Mon Sep 17 00:00:00 2001 From: Elio Struyf Date: Wed, 2 Dec 2020 17:37:14 +0100 Subject: [PATCH] Changes for new panel view --- .gitignore | 3 +- .vscode/launch.json | 2 +- .vscode/tasks.json | 2 +- assets/frontmatter.svg | 17 + assets/media/main.js | 23 + assets/media/reset.css | 30 + assets/media/styles.css | 132 +++ assets/media/vscode.css | 101 +++ package-lock.json | 957 +++++++++++++++++++-- package.json | 41 +- src/commands/Article.ts | 4 +- src/commands/StatusListener.ts | 11 +- src/extension.ts | 11 +- src/helpers/ArticleHelper.ts | 60 -- src/helpers/SlugHelper.ts | 63 ++ src/helpers/index.ts | 2 + src/models/PanelSettings.ts | 17 + src/viewpanel/Command.ts | 5 + src/viewpanel/CommandToCode.ts | 8 + src/viewpanel/TagType.ts | 4 + src/viewpanel/ViewPanel.tsx | 45 + src/viewpanel/components/Actions.tsx | 30 + src/viewpanel/components/DateAction.tsx | 21 + src/viewpanel/components/PublishAction.tsx | 24 + src/viewpanel/components/SeoDetails.tsx | 21 + src/viewpanel/components/SeoStatus.tsx | 25 + src/viewpanel/components/SlugAction.tsx | 29 + src/viewpanel/components/Spinner.tsx | 9 + src/viewpanel/components/Tag.tsx | 17 + src/viewpanel/components/TagPicker.tsx | 97 +++ src/viewpanel/components/Tags.tsx | 23 + src/viewpanel/hooks/useMessages.tsx | 54 ++ src/viewpanel/hooks/usePrevious.tsx | 11 + src/viewpanel/index.tsx | 6 + src/webview/ExplorerView.ts | 226 +++++ tsconfig.json | 10 +- webpack.config.js | 80 +- 37 files changed, 2054 insertions(+), 167 deletions(-) create mode 100644 assets/frontmatter.svg create mode 100644 assets/media/main.js create mode 100644 assets/media/reset.css create mode 100644 assets/media/styles.css create mode 100644 assets/media/vscode.css create mode 100644 src/helpers/SlugHelper.ts create mode 100644 src/models/PanelSettings.ts create mode 100644 src/viewpanel/Command.ts create mode 100644 src/viewpanel/CommandToCode.ts create mode 100644 src/viewpanel/TagType.ts create mode 100644 src/viewpanel/ViewPanel.tsx create mode 100644 src/viewpanel/components/Actions.tsx create mode 100644 src/viewpanel/components/DateAction.tsx create mode 100644 src/viewpanel/components/PublishAction.tsx create mode 100644 src/viewpanel/components/SeoDetails.tsx create mode 100644 src/viewpanel/components/SeoStatus.tsx create mode 100644 src/viewpanel/components/SlugAction.tsx create mode 100644 src/viewpanel/components/Spinner.tsx create mode 100644 src/viewpanel/components/Tag.tsx create mode 100644 src/viewpanel/components/TagPicker.tsx create mode 100644 src/viewpanel/components/Tags.tsx create mode 100644 src/viewpanel/hooks/useMessages.tsx create mode 100644 src/viewpanel/hooks/usePrevious.tsx create mode 100644 src/viewpanel/index.tsx create mode 100644 src/webview/ExplorerView.ts diff --git a/.gitignore b/.gitignore index 02bd6c1a..fa0302b2 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ node_modules .vscode-test/ *.vsix .DS_Store -dist \ No newline at end of file +dist +todo.md \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 506a69a2..a47e93c5 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -16,7 +16,7 @@ "outFiles": [ "${workspaceFolder}/dist/**/*.js" ], - "preLaunchTask": "npm: webpack" + "preLaunchTask": "npm: build:ext" }, { "name": "Extension Tests", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 1872cf03..5ee89177 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -18,7 +18,7 @@ }, { "type": "npm", - "script": "webpack", + "script": "build:ext", "group": { "kind": "build", "isDefault": true diff --git a/assets/frontmatter.svg b/assets/frontmatter.svg new file mode 100644 index 00000000..6b8187cc --- /dev/null +++ b/assets/frontmatter.svg @@ -0,0 +1,17 @@ + + + + +FRONT + +MATTER + + diff --git a/assets/media/main.js b/assets/media/main.js new file mode 100644 index 00000000..69118208 --- /dev/null +++ b/assets/media/main.js @@ -0,0 +1,23 @@ + +(function () { + const vscode = acquireVsCodeApi(); + + window.addEventListener('message', event => { + const message = event.data; + + switch (message.type) { + case 'addColor': + addColor(); + break; + case 'clearColors': + colors = []; + updateColorList(colors); + break; + } + }); + + window.onload = function() { + vscode.postMessage({ command: 'get-data' }); + console.log('Ready to accept data.'); + }; +}()); \ No newline at end of file diff --git a/assets/media/reset.css b/assets/media/reset.css new file mode 100644 index 00000000..b3adf277 --- /dev/null +++ b/assets/media/reset.css @@ -0,0 +1,30 @@ +html { + box-sizing: border-box; + font-size: 13px; +} + +*, +*:before, +*:after { + box-sizing: inherit; +} + +body, +h1, +h2, +h3, +h4, +h5, +h6, +p, +ol, +ul { + margin: 0; + padding: 0; + font-weight: normal; +} + +img { + max-width: 100%; + height: auto; +} \ No newline at end of file diff --git a/assets/media/styles.css b/assets/media/styles.css new file mode 100644 index 00000000..5c589ec8 --- /dev/null +++ b/assets/media/styles.css @@ -0,0 +1,132 @@ +/* Styling: https://code.visualstudio.com/api/references/theme-color */ + +@-webkit-keyframes load7 { + 0%, + 80%, + 100% { + box-shadow: 0 2.5em 0 -1.3em; + } + 40% { + box-shadow: 0 2.5em 0 0; + } +} +@keyframes load7 { + 0%, + 80%, + 100% { + box-shadow: 0 2.5em 0 -1.3em; + } + 40% { + box-shadow: 0 2.5em 0 0; + } +} + +.spinner, +.spinner:before, +.spinner:after { + border-radius: 50%; + width: 2em; + height: 2em; + animation-fill-mode: both; + animation: load7 1.8s infinite ease-in-out; +} + +.spinner { + color: var(--vscode-panelSectionHeader-foreground); + font-size: 10px; + margin: 80px auto; + position: relative; + text-indent: -9999em; + transform: translateZ(0); + animation-delay: -0.16s; +} + +.spinner:before, +.spinner:after { + content: ''; + position: absolute; + top: 0; +} + +.spinner:before { + left: -3.5em; + -webkit-animation-delay: -0.32s; + animation-delay: -0.32s; +} + +.spinner:after { + left: 3.5em; +} + + +.frontmatter h3 { + margin-bottom: 1rem; +} + +.frontmatter p, +.frontmatter h4, +.frontmatter ul { + margin-bottom: .5rem; +} + +.seo__status__details { + margin-bottom: 2rem; +} + +.not-valid { + color: var(--vscode-errorForeground); +} + +.article__actions { + margin-bottom: 2rem; +} + +.article__action { + margin-bottom: 1rem; +} + +.article__tags { + margin-bottom: 1rem; +} + +.article__tags ul { + color: var(--vscode-dropdown-foreground); + background-color: var(--vscode-dropdown-background); +} + +.article__tags li { + padding: var(--input-padding-vertical) var(--input-padding-horizontal); +} + +.article__tags li:active { + color: var(--vscode-button-foreground); + background-color: var(--vscode-button-background); +} + +.article__tags li[data-focus="true"] { + background-color: var(--vscode-button-hoverBackground); +} + +.article__tags li[aria-disabled="true"] { + display: none; +} + +.article__tags__items { + margin-top: 1rem; +} + +.article__tags__items__btn { + display: inline-block; + margin-bottom: .5rem; + margin-right: .5rem; + width: auto; +} + +.article__tags__items__btn span { + margin-left: .5rem; +} + +.article__tags__items__pill_notexists { + color: var(--vscode-inputValidation-errorForeground); + background-color: var(--vscode-inputValidation-errorBackground); +} \ No newline at end of file diff --git a/assets/media/vscode.css b/assets/media/vscode.css new file mode 100644 index 00000000..cb0a647b --- /dev/null +++ b/assets/media/vscode.css @@ -0,0 +1,101 @@ +:root { + --container-paddding: 20px; + --input-padding-vertical: 6px; + --input-padding-horizontal: 4px; + --input-margin-vertical: 4px; + --input-margin-horizontal: 0; +} + +body { + padding: 0 var(--container-paddding); + color: var(--vscode-foreground); + font-size: var(--vscode-font-size); + font-weight: var(--vscode-font-weight); + font-family: var(--vscode-font-family); + background-color: var(--vscode-editor-background); +} + +ol, +ul { + padding-left: var(--container-paddding); +} + +body > *, +form > * { + margin-block-start: var(--input-margin-vertical); + margin-block-end: var(--input-margin-vertical); +} + +*:focus { + outline-color: var(--vscode-focusBorder) !important; +} + +a { + color: var(--vscode-textLink-foreground); +} + +a:hover, +a:active { + color: var(--vscode-textLink-activeForeground); +} + +code { + font-size: var(--vscode-editor-font-size); + font-family: var(--vscode-editor-font-family); +} + +button { + border: none; + padding: var(--input-padding-vertical) var(--input-padding-horizontal); + width: 100%; + text-align: center; + outline: 1px solid transparent; + outline-offset: 2px !important; + color: var(--vscode-button-foreground); + background: var(--vscode-button-background); +} + +button:hover { + cursor: pointer; + background: var(--vscode-button-hoverBackground); +} + +button:focus { + outline-color: var(--vscode-focusBorder); +} + +button:disabled { + background: var(--vscode-button-background); + filter: brightness(40%); +} + +button.secondary { + color: var(--vscode-button-secondaryForeground); + background: var(--vscode-button-secondaryBackground); +} + +button.secondary:hover { + background: var(--vscode-button-secondaryHoverBackground); +} + +button.secondary:disabled { + background: var(--vscode-button-secondaryBackground); + filter: brightness(40%); +} + +input:not([type='checkbox']), +textarea { + display: block; + width: 100%; + border: none; + font-family: var(--vscode-font-family); + padding: var(--input-padding-vertical) var(--input-padding-horizontal); + color: var(--vscode-input-foreground); + outline-color: var(--vscode-input-border); + background-color: var(--vscode-input-background); +} + +input::placeholder, +textarea::placeholder { + color: var(--vscode-input-placeholderForeground); +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index d8a52fb4..dcf2e4e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,11 +24,124 @@ "js-tokens": "^4.0.0" } }, + "@babel/runtime": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz", + "integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + }, "@iarna/toml": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.3.tgz", "integrity": "sha512-FmuxfCuolpLl0AnQ2NHSzoUKWEJDFl63qXjzdoWBVyFCXzMGm1spBzk7LeHNoVCiWCF7mRVms9e6jEV9+MoPbg==" }, + "@material-ui/core": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.11.1.tgz", + "integrity": "sha512-aesI8lOaaw0DRIfNG+Anepf61NH5Q+cmkxJOZvI1oHkmD5cKubkZ0C7INqFKjfFpSFlFnqHkTasoM7ogFAvzOg==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/styles": "^4.11.1", + "@material-ui/system": "^4.9.14", + "@material-ui/types": "^5.1.0", + "@material-ui/utils": "^4.10.2", + "@types/react-transition-group": "^4.2.0", + "clsx": "^1.0.4", + "hoist-non-react-statics": "^3.3.2", + "popper.js": "1.16.1-lts", + "prop-types": "^15.7.2", + "react-is": "^16.8.0", + "react-transition-group": "^4.4.0" + } + }, + "@material-ui/lab": { + "version": "4.0.0-alpha.56", + "resolved": "https://registry.npmjs.org/@material-ui/lab/-/lab-4.0.0-alpha.56.tgz", + "integrity": "sha512-xPlkK+z/6y/24ka4gVJgwPfoCF4RCh8dXb1BNE7MtF9bXEBLN/lBxNTK8VAa0qm3V2oinA6xtUIdcRh0aeRtVw==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.10.2", + "clsx": "^1.0.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0" + } + }, + "@material-ui/styles": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.1.tgz", + "integrity": "sha512-GqzsFsVWT8jXa8OWAd1WD6WIaqtXr2mUPbRZ1EjkiM3Dlta4mCRaToDxkFVv6ZHfXlFjMJzdaIEvCpZOCvZTvg==", + "requires": { + "@babel/runtime": "^7.4.4", + "@emotion/hash": "^0.8.0", + "@material-ui/types": "^5.1.0", + "@material-ui/utils": "^4.9.6", + "clsx": "^1.0.4", + "csstype": "^2.5.2", + "hoist-non-react-statics": "^3.3.2", + "jss": "^10.0.3", + "jss-plugin-camel-case": "^10.0.3", + "jss-plugin-default-unit": "^10.0.3", + "jss-plugin-global": "^10.0.3", + "jss-plugin-nested": "^10.0.3", + "jss-plugin-props-sort": "^10.0.3", + "jss-plugin-rule-value-function": "^10.0.3", + "jss-plugin-vendor-prefixer": "^10.0.3", + "prop-types": "^15.7.2" + }, + "dependencies": { + "csstype": { + "version": "2.6.14", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.14.tgz", + "integrity": "sha512-2mSc+VEpGPblzAxyeR+vZhJKgYg0Og0nnRi7pmRXFYYxSfnOnW8A5wwQb4n4cE2nIOzqKOAzLCaEX6aBmNEv8A==" + } + } + }, + "@material-ui/system": { + "version": "4.9.14", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.9.14.tgz", + "integrity": "sha512-oQbaqfSnNlEkXEziDcJDDIy8pbvwUmZXWNqlmIwDqr/ZdCK8FuV3f4nxikUh7hvClKV2gnQ9djh5CZFTHkZj3w==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.9.6", + "csstype": "^2.5.2", + "prop-types": "^15.7.2" + }, + "dependencies": { + "csstype": { + "version": "2.6.14", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.14.tgz", + "integrity": "sha512-2mSc+VEpGPblzAxyeR+vZhJKgYg0Og0nnRi7pmRXFYYxSfnOnW8A5wwQb4n4cE2nIOzqKOAzLCaEX6aBmNEv8A==" + } + } + }, + "@material-ui/types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", + "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==" + }, + "@material-ui/utils": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.10.2.tgz", + "integrity": "sha512-eg29v74P7W5r6a4tWWDAAfZldXIzfyO1am2fIsC39hdUUHm/33k6pGOKPbgDjg/U/4ifmgAePy/1OjkKN6rFRw==", + "requires": { + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0" + } + }, + "@types/anymatch": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz", + "integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==", + "dev": true + }, "@types/events": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", @@ -46,12 +159,24 @@ "@types/node": "*" } }, + "@types/html-minifier-terser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", + "integrity": "sha512-giAlZwstKbmvMk1OO7WXSj4OZ0keXAcl2TQq4LWHiiPH2ByaH7WeUzng+Qej8UPxxv+8lRTuouo0iaNDBuzIBA==", + "dev": true + }, "@types/js-yaml": { "version": "3.12.1", "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-3.12.1.tgz", "integrity": "sha512-SGGAhXLHDx+PK4YLNcNGa6goPf9XRWQNAUUbffkwVGGXIxmDKWyGGL4inzq2sPmExu431Ekb9aEMn9BkPqEYFA==", "dev": true }, + "@types/json-schema": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", + "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", + "dev": true + }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", @@ -70,12 +195,113 @@ "integrity": "sha512-/opXIbfn0P+VLt+N8DE4l8Mn8rbhiJgabU96ZJ0p9mxOkIks5gh6RUnpHak7Yh0SFkyjO/ODbxsQQPV2bpMmyA==", "dev": true }, - "@types/vscode": { - "version": "1.37.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.37.0.tgz", - "integrity": "sha512-PRfeuqYuzk3vjf+puzxltIUWC+AhEGYpFX29/37w30DQSQnpf5AgMVf7GDBAdmTbWTBou+EMFz/Ne6XCM/KxzQ==", + "@types/prop-types": { + "version": "15.7.3", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", + "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" + }, + "@types/react": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.0.tgz", + "integrity": "sha512-aj/L7RIMsRlWML3YB6KZiXB3fV2t41+5RBGYF8z+tAKU43Px8C3cYUZsDvf1/+Bm4FK21QWBrDutu8ZJ/70qOw==", + "requires": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-dom": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.0.tgz", + "integrity": "sha512-lUqY7OlkF/RbNtD5nIq7ot8NquXrdFrjSOR6+w9a9RFQevGi1oZO1dcJbXMeONAPKtZ2UrZOEJ5UOCVsxbLk/g==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, + "@types/react-transition-group": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.0.tgz", + "integrity": "sha512-/QfLHGpu+2fQOqQaXh8MG9q03bFENooTb/it4jr5kKaZlDQfWvjqWZg48AwzPVMBHlRuTRAY7hRHCEOXz5kV6w==", + "requires": { + "@types/react": "*" + } + }, + "@types/source-list-map": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", + "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", "dev": true }, + "@types/tapable": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.6.tgz", + "integrity": "sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==", + "dev": true + }, + "@types/uglify-js": { + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.11.1.tgz", + "integrity": "sha512-7npvPKV+jINLu1SpSYVWG8KvyJBhBa8tmzMMdDoVc2pWUYHN8KIXlPJhjJ4LT97c4dXJA2SHL/q6ADbDriZN+Q==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@types/vscode": { + "version": "1.51.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.51.0.tgz", + "integrity": "sha512-C/jZ35OT5k/rsJyAK8mS1kM++vMcm89oSWegkzxRCvHllIq0cToZAkIDs6eCY4SKrvik3nrhELizyLcM0onbQA==", + "dev": true + }, + "@types/webpack": { + "version": "4.41.25", + "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.25.tgz", + "integrity": "sha512-cr6kZ+4m9lp86ytQc1jPOJXgINQyz3kLLunZ57jznW+WIAL0JqZbGubQk4GlD42MuQL5JGOABrxdpqqWeovlVQ==", + "dev": true, + "requires": { + "@types/anymatch": "*", + "@types/node": "*", + "@types/tapable": "*", + "@types/uglify-js": "*", + "@types/webpack-sources": "*", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@types/webpack-sources": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-2.0.0.tgz", + "integrity": "sha512-a5kPx98CNFRKQ+wqawroFunvFqv7GHm/3KOI52NY9xWADgc8smu4R6prt4EU/M4QfVjvgBkMqU4fBhw3QfMVkg==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/source-list-map": "*", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, "@webassemblyjs/ast": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", @@ -264,9 +490,9 @@ "dev": true }, "acorn": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", - "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", "dev": true }, "agent-base": { @@ -279,9 +505,9 @@ } }, "ajv": { - "version": "6.12.4", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz", - "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==", + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -501,9 +727,9 @@ } }, "base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "dev": true }, "big.js": { @@ -541,6 +767,12 @@ "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==", "dev": true }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -610,21 +842,13 @@ } }, "browserify-rsa": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", - "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", "dev": true, "requires": { - "bn.js": "^4.1.0", + "bn.js": "^5.0.0", "randombytes": "^2.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.11.9", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", - "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", - "dev": true - } } }, "browserify-sign": { @@ -747,6 +971,16 @@ "unset-value": "^1.0.0" } }, + "camel-case": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.1.tgz", + "integrity": "sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q==", + "dev": true, + "requires": { + "pascal-case": "^3.1.1", + "tslib": "^1.10.0" + } + }, "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -776,9 +1010,9 @@ } }, "chokidar": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz", - "integrity": "sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", + "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", "dev": true, "optional": true, "requires": { @@ -789,7 +1023,7 @@ "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", - "readdirp": "~3.4.0" + "readdirp": "~3.5.0" } }, "chownr": { @@ -840,6 +1074,23 @@ } } }, + "clean-css": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", + "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", + "dev": true, + "requires": { + "source-map": "~0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, "cliui": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", @@ -851,6 +1102,11 @@ "wrap-ansi": "^2.0.0" } }, + "clsx": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", + "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==" + }, "code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", @@ -1033,6 +1289,38 @@ "randomfill": "^1.0.3" } }, + "css-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "dev": true, + "requires": { + "boolbase": "~1.0.0", + "css-what": "2.1", + "domutils": "1.5.1", + "nth-check": "~1.0.1" + } + }, + "css-vendor": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", + "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", + "requires": { + "@babel/runtime": "^7.8.3", + "is-in-browser": "^1.0.2" + } + }, + "css-what": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz", + "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==", + "dev": true + }, + "csstype": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.5.tgz", + "integrity": "sha512-uVDi8LpBUKQj6sdxNaTetL6FpeCqTjOvAQuQUa/qAqq8oOd4ivkbhgnqayl0dnPal8Tb/yB1tF+gOvCBiicaiQ==" + }, "cyclist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", @@ -1157,12 +1445,83 @@ } } }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "requires": { + "utila": "~0.4" + } + }, + "dom-helpers": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.0.tgz", + "integrity": "sha512-Ru5o9+V8CpunKnz5LGgWXkmrH/20cGKwcHwS4m73zIvs54CN9epEmT/HLqFJW3kXpakAFkEdzgy1hzlJe3E4OQ==", + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.2.tgz", + "integrity": "sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA==", + "dev": true + } + } + }, "domain-browser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", "dev": true }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "dev": true + }, + "domhandler": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", + "dev": true, + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "dot-case": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.3.tgz", + "integrity": "sha512-7hwEmg6RiSQfm/GwPL4AAWXKy3YNNZA3oFv2Pdiey0mwkRCPZ9x6SZbkLcn8Ma5PYeVokzoD4Twv2n7LKp5WeA==", + "dev": true, + "requires": { + "no-case": "^3.0.3", + "tslib": "^1.10.0" + } + }, "duplexify": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", @@ -1230,6 +1589,12 @@ "tapable": "^1.0.0" } }, + "entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "dev": true + }, "errno": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", @@ -1989,6 +2354,14 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + }, "homedir-polyfill": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", @@ -1998,6 +2371,179 @@ "parse-passwd": "^1.0.0" } }, + "html-loader": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-1.3.2.tgz", + "integrity": "sha512-DEkUwSd0sijK5PF3kRWspYi56XP7bTNkyg5YWSzBdjaSDmvCufep5c4Vpb3PBf6lUL0YPtLwBfy9fL0t5hBAGA==", + "dev": true, + "requires": { + "html-minifier-terser": "^5.1.1", + "htmlparser2": "^4.1.0", + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "dom-serializer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.1.0.tgz", + "integrity": "sha512-ox7bvGXt2n+uLWtCRLybYx60IrOlWL/aCebWJk1T0d4m3y2tzf4U3ij9wBMUb6YJZpz06HCCYuyCDveE2xXmzQ==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^3.0.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.2.tgz", + "integrity": "sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA==", + "dev": true + }, + "domhandler": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", + "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1" + } + }, + "domutils": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.4.2.tgz", + "integrity": "sha512-NKbgaM8ZJOecTZsIzW5gSuplsX2IWW2mIK7xVr8hTQF2v1CJWTmLZ1HOCh5sH+IzVPAGE5IucooOkvwBRAdowA==", + "dev": true, + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.0.1", + "domhandler": "^3.3.0" + } + }, + "htmlparser2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz", + "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^3.0.0", + "domutils": "^2.0.0", + "entities": "^2.0.0" + } + }, + "json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "html-minifier-terser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", + "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==", + "dev": true, + "requires": { + "camel-case": "^4.1.1", + "clean-css": "^4.2.3", + "commander": "^4.1.1", + "he": "^1.2.0", + "param-case": "^3.0.3", + "relateurl": "^0.2.7", + "terser": "^4.6.3" + }, + "dependencies": { + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true + } + } + }, + "html-webpack-plugin": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.5.0.tgz", + "integrity": "sha512-MouoXEYSjTzCrjIxWwg8gxL5fE2X2WZJLmBYXlaJhQUH5K/b5OrqmV7T4dB7iu0xkmJ6JlUuV6fFVtnqbPopZw==", + "dev": true, + "requires": { + "@types/html-minifier-terser": "^5.0.0", + "@types/tapable": "^1.0.5", + "@types/webpack": "^4.41.8", + "html-minifier-terser": "^5.0.1", + "loader-utils": "^1.2.3", + "lodash": "^4.17.15", + "pretty-error": "^2.1.1", + "tapable": "^1.1.3", + "util.promisify": "1.0.0" + } + }, + "htmlparser2": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz", + "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==", + "dev": true, + "requires": { + "domelementtype": "^1.3.1", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "entities": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", + "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==", + "dev": true + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, "http-proxy-agent": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", @@ -2041,10 +2587,15 @@ "debug": "^3.1.0" } }, + "hyphenate-style-name": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", + "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" + }, "ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "dev": true }, "iferr": { @@ -2069,6 +2620,14 @@ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, + "indefinite-observable": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/indefinite-observable/-/indefinite-observable-2.0.1.tgz", + "integrity": "sha512-G8vgmork+6H9S8lUAg1gtXEj2JxIQTo0g2PbFiYOdjkziSI0F7UYBiVwhZRuixhBCNGczAls34+5HJPyZysvxQ==", + "requires": { + "symbol-observable": "1.2.0" + } + }, "infer-owner": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", @@ -2235,6 +2794,11 @@ "is-extglob": "^2.1.1" } }, + "is-in-browser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", + "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=" + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -2307,8 +2871,7 @@ "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "js-yaml": { "version": "3.13.1", @@ -2349,6 +2912,85 @@ } } }, + "jss": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.5.0.tgz", + "integrity": "sha512-B6151NvG+thUg3murLNHRPLxTLwQ13ep4SH5brj4d8qKtogOx/jupnpfkPGSHPqvcwKJaCLctpj2lEk+5yGwMw==", + "requires": { + "@babel/runtime": "^7.3.1", + "csstype": "^3.0.2", + "indefinite-observable": "^2.0.1", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-camel-case": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.5.0.tgz", + "integrity": "sha512-GSjPL0adGAkuoqeYiXTgO7PlIrmjv5v8lA6TTBdfxbNYpxADOdGKJgIEkffhlyuIZHlPuuiFYTwUreLUmSn7rg==", + "requires": { + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "10.5.0" + } + }, + "jss-plugin-default-unit": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.5.0.tgz", + "integrity": "sha512-rsbTtZGCMrbcb9beiDd+TwL991NGmsAgVYH0hATrYJtue9e+LH/Gn4yFD1ENwE+3JzF3A+rPnM2JuD9L/SIIWw==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.5.0" + } + }, + "jss-plugin-global": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.5.0.tgz", + "integrity": "sha512-FZd9+JE/3D7HMefEG54fEC0XiQ9rhGtDHAT/ols24y8sKQ1D5KIw6OyXEmIdKFmACgxZV2ARQ5pAUypxkk2IFQ==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.5.0" + } + }, + "jss-plugin-nested": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.5.0.tgz", + "integrity": "sha512-ejPlCLNlEGgx8jmMiDk/zarsCZk+DV0YqXfddpgzbO9Toamo0HweCFuwJ3ZO40UFOfqKwfpKMVH/3HUXgxkTMg==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.5.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-props-sort": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.5.0.tgz", + "integrity": "sha512-kTLRvrOetFKz5vM88FAhLNeJIxfjhCepnvq65G7xsAQ/Wgy7HwO1BS/2wE5mx8iLaAWC6Rj5h16mhMk9sKdZxg==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.5.0" + } + }, + "jss-plugin-rule-value-function": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.5.0.tgz", + "integrity": "sha512-jXINGr8BSsB13JVuK274oEtk0LoooYSJqTBCGeBu2cG/VJ3+4FPs1gwLgsq24xTgKshtZ+WEQMVL34OprLidRA==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.5.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-vendor-prefixer": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.5.0.tgz", + "integrity": "sha512-rux3gmfwDdOKCLDx0IQjTwTm03IfBa+Rm/hs747cOw5Q7O3RaTUIMPKjtVfc31Xr/XI9Abz2XEupk1/oMQ7zRA==", + "requires": { + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.8", + "jss": "10.5.0" + } + }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -2406,6 +3048,23 @@ "chalk": "^2.0.1" } }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lower-case": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.1.tgz", + "integrity": "sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ==", + "dev": true, + "requires": { + "tslib": "^1.10.0" + } + }, "lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -2685,9 +3344,9 @@ "dev": true }, "nan": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", - "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==", + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", + "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", "dev": true, "optional": true }, @@ -2743,6 +3402,16 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "no-case": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.3.tgz", + "integrity": "sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw==", + "dev": true, + "requires": { + "lower-case": "^2.0.1", + "tslib": "^1.10.0" + } + }, "node-environment-flags": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", @@ -2808,6 +3477,15 @@ "path-key": "^2.0.0" } }, + "nth-check": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", + "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==", + "dev": true, + "requires": { + "boolbase": "~1.0.0" + } + }, "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", @@ -2817,8 +3495,7 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-copy": { "version": "0.1.0", @@ -2988,6 +3665,16 @@ "readable-stream": "^2.1.5" } }, + "param-case": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.3.tgz", + "integrity": "sha512-VWBVyimc1+QrzappRs7waeN2YmoZFCGXWASRYX1/rGHtXqEcrGEIDm+jqIwFa2fRXNgQEwrxaYuIrX0WcAguTA==", + "dev": true, + "requires": { + "dot-case": "^3.0.3", + "tslib": "^1.10.0" + } + }, "parse-asn1": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", @@ -3007,6 +3694,16 @@ "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", "dev": true }, + "pascal-case": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.1.tgz", + "integrity": "sha512-XIeHKqIrsquVTQL2crjq3NfJUxmdLasn3TYOU0VBM+UX2a6ztAWBlJQBePLGY7VHW8+2dRadeIPK5+KImwTxQA==", + "dev": true, + "requires": { + "no-case": "^3.0.3", + "tslib": "^1.10.0" + } + }, "pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", @@ -3084,12 +3781,35 @@ "find-up": "^3.0.0" } }, + "popper.js": { + "version": "1.16.1-lts", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz", + "integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==" + }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", "dev": true }, + "pretty-error": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz", + "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", + "dev": true, + "requires": { + "lodash": "^4.17.20", + "renderkid": "^2.0.4" + }, + "dependencies": { + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + } + } + }, "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -3108,6 +3828,16 @@ "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", "dev": true }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -3206,6 +3936,41 @@ "safe-buffer": "^5.1.0" } }, + "react": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/react/-/react-17.0.1.tgz", + "integrity": "sha512-lG9c9UuMHdcAexXtigOZLX8exLWkW0Ku29qPRU8uhF2R9BN96dLCt0psvzPLlHc5OWkgymP3qwTRgbnw5BKx3w==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "react-dom": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.1.tgz", + "integrity": "sha512-6eV150oJZ9U2t9svnsspTMrWNyHc6chX0KzDeAOXftRa8bNeOKTTfCJ7KorIwenkHd2xqVTBTCZd79yk/lx/Ug==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "scheduler": "^0.20.1" + } + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "react-transition-group": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz", + "integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==", + "requires": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + } + }, "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -3222,15 +3987,20 @@ } }, "readdirp": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", - "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", + "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", "dev": true, "optional": true, "requires": { "picomatch": "^2.2.1" } }, + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -3262,6 +4032,12 @@ } } }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "dev": true + }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -3269,6 +4045,42 @@ "dev": true, "optional": true }, + "renderkid": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.4.tgz", + "integrity": "sha512-K2eXrSOJdq+HuKzlcjOlGoOarUu5SDguDEhE7+Ah4zuOWL40j8A/oHvLlLob9PSTNvVnBd+/q0Er1QfpEuem5g==", + "dev": true, + "requires": { + "css-select": "^1.1.0", + "dom-converter": "^0.2", + "htmlparser2": "^3.3.0", + "lodash": "^4.17.20", + "strip-ansi": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, "repeat-element": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", @@ -3401,6 +4213,15 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "scheduler": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.1.tgz", + "integrity": "sha512-LKTe+2xNJBNxu/QhHvDR14wUXHRQbVY5ZOYpOGWRzhydZUqrLb2JBvLPY7cAqFmqrWuDED0Mjk7013SZiOz6Bw==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, "schema-utils": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", @@ -3820,6 +4641,11 @@ "has-flag": "^3.0.0" } }, + "symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" + }, "tapable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", @@ -3881,14 +4707,19 @@ } }, "timers-browserify": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", - "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", "dev": true, "requires": { "setimmediate": "^1.0.4" } }, + "tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, "to-arraybuffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", @@ -4177,6 +5008,22 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", + "dev": true + }, "v8-compile-cache": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz", @@ -4201,21 +5048,21 @@ } }, "watchpack": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.4.tgz", - "integrity": "sha512-aWAgTW4MoSJzZPAicljkO1hsi1oKj/RRq/OJQh2PKI2UKL04c2Bs+MBOB+BBABHTXJpf9mCwHN7ANCvYsvY2sg==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", + "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", "dev": true, "requires": { "chokidar": "^3.4.1", "graceful-fs": "^4.1.2", "neo-async": "^2.5.0", - "watchpack-chokidar2": "^2.0.0" + "watchpack-chokidar2": "^2.0.1" } }, "watchpack-chokidar2": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.0.tgz", - "integrity": "sha512-9TyfOyN/zLUbA288wZ8IsMZ+6cbzvsNyEzSBp6e/zkifi6xxbl8SmQ/CxQq32k8NNqrdVEVUVSEf56L4rQ/ZxA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", + "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", "dev": true, "optional": true, "requires": { @@ -4473,9 +5320,9 @@ } }, "webpack": { - "version": "4.44.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.44.1.tgz", - "integrity": "sha512-4UOGAohv/VGUNQJstzEywwNxqX417FnjZgZJpJQegddzPmTvph37eBIRbRTfdySXzVtJXLJfbMN3mMYhM6GdmQ==", + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.44.2.tgz", + "integrity": "sha512-6KJVGlCxYdISyurpQ0IPTklv+DULv05rs2hseIXer6D7KrUicRDLFb4IUM1S6LUAKypPM/nSiVSuv8jHu1m3/Q==", "dev": true, "requires": { "@webassemblyjs/ast": "1.9.0", diff --git a/package.json b/package.json index 722276aa..21b47bf4 100644 --- a/package.json +++ b/package.json @@ -47,10 +47,31 @@ "onCommand:frontMatter.setDate", "onCommand:frontMatter.setLastModifiedDate", "onCommand:frontMatter.generateSlug", - "onCommand:frontMatter.createFromTemplate" + "onCommand:frontMatter.createFromTemplate", + "onView:frontMatter.explorer" ], "main": "./dist/extension", "contributes": { + "viewsContainers": { + "activitybar": [ + { + "id": "frontmatter-explorer", + "title": "FrontMatter", + "icon": "assets/frontmatter.svg" + } + ] + }, + "views": { + "frontmatter-explorer": [ + { + "id": "frontMatter.explorer", + "name": "FrontMatter", + "icon": "assets/frontmatter.svg", + "contextualTitle": "FrontMatter", + "type": "webview" + } + ] + }, "configuration": { "title": "Front Matter: Configuration", "properties": { @@ -191,8 +212,8 @@ }, "scripts": { "vscode:prepublish": "webpack --mode production", - "webpack": "webpack --mode development", - "webpack-dev": "webpack --mode development --watch", + "build:ext": "webpack --mode development", + "dev:ext": "webpack --mode development --watch", "test-compile": "tsc -p ./" }, "devDependencies": { @@ -200,19 +221,27 @@ "@types/js-yaml": "3.12.1", "@types/mocha": "^5.2.6", "@types/node": "^10.12.21", - "@types/vscode": "^1.37.0", + "@types/react": "17.0.0", + "@types/react-dom": "17.0.0", + "@types/vscode": "1.51.0", "date-fns": "2.0.1", "glob": "^7.1.4", "gray-matter": "4.0.2", + "html-loader": "1.3.2", + "html-webpack-plugin": "4.5.0", "mocha": "^6.1.4", "ts-loader": "8.0.3", "tslint": "^5.12.1", "typescript": "4.0.2", "vscode-test": "^1.0.2", - "webpack": "4.44.1", + "webpack": "4.44.2", "webpack-cli": "3.3.12" }, "dependencies": { - "@iarna/toml": "2.2.3" + "@iarna/toml": "2.2.3", + "@material-ui/core": "4.11.1", + "@material-ui/lab": "4.0.0-alpha.56", + "react": "17.0.1", + "react-dom": "17.0.1" } } diff --git a/src/commands/Article.ts b/src/commands/Article.ts index 2415c68d..2885cbf8 100644 --- a/src/commands/Article.ts +++ b/src/commands/Article.ts @@ -3,7 +3,7 @@ import * as vscode from 'vscode'; import { TaxonomyType } from "../models"; import { CONFIG_KEY, SETTING_DATE_FORMAT, EXTENSION_NAME, SETTING_SLUG_PREFIX, SETTING_SLUG_SUFFIX, SETTING_DATE_FIELD } from "../constants/settings"; import { format } from "date-fns"; -import { ArticleHelper, SettingsHelper } from '../helpers'; +import { ArticleHelper, SettingsHelper, SlugHelper } from '../helpers'; import matter = require('gray-matter'); @@ -161,7 +161,7 @@ export class Article { } const articleTitle: string = article.data["title"]; - const slug = ArticleHelper.createSlug(articleTitle); + const slug = SlugHelper.createSlug(articleTitle); if (slug) { article.data["slug"] = `${prefix}${slug}${suffix}`; ArticleHelper.update(editor, article); diff --git a/src/commands/StatusListener.ts b/src/commands/StatusListener.ts index a5bbbde9..e940f7fb 100644 --- a/src/commands/StatusListener.ts +++ b/src/commands/StatusListener.ts @@ -2,6 +2,7 @@ import { SETTING_SEO_DESCRIPTION_LENGTH, SETTING_SEO_TITLE_LENGTH } from './../c import * as vscode from 'vscode'; import { CONFIG_KEY } from '../constants'; import { ArticleHelper, SeoHelper } from '../helpers'; +import { ExplorerView } from '../webview/ExplorerView'; export class StatusListener { @@ -38,8 +39,8 @@ export class StatusListener { // Retrieve the SEO config properties const config = vscode.workspace.getConfiguration(CONFIG_KEY); - let titleLength = config.get(SETTING_SEO_TITLE_LENGTH) as number || -1; - let descLength = config.get(SETTING_SEO_DESCRIPTION_LENGTH) as number || -1; + const titleLength = config.get(SETTING_SEO_TITLE_LENGTH) as number || -1; + const descLength = config.get(SETTING_SEO_DESCRIPTION_LENGTH) as number || -1; if (article.data.title && titleLength > -1) { SeoHelper.checkLength(editor, collection, article, "title", titleLength); @@ -49,6 +50,12 @@ export class StatusListener { SeoHelper.checkLength(editor, collection, article, "description", descLength); } } + + const panel = ExplorerView.getInstance(); + if (panel && panel.visible) { + panel.pushMetadata(article!.data); + } + return; } catch (e) { // Nothing to do diff --git a/src/extension.ts b/src/extension.ts index 8364e060..be19004b 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -2,14 +2,22 @@ import * as vscode from 'vscode'; import { Article, Settings, StatusListener } from './commands'; import { Template } from './commands/Template'; import { TaxonomyType } from './models'; +import { ExplorerView } from './webview/ExplorerView'; let frontMatterStatusBar: vscode.StatusBarItem; let debouncer: { (fnc: any, time: number): void; }; let collection: vscode.DiagnosticCollection; -export function activate({ subscriptions }: vscode.ExtensionContext) { +export function activate({ subscriptions, extensionUri }: vscode.ExtensionContext) { collection = vscode.languages.createDiagnosticCollection('frontMatter'); + const explorerSidebar = ExplorerView.getInstance(extensionUri); + let explorerView = vscode.window.registerWebviewViewProvider(ExplorerView.viewType, explorerSidebar, { + webviewOptions: { + retainContextWhenHidden: true + } + }); + let insertTags = vscode.commands.registerCommand('frontMatter.insertTags', () => { Article.insert(TaxonomyType.Tag); }); @@ -75,6 +83,7 @@ export function activate({ subscriptions }: vscode.ExtensionContext) { // Subscribe all commands subscriptions.push(insertTags); + subscriptions.push(explorerView); subscriptions.push(insertCategories); subscriptions.push(createTag); subscriptions.push(createCategory); diff --git a/src/helpers/ArticleHelper.ts b/src/helpers/ArticleHelper.ts index 26c804cc..894b5145 100644 --- a/src/helpers/ArticleHelper.ts +++ b/src/helpers/ArticleHelper.ts @@ -1,8 +1,6 @@ import * as vscode from 'vscode'; import * as matter from "gray-matter"; import * as fs from "fs"; -import { stopWords } from '../constants/stopwords-en'; -import { charMap } from '../constants/charMap'; import { CONFIG_KEY, SETTING_INDENT_ARRAY, SETTING_REMOVE_QUOTES } from '../constants'; import { DumpOptions } from 'js-yaml'; import { TomlEngine, getFmLanguage, getFormatOpts } from './TomlEngine'; @@ -98,62 +96,4 @@ export class ArticleHelper { indent: spaces || 2 } as DumpOptions as any)); } - - /** - * Generate the slug - * - * @param articleTitle - */ - public static createSlug(articleTitle: string): string | null { - if (!articleTitle) { - return null; - } - - // Remove punctuation from input string, and split it into words. - let cleanTitle = this.removePunctuation(articleTitle); - cleanTitle = cleanTitle.toLowerCase(); - // Split into words - let words = cleanTitle.split(/\s/); - // Removing stop words - words = this.removeStopWords(words); - cleanTitle = words.join("-"); - cleanTitle = this.replaceCharacters(cleanTitle); - return cleanTitle; - } - - /** - * Remove links, periods, commas, semi-colons, etc. - * - * @param value - */ - private static removePunctuation(value: string): string { - const punctuationless = value.replace(/[\.,-\/#!$@%\^&\*;:{}=\-_`'"~()+\?<>]/g, " "); - // Remove double spaces - return punctuationless.replace(/\s{2,}/g," "); - } - - /** - * Remove stop words - * - * @param words - */ - private static removeStopWords(words: string[]) { - const validWords: string[] = []; - for (const word of words) { - if (stopWords.indexOf(word.toLowerCase()) === -1) { - validWords.push(word); - } - } - return validWords; - } - - /** - * Replace characters from title - * - * @param value - */ - private static replaceCharacters(value: string) { - const characters = [...value]; - return characters.map(c => charMap[c] || c).join(""); - } } \ No newline at end of file diff --git a/src/helpers/SlugHelper.ts b/src/helpers/SlugHelper.ts new file mode 100644 index 00000000..00fdc37b --- /dev/null +++ b/src/helpers/SlugHelper.ts @@ -0,0 +1,63 @@ +import { stopWords } from '../constants/stopwords-en'; +import { charMap } from '../constants/charMap'; + +export class SlugHelper { + + /** + * Generate the slug + * + * @param articleTitle + */ + public static createSlug(articleTitle: string): string | null { + if (!articleTitle) { + return null; + } + + // Remove punctuation from input string, and split it into words. + let cleanTitle = this.removePunctuation(articleTitle); + cleanTitle = cleanTitle.toLowerCase(); + // Split into words + let words = cleanTitle.split(/\s/); + // Removing stop words + words = this.removeStopWords(words); + cleanTitle = words.join("-"); + cleanTitle = this.replaceCharacters(cleanTitle); + return cleanTitle; + } + + /** + * Remove links, periods, commas, semi-colons, etc. + * + * @param value + */ + private static removePunctuation(value: string): string { + const punctuationless = value.replace(/[\.,-\/#!$@%\^&\*;:{}=\-_`'"~()+\?<>]/g, " "); + // Remove double spaces + return punctuationless.replace(/\s{2,}/g," "); + } + + /** + * Remove stop words + * + * @param words + */ + private static removeStopWords(words: string[]) { + const validWords: string[] = []; + for (const word of words) { + if (stopWords.indexOf(word.toLowerCase()) === -1) { + validWords.push(word); + } + } + return validWords; + } + + /** + * Replace characters from title + * + * @param value + */ + private static replaceCharacters(value: string) { + const characters = [...value]; + return characters.map(c => charMap[c] || c).join(""); + } +} \ No newline at end of file diff --git a/src/helpers/index.ts b/src/helpers/index.ts index 88ec1f5d..c8afbcab 100644 --- a/src/helpers/index.ts +++ b/src/helpers/index.ts @@ -1,6 +1,8 @@ export * from './ArticleHelper'; export * from './FilesHelper'; +export * from './Sanitize'; export * from './SeoHelper'; export * from './SettingsHelper'; +export * from './SlugHelper'; export * from './StringHelpers'; export * from './TomlEngine'; diff --git a/src/models/PanelSettings.ts b/src/models/PanelSettings.ts new file mode 100644 index 00000000..30b0154f --- /dev/null +++ b/src/models/PanelSettings.ts @@ -0,0 +1,17 @@ + +export interface PanelSettings { + seo: SEO; + slug: Slug; + tags: string[]; + categories: string[]; +} + +export interface SEO { + title: number; + description: number; +} + +export interface Slug { + prefix: number; + suffix: number; +} \ No newline at end of file diff --git a/src/viewpanel/Command.ts b/src/viewpanel/Command.ts new file mode 100644 index 00000000..829ae865 --- /dev/null +++ b/src/viewpanel/Command.ts @@ -0,0 +1,5 @@ +export enum Command { + loading = "loading", + metadata = "metadata", + settings = "settings" +} \ No newline at end of file diff --git a/src/viewpanel/CommandToCode.ts b/src/viewpanel/CommandToCode.ts new file mode 100644 index 00000000..52c9e630 --- /dev/null +++ b/src/viewpanel/CommandToCode.ts @@ -0,0 +1,8 @@ +export enum CommandToCode { + getData = "get-data", + updateSlug = 'update-slug', + updateDate = 'update-date', + publish = 'publish', + updateTags = "update-tags", + updateCategories = "update-categories" +} \ No newline at end of file diff --git a/src/viewpanel/TagType.ts b/src/viewpanel/TagType.ts new file mode 100644 index 00000000..931bb0ae --- /dev/null +++ b/src/viewpanel/TagType.ts @@ -0,0 +1,4 @@ +export enum TagType { + tags = "Tags", + categories = "Categories" +} \ No newline at end of file diff --git a/src/viewpanel/ViewPanel.tsx b/src/viewpanel/ViewPanel.tsx new file mode 100644 index 00000000..3291e68d --- /dev/null +++ b/src/viewpanel/ViewPanel.tsx @@ -0,0 +1,45 @@ +import * as React from 'react'; +import { Actions } from './components/Actions'; +import { SeoStatus } from './components/SeoStatus'; +import { Spinner } from './components/Spinner'; +import { TagPicker } from './components/TagPicker'; +import useMessages from './hooks/useMessages'; +import { TagType } from './TagType'; + +export interface IViewPanelProps { +} + +export const ViewPanel: React.FunctionComponent = (props: React.PropsWithChildren) => { + const { loading, metadata, settings } = useMessages(); + + if (loading) { + return ( + + ); + } + + if (!metadata || Object.keys(metadata).length === 0) { + return ( +
+

Current view/file is not supported by FrontMatter.

+
+ ); + } + + return ( +
+ { + settings && settings.seo && + } + { + settings && metadata && + } + { + (settings && settings.tags && settings.tags.length > 0) && + } + { + (settings && settings.categories && settings.categories.length > 0) && + } +
+ ); +}; \ No newline at end of file diff --git a/src/viewpanel/components/Actions.tsx b/src/viewpanel/components/Actions.tsx new file mode 100644 index 00000000..42b67fb9 --- /dev/null +++ b/src/viewpanel/components/Actions.tsx @@ -0,0 +1,30 @@ +import * as React from 'react'; +import { PanelSettings } from '../../models/PanelSettings'; +import { DateAction } from './DateAction'; +import { PublishAction } from './PublishAction'; +import { SlugAction } from './SlugAction'; + +export interface IActionsProps { + metadata: any; + settings: PanelSettings; +} + +export const Actions: React.FunctionComponent = (props: React.PropsWithChildren) => { + const { metadata, settings } = props; + + if (!metadata || Object.keys(metadata).length === 0 || !settings) { + return null; + } + + return ( +
+

Actions

+ + { metadata && metadata.title && } + + + + { metadata && typeof metadata.draft !== undefined && } +
+ ); +}; \ No newline at end of file diff --git a/src/viewpanel/components/DateAction.tsx b/src/viewpanel/components/DateAction.tsx new file mode 100644 index 00000000..67b67add --- /dev/null +++ b/src/viewpanel/components/DateAction.tsx @@ -0,0 +1,21 @@ + + +import * as React from 'react'; +import { CommandToCode } from '../CommandToCode'; +import useMessages from '../hooks/useMessages'; + +export interface IDateActionProps {} + +export const DateAction: React.FunctionComponent = (props: React.PropsWithChildren) => { + const { sendMessage } = useMessages(); + + const setDate = () => { + sendMessage(CommandToCode.updateDate); + }; + + return ( +
+ +
+ ); +}; \ No newline at end of file diff --git a/src/viewpanel/components/PublishAction.tsx b/src/viewpanel/components/PublishAction.tsx new file mode 100644 index 00000000..49a49298 --- /dev/null +++ b/src/viewpanel/components/PublishAction.tsx @@ -0,0 +1,24 @@ + + +import * as React from 'react'; +import { CommandToCode } from '../CommandToCode'; +import useMessages from '../hooks/useMessages'; + +export interface IPublishActionProps { + draft: boolean; +} + +export const PublishAction: React.FunctionComponent = (props: React.PropsWithChildren) => { + const { sendMessage } = useMessages(); + const { draft } = props; + + const publish = () => { + sendMessage(CommandToCode.publish); + }; + + return ( +
+ +
+ ); +}; \ No newline at end of file diff --git a/src/viewpanel/components/SeoDetails.tsx b/src/viewpanel/components/SeoDetails.tsx new file mode 100644 index 00000000..c85179e0 --- /dev/null +++ b/src/viewpanel/components/SeoDetails.tsx @@ -0,0 +1,21 @@ +import * as React from 'react'; + +export interface ISeoDetailsProps { + allowedLength: number; + title: string; + value: string; +} + +export const SeoDetails: React.FunctionComponent = (props: React.PropsWithChildren) => { + const { allowedLength, title, value } = props; + + return ( +
+

{title}

+
    +
  • Length: {value.length}
  • +
  • Allowed length: {allowedLength}
  • +
+
+ ); +}; \ No newline at end of file diff --git a/src/viewpanel/components/SeoStatus.tsx b/src/viewpanel/components/SeoStatus.tsx new file mode 100644 index 00000000..466683bc --- /dev/null +++ b/src/viewpanel/components/SeoStatus.tsx @@ -0,0 +1,25 @@ +import * as React from 'react'; +import { SEO } from '../../models/PanelSettings'; +import { SeoDetails } from './SeoDetails'; + +export interface ISeoStatusProps { + seo: SEO; + data: any; +} + +export const SeoStatus: React.FunctionComponent = (props: React.PropsWithChildren) => { + const { data, seo } = props; + const { title, description } = data; + + if (!title && !description) { + return null; + } + + return ( +
+

SEO Status

+ { (title && seo.title > 0) && } + { (description && seo.description > 0) && } +
+ ); +}; \ No newline at end of file diff --git a/src/viewpanel/components/SlugAction.tsx b/src/viewpanel/components/SlugAction.tsx new file mode 100644 index 00000000..f8ffaf8e --- /dev/null +++ b/src/viewpanel/components/SlugAction.tsx @@ -0,0 +1,29 @@ +import * as React from 'react'; +import { SlugHelper } from '../../helpers/SlugHelper'; +import { Slug } from '../../models/PanelSettings'; +import { CommandToCode } from '../CommandToCode'; +import useMessages from '../hooks/useMessages'; + +export interface ISlugActionProps { + value: string; + crntValue: string; + slugOpts: Slug; +} + +export const SlugAction: React.FunctionComponent = (props: React.PropsWithChildren) => { + const { value, crntValue, slugOpts } = props; + const { sendMessage } = useMessages(); + + let slug = SlugHelper.createSlug(value); + slug = `${slugOpts.prefix}${slug}${slugOpts.suffix}`; + + const optimize = () => { + sendMessage(CommandToCode.updateSlug); + }; + + return ( +
+ +
+ ); +}; \ No newline at end of file diff --git a/src/viewpanel/components/Spinner.tsx b/src/viewpanel/components/Spinner.tsx new file mode 100644 index 00000000..4b0d34ac --- /dev/null +++ b/src/viewpanel/components/Spinner.tsx @@ -0,0 +1,9 @@ +import * as React from 'react'; + +export interface ISpinnerProps {} + +export const Spinner: React.FunctionComponent = (props: React.PropsWithChildren) => { + return ( +
Loading...
+ ); +}; \ No newline at end of file diff --git a/src/viewpanel/components/Tag.tsx b/src/viewpanel/components/Tag.tsx new file mode 100644 index 00000000..c94d7ecc --- /dev/null +++ b/src/viewpanel/components/Tag.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; + +export interface ITagProps { + className: string; + value: string; + title: string; + + onRemove: (tags: string) => void; +} + +export const Tag: React.FunctionComponent = (props: React.PropsWithChildren) => { + const { value, className, title, onRemove } = props; + + return ( + + ); +}; \ No newline at end of file diff --git a/src/viewpanel/components/TagPicker.tsx b/src/viewpanel/components/TagPicker.tsx new file mode 100644 index 00000000..afebdeb8 --- /dev/null +++ b/src/viewpanel/components/TagPicker.tsx @@ -0,0 +1,97 @@ +import * as React from 'react'; +import useAutocomplete from '@material-ui/lab/useAutocomplete'; +import { makeStyles, createStyles } from '@material-ui/core/styles'; +import { Tags } from './Tags'; +import { usePrevious } from '../hooks/usePrevious'; +import useMessages from '../hooks/useMessages'; +import { CommandToCode } from '../CommandToCode'; +import { TagType } from '../TagType'; + +export interface ITagPickerProps { + type: string; + crntSelected: string[]; + options: string[]; +} + +const useStyles = makeStyles(() => + createStyles({ + label: { + display: 'block', + }, + input: { + width: 200, + }, + listbox: { + width: 200, + margin: 0, + padding: 0, + zIndex: 1, + position: 'absolute', + listStyle: 'none', + overflow: 'auto', + maxHeight: 200, + border: '1px solid rgba(0,0,0,.8)' + }, + }), +); + +export const TagPicker: React.FunctionComponent = (props: React.PropsWithChildren) => { + const { type, crntSelected, options } = props; + const [ selected, setSelected ] = React.useState([]); + const prevSelected = usePrevious(crntSelected); + const { sendMessage } = useMessages(); + + const classes = useStyles(); + const { getRootProps, getInputProps, getListboxProps, getOptionProps, groupedOptions } = useAutocomplete({ + id: 'use-autocomplete', + options: options, + multiple: true, + autoComplete: true, + value: crntSelected, + getOptionDisabled: (option) => selected.includes(option), + onChange: (e, values: string[]) => { + const uniqValues = Array.from(new Set([...selected, ...values])); + setSelected(uniqValues); + sendUpdate(uniqValues); + } + }); + + const onRemove = (tag: string) => { + const newSelection = selected.filter(s => s !== tag); + setSelected(newSelection); + sendUpdate(newSelection); + }; + + const sendUpdate = (values: string[]) => { + const cmdType = type === TagType.tags ? CommandToCode.updateTags : CommandToCode.updateCategories; + sendMessage(cmdType, values); + }; + + React.useEffect(() => { + if (prevSelected !== crntSelected) { + setSelected(crntSelected); + } + }, [crntSelected]); + + return ( +
+

{type}

+ +
+ +
+ + { + groupedOptions.length > 0 ? ( +
    + {groupedOptions.map((option, index) => ( +
  • {option}
  • + ))} +
+ ) : null + } + + +
+ ); +}; \ No newline at end of file diff --git a/src/viewpanel/components/Tags.tsx b/src/viewpanel/components/Tags.tsx new file mode 100644 index 00000000..25d6b520 --- /dev/null +++ b/src/viewpanel/components/Tags.tsx @@ -0,0 +1,23 @@ +import * as React from 'react'; +import { Tag } from './Tag'; + +export interface ITagsProps { + values: string[]; + options: string[]; + + onRemove: (tags: string) => void; +} + +export const Tags: React.FunctionComponent = (props: React.PropsWithChildren) => { + const { values, options, onRemove } = props; + + return ( +
+ { + values.map(t => ( + + )) + } +
+ ); +}; \ No newline at end of file diff --git a/src/viewpanel/hooks/useMessages.tsx b/src/viewpanel/hooks/useMessages.tsx new file mode 100644 index 00000000..0c3b7140 --- /dev/null +++ b/src/viewpanel/hooks/useMessages.tsx @@ -0,0 +1,54 @@ +import { useState, useEffect } from 'react'; +import { PanelSettings } from '../../models/PanelSettings'; +import { Command } from '../Command'; +import { CommandToCode } from '../CommandToCode'; + +declare const acquireVsCodeApi: () => { + getState: () => T; + setState: (data: T) => void; + postMessage: (msg: unknown) => void; +}; + +const vscode = acquireVsCodeApi(); + +export default function useMessages() { + const [metadata, setMetadata] = useState({}); + const [settings, setSettings] = useState(); + const [loading, setLoading] = useState(false); + + window.addEventListener('message', event => { + const message = event.data; + + switch (message.command) { + case Command.metadata: + setMetadata(message.data); + setLoading(false); + break; + case Command.settings: + setSettings(message.data); + setLoading(false); + break; + case Command.loading: + setLoading(message.data); + break; + } + }); + + useEffect(() => { + setLoading(true); + vscode.postMessage({ command: CommandToCode.getData }); + }, ['']); + + return { + metadata, + settings, + loading, + sendMessage: (command: CommandToCode, data?: any) => { + if (data) { + vscode.postMessage({ command, data }); + } else { + vscode.postMessage({ command }); + } + } + }; +} \ No newline at end of file diff --git a/src/viewpanel/hooks/usePrevious.tsx b/src/viewpanel/hooks/usePrevious.tsx new file mode 100644 index 00000000..764dad9c --- /dev/null +++ b/src/viewpanel/hooks/usePrevious.tsx @@ -0,0 +1,11 @@ +import { useEffect, useRef } from 'react'; + +export function usePrevious(value: T): T | undefined { + const ref = useRef(); + + useEffect(() => { + ref.current = value; + }, [value]); + + return ref.current; +} \ No newline at end of file diff --git a/src/viewpanel/index.tsx b/src/viewpanel/index.tsx new file mode 100644 index 00000000..33d17711 --- /dev/null +++ b/src/viewpanel/index.tsx @@ -0,0 +1,6 @@ +import * as React from "react"; +import { render } from "react-dom"; +import { ViewPanel } from "./ViewPanel"; + +const elm = document.querySelector("#app"); +render(, elm); \ No newline at end of file diff --git a/src/webview/ExplorerView.ts b/src/webview/ExplorerView.ts new file mode 100644 index 00000000..0eae7729 --- /dev/null +++ b/src/webview/ExplorerView.ts @@ -0,0 +1,226 @@ +import { PanelSettings } from './../models/PanelSettings'; +import { CancellationToken, Disposable, Uri, Webview, WebviewView, WebviewViewProvider, WebviewViewResolveContext, window, workspace } from "vscode"; +import { CONFIG_KEY, SETTING_SEO_DESCRIPTION_LENGTH, SETTING_SEO_TITLE_LENGTH, SETTING_SLUG_PREFIX, SETTING_SLUG_SUFFIX, SETTING_TAXONOMY_CATEGORIES, SETTING_TAXONOMY_TAGS } from "../constants"; +import { ArticleHelper } from "../helpers"; +import { Command } from "../viewpanel/Command"; +import { CommandToCode } from '../viewpanel/CommandToCode'; +import { Article } from '../commands'; +import { TagType } from '../viewpanel/TagType'; + + + +export class ExplorerView implements WebviewViewProvider, Disposable { + public static readonly viewType = "frontMatter.explorer"; + private static instance: ExplorerView; + + private panel: WebviewView | null = null; + private disposable: Disposable | null = null; + + private constructor(private readonly extPath: Uri) {} + + /** + * Creates the singleton instance for the panel + * @param extPath + */ + public static getInstance(extPath?: Uri): ExplorerView { + if (!ExplorerView.instance) { + ExplorerView.instance = new ExplorerView(extPath as Uri); + } + + return ExplorerView.instance; + } + + /** + * Retrieve the visibility of the webview + */ + get visible() { + return this.panel ? this.panel.visible : false; + } + + /** + * Webview panel dispose + */ + public dispose() { + if (this.disposable) { + this.disposable.dispose(); + } + } + + /** + * Default resolve webview panel + * @param webviewView + * @param context + * @param token + */ + public async resolveWebviewView(webviewView: WebviewView, context: WebviewViewResolveContext, token: CancellationToken): Promise { + + this.panel = webviewView; + + webviewView.webview.options = { + enableScripts: true, + enableCommandUris: true, + localResourceRoots: [this.extPath] + }; + + webviewView.webview.html = this.getWebviewContent(webviewView.webview); + + this.disposable = Disposable.from( + webviewView.onDidDispose(() => { webviewView.webview.html = ""; }, this), + // window.onDidChangeWindowState(() => { console.log(`onDidChangeWindowState visible`, this.visible); }, this) + ); + + webviewView.webview.onDidReceiveMessage(msg => { + switch(msg.command) { + case CommandToCode.getData: + this.getSettings(); + this.getFileData(); + break; + case CommandToCode.updateSlug: + Article.generateSlug(); + break; + case CommandToCode.updateDate: + Article.setDate(); + break; + case CommandToCode.publish: + Article.toggleDraft(); + break; + case CommandToCode.updateTags: + this.updateTags(TagType.tags, msg.data || []); + break; + case CommandToCode.updateCategories: + this.updateTags(TagType.categories, msg.data || []); + break; + } + }); + + webviewView.onDidChangeVisibility(() => { + if (this.visible) { + this.getFileData(); + } + }); + + window.onDidChangeActiveTextEditor(() => { + this.postWebviewMessage({ command: Command.loading, data: true }); + if (this.visible) { + this.getFileData(); + } + }, this); + + workspace.onDidChangeConfiguration(() => { + this.getSettings(); + }); + } + + /** + * Triggers a metadata change in the panel + * @param metadata + */ + public pushMetadata(metadata: any) { + this.postWebviewMessage({ command: Command.metadata, data: metadata }); + } + + /** + * Retrieve the extension settings + */ + private getSettings() { + const config = workspace.getConfiguration(CONFIG_KEY); + + this.postWebviewMessage({ + command: Command.settings, + data: { + seo: { + title: config.get(SETTING_SEO_TITLE_LENGTH) as number || -1, + description: config.get(SETTING_SEO_DESCRIPTION_LENGTH) as number || -1 + }, + slug: { + prefix: config.get(SETTING_SLUG_PREFIX) || "", + suffix: config.get(SETTING_SLUG_SUFFIX) || "" + }, + tags: config.get(SETTING_TAXONOMY_TAGS) || [], + categories: config.get(SETTING_TAXONOMY_CATEGORIES) || [] + } as PanelSettings + }); + } + + /** + * Retrieve the file its front matter + */ + private getFileData() { + const editor = window.activeTextEditor; + if (!editor) { + return ""; + } + + const article = ArticleHelper.getFrontMatter(editor); + this.postWebviewMessage({ command: Command.metadata, data: article!.data }); + } + + /** + * Update the tags in the current document + * @param tagType + * @param values + */ + private updateTags(tagType: TagType, values: string[]) { + const editor = window.activeTextEditor; + if (!editor) { + return ""; + } + + const article = ArticleHelper.getFrontMatter(editor); + if (article && article.data) { + article.data[tagType.toLowerCase()] = values || []; + ArticleHelper.update(editor, article); + this.postWebviewMessage({ command: Command.metadata, data: article.data }); + } + } + + /** + * Post data to the panel + * @param msg + */ + private postWebviewMessage(msg: { command: Command, data: any }) { + this.panel!.webview.postMessage(msg); + } + + + private getNonce() { + let text = ''; + const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + for (let i = 0; i < 32; i++) { + text += possible.charAt(Math.floor(Math.random() * possible.length)); + } + return text; + } + + /** + * Retrieve the webview HTML contents + * @param webView + */ + private getWebviewContent(webView: Webview): string { + const styleVSCodeUri = webView.asWebviewUri(Uri.joinPath(this.extPath, 'assets/media', 'vscode.css')); + const styleResetUri = webView.asWebviewUri(Uri.joinPath(this.extPath, 'assets/media', 'reset.css')); + const stylesUri = webView.asWebviewUri(Uri.joinPath(this.extPath, 'assets/media', 'styles.css')); + const scriptUri = webView.asWebviewUri(Uri.joinPath(this.extPath, 'dist', 'bundle.js')); + const nonce = this.getNonce(); + + return ` + + + + + + + + + + FrontMatter + + +
+ + + + + `; + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index b65c7451..b0cde195 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,15 +4,13 @@ "target": "es6", "outDir": "out", "lib": [ - "es6" + "es6", + "DOM" ], "sourceMap": true, "rootDir": "src", - "strict": true /* enable all strict type-checking options */ - /* Additional Checks */ - // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - // "noUnusedParameters": true, /* Report errors on unused parameters. */ + "strict": true, + "jsx": "react" }, "exclude": [ "node_modules", diff --git a/webpack.config.js b/webpack.config.js index a76643bb..fdb686da 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -4,38 +4,54 @@ const path = require('path'); -/**@type {import('webpack').Configuration}*/ -const config = { - target: 'node', // vscode extensions run in a Node.js-context 📖 -> https://webpack.js.org/configuration/node/ - - entry: './src/extension.ts', // the entry point of this extension, 📖 -> https://webpack.js.org/configuration/entry-context/ - output: { - // the bundle is stored in the 'dist' folder (check package.json), 📖 -> https://webpack.js.org/configuration/output/ - path: path.resolve(__dirname, 'dist'), - filename: 'extension.js', - libraryTarget: 'commonjs2', - devtoolModuleFilenameTemplate: '../[resource-path]' - }, - devtool: 'source-map', - externals: { - vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, 📖 -> https://webpack.js.org/configuration/externals/ - }, - resolve: { - // support reading TypeScript and JavaScript files, 📖 -> https://github.com/TypeStrong/ts-loader - extensions: ['.ts', '.js'] - }, - module: { - rules: [ - { +module.exports = [ + { + name: 'extension', + target: 'node', + entry: './src/extension.ts', + output: { + path: path.resolve(__dirname, 'dist'), + filename: 'extension.js', + libraryTarget: 'commonjs2', + devtoolModuleFilenameTemplate: '../[resource-path]' + }, + devtool: 'source-map', + externals: { + vscode: 'commonjs vscode' + }, + resolve: { + extensions: ['.ts', '.js', '.tsx', '.jsx'] + }, + module: { + rules: [{ test: /\.ts$/, exclude: /node_modules/, - use: [ - { - loader: 'ts-loader' - } - ] - } - ] + use: [{ + loader: 'ts-loader' + }] + }] + } + }, + { + name: 'viewpanel', + target: 'web', + entry: './src/viewpanel/index.tsx', + output: { + path: path.resolve(__dirname, 'dist'), + filename: 'bundle.js' + }, + devtool: 'source-map', + resolve: { + extensions: ['.ts', '.js', '.tsx', '.jsx'] + }, + module: { + rules: [{ + test: /\.(ts|tsx)$/, + exclude: /node_modules/, + use: [{ + loader: 'ts-loader' + }] + }] + } } -}; -module.exports = config; \ No newline at end of file +]; \ No newline at end of file