From 28cb8a5b7007b67b5bcfbc195491e221824391c8 Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Mon, 25 Oct 2021 21:06:54 -0400 Subject: [PATCH 01/45] Add router to pages --- client/package-lock.json | 314 ++++++++++++++++++ client/package.json | 4 + client/src/app/components/PageManager.tsx | 23 +- .../pageManager/CloudProviderPage.tsx | 15 +- .../pageManager/SelectCloudProviderPage.tsx | 22 +- .../cloudProviderPage/UICloudProviderPage.tsx | 12 +- .../providerItem/useProviderItem.ts | 22 +- .../app/components/sideMenu/CloudButton.tsx | 12 +- client/src/app/hooks/contexts/index.ts | 1 - .../src/app/hooks/contexts/usePageStore.tsx | 61 ---- client/src/app/index.tsx | 28 +- 11 files changed, 367 insertions(+), 147 deletions(-) delete mode 100644 client/src/app/hooks/contexts/usePageStore.tsx diff --git a/client/package-lock.json b/client/package-lock.json index ed248ee..3422b5c 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -24,6 +24,8 @@ "react": "^17.0.2", "react-dom": "^17.0.2", "react-hook-form": "^7.16.1", + "react-router": "^5.2.1", + "react-router-dom": "^5.3.0", "typesafe-actions": "^5.1.0", "yup": "^0.32.9" }, @@ -40,6 +42,8 @@ "@types/jest": "^27.0.2", "@types/mock-fs": "^4.13.1", "@types/react": "^17.0.24", + "@types/react-router": "^5.1.17", + "@types/react-router-dom": "^5.3.2", "autoprefixer": "^10.3.5", "babel-jest": "^27.2.5", "css-loader": "^6.3.0", @@ -2712,6 +2716,12 @@ "@types/node": "*" } }, + "node_modules/@types/history": { + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz", + "integrity": "sha512-MUc6zSmU3tEVnkQ78q0peeEjKWPUADMlC/t++2bI8WnAG2tvYRPIgHG8lWkXwqc8MsUF6Z2MOf+Mh5sazOmhiQ==", + "dev": true + }, "node_modules/@types/html-minifier-terser": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz", @@ -2823,6 +2833,27 @@ "@types/react": "*" } }, + "node_modules/@types/react-router": { + "version": "5.1.17", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.17.tgz", + "integrity": "sha512-RNSXOyb3VyRs/EOGmjBhhGKTbnN6fHWvy5FNLzWfOWOGjgVUKqJZXfpKzLmgoU8h6Hj8mpALj/mbXQASOb92wQ==", + "dev": true, + "dependencies": { + "@types/history": "*", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.2.tgz", + "integrity": "sha512-ELEYRUie2czuJzaZ5+ziIp9Hhw+juEw8b7C11YNA4QdLCVbQ3qLi2l4aq8XnlqM7V31LZX8dxUuFUCrzHm6sqQ==", + "dev": true, + "dependencies": { + "@types/history": "*", + "@types/react": "*", + "@types/react-router": "*" + } + }, "node_modules/@types/react-test-renderer": { "version": "17.0.1", "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-17.0.1.tgz", @@ -6591,6 +6622,32 @@ "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==" }, + "node_modules/history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "dependencies": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^1.0.1" + } + }, + "node_modules/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==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/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==" + }, "node_modules/home-or-tmp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", @@ -9325,6 +9382,19 @@ "node": ">=4" } }, + "node_modules/mini-create-react-context": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", + "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", + "dependencies": { + "@babel/runtime": "^7.12.1", + "tiny-warning": "^1.0.3" + }, + "peerDependencies": { + "prop-types": "^15.0.0", + "react": "^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, "node_modules/mini-css-extract-plugin": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.3.0.tgz", @@ -10028,6 +10098,19 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "node_modules/path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dependencies": { + "isarray": "0.0.1" + } + }, + "node_modules/path-to-regexp/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -10585,6 +10668,21 @@ "extend": "^3.0.0" } }, + "node_modules/prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, + "node_modules/prop-types/node_modules/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==" + }, "node_modules/property-expr": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.4.tgz", @@ -10794,6 +10892,48 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, + "node_modules/react-router": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.1.tgz", + "integrity": "sha512-lIboRiOtDLFdg1VTemMwud9vRVuOCZmUIT/7lUoZiSpPODiiH1UQlfXy+vPLC/7IWdFYnhRwAyNqA/+I7wnvKQ==", + "dependencies": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "mini-create-react-context": "^0.4.0", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/react-router-dom": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.0.tgz", + "integrity": "sha512-ObVBLjUZsphUUMVycibxgMdh5jJ1e3o+KpAZBVeHcNQZ4W+uUGGWsokurzlF4YOldQYRQL4y6yFRWM4m3svmuQ==", + "dependencies": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.2.1", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "peerDependencies": { + "react": ">=15" + } + }, + "node_modules/react-router/node_modules/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==" + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -11100,6 +11240,11 @@ "node": ">=8" } }, + "node_modules/resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + }, "node_modules/resolve.exports": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", @@ -12126,6 +12271,16 @@ "node": ">=0.10.0" } }, + "node_modules/tiny-invariant": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", + "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==" + }, + "node_modules/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==" + }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -12752,6 +12907,11 @@ "builtins": "^1.0.3" } }, + "node_modules/value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + }, "node_modules/w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -15183,6 +15343,12 @@ "@types/node": "*" } }, + "@types/history": { + "version": "4.7.9", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz", + "integrity": "sha512-MUc6zSmU3tEVnkQ78q0peeEjKWPUADMlC/t++2bI8WnAG2tvYRPIgHG8lWkXwqc8MsUF6Z2MOf+Mh5sazOmhiQ==", + "dev": true + }, "@types/html-minifier-terser": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz", @@ -15294,6 +15460,27 @@ "@types/react": "*" } }, + "@types/react-router": { + "version": "5.1.17", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.17.tgz", + "integrity": "sha512-RNSXOyb3VyRs/EOGmjBhhGKTbnN6fHWvy5FNLzWfOWOGjgVUKqJZXfpKzLmgoU8h6Hj8mpALj/mbXQASOb92wQ==", + "dev": true, + "requires": { + "@types/history": "*", + "@types/react": "*" + } + }, + "@types/react-router-dom": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.2.tgz", + "integrity": "sha512-ELEYRUie2czuJzaZ5+ziIp9Hhw+juEw8b7C11YNA4QdLCVbQ3qLi2l4aq8XnlqM7V31LZX8dxUuFUCrzHm6sqQ==", + "dev": true, + "requires": { + "@types/history": "*", + "@types/react": "*", + "@types/react-router": "*" + } + }, "@types/react-test-renderer": { "version": "17.0.1", "resolved": "https://registry.npmjs.org/@types/react-test-renderer/-/react-test-renderer-17.0.1.tgz", @@ -18250,6 +18437,34 @@ "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==" }, + "history": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", + "integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==", + "requires": { + "@babel/runtime": "^7.1.2", + "loose-envify": "^1.2.0", + "resolve-pathname": "^3.0.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0", + "value-equal": "^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" + }, + "dependencies": { + "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==" + } + } + }, "home-or-tmp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", @@ -20339,6 +20554,15 @@ "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true }, + "mini-create-react-context": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz", + "integrity": "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ==", + "requires": { + "@babel/runtime": "^7.12.1", + "tiny-warning": "^1.0.3" + } + }, "mini-css-extract-plugin": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.3.0.tgz", @@ -20883,6 +21107,21 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "requires": { + "isarray": "0.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + } + } + }, "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -21266,6 +21505,23 @@ "extend": "^3.0.0" } }, + "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" + }, + "dependencies": { + "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==" + } + } + }, "property-expr": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.4.tgz", @@ -21413,6 +21669,44 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, + "react-router": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.1.tgz", + "integrity": "sha512-lIboRiOtDLFdg1VTemMwud9vRVuOCZmUIT/7lUoZiSpPODiiH1UQlfXy+vPLC/7IWdFYnhRwAyNqA/+I7wnvKQ==", + "requires": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "hoist-non-react-statics": "^3.1.0", + "loose-envify": "^1.3.1", + "mini-create-react-context": "^0.4.0", + "path-to-regexp": "^1.7.0", + "prop-types": "^15.6.2", + "react-is": "^16.6.0", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + }, + "dependencies": { + "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-router-dom": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.0.tgz", + "integrity": "sha512-ObVBLjUZsphUUMVycibxgMdh5jJ1e3o+KpAZBVeHcNQZ4W+uUGGWsokurzlF4YOldQYRQL4y6yFRWM4m3svmuQ==", + "requires": { + "@babel/runtime": "^7.12.13", + "history": "^4.9.0", + "loose-envify": "^1.3.1", + "prop-types": "^15.6.2", + "react-router": "5.2.1", + "tiny-invariant": "^1.0.2", + "tiny-warning": "^1.0.0" + } + }, "read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -21669,6 +21963,11 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" }, + "resolve-pathname": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz", + "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==" + }, "resolve.exports": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", @@ -22435,6 +22734,16 @@ "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" }, + "tiny-invariant": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.1.0.tgz", + "integrity": "sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==" + }, + "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==" + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -22891,6 +23200,11 @@ "builtins": "^1.0.3" } }, + "value-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz", + "integrity": "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==" + }, "w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", diff --git a/client/package.json b/client/package.json index b44c2db..4329019 100644 --- a/client/package.json +++ b/client/package.json @@ -26,6 +26,8 @@ "@types/jest": "^27.0.2", "@types/mock-fs": "^4.13.1", "@types/react": "^17.0.24", + "@types/react-router": "^5.1.17", + "@types/react-router-dom": "^5.3.2", "autoprefixer": "^10.3.5", "babel-jest": "^27.2.5", "css-loader": "^6.3.0", @@ -68,6 +70,8 @@ "react": "^17.0.2", "react-dom": "^17.0.2", "react-hook-form": "^7.16.1", + "react-router": "^5.2.1", + "react-router-dom": "^5.3.0", "typesafe-actions": "^5.1.0", "yup": "^0.32.9" } diff --git a/client/src/app/components/PageManager.tsx b/client/src/app/components/PageManager.tsx index bce9656..95c774b 100644 --- a/client/src/app/components/PageManager.tsx +++ b/client/src/app/components/PageManager.tsx @@ -1,19 +1,16 @@ import React from 'react'; -import { usePageStore } from '@hooks'; import { CloudProviderPage } from './pageManager/cloudProviderPage'; import { SelectCloudProviderPage } from './pageManager/selectCloudProviderPage'; +import { Route } from 'react-router'; export function PageManager() { - const [{ cloudProviderPageVisible, selectCloudProviderPageVisible }] = - usePageStore(); - - let render: JSX.Element | null = null; - - if (cloudProviderPageVisible) { - render = ; - } else if (selectCloudProviderPageVisible) { - render = ; - } - - return render; + return ( + <> + } /> + } + /> + + ); } diff --git a/client/src/app/components/pageManager/CloudProviderPage.tsx b/client/src/app/components/pageManager/CloudProviderPage.tsx index 3972df4..0627996 100644 --- a/client/src/app/components/pageManager/CloudProviderPage.tsx +++ b/client/src/app/components/pageManager/CloudProviderPage.tsx @@ -1,18 +1,9 @@ import React from 'react'; -import { usePageStore } from '@hooks'; import { UICloudProviderPage } from './cloudProviderPage/UICloudProviderPage'; +import { useHistory } from 'react-router-dom'; export function CloudProviderPage() { - const [, pageDispatch] = usePageStore(); + let history = useHistory(); - return ( - - pageDispatch({ - type: 'cloudProviderPage', - cloudProviderPageVisible: false - }) - } - /> - ); + return history.push('/')} />; } diff --git a/client/src/app/components/pageManager/SelectCloudProviderPage.tsx b/client/src/app/components/pageManager/SelectCloudProviderPage.tsx index db481e8..5ce9801 100644 --- a/client/src/app/components/pageManager/SelectCloudProviderPage.tsx +++ b/client/src/app/components/pageManager/SelectCloudProviderPage.tsx @@ -1,11 +1,13 @@ import React from 'react'; import { Page } from './Page'; -import { usePageStore, useConfig } from '@hooks'; +import { useConfig } from '@hooks'; import { ProviderItem } from './cloudProviderPage/ProviderItem'; +import { useHistory } from 'react-router'; export function SelectCloudProviderPage() { - const [, pageDispatch] = usePageStore(); const [config] = useConfig(); + let history = useHistory(); + const providers = config?.connectedProviders || []; const configProviderNames = providers.map((p) => p.name); @@ -15,14 +17,7 @@ export function SelectCloudProviderPage() { }); return ( - - pageDispatch({ - type: 'selectCloudProviderPage', - selectCloudProviderPageVisible: false - }) - } - > + history.push('/')}>

@@ -56,12 +51,7 @@ export function SelectCloudProviderPage() { )}
); diff --git a/client/src/app/components/fileExplorer/node/useNode.ts b/client/src/app/components/fileExplorer/node/useNode.ts new file mode 100644 index 0000000..1a06c19 --- /dev/null +++ b/client/src/app/components/fileExplorer/node/useNode.ts @@ -0,0 +1,5 @@ +interface Args {} + +export function useNode({}: Args) { + return {}; +} diff --git a/client/src/shared/types.d.ts b/client/src/shared/types.d.ts index 1b08161..f2d5bed 100644 --- a/client/src/shared/types.d.ts +++ b/client/src/shared/types.d.ts @@ -1,10 +1,12 @@ import { Dispatch } from 'react'; import { PayloadAction } from 'typesafe-actions'; +export type FileSystemItemTypes = 'note' | 'directory' | 'attachment'; + export interface FileSystemItem { name: string; path: string; - type: 'note' | 'directory'; + type: FileSystemItemTypes; } export type FileItem = Omit; From aeffabb72290be4557d06b6022229701e07f7170 Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Thu, 28 Oct 2021 11:17:14 -0400 Subject: [PATCH 14/45] Add icon styles --- client/src/app/components/fileExplorer/Node.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/client/src/app/components/fileExplorer/Node.tsx b/client/src/app/components/fileExplorer/Node.tsx index 8c51019..f98f7fb 100644 --- a/client/src/app/components/fileExplorer/Node.tsx +++ b/client/src/app/components/fileExplorer/Node.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { CSSProperties } from 'react'; import { useNode } from './node/useNode'; import { FileSystemItem } from '@types'; import DirectoryIcon from '@assets/icons/folder-f.svg'; @@ -14,16 +14,20 @@ export function Node({ item }: Props) { const {} = useNode({ item }); let icon: JSX.Element; + const iconStyle = { + fill: '#9CA3AF', + className: 'self-end w-5 mr-1 align-bottom' + }; switch (item.type) { case 'directory': - icon = ; + icon = ; break; case 'note': - icon = ; + icon = ; break; case 'attachment': - icon = ; + icon = ; break; } From 7a3e4697dd4e8109f3019440bad73ea86d1c2ffb Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Thu, 28 Oct 2021 11:48:21 -0400 Subject: [PATCH 15/45] Add basic node UI --- .../src/app/components/fileExplorer/Node.tsx | 4 +- .../fileExplorer/node/RenameField.tsx | 7 ++ .../components/fileExplorer/node/UINode.tsx | 68 +++++++++++++++++++ 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 client/src/app/components/fileExplorer/node/RenameField.tsx create mode 100644 client/src/app/components/fileExplorer/node/UINode.tsx diff --git a/client/src/app/components/fileExplorer/Node.tsx b/client/src/app/components/fileExplorer/Node.tsx index f98f7fb..38ebd40 100644 --- a/client/src/app/components/fileExplorer/Node.tsx +++ b/client/src/app/components/fileExplorer/Node.tsx @@ -1,4 +1,4 @@ -import React, { CSSProperties } from 'react'; +import React from 'react'; import { useNode } from './node/useNode'; import { FileSystemItem } from '@types'; import DirectoryIcon from '@assets/icons/folder-f.svg'; @@ -31,5 +31,7 @@ export function Node({ item }: Props) { break; } + console.log(icon); + return <>; } diff --git a/client/src/app/components/fileExplorer/node/RenameField.tsx b/client/src/app/components/fileExplorer/node/RenameField.tsx new file mode 100644 index 0000000..406d8eb --- /dev/null +++ b/client/src/app/components/fileExplorer/node/RenameField.tsx @@ -0,0 +1,7 @@ +import React from 'react'; + +interface Props {} + +export function RenameField({}: Props) { + return <>; +} diff --git a/client/src/app/components/fileExplorer/node/UINode.tsx b/client/src/app/components/fileExplorer/node/UINode.tsx new file mode 100644 index 0000000..21ad3ad --- /dev/null +++ b/client/src/app/components/fileExplorer/node/UINode.tsx @@ -0,0 +1,68 @@ +import React from 'react'; +import { Node } from '../Node'; +import ChevronDownIcon from '@assets/icons/chevron-down.svg'; +import ChevronRightIcon from '@assets/icons/chevron-right.svg'; +import { FileSystemItem } from '@types'; + +interface Props { + name: string; + depth: number; + foldable?: boolean; + opened?: boolean; + primarySelected?: boolean; + secondarySelected?: boolean; + icon: JSX.Element; + children: FileSystemItem[]; +} + +export function UINode({ + name, + depth = 0, + foldable = false, + opened = false, + primarySelected = false, + secondarySelected = false, + icon, + children +}: Props) { + let selectionStyle = ''; + + if (secondarySelected) { + selectionStyle = 'border-blue-500 border-2 border-opacity-70'; + } else if (primarySelected) { + selectionStyle = + 'bg-blue-500 border-blue-300 border bg-opacity-30 border-opacity-30'; + } else { + selectionStyle = + 'hover:bg-opacity-30 hover:bg-gray-700 border border-transparent'; + } + + let chevronIcon: JSX.Element | null = null; + if (foldable && opened) { + chevronIcon = ; + } else if (foldable && !opened) { + chevronIcon = ; + } + + return ( +
+
+ {chevronIcon} + {icon} +

{name}

+
+
+
+ {children.map((item) => ( + + ))} +
+
+ ); +} From 2747dfb83bfe745ab59e7fcd045f6b2232557249 Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Thu, 28 Oct 2021 12:06:15 -0400 Subject: [PATCH 16/45] Rename currentNote state to currentFile --- client/src/app/App.tsx | 4 ++-- .../createNotebookModal/useCreateNotebookModal.ts | 2 +- .../src/app/components/editorPanel/UIEditorPanel.tsx | 4 ++-- .../editorPanel/editor/breadcrumb/Breadcrumb.test.tsx | 2 +- .../editorPanel/editor/breadcrumb/useBreadcrumb.ts | 6 +++--- .../app/components/editorPanel/editor/useEditor.ts | 10 +++++----- .../src/app/components/editorPanel/useEditorPanel.ts | 10 +++++----- .../components/fileExplorer/directory/useDirectory.ts | 6 +++--- .../src/app/components/fileExplorer/node/useNode.ts | 11 +++++++++-- .../src/app/components/fileExplorer/note/UINote.tsx | 4 ++-- .../src/app/components/fileExplorer/note/useNote.ts | 8 ++++---- .../app/components/fileExplorer/useFileExplorer.ts | 8 ++++---- client/src/app/hooks/useIpcListeners.ts | 8 ++++---- client/src/app/index.tsx | 2 +- client/src/shared/types.d.ts | 2 +- 15 files changed, 47 insertions(+), 40 deletions(-) diff --git a/client/src/app/App.tsx b/client/src/app/App.tsx index 98b2526..3e02a67 100644 --- a/client/src/app/App.tsx +++ b/client/src/app/App.tsx @@ -26,7 +26,7 @@ export const editorReducer = (state: EditorState, action: EditorAction) => { }; export function App() { - const [{ currentNote, notebook }] = useStore(); + const [{ currentFile, notebook }] = useStore(); const [, userDispatch] = useUserStore(); useIpcListeners(); @@ -36,7 +36,7 @@ export function App() { getUser().then(({ user }) => { if (user) userDispatch({ type: 'login', user }); }); - }, [currentNote, notebook]); + }, [currentFile, notebook]); return ( <> diff --git a/client/src/app/components/createNotebookModal/useCreateNotebookModal.ts b/client/src/app/components/createNotebookModal/useCreateNotebookModal.ts index 9e2226d..d54e9c2 100644 --- a/client/src/app/components/createNotebookModal/useCreateNotebookModal.ts +++ b/client/src/app/components/createNotebookModal/useCreateNotebookModal.ts @@ -65,7 +65,7 @@ export function useCreateNotebookModal() { dispatch({ type: 'openNote', - currentNote: undefined + currentFile: undefined }); dispatch({ diff --git a/client/src/app/components/editorPanel/UIEditorPanel.tsx b/client/src/app/components/editorPanel/UIEditorPanel.tsx index a2ede36..ff29c0f 100644 --- a/client/src/app/components/editorPanel/UIEditorPanel.tsx +++ b/client/src/app/components/editorPanel/UIEditorPanel.tsx @@ -11,13 +11,13 @@ interface Props { } export function UIEditorPanel({ text, setText }: Props) { - const [{ currentNote }] = useStore(); + const [{ currentFile }] = useStore(); return (
- {currentNote ? ( + {currentFile ? (
diff --git a/client/src/app/components/editorPanel/editor/breadcrumb/Breadcrumb.test.tsx b/client/src/app/components/editorPanel/editor/breadcrumb/Breadcrumb.test.tsx index 8fac6d5..9e915d6 100644 --- a/client/src/app/components/editorPanel/editor/breadcrumb/Breadcrumb.test.tsx +++ b/client/src/app/components/editorPanel/editor/breadcrumb/Breadcrumb.test.tsx @@ -41,7 +41,7 @@ describe.skip('Breadcrumb Logic', () => { const initialState: AppState = { notebook: '/Users/admin/Documents/notebook', - currentNote: { + currentFile: { name: 'segments.md', path: 'testing/path/segments.md' } diff --git a/client/src/app/components/editorPanel/editor/breadcrumb/useBreadcrumb.ts b/client/src/app/components/editorPanel/editor/breadcrumb/useBreadcrumb.ts index 4a32d3d..6fb24ad 100644 --- a/client/src/app/components/editorPanel/editor/breadcrumb/useBreadcrumb.ts +++ b/client/src/app/components/editorPanel/editor/breadcrumb/useBreadcrumb.ts @@ -6,10 +6,10 @@ interface Args { } export function useBreadcrumb({ unsaved }: Args) { - const [{ notebook, currentNote }] = useStore(); + const [{ notebook, currentFile }] = useStore(); const [, editorDispatch] = useEditorStore(); - const pathSegments = useRelativePath(notebook!, currentNote!.path).split( + const pathSegments = useRelativePath(notebook!, currentFile!.path).split( /[\/\\]/ ); @@ -36,7 +36,7 @@ export function useBreadcrumb({ unsaved }: Args) { let text = segment; if (index === pathSegments.length - 1) { - text = unsaved ? currentNote!.name.concat('*') : currentNote!.name; + text = unsaved ? currentFile!.name.concat('*') : currentFile!.name; } return text; diff --git a/client/src/app/components/editorPanel/editor/useEditor.ts b/client/src/app/components/editorPanel/editor/useEditor.ts index 6ed3ccd..ab3bd28 100644 --- a/client/src/app/components/editorPanel/editor/useEditor.ts +++ b/client/src/app/components/editorPanel/editor/useEditor.ts @@ -11,7 +11,7 @@ interface Args { } export function useEditor({ text, setText }: Args) { - const [{ currentNote }] = useStore(); + const [{ currentFile }] = useStore(); const [unsaved, setUnsaved] = useState(false); const [manualSave, setManualSave] = useState(false); @@ -22,26 +22,26 @@ export function useEditor({ text, setText }: Args) { setText(value); if (autoSave) { - saveFile(currentNote!, value); + saveFile(currentFile!, value); } else { setUnsaved(true); } }; if (manualSave) { - saveFile(currentNote!, text); + saveFile(currentFile!, text); setUnsaved(false); setManualSave(false); } useEffect(() => { - let buffer = fs.readFileSync(currentNote!.path); + let buffer = fs.readFileSync(currentFile!.path); setText(buffer.toString()); ipcRenderer.on('saveNote', () => { setManualSave(true); }); - }, [currentNote]); + }, [currentFile]); return { unsaved, text, handleChange }; } diff --git a/client/src/app/components/editorPanel/useEditorPanel.ts b/client/src/app/components/editorPanel/useEditorPanel.ts index 9ddea26..7d1253e 100644 --- a/client/src/app/components/editorPanel/useEditorPanel.ts +++ b/client/src/app/components/editorPanel/useEditorPanel.ts @@ -10,7 +10,7 @@ import { import { useEditorStore } from '@hooks'; export function useEditorPanel() { - const [{ notebook, currentNote }, dispatch] = useStore(); + const [{ notebook, currentFile }, dispatch] = useStore(); const [ { primarySelection, secondarySelection, isRenaming }, editorDispatch @@ -29,7 +29,7 @@ export function useEditorPanel() { dispatch({ type: 'openNote', - currentNote: newFile + currentFile: newFile }); }); @@ -52,12 +52,12 @@ export function useEditorPanel() { ipcRenderer.on('deleteExplorerItem', () => { deleteExplorerItem(secondarySelection?.path).then(() => { if ( - currentNote?.path === secondarySelection?.path || - !fileExist(currentNote?.path) + currentFile?.path === secondarySelection?.path || + !fileExist(currentFile?.path) ) { dispatch({ type: 'openNote', - currentNote: undefined + currentFile: undefined }); } diff --git a/client/src/app/components/fileExplorer/directory/useDirectory.ts b/client/src/app/components/fileExplorer/directory/useDirectory.ts index ea91f27..3ba7c73 100644 --- a/client/src/app/components/fileExplorer/directory/useDirectory.ts +++ b/client/src/app/components/fileExplorer/directory/useDirectory.ts @@ -14,7 +14,7 @@ interface Args { } export function useDirectory({ item, renameText, setRenameText }: Args) { - const [{ currentNote }, dispatch] = useStore(); + const [{ currentFile }, dispatch] = useStore(); const [{ secondarySelection, isRenaming }, editorDispatch] = useEditorStore(); const [isOpened, setIsOpened] = useState(false); @@ -76,10 +76,10 @@ export function useDirectory({ item, renameText, setRenameText }: Args) { isRenaming }); - if (item.path == currentNote?.path) { + if (item.path == currentFile?.path) { dispatch({ type: 'openNote', - currentNote: renamedItem + currentFile: renamedItem }); } }) diff --git a/client/src/app/components/fileExplorer/node/useNode.ts b/client/src/app/components/fileExplorer/node/useNode.ts index 1a06c19..b542cbe 100644 --- a/client/src/app/components/fileExplorer/node/useNode.ts +++ b/client/src/app/components/fileExplorer/node/useNode.ts @@ -1,5 +1,12 @@ -interface Args {} +//import { useStore } from "@hooks"; +import { FileSystemItem } from '@types'; -export function useNode({}: Args) { +interface Args { + item: FileSystemItem; +} + +export function useNode({ item }: Args) { + //const [{ currentFile }, dispatch] = useStore(); + console.log(item); return {}; } diff --git a/client/src/app/components/fileExplorer/note/UINote.tsx b/client/src/app/components/fileExplorer/note/UINote.tsx index b1b42cc..04cf433 100644 --- a/client/src/app/components/fileExplorer/note/UINote.tsx +++ b/client/src/app/components/fileExplorer/note/UINote.tsx @@ -27,7 +27,7 @@ export function UINote({ handleRenameFocus, handleRenameKeyDown }: Props) { - const [{ currentNote }] = useStore(); + const [{ currentFile }] = useStore(); const [{ primarySelection, secondarySelection, isRenaming }] = useEditorStore(); @@ -60,7 +60,7 @@ export function UINote({ displayItem = (

{ @@ -33,7 +33,7 @@ export function useNote({ item, renameText, setRenameText }: Args) { dispatch({ type: 'openNote', - currentNote: { + currentFile: { name: item.name, path: item.path } @@ -72,10 +72,10 @@ export function useNote({ item, renameText, setRenameText }: Args) { isRenaming }); - if (item.path == currentNote?.path) { + if (item.path == currentFile?.path) { dispatch({ type: 'openNote', - currentNote: renamedItem + currentFile: renamedItem }); } }); diff --git a/client/src/app/components/fileExplorer/useFileExplorer.ts b/client/src/app/components/fileExplorer/useFileExplorer.ts index 11b4640..47ded0b 100644 --- a/client/src/app/components/fileExplorer/useFileExplorer.ts +++ b/client/src/app/components/fileExplorer/useFileExplorer.ts @@ -8,7 +8,7 @@ import { } from '@utils'; export function useFileExplorer() { - const [{ notebook, currentNote }, dispatch] = useStore(); + const [{ notebook, currentFile }, dispatch] = useStore(); const [ { primarySelection, secondarySelection, isRenaming }, editorDispatch @@ -23,7 +23,7 @@ export function useFileExplorer() { dispatch({ type: 'openNote', - currentNote: newFile + currentFile: newFile }); }; @@ -69,10 +69,10 @@ export function useFileExplorer() { isRenaming }); - if (secondarySelection?.path == currentNote?.path) { + if (secondarySelection?.path == currentFile?.path) { dispatch({ type: 'openNote', - currentNote: renamedItem + currentFile: renamedItem }); } }) diff --git a/client/src/app/hooks/useIpcListeners.ts b/client/src/app/hooks/useIpcListeners.ts index 97e3352..8fcc482 100644 --- a/client/src/app/hooks/useIpcListeners.ts +++ b/client/src/app/hooks/useIpcListeners.ts @@ -11,7 +11,7 @@ const createListener = (channel: string, callback: (...args: any) => void) => { }; export function useIpcListeners() { - const [{ currentNote, notebook }, dispatch] = useStore(); + const [{ currentFile, notebook }, dispatch] = useStore(); const [, configDispatch] = useConfig(); let history = useHistory(); @@ -33,7 +33,7 @@ export function useIpcListeners() { dispatch({ type: 'openNote', - currentNote: undefined + currentFile: undefined }); dispatch({ @@ -49,7 +49,7 @@ export function useIpcListeners() { ); createListener('exportNote', () => { - ipcRenderer.send('currentFileToExport', currentNote); + ipcRenderer.send('currentFileToExport', currentFile); }); createListener( @@ -85,5 +85,5 @@ export function useIpcListeners() { console.error(err); }); }); - }, [currentNote, notebook]); + }, [currentFile, notebook]); } diff --git a/client/src/app/index.tsx b/client/src/app/index.tsx index aaded5b..ec71968 100644 --- a/client/src/app/index.tsx +++ b/client/src/app/index.tsx @@ -23,7 +23,7 @@ const storeReducer = (state: AppState, action: AppAction) => { case 'openNote': return { ...state, - currentNote: action.currentNote + currentNote: action.currentFile }; default: throw new Error('An unknown action has been sent to the store.'); diff --git a/client/src/shared/types.d.ts b/client/src/shared/types.d.ts index f2d5bed..b0d67cc 100644 --- a/client/src/shared/types.d.ts +++ b/client/src/shared/types.d.ts @@ -51,7 +51,7 @@ type ConfigDispatch = Dispatch< // Reducer Types export interface AppState { notebook?: string; - currentNote?: FileItem; + currentFile?: FileItem; } export interface AppAction extends AppState { From 03326af87196b6801b8695793141368ba5270443 Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Thu, 28 Oct 2021 12:27:18 -0400 Subject: [PATCH 17/45] Add basic ui to Node --- client/src/app/App.tsx | 6 +- .../src/app/components/fileExplorer/Node.tsx | 21 +++++-- .../components/fileExplorer/node/useNode.ts | 55 +++++++++++++++++-- client/src/shared/types.d.ts | 2 +- 4 files changed, 71 insertions(+), 13 deletions(-) diff --git a/client/src/app/App.tsx b/client/src/app/App.tsx index 3e02a67..fbc7afa 100644 --- a/client/src/app/App.tsx +++ b/client/src/app/App.tsx @@ -17,11 +17,11 @@ import { NotificationArea } from './components/NotificationArea'; export const editorReducer = (state: EditorState, action: EditorAction) => { switch (action.type) { case 'primarySelect': - return { ...state, primarySelection: action.primarySelection }; + return { ...state, primarySelection: action.primarySelection! }; case 'secondarySelect': - return { ...state, secondarySelection: action.secondarySelection }; + return { ...state, secondarySelection: action.secondarySelection! }; case 'rename': - return { ...state, isRenaming: action.isRenaming }; + return { ...state, isRenaming: action.isRenaming! }; } }; diff --git a/client/src/app/components/fileExplorer/Node.tsx b/client/src/app/components/fileExplorer/Node.tsx index 38ebd40..1e0a516 100644 --- a/client/src/app/components/fileExplorer/Node.tsx +++ b/client/src/app/components/fileExplorer/Node.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { UINode } from './node/UINode'; import { useNode } from './node/useNode'; import { FileSystemItem } from '@types'; import DirectoryIcon from '@assets/icons/folder-f.svg'; @@ -10,8 +11,9 @@ interface Props { depth?: number; } -export function Node({ item }: Props) { - const {} = useNode({ item }); +export function Node({ item, depth = 0 }: Props) { + const { opened, foldable, primarySelected, secondarySelected, children } = + useNode({ item }); let icon: JSX.Element; const iconStyle = { @@ -31,7 +33,16 @@ export function Node({ item }: Props) { break; } - console.log(icon); - - return <>; + return ( + + ); } diff --git a/client/src/app/components/fileExplorer/node/useNode.ts b/client/src/app/components/fileExplorer/node/useNode.ts index b542cbe..b42bec6 100644 --- a/client/src/app/components/fileExplorer/node/useNode.ts +++ b/client/src/app/components/fileExplorer/node/useNode.ts @@ -1,4 +1,5 @@ -//import { useStore } from "@hooks"; +import { useEditorStore, useStore } from '@hooks'; +import { getFileSystemItems } from '@utils'; import { FileSystemItem } from '@types'; interface Args { @@ -6,7 +7,53 @@ interface Args { } export function useNode({ item }: Args) { - //const [{ currentFile }, dispatch] = useStore(); - console.log(item); - return {}; + const [{}, dispatch] = useStore(); + const [{ primarySelection, secondarySelection }, editorDispatch] = + useEditorStore(); + + const opened = primarySelection?.path === item.path; + + let children: FileSystemItem[] = opened + ? getFileSystemItems(item.path) + : []; + + const foldable = item.type === 'directory'; + + const primarySelected = primarySelection?.path === item.path; + const secondarySelected = secondarySelection?.path === item.path; + + const handleClick = () => { + if (secondarySelected) return; + + if (secondarySelection) { + editorDispatch({ + type: 'secondarySelect', + secondarySelection: undefined + }); + } + + editorDispatch({ + type: 'primarySelect', + primarySelection: item + }); + + if (item.type === 'note') { + dispatch({ + type: 'openNote', + currentFile: { + name: item.name, + path: item.path + } + }); + } + }; + + return { + children, + opened, + foldable, + primarySelected, + secondarySelected, + handleClick + }; } diff --git a/client/src/shared/types.d.ts b/client/src/shared/types.d.ts index b0d67cc..a6e6393 100644 --- a/client/src/shared/types.d.ts +++ b/client/src/shared/types.d.ts @@ -72,7 +72,7 @@ export interface EditorState { isRenaming: boolean; } -export interface EditorAction extends EditorState { +export interface EditorAction extends Partial { type: 'primarySelect' | 'secondarySelect' | 'rename'; } From 5cdbf2e71c10e406b0812bad1f90ae86cd48ff77 Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Thu, 28 Oct 2021 12:32:27 -0400 Subject: [PATCH 18/45] Display attachments --- client/src/shared/types.d.ts | 4 ++-- .../utils/fileSystem/getFileSystemItems.ts | 20 +++++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/client/src/shared/types.d.ts b/client/src/shared/types.d.ts index a6e6393..aa36872 100644 --- a/client/src/shared/types.d.ts +++ b/client/src/shared/types.d.ts @@ -1,12 +1,12 @@ import { Dispatch } from 'react'; import { PayloadAction } from 'typesafe-actions'; -export type FileSystemItemTypes = 'note' | 'directory' | 'attachment'; +export type FileSystemItemType = 'note' | 'directory' | 'attachment'; export interface FileSystemItem { name: string; path: string; - type: FileSystemItemTypes; + type: FileSystemItemType; } export type FileItem = Omit; diff --git a/client/src/shared/utils/fileSystem/getFileSystemItems.ts b/client/src/shared/utils/fileSystem/getFileSystemItems.ts index 8c4dd1e..5de39e0 100644 --- a/client/src/shared/utils/fileSystem/getFileSystemItems.ts +++ b/client/src/shared/utils/fileSystem/getFileSystemItems.ts @@ -1,5 +1,5 @@ import fs from 'fs'; -import { FileSystemItem } from '../../types'; +import { FileSystemItem, FileSystemItemType } from '../../types'; /** Gets the immediate files and directories of the supplied path * @param path The absolute path of the targetted directory @@ -9,19 +9,23 @@ export const getFileSystemItems = (path: string): FileSystemItem[] => { const itemNames = fs.readdirSync(path); return itemNames - .filter( - (name) => - (fs.statSync(`${path}/${name}`).isDirectory() || - name.endsWith('.md')) && - !name.startsWith('.') - ) + .filter((name) => !name.startsWith('.')) .map((name) => { const data = fs.statSync(`${path}/${name}`); + let type: FileSystemItemType; + if (data.isDirectory()) { + type = 'directory'; + } else if (name.endsWith('.md')) { + type = 'note'; + } else { + type = 'attachment'; + } + return { name, path: `${path}/${name}`, - type: data.isDirectory() ? 'directory' : 'note' + type }; }) .sort((a, b) => { From 5ab32bbb19dcdc82bff4a6a7821a21de46128177 Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Thu, 28 Oct 2021 12:58:57 -0400 Subject: [PATCH 19/45] Add click behaviour to nodes --- .../app/components/editorPanel/editor/useEditor.ts | 1 + client/src/app/components/fileExplorer/Node.tsx | 11 +++++++++-- .../app/components/fileExplorer/node/UINode.tsx | 5 ++++- .../app/components/fileExplorer/node/useNode.ts | 14 ++++++++------ client/src/app/index.tsx | 2 +- 5 files changed, 23 insertions(+), 10 deletions(-) diff --git a/client/src/app/components/editorPanel/editor/useEditor.ts b/client/src/app/components/editorPanel/editor/useEditor.ts index ab3bd28..dc8ede1 100644 --- a/client/src/app/components/editorPanel/editor/useEditor.ts +++ b/client/src/app/components/editorPanel/editor/useEditor.ts @@ -36,6 +36,7 @@ export function useEditor({ text, setText }: Args) { useEffect(() => { let buffer = fs.readFileSync(currentFile!.path); + console.log(currentFile); setText(buffer.toString()); ipcRenderer.on('saveNote', () => { diff --git a/client/src/app/components/fileExplorer/Node.tsx b/client/src/app/components/fileExplorer/Node.tsx index 1e0a516..6bf1025 100644 --- a/client/src/app/components/fileExplorer/Node.tsx +++ b/client/src/app/components/fileExplorer/Node.tsx @@ -12,8 +12,14 @@ interface Props { } export function Node({ item, depth = 0 }: Props) { - const { opened, foldable, primarySelected, secondarySelected, children } = - useNode({ item }); + const { + opened, + foldable, + primarySelected, + secondarySelected, + children, + handleClick + } = useNode({ item }); let icon: JSX.Element; const iconStyle = { @@ -43,6 +49,7 @@ export function Node({ item, depth = 0 }: Props) { opened={opened} primarySelected={primarySelected} secondarySelected={secondarySelected} + onClick={handleClick} /> ); } diff --git a/client/src/app/components/fileExplorer/node/UINode.tsx b/client/src/app/components/fileExplorer/node/UINode.tsx index 21ad3ad..f3a1736 100644 --- a/client/src/app/components/fileExplorer/node/UINode.tsx +++ b/client/src/app/components/fileExplorer/node/UINode.tsx @@ -13,6 +13,7 @@ interface Props { secondarySelected?: boolean; icon: JSX.Element; children: FileSystemItem[]; + onClick: () => void; } export function UINode({ @@ -23,7 +24,8 @@ export function UINode({ primarySelected = false, secondarySelected = false, icon, - children + children, + onClick }: Props) { let selectionStyle = ''; @@ -47,6 +49,7 @@ export function UINode({ return (

diff --git a/client/src/app/components/fileExplorer/node/useNode.ts b/client/src/app/components/fileExplorer/node/useNode.ts index b42bec6..1067d6e 100644 --- a/client/src/app/components/fileExplorer/node/useNode.ts +++ b/client/src/app/components/fileExplorer/node/useNode.ts @@ -1,3 +1,4 @@ +import { useState } from 'react'; import { useEditorStore, useStore } from '@hooks'; import { getFileSystemItems } from '@utils'; import { FileSystemItem } from '@types'; @@ -7,18 +8,16 @@ interface Args { } export function useNode({ item }: Args) { + const [opened, setOpened] = useState(false); const [{}, dispatch] = useStore(); const [{ primarySelection, secondarySelection }, editorDispatch] = useEditorStore(); - const opened = primarySelection?.path === item.path; - - let children: FileSystemItem[] = opened - ? getFileSystemItems(item.path) - : []; - const foldable = item.type === 'directory'; + let children: FileSystemItem[] = + foldable && opened ? getFileSystemItems(item.path) : []; + const primarySelected = primarySelection?.path === item.path; const secondarySelected = secondarySelection?.path === item.path; @@ -38,6 +37,7 @@ export function useNode({ item }: Args) { }); if (item.type === 'note') { + console.log('opening ' + item.name); dispatch({ type: 'openNote', currentFile: { @@ -46,6 +46,8 @@ export function useNode({ item }: Args) { } }); } + + if (foldable) setOpened(!opened); }; return { diff --git a/client/src/app/index.tsx b/client/src/app/index.tsx index ec71968..d122291 100644 --- a/client/src/app/index.tsx +++ b/client/src/app/index.tsx @@ -23,7 +23,7 @@ const storeReducer = (state: AppState, action: AppAction) => { case 'openNote': return { ...state, - currentNote: action.currentFile + currentFile: action.currentFile }; default: throw new Error('An unknown action has been sent to the store.'); From a062cd1f957249bf37e542454b72784993c5450b Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Thu, 28 Oct 2021 13:03:02 -0400 Subject: [PATCH 20/45] Add context menu to node with delete functionality --- client/src/app/components/fileExplorer/Node.tsx | 4 +++- .../app/components/fileExplorer/node/UINode.tsx | 5 ++++- .../app/components/fileExplorer/node/useNode.ts | 15 ++++++++++++++- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/client/src/app/components/fileExplorer/Node.tsx b/client/src/app/components/fileExplorer/Node.tsx index 6bf1025..1b1492c 100644 --- a/client/src/app/components/fileExplorer/Node.tsx +++ b/client/src/app/components/fileExplorer/Node.tsx @@ -18,7 +18,8 @@ export function Node({ item, depth = 0 }: Props) { primarySelected, secondarySelected, children, - handleClick + handleClick, + handleContextMenu } = useNode({ item }); let icon: JSX.Element; @@ -50,6 +51,7 @@ export function Node({ item, depth = 0 }: Props) { primarySelected={primarySelected} secondarySelected={secondarySelected} onClick={handleClick} + onContextMenu={handleContextMenu} /> ); } diff --git a/client/src/app/components/fileExplorer/node/UINode.tsx b/client/src/app/components/fileExplorer/node/UINode.tsx index f3a1736..8674a84 100644 --- a/client/src/app/components/fileExplorer/node/UINode.tsx +++ b/client/src/app/components/fileExplorer/node/UINode.tsx @@ -14,6 +14,7 @@ interface Props { icon: JSX.Element; children: FileSystemItem[]; onClick: () => void; + onContextMenu: () => void; } export function UINode({ @@ -25,7 +26,8 @@ export function UINode({ secondarySelected = false, icon, children, - onClick + onClick, + onContextMenu }: Props) { let selectionStyle = ''; @@ -50,6 +52,7 @@ export function UINode({
diff --git a/client/src/app/components/fileExplorer/node/useNode.ts b/client/src/app/components/fileExplorer/node/useNode.ts index 1067d6e..f6a47f2 100644 --- a/client/src/app/components/fileExplorer/node/useNode.ts +++ b/client/src/app/components/fileExplorer/node/useNode.ts @@ -2,6 +2,7 @@ import { useState } from 'react'; import { useEditorStore, useStore } from '@hooks'; import { getFileSystemItems } from '@utils'; import { FileSystemItem } from '@types'; +import { ipcRenderer } from 'electron'; interface Args { item: FileSystemItem; @@ -50,12 +51,24 @@ export function useNode({ item }: Args) { if (foldable) setOpened(!opened); }; + const handleContextMenu = () => { + ipcRenderer.send('openExplorerFileContextMenu'); + + editorDispatch({ + type: 'secondarySelect', + secondarySelection: item + }); + + // set rename text? + }; + return { children, opened, foldable, primarySelected, secondarySelected, - handleClick + handleClick, + handleContextMenu }; } From 116d4e5a2a48549a629c31caaea0068e39912102 Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Thu, 28 Oct 2021 14:12:29 -0400 Subject: [PATCH 21/45] Add partial rename functionality --- .../src/app/components/fileExplorer/Node.tsx | 7 ++- .../fileExplorer/node/RenameField.tsx | 23 ++++++++-- .../components/fileExplorer/node/UINode.tsx | 19 +++++++- .../node/renameField/UIRenameField.tsx | 30 ++++++++++++ .../node/renameField/useRenameField.ts | 46 +++++++++++++++++++ .../components/fileExplorer/node/useNode.ts | 14 ++++-- .../electron/menus/explorerItemContextMenu.ts | 1 + 7 files changed, 131 insertions(+), 9 deletions(-) create mode 100644 client/src/app/components/fileExplorer/node/renameField/UIRenameField.tsx create mode 100644 client/src/app/components/fileExplorer/node/renameField/useRenameField.ts diff --git a/client/src/app/components/fileExplorer/Node.tsx b/client/src/app/components/fileExplorer/Node.tsx index 1b1492c..2985e49 100644 --- a/client/src/app/components/fileExplorer/Node.tsx +++ b/client/src/app/components/fileExplorer/Node.tsx @@ -19,7 +19,9 @@ export function Node({ item, depth = 0 }: Props) { secondarySelected, children, handleClick, - handleContextMenu + handleContextMenu, + renaming, + setRenaming } = useNode({ item }); let icon: JSX.Element; @@ -42,6 +44,7 @@ export function Node({ item, depth = 0 }: Props) { return ( ); } diff --git a/client/src/app/components/fileExplorer/node/RenameField.tsx b/client/src/app/components/fileExplorer/node/RenameField.tsx index 406d8eb..014d3bc 100644 --- a/client/src/app/components/fileExplorer/node/RenameField.tsx +++ b/client/src/app/components/fileExplorer/node/RenameField.tsx @@ -1,7 +1,24 @@ import React from 'react'; +import { UIRenameField } from './renameField/UIRenameField'; +import { useRenameField } from './renameField/useRenameField'; -interface Props {} +interface Props { + name: string; + path: string; + setRenaming: React.Dispatch; +} + +export function RenameField({ name, path, setRenaming }: Props) { + const { text, handleChange, handleKeyDown, handleFocus, handleBlur } = + useRenameField({ name, path, setRenaming }); -export function RenameField({}: Props) { - return <>; + return ( + + ); } diff --git a/client/src/app/components/fileExplorer/node/UINode.tsx b/client/src/app/components/fileExplorer/node/UINode.tsx index 8674a84..d625fa3 100644 --- a/client/src/app/components/fileExplorer/node/UINode.tsx +++ b/client/src/app/components/fileExplorer/node/UINode.tsx @@ -3,9 +3,11 @@ import { Node } from '../Node'; import ChevronDownIcon from '@assets/icons/chevron-down.svg'; import ChevronRightIcon from '@assets/icons/chevron-right.svg'; import { FileSystemItem } from '@types'; +import { RenameField } from './RenameField'; interface Props { name: string; + path: string; depth: number; foldable?: boolean; opened?: boolean; @@ -15,10 +17,13 @@ interface Props { children: FileSystemItem[]; onClick: () => void; onContextMenu: () => void; + renaming: boolean; + setRenaming: React.Dispatch; } export function UINode({ name, + path, depth = 0, foldable = false, opened = false, @@ -27,7 +32,9 @@ export function UINode({ icon, children, onClick, - onContextMenu + onContextMenu, + renaming, + setRenaming }: Props) { let selectionStyle = ''; @@ -58,7 +65,15 @@ export function UINode({ > {chevronIcon} {icon} -

{name}

+ {renaming ? ( + + ) : ( +

{name}

+ )}
) => void; + onKeyDown: (event: React.KeyboardEvent) => void; + onFocus: (event: React.FocusEvent) => void; + onBlur: () => void; +} + +export function UIRenameField({ + text, + onChange, + onKeyDown, + onFocus, + onBlur +}: Props) { + return ( + + ); +} diff --git a/client/src/app/components/fileExplorer/node/renameField/useRenameField.ts b/client/src/app/components/fileExplorer/node/renameField/useRenameField.ts new file mode 100644 index 0000000..096455e --- /dev/null +++ b/client/src/app/components/fileExplorer/node/renameField/useRenameField.ts @@ -0,0 +1,46 @@ +import { useEditorStore } from '@hooks'; +import { renameExplorerItem } from '@utils'; +import React, { useState } from 'react'; + +interface Args { + path: string; + name: string; + setRenaming: React.Dispatch; +} + +export function useRenameField({ name, path, setRenaming }: Args) { + const [text, setText] = useState(name); + const [, editorDispatch] = useEditorStore(); + + const handleChange = (event: React.ChangeEvent) => { + setText(event.target.value); + }; + + const handleKeyDown = (event: React.KeyboardEvent) => { + if (event.key === 'Enter' || event.code === '13') { + renameExplorerItem(path, text).then(() => { + setRenaming(false); + editorDispatch({ + type: 'secondarySelect', + secondarySelection: undefined + }); + }); + } else if (event.key === 'Escape' || event.code === '27') { + setRenaming(false); + editorDispatch({ + type: 'secondarySelect', + secondarySelection: undefined + }); + } + }; + + const handleFocus = (event: React.FocusEvent) => { + event.target.select(); + }; + + const handleBlur = () => { + setRenaming(false); + }; + + return { text, handleChange, handleKeyDown, handleFocus, handleBlur }; +} diff --git a/client/src/app/components/fileExplorer/node/useNode.ts b/client/src/app/components/fileExplorer/node/useNode.ts index f6a47f2..29f8697 100644 --- a/client/src/app/components/fileExplorer/node/useNode.ts +++ b/client/src/app/components/fileExplorer/node/useNode.ts @@ -10,6 +10,7 @@ interface Args { export function useNode({ item }: Args) { const [opened, setOpened] = useState(false); + const [renaming, setRenaming] = useState(false); const [{}, dispatch] = useStore(); const [{ primarySelection, secondarySelection }, editorDispatch] = useEditorStore(); @@ -38,7 +39,6 @@ export function useNode({ item }: Args) { }); if (item.type === 'note') { - console.log('opening ' + item.name); dispatch({ type: 'openNote', currentFile: { @@ -59,7 +59,13 @@ export function useNode({ item }: Args) { secondarySelection: item }); - // set rename text? + console.log('context menu'); + + ipcRenderer.removeAllListeners('renameExplorerItem'); + ipcRenderer.on('renameExplorerItem', () => { + console.log('renaming'); + setRenaming(true); + }); }; return { @@ -69,6 +75,8 @@ export function useNode({ item }: Args) { primarySelected, secondarySelected, handleClick, - handleContextMenu + handleContextMenu, + renaming, + setRenaming }; } diff --git a/client/src/electron/menus/explorerItemContextMenu.ts b/client/src/electron/menus/explorerItemContextMenu.ts index dc44867..a540cef 100644 --- a/client/src/electron/menus/explorerItemContextMenu.ts +++ b/client/src/electron/menus/explorerItemContextMenu.ts @@ -5,6 +5,7 @@ const template: MenuItemConstructorOptions[] = [ label: 'Rename', click(_, window) { if (!window) return; + console.log('renamed clicked and sending event'); window.webContents.send('renameExplorerItem'); } }, From 773a12ce1e487a1c322969344b37e84d86e5688e Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Thu, 28 Oct 2021 16:28:12 -0400 Subject: [PATCH 22/45] Rename functionality finished --- client/src/app/App.tsx | 7 +- .../editor/breadcrumb/useBreadcrumb.ts | 3 +- .../components/editorPanel/useEditorPanel.ts | 14 +- .../app/components/fileExplorer/Directory.tsx | 50 ------- .../src/app/components/fileExplorer/Note.tsx | 41 ------ .../fileExplorer/directory/UIDirectory.tsx | 116 ---------------- .../fileExplorer/directory/useDirectory.ts | 125 ------------------ .../node/renameField/useRenameField.ts | 1 + .../components/fileExplorer/note/UINote.tsx | 84 ------------ .../components/fileExplorer/note/useNote.ts | 117 ---------------- .../fileExplorer/useFileExplorer.ts | 28 ++-- client/src/shared/types.d.ts | 3 +- 12 files changed, 17 insertions(+), 572 deletions(-) delete mode 100644 client/src/app/components/fileExplorer/Directory.tsx delete mode 100644 client/src/app/components/fileExplorer/Note.tsx delete mode 100644 client/src/app/components/fileExplorer/directory/UIDirectory.tsx delete mode 100644 client/src/app/components/fileExplorer/directory/useDirectory.ts delete mode 100644 client/src/app/components/fileExplorer/note/UINote.tsx delete mode 100644 client/src/app/components/fileExplorer/note/useNote.ts diff --git a/client/src/app/App.tsx b/client/src/app/App.tsx index fbc7afa..f6f3760 100644 --- a/client/src/app/App.tsx +++ b/client/src/app/App.tsx @@ -20,8 +20,6 @@ export const editorReducer = (state: EditorState, action: EditorAction) => { return { ...state, primarySelection: action.primarySelection! }; case 'secondarySelect': return { ...state, secondarySelection: action.secondarySelection! }; - case 'rename': - return { ...state, isRenaming: action.isRenaming! }; } }; @@ -42,10 +40,7 @@ export function App() { <>
- + {notebook ? ( <> { @@ -39,14 +37,14 @@ export function useEditorPanel() { //setFileExplorerVisible(!fileExplorerVisible); //}); - + /* ipcRenderer.removeAllListeners('renameExplorerItem'); ipcRenderer.on('renameExplorerItem', () => { editorDispatch({ type: 'rename', isRenaming: true }); - }); + });*/ ipcRenderer.removeAllListeners('deleteExplorerItem'); ipcRenderer.on('deleteExplorerItem', () => { @@ -63,8 +61,7 @@ export function useEditorPanel() { editorDispatch({ type: 'secondarySelect', - secondarySelection: undefined, - isRenaming // find a way to not need this + secondarySelection: undefined }); }); }); @@ -73,7 +70,6 @@ export function useEditorPanel() { return { primarySelection, secondarySelection, - isRenaming, editorDispatch, text, setText diff --git a/client/src/app/components/fileExplorer/Directory.tsx b/client/src/app/components/fileExplorer/Directory.tsx deleted file mode 100644 index de7d5ac..0000000 --- a/client/src/app/components/fileExplorer/Directory.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import React from 'react'; -import { FileSystemItem } from '@types'; -import { UIDirectory } from './directory/UIDirectory'; -import { useDirectory } from './directory/useDirectory'; - -interface Props { - item: FileSystemItem; - depth?: number; - renameText: string; - setRenameText: React.Dispatch; -} - -export function Directory({ - item, - depth = 0, - renameText, - setRenameText -}: Props) { - const { - isOpened, - childItems, - handleClick, - handleContextMenu, - handleRenameKeyDown, - handleRenameFocus, - handleRenameChange, - handleRenameBlur - } = useDirectory({ - item, - renameText, - setRenameText - }); - - return ( - - ); -} diff --git a/client/src/app/components/fileExplorer/Note.tsx b/client/src/app/components/fileExplorer/Note.tsx deleted file mode 100644 index 0e2637f..0000000 --- a/client/src/app/components/fileExplorer/Note.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import React from 'react'; -import { FileSystemItem } from '@types'; -import { useNote } from './note/useNote'; -import { UINote } from './note/UINote'; - -interface Props { - item: FileSystemItem; - depth?: number; - renameText: string; - setRenameText: React.Dispatch; -} - -export function Note({ item, depth = 0, renameText, setRenameText }: Props) { - const { - handleRenameKeyDown, - handleRenameBlur, - handleClick, - handleContextMenu, - handleRenameChange, - handleRenameFocus - } = useNote({ - item, - renameText, - setRenameText - }); - - return ( - - ); -} diff --git a/client/src/app/components/fileExplorer/directory/UIDirectory.tsx b/client/src/app/components/fileExplorer/directory/UIDirectory.tsx deleted file mode 100644 index 05f2f2e..0000000 --- a/client/src/app/components/fileExplorer/directory/UIDirectory.tsx +++ /dev/null @@ -1,116 +0,0 @@ -import React from 'react'; -import { FileSystemItem } from '@types'; -import { Note } from '../Note'; -import { Directory } from '../Directory'; -import ChevronRightIcon from '@assets/icons/chevron-right.svg'; -import ChevronDownIcon from '@assets/icons/chevron-down.svg'; -import FolderIcon from '@assets/icons/folder-f.svg'; -import { useEditorStore } from '@hooks'; - -interface Props { - item: FileSystemItem; - childItems: FileSystemItem[]; - depth: number; - isOpened: boolean; - renameText: string; - setRenameText: React.Dispatch; - handleClick: () => void; - handleRenameBlur: () => void; - handleRenameChange: (event: React.ChangeEvent) => void; - handleRenameFocus: (event: React.FocusEvent) => void; - handleRenameKeyDown: (event: React.KeyboardEvent) => void; - handleContextMenu: () => void; -} - -export function UIDirectory({ - item, - childItems, - depth, - isOpened, - renameText, - setRenameText, - handleClick, - handleRenameBlur, - handleRenameChange, - handleRenameFocus, - handleRenameKeyDown, - handleContextMenu -}: Props) { - const [{ primarySelection, secondarySelection, isRenaming }] = - useEditorStore(); - - let style = ''; - - if (secondarySelection?.path === item.path) { - style = 'border-blue-500 border-opacity-70 border-2'; - } else if (primarySelection?.path === item.path) { - style = - 'bg-blue-500 border-blue-300 border bg-opacity-30 border-opacity-30'; - } else { - style = - 'hover:bg-opacity-30 hover:bg-gray-700 border border-transparent'; - } - - let displayItem = undefined; - if (isRenaming && secondarySelection?.path === item.path) { - displayItem = ( - - ); - } else { - displayItem =

{item.name}

; - } - - return ( -
-
- {isOpened ? ( - - ) : ( - - )} - - {displayItem} -
-
-
- {childItems.map((item) => { - return item.type === 'directory' ? ( - - ) : ( - - ); - })} -
-
- ); -} diff --git a/client/src/app/components/fileExplorer/directory/useDirectory.ts b/client/src/app/components/fileExplorer/directory/useDirectory.ts deleted file mode 100644 index 3ba7c73..0000000 --- a/client/src/app/components/fileExplorer/directory/useDirectory.ts +++ /dev/null @@ -1,125 +0,0 @@ -import React, { useState } from 'react'; -import { useEditorStore, useStore } from '../../../hooks'; -import { ipcRenderer } from 'electron'; -import { FileSystemItem } from '@types'; -import { - renameExplorerItem, - getFileSystemItems -} from '../../../../shared/utils'; - -interface Args { - item: FileSystemItem; - renameText: string; - setRenameText: React.Dispatch; -} - -export function useDirectory({ item, renameText, setRenameText }: Args) { - const [{ currentFile }, dispatch] = useStore(); - const [{ secondarySelection, isRenaming }, editorDispatch] = - useEditorStore(); - const [isOpened, setIsOpened] = useState(false); - - let childItems: FileSystemItem[] = isOpened - ? getFileSystemItems(item.path) - : []; - - const handleClick = () => { - if (secondarySelection?.path === item.path) { - return; - } else if (secondarySelection) { - editorDispatch({ - type: 'secondarySelect', - secondarySelection: undefined, - isRenaming - }); - } - - editorDispatch({ - type: 'primarySelect', - primarySelection: item, - isRenaming - }); - - setIsOpened(!isOpened); - }; - - const handleContextMenu = () => { - ipcRenderer.send('openExplorerFileContextMenu'); - - editorDispatch({ - type: 'secondarySelect', - secondarySelection: item, - isRenaming - }); - - setRenameText(item.name); - }; - - const handleRenameChange = (event: React.ChangeEvent) => { - setRenameText(event.target.value); - }; - - const handleRenameKeyDown = ( - event: React.KeyboardEvent - ) => { - if (event.key === 'Enter' || event.code === '13') { - renameExplorerItem(item.path, renameText) - .then((renamedItem) => { - editorDispatch({ - type: 'rename', - isRenaming: false - }); - - editorDispatch({ - type: 'secondarySelect', - secondarySelection: undefined, - isRenaming - }); - - if (item.path == currentFile?.path) { - dispatch({ - type: 'openNote', - currentFile: renamedItem - }); - } - }) - .catch((error) => { - console.log(error); - }); - } - if (event.key === 'Escape' || event.code === '27') { - editorDispatch({ - type: 'rename', - isRenaming: false - }); - - editorDispatch({ - type: 'secondarySelect', - secondarySelection: undefined, - isRenaming - }); - } - }; - - const handleRenameBlur = () => { - editorDispatch({ - type: 'rename', - isRenaming: false - }); - }; - - const handleRenameFocus = (event: React.FocusEvent) => { - event.target.select(); - }; - - return { - childItems, - isOpened, - handleClick, - handleRenameBlur, - handleRenameChange, - handleRenameFocus, - handleRenameKeyDown, - handleContextMenu - }; -} diff --git a/client/src/app/components/fileExplorer/node/renameField/useRenameField.ts b/client/src/app/components/fileExplorer/node/renameField/useRenameField.ts index 096455e..20f9314 100644 --- a/client/src/app/components/fileExplorer/node/renameField/useRenameField.ts +++ b/client/src/app/components/fileExplorer/node/renameField/useRenameField.ts @@ -31,6 +31,7 @@ export function useRenameField({ name, path, setRenaming }: Args) { type: 'secondarySelect', secondarySelection: undefined }); + setText(name); } }; diff --git a/client/src/app/components/fileExplorer/note/UINote.tsx b/client/src/app/components/fileExplorer/note/UINote.tsx deleted file mode 100644 index 04cf433..0000000 --- a/client/src/app/components/fileExplorer/note/UINote.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import React from 'react'; -import { useEditorStore, useStore } from '@hooks'; -import { FileSystemItem } from '@types'; -import FileIcon from '@assets/icons/file.svg'; - -interface Props { - item: FileSystemItem; - depth: number; - renameText: string; - setRenameText: React.Dispatch; - handleRenameKeyDown: (event: React.KeyboardEvent) => void; - handleRenameBlur: () => void; - handleClick: () => void; - handleContextMenu: () => void; - handleRenameChange: (event: React.ChangeEvent) => void; - handleRenameFocus: (event: React.FocusEvent) => void; -} - -export function UINote({ - item, - renameText, - depth = 0, - handleRenameBlur, - handleClick, - handleContextMenu, - handleRenameChange, - handleRenameFocus, - handleRenameKeyDown -}: Props) { - const [{ currentFile }] = useStore(); - const [{ primarySelection, secondarySelection, isRenaming }] = - useEditorStore(); - - let style = ''; - - if (secondarySelection?.path === item.path) { - style = 'border-blue-500 border-opacity-70 border-2'; - } else if (primarySelection?.path === item.path) { - style = - 'bg-blue-500 border-blue-300 border bg-opacity-30 border-opacity-30'; - } else { - style = 'hover:bg-opacity-30 hover:bg-gray-700 border-transparent'; - } - - let displayItem = undefined; - if (isRenaming && secondarySelection?.path === item.path) { - displayItem = ( - - ); - } else { - displayItem = ( -

- {item.name} -

- ); - } - - return ( -
- - {displayItem} -
- ); -} diff --git a/client/src/app/components/fileExplorer/note/useNote.ts b/client/src/app/components/fileExplorer/note/useNote.ts deleted file mode 100644 index 4c24af0..0000000 --- a/client/src/app/components/fileExplorer/note/useNote.ts +++ /dev/null @@ -1,117 +0,0 @@ -import React from 'react'; -import { useEditorStore, useStore } from '../../../hooks'; -import { ipcRenderer } from 'electron'; -import { FileSystemItem } from '../../../../shared/types'; -import { renameExplorerItem } from '../../../../shared/utils'; - -interface Args { - item: FileSystemItem; - renameText: string; - setRenameText: React.Dispatch; -} - -export function useNote({ item, renameText, setRenameText }: Args) { - const [{ currentFile }, dispatch] = useStore(); - const [{ secondarySelection, isRenaming }, editorDispatch] = - useEditorStore(); - const handleClick = () => { - if (secondarySelection?.path === item.path) { - return; - } else if (secondarySelection) { - editorDispatch({ - type: 'secondarySelect', - secondarySelection: undefined, - isRenaming - }); - } - - editorDispatch({ - type: 'primarySelect', - primarySelection: item, - isRenaming - }); - - dispatch({ - type: 'openNote', - currentFile: { - name: item.name, - path: item.path - } - }); - }; - - const handleContextMenu = () => { - ipcRenderer.send('openExplorerFileContextMenu'); - - editorDispatch({ - type: 'secondarySelect', - secondarySelection: item, - isRenaming - }); - - setRenameText(item.name); - }; - - const handleRenameChange = (event: React.ChangeEvent) => { - setRenameText(event.target.value); - }; - - const handleRenameKeyDown = ( - event: React.KeyboardEvent - ) => { - if (event.key === 'Enter' || event.code === '13') { - renameExplorerItem(item.path, renameText).then((renamedItem) => { - editorDispatch({ - type: 'rename', - isRenaming: false - }); - - editorDispatch({ - type: 'secondarySelect', - secondarySelection: undefined, - isRenaming - }); - - if (item.path == currentFile?.path) { - dispatch({ - type: 'openNote', - currentFile: renamedItem - }); - } - }); - } - - if (event.key === 'Escape' || event.code === '27') { - editorDispatch({ - type: 'rename', - isRenaming: false - }); - - editorDispatch({ - type: 'secondarySelect', - secondarySelection: undefined, - isRenaming - }); - } - }; - - const handleRenameBlur = () => { - editorDispatch({ - type: 'rename', - isRenaming: false - }); - }; - - const handleRenameFocus = (event: React.FocusEvent) => { - event.target.select(); - }; - - return { - handleClick, - handleContextMenu, - handleRenameChange, - handleRenameKeyDown, - handleRenameBlur, - handleRenameFocus - }; -} diff --git a/client/src/app/components/fileExplorer/useFileExplorer.ts b/client/src/app/components/fileExplorer/useFileExplorer.ts index 47ded0b..ae70387 100644 --- a/client/src/app/components/fileExplorer/useFileExplorer.ts +++ b/client/src/app/components/fileExplorer/useFileExplorer.ts @@ -1,18 +1,10 @@ import React, { useState } from 'react'; import { useEditorStore, useStore } from '@hooks'; -import { - createFile, - getParentDirectory, - createDirectory, - renameExplorerItem -} from '@utils'; +import { createFile, getParentDirectory, createDirectory } from '@utils'; export function useFileExplorer() { - const [{ notebook, currentFile }, dispatch] = useStore(); - const [ - { primarySelection, secondarySelection, isRenaming }, - editorDispatch - ] = useEditorStore(); + const [{ notebook }, dispatch] = useStore(); + const [{ primarySelection }, editorDispatch] = useEditorStore(); const [renameText, setRenameText] = useState(''); const handleAddFileClick = () => { @@ -35,8 +27,7 @@ export function useFileExplorer() { editorDispatch({ type: 'primarySelect', - primarySelection: newDirectory, - isRenaming + primarySelection: newDirectory }); }; @@ -45,16 +36,14 @@ export function useFileExplorer() { editorDispatch({ type: 'primarySelect', - primarySelection: undefined, - isRenaming + primarySelection: undefined }); editorDispatch({ type: 'secondarySelect', - secondarySelection: undefined, - isRenaming + secondarySelection: undefined }); - + /* if (isRenaming) { renameExplorerItem(secondarySelection?.path!, renameText) .then((renamedItem) => { @@ -66,7 +55,6 @@ export function useFileExplorer() { editorDispatch({ type: 'secondarySelect', secondarySelection: undefined, - isRenaming }); if (secondarySelection?.path == currentFile?.path) { @@ -79,7 +67,7 @@ export function useFileExplorer() { .catch((error) => { console.log(error); }); - } + }*/ }; return { diff --git a/client/src/shared/types.d.ts b/client/src/shared/types.d.ts index aa36872..9768b20 100644 --- a/client/src/shared/types.d.ts +++ b/client/src/shared/types.d.ts @@ -69,11 +69,10 @@ export interface UserAction extends UserState { export interface EditorState { primarySelection?: FileSystemItem; secondarySelection?: FileSystemItem; - isRenaming: boolean; } export interface EditorAction extends Partial { - type: 'primarySelect' | 'secondarySelect' | 'rename'; + type: 'primarySelect' | 'secondarySelect'; } export interface RegisterFormValues { From a8a8c5c189764b9676b23cd2a3b159f62d2291c5 Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Thu, 28 Oct 2021 17:25:18 -0400 Subject: [PATCH 23/45] Add file explorer refresh with chokidar --- client/package-lock.json | 30 +++++++++++ client/package.json | 2 + client/src/app/App.tsx | 5 +- client/src/app/components/FileExplorer.tsx | 14 ++--- .../fileExplorer/UIFileExplorer.tsx | 2 - .../fileExplorer/useFileExplorer.ts | 52 +++++++------------ client/src/app/hooks/index.ts | 1 + client/src/app/hooks/useForceUpdate.ts | 11 ++++ .../shared/utils/fileSystem/watchDirectory.ts | 5 ++ client/src/shared/utils/index.ts | 1 + client/webpack.config.js | 12 ++++- 11 files changed, 85 insertions(+), 50 deletions(-) create mode 100644 client/src/app/hooks/useForceUpdate.ts create mode 100644 client/src/shared/utils/fileSystem/watchDirectory.ts diff --git a/client/package-lock.json b/client/package-lock.json index 380803b..469b0c0 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -18,6 +18,7 @@ "axios": "^0.23.0", "babel-core": "^6.26.3", "babel-preset-react": "^6.24.1", + "chokidar": "^3.5.2", "google-auth-library": "^7.10.1", "googleapis": "^89.0.0", "highlight.js": "^11.3.1", @@ -66,6 +67,7 @@ "mini-css-extract-plugin": "^2.3.0", "mock-fs": "^5.1.1", "module-alias": "^2.2.2", + "node-loader": "^2.0.0", "postcss-cli": "^8.3.1", "postcss-loader": "^6.1.1", "prettier": "2.4.1", @@ -9901,6 +9903,25 @@ "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", "dev": true }, + "node_modules/node-loader": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/node-loader/-/node-loader-2.0.0.tgz", + "integrity": "sha512-I5VN34NO4/5UYJaUBtkrODPWxbobrE4hgDqPrjB25yPkonFhCmZ146vTH+Zg417E9Iwoh1l/MbRs1apc5J295Q==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, "node_modules/node-modules-regexp": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", @@ -21310,6 +21331,15 @@ "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", "dev": true }, + "node-loader": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/node-loader/-/node-loader-2.0.0.tgz", + "integrity": "sha512-I5VN34NO4/5UYJaUBtkrODPWxbobrE4hgDqPrjB25yPkonFhCmZ146vTH+Zg417E9Iwoh1l/MbRs1apc5J295Q==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0" + } + }, "node-modules-regexp": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", diff --git a/client/package.json b/client/package.json index ee9bb99..248cdae 100644 --- a/client/package.json +++ b/client/package.json @@ -43,6 +43,7 @@ "mini-css-extract-plugin": "^2.3.0", "mock-fs": "^5.1.1", "module-alias": "^2.2.2", + "node-loader": "^2.0.0", "postcss-cli": "^8.3.1", "postcss-loader": "^6.1.1", "prettier": "2.4.1", @@ -66,6 +67,7 @@ "axios": "^0.23.0", "babel-core": "^6.26.3", "babel-preset-react": "^6.24.1", + "chokidar": "^3.5.2", "google-auth-library": "^7.10.1", "googleapis": "^89.0.0", "highlight.js": "^11.3.1", diff --git a/client/src/app/App.tsx b/client/src/app/App.tsx index f6f3760..b365016 100644 --- a/client/src/app/App.tsx +++ b/client/src/app/App.tsx @@ -10,7 +10,6 @@ import { getUser } from '@shared/Api/getUser'; import { useIpcListeners } from './hooks/useIpcListeners'; import { useGoogleDrive } from './hooks/useGoogleDrive'; import { FileExplorer } from './components/FileExplorer'; -import { getFileSystemItems } from '@shared/utils'; import { Placeholder } from './components/Placeholder'; import { NotificationArea } from './components/NotificationArea'; @@ -43,9 +42,7 @@ export function App() { {notebook ? ( <> - + ) : ( diff --git a/client/src/app/components/FileExplorer.tsx b/client/src/app/components/FileExplorer.tsx index 73df14e..c3a0aa1 100644 --- a/client/src/app/components/FileExplorer.tsx +++ b/client/src/app/components/FileExplorer.tsx @@ -1,19 +1,13 @@ import React from 'react'; -import { FileSystemItem } from '@types'; import { UIFileExplorer } from './fileExplorer/UIFileExplorer'; import { useFileExplorer } from './fileExplorer/useFileExplorer'; -interface Props { - items: FileSystemItem[]; -} - -export function FileExplorer({ items }: Props) { +export function FileExplorer() { const { + items, handleAddDirectoryClick, handleAddFileClick, - handleOuterClick, - renameText, - setRenameText + handleOuterClick } = useFileExplorer(); return ( @@ -22,8 +16,6 @@ export function FileExplorer({ items }: Props) { handleAddDirectoryClick={handleAddDirectoryClick} handleAddFileClick={handleAddFileClick} handleOuterClick={handleOuterClick} - renameText={renameText} - setRenameText={setRenameText} /> ); } diff --git a/client/src/app/components/fileExplorer/UIFileExplorer.tsx b/client/src/app/components/fileExplorer/UIFileExplorer.tsx index 7b25190..1004945 100644 --- a/client/src/app/components/fileExplorer/UIFileExplorer.tsx +++ b/client/src/app/components/fileExplorer/UIFileExplorer.tsx @@ -11,8 +11,6 @@ interface Props { handleAddFileClick: () => void; handleAddDirectoryClick: () => void; handleOuterClick: (event: React.MouseEvent) => void; - renameText: string; - setRenameText: React.Dispatch; } export function UIFileExplorer({ diff --git a/client/src/app/components/fileExplorer/useFileExplorer.ts b/client/src/app/components/fileExplorer/useFileExplorer.ts index ae70387..8714b3c 100644 --- a/client/src/app/components/fileExplorer/useFileExplorer.ts +++ b/client/src/app/components/fileExplorer/useFileExplorer.ts @@ -1,11 +1,25 @@ -import React, { useState } from 'react'; -import { useEditorStore, useStore } from '@hooks'; -import { createFile, getParentDirectory, createDirectory } from '@utils'; +import React, { useEffect } from 'react'; +import { useEditorStore, useStore, useForceUpdate } from '@hooks'; +import { + createFile, + getParentDirectory, + createDirectory, + getFileSystemItems, + watchDirectory +} from '@utils'; export function useFileExplorer() { const [{ notebook }, dispatch] = useStore(); const [{ primarySelection }, editorDispatch] = useEditorStore(); - const [renameText, setRenameText] = useState(''); + const forceUpdate = useForceUpdate(); + + const items = notebook ? getFileSystemItems(notebook) : []; + + useEffect(() => { + if (!notebook) return; + + watchDirectory(notebook, () => forceUpdate()); + }, [notebook]); const handleAddFileClick = () => { const newFilePath = primarySelection @@ -43,38 +57,12 @@ export function useFileExplorer() { type: 'secondarySelect', secondarySelection: undefined }); - /* - if (isRenaming) { - renameExplorerItem(secondarySelection?.path!, renameText) - .then((renamedItem) => { - editorDispatch({ - type: 'rename', - isRenaming: false - }); - - editorDispatch({ - type: 'secondarySelect', - secondarySelection: undefined, - }); - - if (secondarySelection?.path == currentFile?.path) { - dispatch({ - type: 'openNote', - currentFile: renamedItem - }); - } - }) - .catch((error) => { - console.log(error); - }); - }*/ }; return { + items, handleAddFileClick, handleAddDirectoryClick, - handleOuterClick, - renameText, - setRenameText + handleOuterClick }; } diff --git a/client/src/app/hooks/index.ts b/client/src/app/hooks/index.ts index 99749fb..b155f01 100644 --- a/client/src/app/hooks/index.ts +++ b/client/src/app/hooks/index.ts @@ -1,2 +1,3 @@ export * from './contexts'; export { useVerificationForm } from './useVerificationForm'; +export { useForceUpdate } from './useForceUpdate'; diff --git a/client/src/app/hooks/useForceUpdate.ts b/client/src/app/hooks/useForceUpdate.ts new file mode 100644 index 0000000..af9a6c8 --- /dev/null +++ b/client/src/app/hooks/useForceUpdate.ts @@ -0,0 +1,11 @@ +import { useState } from 'react'; + +export function useForceUpdate() { + const [trigger, setTrigger] = useState(false); + + const forceUpdate = () => { + setTrigger(!trigger); + }; + + return forceUpdate; +} diff --git a/client/src/shared/utils/fileSystem/watchDirectory.ts b/client/src/shared/utils/fileSystem/watchDirectory.ts new file mode 100644 index 0000000..570e45f --- /dev/null +++ b/client/src/shared/utils/fileSystem/watchDirectory.ts @@ -0,0 +1,5 @@ +import chokidar from 'chokidar'; + +export const watchDirectory = (path: string, cb: () => any) => { + chokidar.watch(path).on('all', cb); +}; diff --git a/client/src/shared/utils/index.ts b/client/src/shared/utils/index.ts index cf6bf85..208703b 100644 --- a/client/src/shared/utils/index.ts +++ b/client/src/shared/utils/index.ts @@ -15,3 +15,4 @@ export { saveFile } from './fileSystem/saveFile'; export { useRelativePath } from './fileSystem/useRelativePath'; export { parseCodeFromUrl } from './parseCodeFromUrl'; export { updateConfig } from './updateConfig'; +export { watchDirectory } from './fileSystem/watchDirectory'; diff --git a/client/webpack.config.js b/client/webpack.config.js index 9124b2a..83ec5d4 100644 --- a/client/webpack.config.js +++ b/client/webpack.config.js @@ -24,6 +24,9 @@ module.exports = [ output: { path: __dirname + '/dist', filename: 'electron.js' + }, + externals: { + fsevents: require('fsevents') } }, { @@ -66,6 +69,10 @@ module.exports = [ { test: /\.svg/, use: ['@svgr/webpack'] + }, + { + test: /.node$/, + loader: 'node-loader' } ] }, @@ -84,6 +91,9 @@ module.exports = [ new HtmlWebpackInlineSVGPlugin({ runPreEmit: true }) - ] + ], + externals: { + fsevents: require('fsevents') + } } ]; From 3adf7c45f9949ce1a128db23a3b731f86809cafe Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Thu, 28 Oct 2021 18:56:05 -0400 Subject: [PATCH 24/45] Relative paths for images --- client/src/app/components/editorPanel/preview/usePreview.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client/src/app/components/editorPanel/preview/usePreview.ts b/client/src/app/components/editorPanel/preview/usePreview.ts index 47ac4f4..602b35d 100644 --- a/client/src/app/components/editorPanel/preview/usePreview.ts +++ b/client/src/app/components/editorPanel/preview/usePreview.ts @@ -1,12 +1,16 @@ import marked from 'marked'; import parse from 'html-react-parser'; import hljs from 'highlight.js'; +import { useStore } from '@hooks'; export function usePreview(text: string) { + const [{ notebook }] = useStore(); + const html = marked(text, { highlight: (code: string) => { return hljs.highlightAuto(code).value; // no lang selected ,throws error - } + }, + baseUrl: notebook }); return parse(html); From 964c497c1f7c91125450968f376a3471d486d6e9 Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Thu, 28 Oct 2021 22:25:50 -0400 Subject: [PATCH 25/45] Add embedded attachments --- .../components/editorPanel/preview/theme.css | 6 +- .../editorPanel/preview/usePreview.ts | 17 ---- .../editorPanel/preview/usePreview.tsx | 92 +++++++++++++++++++ .../shared/utils/fileSystem/getFileSize.ts | 7 ++ client/src/shared/utils/index.ts | 1 + 5 files changed, 105 insertions(+), 18 deletions(-) delete mode 100644 client/src/app/components/editorPanel/preview/usePreview.ts create mode 100644 client/src/app/components/editorPanel/preview/usePreview.tsx create mode 100644 client/src/shared/utils/fileSystem/getFileSize.ts diff --git a/client/src/app/components/editorPanel/preview/theme.css b/client/src/app/components/editorPanel/preview/theme.css index 8ce4d8b..be9a5d9 100644 --- a/client/src/app/components/editorPanel/preview/theme.css +++ b/client/src/app/components/editorPanel/preview/theme.css @@ -30,10 +30,14 @@ @apply rounded-xl; } -#wrapper a { +#wrapper a:not(.attachment-link) { @apply text-blue-500 hover:underline; } +#wrapper .attachment-link a { + @apply hover:no-underline text-gray-400; +} + #wrapper > p > code { @apply inline-block bg-gray-800 border border-gray-700 rounded-md p-0.5 m-0.5 text-sm font-mono; } diff --git a/client/src/app/components/editorPanel/preview/usePreview.ts b/client/src/app/components/editorPanel/preview/usePreview.ts deleted file mode 100644 index 602b35d..0000000 --- a/client/src/app/components/editorPanel/preview/usePreview.ts +++ /dev/null @@ -1,17 +0,0 @@ -import marked from 'marked'; -import parse from 'html-react-parser'; -import hljs from 'highlight.js'; -import { useStore } from '@hooks'; - -export function usePreview(text: string) { - const [{ notebook }] = useStore(); - - const html = marked(text, { - highlight: (code: string) => { - return hljs.highlightAuto(code).value; // no lang selected ,throws error - }, - baseUrl: notebook - }); - - return parse(html); -} diff --git a/client/src/app/components/editorPanel/preview/usePreview.tsx b/client/src/app/components/editorPanel/preview/usePreview.tsx new file mode 100644 index 0000000..07ab444 --- /dev/null +++ b/client/src/app/components/editorPanel/preview/usePreview.tsx @@ -0,0 +1,92 @@ +import React from 'react'; +import marked from 'marked'; +import parse from 'html-react-parser'; +import hljs from 'highlight.js'; +import { useStore } from '@hooks'; +import AttachmentIcon from '@assets/icons/attachment.svg'; +import { renderToString } from 'react-dom/server'; +import { fileExist, getFileSize } from '@utils'; +import path from 'path'; + +export function usePreview(text: string) { + const [{ notebook }] = useStore(); + + const baseUrl = notebook!; + + const attachments: any = { + name: 'attachment', + level: 'block', + start(src: string) { + return src.match(/^\[.*]\{(.*\..*)\}\s?$/)?.index || -1; + }, + tokenizer(src: string, _: any) { + // goal: /^\[.*]\((.*\..*)\)\s?$/ + const rule = /^\[(.*)]\{(.*\..*)\}\s?$/; + const match = rule.exec(src); + + if (match) { + const token = { + type: 'attachment', + raw: match[0], + text: match[1].trim(), + link: match[2].trim(), + tokens: [] + }; + + this.lexer.inline(token.text, token.tokens); + + return token; + } + + return; + }, + renderer(token: any) { + let baseUrlParent = baseUrl.substring(0, baseUrl.lastIndexOf('/')); + const fileUrl = path.join(baseUrlParent, token.link); + const found = fileExist(fileUrl); + + const render = found + ? ` + +
+ ${renderToString()} +

${ + token.text + }

+
+

${getFileSize( + fileUrl + )} kB

+
+ ` + : ` +
+ ${renderToString()} +

${token.text}

+
+ `; + + return `
+ ${render} +
`; + }, + childTokens: [] + }; + + marked.use({ + extensions: [attachments] + }); + + const html = marked(text, { + highlight: (code: string) => { + return hljs.highlightAuto(code).value; // no lang selected ,throws error + }, + baseUrl + }); + + return parse(html); +} diff --git a/client/src/shared/utils/fileSystem/getFileSize.ts b/client/src/shared/utils/fileSystem/getFileSize.ts new file mode 100644 index 0000000..797ba75 --- /dev/null +++ b/client/src/shared/utils/fileSystem/getFileSize.ts @@ -0,0 +1,7 @@ +import fs from 'fs'; + +/** Returns file size in kB */ +export const getFileSize = (path: string) => { + const fileStats = fs.statSync(path); + return (fileStats.size / 1024).toFixed(2); +}; diff --git a/client/src/shared/utils/index.ts b/client/src/shared/utils/index.ts index 208703b..b5e133f 100644 --- a/client/src/shared/utils/index.ts +++ b/client/src/shared/utils/index.ts @@ -16,3 +16,4 @@ export { useRelativePath } from './fileSystem/useRelativePath'; export { parseCodeFromUrl } from './parseCodeFromUrl'; export { updateConfig } from './updateConfig'; export { watchDirectory } from './fileSystem/watchDirectory'; +export { getFileSize } from './fileSystem/getFileSize'; From 1da4aa4ea250c90155cf623121905051de529b37 Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Thu, 28 Oct 2021 22:40:59 -0400 Subject: [PATCH 26/45] make fsevents optional --- client/package-lock.json | 4 ++++ client/package.json | 3 +++ client/webpack.config.js | 3 ++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/client/package-lock.json b/client/package-lock.json index 469b0c0..7978ea1 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -19,6 +19,7 @@ "babel-core": "^6.26.3", "babel-preset-react": "^6.24.1", "chokidar": "^3.5.2", + "fsevents": "*", "google-auth-library": "^7.10.1", "googleapis": "^89.0.0", "highlight.js": "^11.3.1", @@ -80,6 +81,9 @@ "url-loader": "^4.1.1", "webpack": "^5.53.0", "webpack-cli": "^4.8.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" } }, "node_modules/@babel/cli": { diff --git a/client/package.json b/client/package.json index 248cdae..bcfe229 100644 --- a/client/package.json +++ b/client/package.json @@ -85,5 +85,8 @@ "react-syntax-highlighter": "^15.4.4", "typesafe-actions": "^5.1.0", "yup": "^0.32.9" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" } } diff --git a/client/webpack.config.js b/client/webpack.config.js index 83ec5d4..56cf57e 100644 --- a/client/webpack.config.js +++ b/client/webpack.config.js @@ -2,6 +2,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const HtmlWebpackInlineSVGPlugin = require('html-webpack-inline-svg-plugin'); const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin'); +const { node } = require('webpack'); module.exports = [ { @@ -93,7 +94,7 @@ module.exports = [ }) ], externals: { - fsevents: require('fsevents') + fsevents: require('fsevents') || undefined } } ]; From 8d526153afdf8cbf944b9225c02d6a6283805d04 Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Thu, 28 Oct 2021 22:50:07 -0400 Subject: [PATCH 27/45] Add fsevents to mac-only --- client/webpack.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/webpack.config.js b/client/webpack.config.js index 56cf57e..9de5688 100644 --- a/client/webpack.config.js +++ b/client/webpack.config.js @@ -94,7 +94,7 @@ module.exports = [ }) ], externals: { - fsevents: require('fsevents') || undefined + fsevents: process.platform === 'darwin' && require('fsevents') } } ]; From 2a5d5fbfa55542555f04da33265e598eaec5fc37 Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Thu, 28 Oct 2021 23:26:37 -0400 Subject: [PATCH 28/45] Replace chokidar with node-watch --- client/package-lock.json | 18 ++++++++++++++---- client/package.json | 4 +--- .../shared/utils/fileSystem/watchDirectory.ts | 4 ++-- client/webpack.config.js | 8 +------- 4 files changed, 18 insertions(+), 16 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index 7978ea1..7827c13 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -19,7 +19,6 @@ "babel-core": "^6.26.3", "babel-preset-react": "^6.24.1", "chokidar": "^3.5.2", - "fsevents": "*", "google-auth-library": "^7.10.1", "googleapis": "^89.0.0", "highlight.js": "^11.3.1", @@ -28,6 +27,7 @@ "marked": "^3.0.8", "monaco-editor": "^0.29.1", "mrm": "^3.0.9", + "node-watch": "^0.7.2", "nodemailer": "^6.7.0", "react": "^17.0.2", "react-dom": "^17.0.2", @@ -81,9 +81,6 @@ "url-loader": "^4.1.1", "webpack": "^5.53.0", "webpack-cli": "^4.8.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" } }, "node_modules/@babel/cli": { @@ -9940,6 +9937,14 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.76.tgz", "integrity": "sha512-9/IECtNr8dXNmPWmFXepT0/7o5eolGesHUa3mtr0KlgnCvnZxwh2qensKL42JJY2vQKC3nIBXetFAqR+PW1CmA==" }, + "node_modules/node-watch": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/node-watch/-/node-watch-0.7.2.tgz", + "integrity": "sha512-g53VjSARRv1JdST0LZRIg8RiuLr1TaBbVPsVvxh0/0Ymvi0xYUjDuoqQQAWtHJQUXhiShowPT/aXKNeHBcyQsw==", + "engines": { + "node": ">=6" + } + }, "node_modules/nodemailer": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.0.tgz", @@ -21355,6 +21360,11 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.76.tgz", "integrity": "sha512-9/IECtNr8dXNmPWmFXepT0/7o5eolGesHUa3mtr0KlgnCvnZxwh2qensKL42JJY2vQKC3nIBXetFAqR+PW1CmA==" }, + "node-watch": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/node-watch/-/node-watch-0.7.2.tgz", + "integrity": "sha512-g53VjSARRv1JdST0LZRIg8RiuLr1TaBbVPsVvxh0/0Ymvi0xYUjDuoqQQAWtHJQUXhiShowPT/aXKNeHBcyQsw==" + }, "nodemailer": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.0.tgz", diff --git a/client/package.json b/client/package.json index bcfe229..353cad4 100644 --- a/client/package.json +++ b/client/package.json @@ -76,6 +76,7 @@ "marked": "^3.0.8", "monaco-editor": "^0.29.1", "mrm": "^3.0.9", + "node-watch": "^0.7.2", "nodemailer": "^6.7.0", "react": "^17.0.2", "react-dom": "^17.0.2", @@ -85,8 +86,5 @@ "react-syntax-highlighter": "^15.4.4", "typesafe-actions": "^5.1.0", "yup": "^0.32.9" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" } } diff --git a/client/src/shared/utils/fileSystem/watchDirectory.ts b/client/src/shared/utils/fileSystem/watchDirectory.ts index 570e45f..ae6f7e8 100644 --- a/client/src/shared/utils/fileSystem/watchDirectory.ts +++ b/client/src/shared/utils/fileSystem/watchDirectory.ts @@ -1,5 +1,5 @@ -import chokidar from 'chokidar'; +import watch from 'node-watch'; export const watchDirectory = (path: string, cb: () => any) => { - chokidar.watch(path).on('all', cb); + watch(path, { recursive: true }, cb); }; diff --git a/client/webpack.config.js b/client/webpack.config.js index 9de5688..c820efa 100644 --- a/client/webpack.config.js +++ b/client/webpack.config.js @@ -25,9 +25,6 @@ module.exports = [ output: { path: __dirname + '/dist', filename: 'electron.js' - }, - externals: { - fsevents: require('fsevents') } }, { @@ -92,9 +89,6 @@ module.exports = [ new HtmlWebpackInlineSVGPlugin({ runPreEmit: true }) - ], - externals: { - fsevents: process.platform === 'darwin' && require('fsevents') - } + ] } ]; From 450f19b40781f10b26b05b466e49565066d21596 Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Fri, 29 Oct 2021 00:15:40 -0400 Subject: [PATCH 29/45] Display extension on embedded attachment --- client/package-lock.json | 14 ++++---- client/package.json | 2 +- .../editorPanel/preview/usePreview.tsx | 24 +++++++++----- .../components/fileExplorer/Attachment.tsx | 21 ------------ .../fileExplorer/attachment/UIAttachment.tsx | 33 ------------------- .../fileExplorer/attachment/useAttachment.ts | 12 ------- 6 files changed, 23 insertions(+), 83 deletions(-) delete mode 100644 client/src/app/components/fileExplorer/Attachment.tsx delete mode 100644 client/src/app/components/fileExplorer/attachment/UIAttachment.tsx delete mode 100644 client/src/app/components/fileExplorer/attachment/useAttachment.ts diff --git a/client/package-lock.json b/client/package-lock.json index 7827c13..40bcb8b 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -51,7 +51,7 @@ "@types/jest": "^27.0.2", "@types/marked": "^3.0.2", "@types/mock-fs": "^4.13.1", - "@types/react": "^17.0.24", + "@types/react": "^17.0.33", "@types/react-router": "^5.1.17", "@types/react-router-dom": "^5.3.2", "@types/react-syntax-highlighter": "^13.5.2", @@ -2867,9 +2867,9 @@ "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==" }, "node_modules/@types/react": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.24.tgz", - "integrity": "sha512-eIpyco99gTH+FTI3J7Oi/OH8MZoFMJuztNRimDOJwH4iGIsKV2qkGnk4M9VzlaVWeEEWLWSQRy0FEA0Kz218cg==", + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.33.tgz", + "integrity": "sha512-pLWntxXpDPaU+RTAuSGWGSEL2FRTNyRQOjSWDke/rxRg14ncsZvx8AKWMWZqvc1UOaJIAoObdZhAWvRaHFi5rw==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -15873,9 +15873,9 @@ "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==" }, "@types/react": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.24.tgz", - "integrity": "sha512-eIpyco99gTH+FTI3J7Oi/OH8MZoFMJuztNRimDOJwH4iGIsKV2qkGnk4M9VzlaVWeEEWLWSQRy0FEA0Kz218cg==", + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.33.tgz", + "integrity": "sha512-pLWntxXpDPaU+RTAuSGWGSEL2FRTNyRQOjSWDke/rxRg14ncsZvx8AKWMWZqvc1UOaJIAoObdZhAWvRaHFi5rw==", "requires": { "@types/prop-types": "*", "@types/scheduler": "*", diff --git a/client/package.json b/client/package.json index 353cad4..8d8e36c 100644 --- a/client/package.json +++ b/client/package.json @@ -26,7 +26,7 @@ "@types/jest": "^27.0.2", "@types/marked": "^3.0.2", "@types/mock-fs": "^4.13.1", - "@types/react": "^17.0.24", + "@types/react": "^17.0.33", "@types/react-router": "^5.1.17", "@types/react-router-dom": "^5.3.2", "@types/react-syntax-highlighter": "^13.5.2", diff --git a/client/src/app/components/editorPanel/preview/usePreview.tsx b/client/src/app/components/editorPanel/preview/usePreview.tsx index 07ab444..7d2801a 100644 --- a/client/src/app/components/editorPanel/preview/usePreview.tsx +++ b/client/src/app/components/editorPanel/preview/usePreview.tsx @@ -43,20 +43,26 @@ export function usePreview(text: string) { renderer(token: any) { let baseUrlParent = baseUrl.substring(0, baseUrl.lastIndexOf('/')); const fileUrl = path.join(baseUrlParent, token.link); + const fileExt = fileUrl.substring(fileUrl.lastIndexOf('.') + 1); const found = fileExist(fileUrl); const render = found ? ` - - `; - return `
+ } p-2 my-2 cursor-pointer rounded-md min-w-min w-4/6 mr-auto'> ${render}
`; }, diff --git a/client/src/app/components/fileExplorer/Attachment.tsx b/client/src/app/components/fileExplorer/Attachment.tsx deleted file mode 100644 index 594cedd..0000000 --- a/client/src/app/components/fileExplorer/Attachment.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; -import { FileSystemItem } from '@types'; -import { useAttachment } from './attachment/useAttachment'; -import { UIAttachment } from './attachment/UIAttachment'; - -interface props { - item: FileSystemItem; - depth?: number; - renameText: string; - setRenameText: React.Dispatch; -} - -export function Attachment({ - item, - depth = 0, - renameText, - setRenameText -}: props) { - useAttachment({ item, renameText, setRenameText }); - return ; -} diff --git a/client/src/app/components/fileExplorer/attachment/UIAttachment.tsx b/client/src/app/components/fileExplorer/attachment/UIAttachment.tsx deleted file mode 100644 index 396c4c2..0000000 --- a/client/src/app/components/fileExplorer/attachment/UIAttachment.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import React from 'react'; -import AttachmentIcon from '@assets/icons/attachment.svg'; -import { useEditorStore } from '@hooks'; -import { FileSystemItem } from '@types'; - -interface Props { - depth: number; - item: FileSystemItem; -} - -export function UIAttachment({ depth, item }: Props) { - const [{ primarySelection, secondarySelection }] = useEditorStore(); - - let style = ''; - - if (secondarySelection?.path === item.path) { - style = 'border-blue-500 border-opacity-70 border-2'; - } else if (primarySelection?.path === item.path) { - style = - 'bg-blue-500 border-blue-300 border bg-opacity-30 border-opacity-30'; - } else { - style = 'hover:bg-opacity-30 hover:bg-gray-700 border-transparent'; - } - - return ( -
- -
- ); -} diff --git a/client/src/app/components/fileExplorer/attachment/useAttachment.ts b/client/src/app/components/fileExplorer/attachment/useAttachment.ts deleted file mode 100644 index e70f9f5..0000000 --- a/client/src/app/components/fileExplorer/attachment/useAttachment.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { FileSystemItem } from '@types'; - -interface args { - item: FileSystemItem; - renameText: string; - setRenameText: React.Dispatch; -} - -export function useAttachment({}: args) { - const x: Partial = {}; - console.log(x); -} From e2736928c8fa82aeef1c9b9b0848c998cee32bc8 Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Fri, 29 Oct 2021 09:31:00 -0400 Subject: [PATCH 30/45] Fix spacing for ext --- client/src/app/components/editorPanel/preview/usePreview.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/app/components/editorPanel/preview/usePreview.tsx b/client/src/app/components/editorPanel/preview/usePreview.tsx index 7d2801a..2f2673d 100644 --- a/client/src/app/components/editorPanel/preview/usePreview.tsx +++ b/client/src/app/components/editorPanel/preview/usePreview.tsx @@ -55,8 +55,8 @@ export function usePreview(text: string) { token.text }

-
-

+

+

${fileExt}

From 1eb5534579527ba72f90dfd1d23c42f034024c53 Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Fri, 29 Oct 2021 12:49:11 -0400 Subject: [PATCH 31/45] Detect drop --- client/package-lock.json | 71 +++++++++++++++++++ client/package.json | 1 + .../editorPanel/editor/Dropzone.tsx | 35 +++++++++ .../editorPanel/editor/UIEditor.tsx | 63 ++++++++-------- client/src/app/hooks/index.ts | 1 + client/src/app/hooks/useEditorDrop.ts | 12 ++++ 6 files changed, 153 insertions(+), 30 deletions(-) create mode 100644 client/src/app/components/editorPanel/editor/Dropzone.tsx create mode 100644 client/src/app/hooks/useEditorDrop.ts diff --git a/client/package-lock.json b/client/package-lock.json index 40bcb8b..7ceced9 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -31,6 +31,7 @@ "nodemailer": "^6.7.0", "react": "^17.0.2", "react-dom": "^17.0.2", + "react-dropzone": "^11.4.2", "react-hook-form": "^7.16.1", "react-router": "^5.2.1", "react-router-dom": "^5.3.0", @@ -3458,6 +3459,14 @@ "node": ">= 4.5.0" } }, + "node_modules/attr-accept": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz", + "integrity": "sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==", + "engines": { + "node": ">=4" + } + }, "node_modules/autoprefixer": { "version": "10.3.5", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.3.5.tgz", @@ -6090,6 +6099,22 @@ "webpack": "^4.0.0 || ^5.0.0" } }, + "node_modules/file-selector": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.2.4.tgz", + "integrity": "sha512-ZDsQNbrv6qRi1YTDOEWzf5J2KjZ9KMI1Q2SGeTkCJmNNW25Jg4TW4UMcmoqcg4WrAyKRcpBXdbWRxkfrOzVRbA==", + "dependencies": { + "tslib": "^2.0.3" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/file-selector/node_modules/tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -11185,6 +11210,22 @@ "react": "17.0.2" } }, + "node_modules/react-dropzone": { + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-11.4.2.tgz", + "integrity": "sha512-ocYzYn7Qgp0tFc1gQtUTOaHHSzVTwhWHxxY+r7cj2jJTPfMTZB5GWSJHdIVoxsl+EQENpjJ/6Zvcw0BqKZQ+Eg==", + "dependencies": { + "attr-accept": "^2.2.1", + "file-selector": "^0.2.2", + "prop-types": "^15.7.2" + }, + "engines": { + "node": ">= 10" + }, + "peerDependencies": { + "react": ">= 16.8" + } + }, "node_modules/react-error-boundary": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.3.tgz", @@ -16376,6 +16417,11 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, + "attr-accept": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.2.tgz", + "integrity": "sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==" + }, "autoprefixer": { "version": "10.3.5", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.3.5.tgz", @@ -18444,6 +18490,21 @@ "schema-utils": "^3.0.0" } }, + "file-selector": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.2.4.tgz", + "integrity": "sha512-ZDsQNbrv6qRi1YTDOEWzf5J2KjZ9KMI1Q2SGeTkCJmNNW25Jg4TW4UMcmoqcg4WrAyKRcpBXdbWRxkfrOzVRbA==", + "requires": { + "tslib": "^2.0.3" + }, + "dependencies": { + "tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + } + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -22264,6 +22325,16 @@ "scheduler": "^0.20.2" } }, + "react-dropzone": { + "version": "11.4.2", + "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-11.4.2.tgz", + "integrity": "sha512-ocYzYn7Qgp0tFc1gQtUTOaHHSzVTwhWHxxY+r7cj2jJTPfMTZB5GWSJHdIVoxsl+EQENpjJ/6Zvcw0BqKZQ+Eg==", + "requires": { + "attr-accept": "^2.2.1", + "file-selector": "^0.2.2", + "prop-types": "^15.7.2" + } + }, "react-error-boundary": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-3.1.3.tgz", diff --git a/client/package.json b/client/package.json index 8d8e36c..8c779cc 100644 --- a/client/package.json +++ b/client/package.json @@ -80,6 +80,7 @@ "nodemailer": "^6.7.0", "react": "^17.0.2", "react-dom": "^17.0.2", + "react-dropzone": "^11.4.2", "react-hook-form": "^7.16.1", "react-router": "^5.2.1", "react-router-dom": "^5.3.0", diff --git a/client/src/app/components/editorPanel/editor/Dropzone.tsx b/client/src/app/components/editorPanel/editor/Dropzone.tsx new file mode 100644 index 0000000..d8ed66c --- /dev/null +++ b/client/src/app/components/editorPanel/editor/Dropzone.tsx @@ -0,0 +1,35 @@ +import { useEditorDrop } from '@hooks'; +import React, { PropsWithChildren, DragEvent, useCallback } from 'react'; +import { useDropzone, DropzoneOptions, DropEvent } from 'react-dropzone'; + +type OnDrop = DropzoneOptions['onDrop']; + +interface Props { + className?: string; +} + +export function Dropzone({ className, children }: PropsWithChildren) { + const { drop } = useEditorDrop(); + const onDrop: OnDrop = useCallback((acceptedFiles, _, event: DropEvent) => { + // not type safe: need to discriminate DragEvent from DropEvent + let dragEvent = event as DragEvent; + drop(acceptedFiles, [dragEvent.pageX, dragEvent.pageY]); + }, []); + + const { getRootProps, getInputProps, isDragActive } = useDropzone({ + onDrop, + noClick: true + }); + + return ( +

+ + {children} +
+ ); +} diff --git a/client/src/app/components/editorPanel/editor/UIEditor.tsx b/client/src/app/components/editorPanel/editor/UIEditor.tsx index 3f429de..0c0f682 100644 --- a/client/src/app/components/editorPanel/editor/UIEditor.tsx +++ b/client/src/app/components/editorPanel/editor/UIEditor.tsx @@ -1,8 +1,8 @@ import React from 'react'; import { Breadcrumb } from './Breadcrumb'; -//import Markdown from 'markdown-to-jsx'; // for the useEditor business logic, gets HTML from markdown import MonicoEditor, { loader, Monaco, OnChange } from '@monaco-editor/react'; import path from 'path'; +import { Dropzone } from './Dropzone'; interface Props { unsaved: boolean; @@ -20,8 +20,6 @@ function uriFromPath(_path: string) { } export function UIEditor({ unsaved, text, handleChange }: Props) { - //const monaco = useMonaco(); - loader.config({ paths: { vs: uriFromPath( @@ -49,33 +47,38 @@ export function UIEditor({ unsaved, text, handleChange }: Props) { return (
-
-
- +
console.log('dragging')} + > +
+ + +
diff --git a/client/src/app/hooks/index.ts b/client/src/app/hooks/index.ts index b155f01..82cdf14 100644 --- a/client/src/app/hooks/index.ts +++ b/client/src/app/hooks/index.ts @@ -1,3 +1,4 @@ export * from './contexts'; export { useVerificationForm } from './useVerificationForm'; export { useForceUpdate } from './useForceUpdate'; +export { useEditorDrop } from './useEditorDrop'; diff --git a/client/src/app/hooks/useEditorDrop.ts b/client/src/app/hooks/useEditorDrop.ts new file mode 100644 index 0000000..7b64c26 --- /dev/null +++ b/client/src/app/hooks/useEditorDrop.ts @@ -0,0 +1,12 @@ +export function useEditorDrop() { + const drop = (files: any[], cursorPosition: [x: number, y: number]) => { + console.log(files); + console.log(cursorPosition); + }; + + const insert = (text: string, cursorPosition: [x: number, y: number]) => { + console.log(text, cursorPosition); + }; + + return { drop, insert }; +} From 995c53247d6a42a34545f1b59a53f718da8ee4e0 Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Fri, 29 Oct 2021 13:15:51 -0400 Subject: [PATCH 32/45] Copy attachments on drop --- client/src/app/components/editorPanel/Editor.tsx | 9 +++++++-- .../components/editorPanel/editor/Dropzone.tsx | 11 +++++++---- .../components/editorPanel/editor/UIEditor.tsx | 5 +++-- .../components/editorPanel/editor/useEditor.ts | 5 +++-- client/src/app/hooks/useEditorDrop.ts | 15 ++++++++++++++- 5 files changed, 34 insertions(+), 11 deletions(-) diff --git a/client/src/app/components/editorPanel/Editor.tsx b/client/src/app/components/editorPanel/Editor.tsx index 8435f2d..bcf47fb 100644 --- a/client/src/app/components/editorPanel/Editor.tsx +++ b/client/src/app/components/editorPanel/Editor.tsx @@ -8,9 +8,14 @@ interface Props { } export function Editor({ text, setText }: Props) { - const { unsaved, handleChange } = useEditor({ text, setText }); + const { unsaved, handleChange, handleDrop } = useEditor({ text, setText }); return ( - + ); } diff --git a/client/src/app/components/editorPanel/editor/Dropzone.tsx b/client/src/app/components/editorPanel/editor/Dropzone.tsx index d8ed66c..5abcb87 100644 --- a/client/src/app/components/editorPanel/editor/Dropzone.tsx +++ b/client/src/app/components/editorPanel/editor/Dropzone.tsx @@ -1,4 +1,3 @@ -import { useEditorDrop } from '@hooks'; import React, { PropsWithChildren, DragEvent, useCallback } from 'react'; import { useDropzone, DropzoneOptions, DropEvent } from 'react-dropzone'; @@ -6,14 +5,18 @@ type OnDrop = DropzoneOptions['onDrop']; interface Props { className?: string; + onDrop: (files: any[], cursorPosition: [number, number]) => void; } -export function Dropzone({ className, children }: PropsWithChildren) { - const { drop } = useEditorDrop(); +export function Dropzone({ + className, + children, + onDrop: handleDrop +}: PropsWithChildren) { const onDrop: OnDrop = useCallback((acceptedFiles, _, event: DropEvent) => { // not type safe: need to discriminate DragEvent from DropEvent let dragEvent = event as DragEvent; - drop(acceptedFiles, [dragEvent.pageX, dragEvent.pageY]); + handleDrop(acceptedFiles, [dragEvent.pageX, dragEvent.pageY]); }, []); const { getRootProps, getInputProps, isDragActive } = useDropzone({ diff --git a/client/src/app/components/editorPanel/editor/UIEditor.tsx b/client/src/app/components/editorPanel/editor/UIEditor.tsx index 0c0f682..48efa20 100644 --- a/client/src/app/components/editorPanel/editor/UIEditor.tsx +++ b/client/src/app/components/editorPanel/editor/UIEditor.tsx @@ -8,6 +8,7 @@ interface Props { unsaved: boolean; text: string; handleChange: OnChange; + handleDrop: (files: any[], cursorPosition: [number, number]) => void; } function ensureFirstBackSlash(str: string) { @@ -19,7 +20,7 @@ function uriFromPath(_path: string) { return encodeURI('file://' + ensureFirstBackSlash(pathName)); } -export function UIEditor({ unsaved, text, handleChange }: Props) { +export function UIEditor({ unsaved, text, handleChange, handleDrop }: Props) { loader.config({ paths: { vs: uriFromPath( @@ -52,7 +53,7 @@ export function UIEditor({ unsaved, text, handleChange }: Props) { onDragCapture={() => console.log('dragging')} >
- + { - console.log(files); console.log(cursorPosition); + + files.forEach((file: File) => { + fs.copyFileSync(file.path, `${currentFileParentPath}/${file.name}`); + }); }; const insert = (text: string, cursorPosition: [x: number, y: number]) => { From f0562758070d2532f1599a2a35c24909721445e1 Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Fri, 29 Oct 2021 17:08:02 -0400 Subject: [PATCH 33/45] Add ref for useEditorDrop callback --- .../src/app/components/editorPanel/Editor.tsx | 9 ++----- .../editorPanel/editor/UIEditor.tsx | 10 +++++-- .../editorPanel/editor/useEditor.ts | 5 ++-- client/src/app/hooks/useEditorDrop.ts | 26 ++++++++++++++----- 4 files changed, 31 insertions(+), 19 deletions(-) diff --git a/client/src/app/components/editorPanel/Editor.tsx b/client/src/app/components/editorPanel/Editor.tsx index bcf47fb..8435f2d 100644 --- a/client/src/app/components/editorPanel/Editor.tsx +++ b/client/src/app/components/editorPanel/Editor.tsx @@ -8,14 +8,9 @@ interface Props { } export function Editor({ text, setText }: Props) { - const { unsaved, handleChange, handleDrop } = useEditor({ text, setText }); + const { unsaved, handleChange } = useEditor({ text, setText }); return ( - + ); } diff --git a/client/src/app/components/editorPanel/editor/UIEditor.tsx b/client/src/app/components/editorPanel/editor/UIEditor.tsx index 48efa20..86a8913 100644 --- a/client/src/app/components/editorPanel/editor/UIEditor.tsx +++ b/client/src/app/components/editorPanel/editor/UIEditor.tsx @@ -3,12 +3,12 @@ import { Breadcrumb } from './Breadcrumb'; import MonicoEditor, { loader, Monaco, OnChange } from '@monaco-editor/react'; import path from 'path'; import { Dropzone } from './Dropzone'; +import { useEditorDrop } from '@hooks'; interface Props { unsaved: boolean; text: string; handleChange: OnChange; - handleDrop: (files: any[], cursorPosition: [number, number]) => void; } function ensureFirstBackSlash(str: string) { @@ -20,7 +20,9 @@ function uriFromPath(_path: string) { return encodeURI('file://' + ensureFirstBackSlash(pathName)); } -export function UIEditor({ unsaved, text, handleChange, handleDrop }: Props) { +export function UIEditor({ unsaved, text, handleChange }: Props) { + const { drop: handleDrop, init } = useEditorDrop(); + loader.config({ paths: { vs: uriFromPath( @@ -43,6 +45,10 @@ export function UIEditor({ unsaved, text, handleChange, handleDrop }: Props) { }); monaco.editor.setTheme('Default'); + + init((path: string, cursorPosition: [number, number]) => { + console.log(path, cursorPosition); + }); }; return ( diff --git a/client/src/app/components/editorPanel/editor/useEditor.ts b/client/src/app/components/editorPanel/editor/useEditor.ts index d132f1f..dc8ede1 100644 --- a/client/src/app/components/editorPanel/editor/useEditor.ts +++ b/client/src/app/components/editorPanel/editor/useEditor.ts @@ -1,5 +1,5 @@ import { Dispatch, useEffect, useState } from 'react'; -import { useEditorDrop, useStore } from '@hooks'; +import { useStore } from '@hooks'; import { ipcRenderer } from 'electron'; import { saveFile } from '@utils'; import { OnChange } from '@monaco-editor/react'; @@ -14,7 +14,6 @@ export function useEditor({ text, setText }: Args) { const [{ currentFile }] = useStore(); const [unsaved, setUnsaved] = useState(false); const [manualSave, setManualSave] = useState(false); - const { drop: handleDrop } = useEditorDrop(); const autoSave = true; // ADD TO SETTINGS @@ -45,5 +44,5 @@ export function useEditor({ text, setText }: Args) { }); }, [currentFile]); - return { unsaved, text, handleChange, handleDrop }; + return { unsaved, text, handleChange }; } diff --git a/client/src/app/hooks/useEditorDrop.ts b/client/src/app/hooks/useEditorDrop.ts index 68e324b..20d8e88 100644 --- a/client/src/app/hooks/useEditorDrop.ts +++ b/client/src/app/hooks/useEditorDrop.ts @@ -1,25 +1,37 @@ import fs from 'fs'; import { useStore } from '@hooks'; +import { useRef } from 'react'; + +type CallbackFunction = ( + path: string, + cursorPosition: [number, number] +) => void; export function useEditorDrop() { const [{ currentFile }] = useStore(); - const currentFileParentPath = currentFile!.path.substring( 0, currentFile!.path.lastIndexOf('/') ); - const drop = (files: any[], cursorPosition: [x: number, y: number]) => { - console.log(cursorPosition); + const callbackRef = useRef((_, __) => { + return; + }); + const drop = (files: any[], cursorPosition: [x: number, y: number]) => { files.forEach((file: File) => { - fs.copyFileSync(file.path, `${currentFileParentPath}/${file.name}`); + const copyPath = `${currentFileParentPath}/${file.name}`; + fs.copyFileSync(file.path, copyPath); + + if (callbackRef.current) { + callbackRef.current(copyPath, cursorPosition); + } }); }; - const insert = (text: string, cursorPosition: [x: number, y: number]) => { - console.log(text, cursorPosition); + const init = (cb: CallbackFunction) => { + callbackRef.current = cb; }; - return { drop, insert }; + return { drop, init }; } From d96485561cc265a557937cf0ec063ac7124845dc Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Fri, 29 Oct 2021 17:31:58 -0400 Subject: [PATCH 34/45] Paste embed link on drag and drop --- .../components/editorPanel/editor/UIEditor.tsx | 18 +++++++++++++++--- client/src/app/hooks/useEditorDrop.ts | 6 ++---- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/client/src/app/components/editorPanel/editor/UIEditor.tsx b/client/src/app/components/editorPanel/editor/UIEditor.tsx index 86a8913..51e8bcc 100644 --- a/client/src/app/components/editorPanel/editor/UIEditor.tsx +++ b/client/src/app/components/editorPanel/editor/UIEditor.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { Breadcrumb } from './Breadcrumb'; -import MonicoEditor, { loader, Monaco, OnChange } from '@monaco-editor/react'; +import MonicoEditor, { loader, OnChange, OnMount } from '@monaco-editor/react'; import path from 'path'; import { Dropzone } from './Dropzone'; import { useEditorDrop } from '@hooks'; @@ -31,7 +31,7 @@ export function UIEditor({ unsaved, text, handleChange }: Props) { } }); - const handleMount = (_: any, monaco: Monaco) => { + const handleMount: OnMount = (event, monaco) => { monaco.editor.defineTheme('Default', { base: 'vs-dark', colors: { 'editor.background': '#11182700' }, @@ -47,7 +47,19 @@ export function UIEditor({ unsaved, text, handleChange }: Props) { monaco.editor.setTheme('Default'); init((path: string, cursorPosition: [number, number]) => { - console.log(path, cursorPosition); + console.log('run', path); + const target = event.getTargetAtClientPoint( + cursorPosition[0], + cursorPosition[1] + ); + + if (!target) return; + + event.setPosition(target.position!); + const textToInsert = `[file_name]{${path}}`; + event.trigger('keyboard', 'type', { text: textToInsert }); + + console.log(target); }); }; diff --git a/client/src/app/hooks/useEditorDrop.ts b/client/src/app/hooks/useEditorDrop.ts index 20d8e88..bdd024d 100644 --- a/client/src/app/hooks/useEditorDrop.ts +++ b/client/src/app/hooks/useEditorDrop.ts @@ -21,11 +21,9 @@ export function useEditorDrop() { const drop = (files: any[], cursorPosition: [x: number, y: number]) => { files.forEach((file: File) => { const copyPath = `${currentFileParentPath}/${file.name}`; - fs.copyFileSync(file.path, copyPath); - - if (callbackRef.current) { + fs.copyFile(file.path, copyPath, () => {}); + if (callbackRef.current) callbackRef.current(copyPath, cursorPosition); - } }); }; From 7ce44184635d9a01b2b27ba5961faa8d357e1972 Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Fri, 29 Oct 2021 18:16:20 -0400 Subject: [PATCH 35/45] Insert proper text of embed --- .../editorPanel/editor/UIEditor.tsx | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/client/src/app/components/editorPanel/editor/UIEditor.tsx b/client/src/app/components/editorPanel/editor/UIEditor.tsx index 51e8bcc..1dd021c 100644 --- a/client/src/app/components/editorPanel/editor/UIEditor.tsx +++ b/client/src/app/components/editorPanel/editor/UIEditor.tsx @@ -56,10 +56,30 @@ export function UIEditor({ unsaved, text, handleChange }: Props) { if (!target) return; event.setPosition(target.position!); - const textToInsert = `[file_name]{${path}}`; - event.trigger('keyboard', 'type', { text: textToInsert }); - console.log(target); + const fileName = path.substring( + path.lastIndexOf('/') + 1, + path.lastIndexOf('.') + ); + + const line = event.getPosition(); + const range = new monaco.Range( + line!.lineNumber, + 1, + line!.lineNumber, + 1 + ); + + var id = { major: 1, minor: 1 }; + const textToInsert = `\n[${fileName}]{${path}}\n`; + const op = { + identifier: id, + range, + text: textToInsert, + forceMoveMarkers: true + }; + + event.executeEdits('', [op]); }); }; From b953376efc26d91d6005ba178be696c13d85db8b Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Fri, 29 Oct 2021 19:07:59 -0400 Subject: [PATCH 36/45] Fix links to use relative path --- client/src/app/hooks/useEditorDrop.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/client/src/app/hooks/useEditorDrop.ts b/client/src/app/hooks/useEditorDrop.ts index bdd024d..e390347 100644 --- a/client/src/app/hooks/useEditorDrop.ts +++ b/client/src/app/hooks/useEditorDrop.ts @@ -8,7 +8,7 @@ type CallbackFunction = ( ) => void; export function useEditorDrop() { - const [{ currentFile }] = useStore(); + const [{ currentFile, notebook }] = useStore(); const currentFileParentPath = currentFile!.path.substring( 0, currentFile!.path.lastIndexOf('/') @@ -22,8 +22,13 @@ export function useEditorDrop() { files.forEach((file: File) => { const copyPath = `${currentFileParentPath}/${file.name}`; fs.copyFile(file.path, copyPath, () => {}); + + const copyPathRelative = copyPath.substring( + notebook!.lastIndexOf('/') + 1 + ); + if (callbackRef.current) - callbackRef.current(copyPath, cursorPosition); + callbackRef.current(copyPathRelative, cursorPosition); }); }; From 26c27c9d2edf5011fcd0bf4123dfd5c37a44f261 Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Fri, 29 Oct 2021 19:28:52 -0400 Subject: [PATCH 37/45] Fix panel titlebar from appearing over modals --- client/src/app/components/editorPanel/editor/UIEditor.tsx | 5 +---- client/src/app/components/editorPanel/preview/UIPreview.tsx | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/client/src/app/components/editorPanel/editor/UIEditor.tsx b/client/src/app/components/editorPanel/editor/UIEditor.tsx index 1dd021c..01f19c6 100644 --- a/client/src/app/components/editorPanel/editor/UIEditor.tsx +++ b/client/src/app/components/editorPanel/editor/UIEditor.tsx @@ -86,10 +86,7 @@ export function UIEditor({ unsaved, text, handleChange }: Props) { return (
-
console.log('dragging')} - > +
-
-

Live Preview

+
+

Preview

Date: Sat, 30 Oct 2021 11:46:56 -0400 Subject: [PATCH 38/45] Add split pane for editor and preview --- client/package-lock.json | 753 +++++++++++++++++- client/package.json | 1 + .../components/editorPanel/UIEditorPanel.tsx | 13 +- .../editorPanel/editor/UIEditor.tsx | 2 +- .../editorPanel/preview/UIPreview.tsx | 2 +- 5 files changed, 762 insertions(+), 9 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index 7ceced9..2889f76 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -30,6 +30,7 @@ "node-watch": "^0.7.2", "nodemailer": "^6.7.0", "react": "^17.0.2", + "react-collapse-pane": "^2.0.1", "react-dom": "^17.0.2", "react-dropzone": "^11.4.2", "react-hook-form": "^7.16.1", @@ -1903,6 +1904,34 @@ "global-tunnel-ng": "^2.7.1" } }, + "node_modules/@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", + "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "dependencies": { + "@emotion/memoize": "0.7.4" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" + }, + "node_modules/@emotion/stylis": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", + "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==" + }, + "node_modules/@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" + }, "node_modules/@hookform/resolvers": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-2.8.1.tgz", @@ -2227,6 +2256,150 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, + "node_modules/@material-ui/core": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.3.tgz", + "integrity": "sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw==", + "dependencies": { + "@babel/runtime": "^7.4.4", + "@material-ui/styles": "^4.11.4", + "@material-ui/system": "^4.12.1", + "@material-ui/types": "5.1.0", + "@material-ui/utils": "^4.11.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 || ^17.0.0", + "react-transition-group": "^4.4.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/material-ui" + }, + "peerDependencies": { + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@material-ui/styles": { + "version": "4.11.4", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.4.tgz", + "integrity": "sha512-KNTIZcnj/zprG5LW0Sao7zw+yG3O35pviHzejMdcSGCdWbiO8qzRgOYL8JAxAsWBKOKYwVZxXtHWaB5T2Kvxew==", + "dependencies": { + "@babel/runtime": "^7.4.4", + "@emotion/hash": "^0.8.0", + "@material-ui/types": "5.1.0", + "@material-ui/utils": "^4.11.2", + "clsx": "^1.0.4", + "csstype": "^2.5.2", + "hoist-non-react-statics": "^3.3.2", + "jss": "^10.5.1", + "jss-plugin-camel-case": "^10.5.1", + "jss-plugin-default-unit": "^10.5.1", + "jss-plugin-global": "^10.5.1", + "jss-plugin-nested": "^10.5.1", + "jss-plugin-props-sort": "^10.5.1", + "jss-plugin-rule-value-function": "^10.5.1", + "jss-plugin-vendor-prefixer": "^10.5.1", + "prop-types": "^15.7.2" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/material-ui" + }, + "peerDependencies": { + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@material-ui/styles/node_modules/csstype": { + "version": "2.6.18", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.18.tgz", + "integrity": "sha512-RSU6Hyeg14am3Ah4VZEmeX8H7kLwEEirXe6aU2IPfKNvhXwTflK5HQRDNI0ypQXoqmm+QPyG2IaPuQE5zMwSIQ==" + }, + "node_modules/@material-ui/system": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.1.tgz", + "integrity": "sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw==", + "dependencies": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.11.2", + "csstype": "^2.5.2", + "prop-types": "^15.7.2" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/material-ui" + }, + "peerDependencies": { + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@material-ui/system/node_modules/csstype": { + "version": "2.6.18", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.18.tgz", + "integrity": "sha512-RSU6Hyeg14am3Ah4VZEmeX8H7kLwEEirXe6aU2IPfKNvhXwTflK5HQRDNI0ypQXoqmm+QPyG2IaPuQE5zMwSIQ==" + }, + "node_modules/@material-ui/types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", + "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==", + "peerDependencies": { + "@types/react": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@material-ui/utils": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.2.tgz", + "integrity": "sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA==", + "dependencies": { + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, "node_modules/@monaco-editor/loader": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.2.0.tgz", @@ -2924,6 +3097,14 @@ "@types/react": "*" } }, + "node_modules/@types/react-transition-group": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.4.tgz", + "integrity": "sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/scheduler": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", @@ -3807,6 +3988,20 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/babel-plugin-styled-components": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-1.13.3.tgz", + "integrity": "sha512-meGStRGv+VuKA/q0/jXxrPNWEm4LPfYIqxooDTdmh8kFsP/Ph7jJG5rUPwUPX3QHUvggwdbgdGpo88P/rRYsVw==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.15.4", + "@babel/helper-module-imports": "^7.15.4", + "babel-plugin-syntax-jsx": "^6.18.0", + "lodash": "^4.17.11" + }, + "peerDependencies": { + "styled-components": ">= 2" + } + }, "node_modules/babel-plugin-syntax-flow": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz", @@ -4350,6 +4545,11 @@ "node": ">= 6" } }, + "node_modules/camelize": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", + "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" + }, "node_modules/caniuse-lite": { "version": "1.0.30001260", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001260.tgz", @@ -4628,6 +4828,14 @@ "mimic-response": "^1.0.0" } }, + "node_modules/clsx": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", + "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==", + "engines": { + "node": ">=6" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -4977,6 +5185,14 @@ "source-map-resolve": "^0.6.0" } }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=", + "engines": { + "node": ">=4" + } + }, "node_modules/css-color-names": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", @@ -5065,6 +5281,16 @@ "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" }, + "node_modules/css-to-react-native": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz", + "integrity": "sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ==", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, "node_modules/css-tree": { "version": "1.0.0-alpha.37", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", @@ -5082,6 +5308,15 @@ "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz", "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==" }, + "node_modules/css-vendor": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", + "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", + "dependencies": { + "@babel/runtime": "^7.8.3", + "is-in-browser": "^1.0.2" + } + }, "node_modules/css-what": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz", @@ -5385,6 +5620,15 @@ "utila": "~0.4" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/dom-serializer": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", @@ -7073,6 +7317,11 @@ "url": "https://github.com/sponsors/typicode" } }, + "node_modules/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==" + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -7473,6 +7722,11 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/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=" + }, "node_modules/is-installed-globally": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", @@ -8698,6 +8952,88 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jss": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.8.2.tgz", + "integrity": "sha512-FkoUNxI329CKQ9OQC8L72MBF9KPf5q8mIupAJ5twU7G7XREW7ahb+7jFfrjZ4iy1qvhx1HwIWUIvkZBDnKkEdQ==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "csstype": "^3.0.2", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/jss" + } + }, + "node_modules/jss-plugin-camel-case": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.8.2.tgz", + "integrity": "sha512-2INyxR+1UdNuKf4v9It3tNfPvf7IPrtkiwzofeKuMd5D58/dxDJVUQYRVg/n460rTlHUfsEQx43hDrcxi9dSPA==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "10.8.2" + } + }, + "node_modules/jss-plugin-default-unit": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.8.2.tgz", + "integrity": "sha512-UZ7cwT9NFYSG+SEy7noRU50s4zifulFdjkUNKE+u6mW7vFP960+RglWjTgMfh79G6OENZmaYnjHV/gcKV4nSxg==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.8.2" + } + }, + "node_modules/jss-plugin-global": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.8.2.tgz", + "integrity": "sha512-UaYMSPsYZ7s/ECGoj4KoHC2jwQd5iQ7K+FFGnCAILdQrv7hPmvM2Ydg45ThT/sH46DqktCRV2SqjRuxeBH8nRA==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.8.2" + } + }, + "node_modules/jss-plugin-nested": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.8.2.tgz", + "integrity": "sha512-acRvuPJOb930fuYmhkJaa994EADpt8TxI63Iyg96C8FJ9T2xRyU5T6R1IYKRwUiqZo+2Sr7fdGzRTDD4uBZaMA==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.8.2", + "tiny-warning": "^1.0.2" + } + }, + "node_modules/jss-plugin-props-sort": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.8.2.tgz", + "integrity": "sha512-wqdcjayKRWBZnNpLUrXvsWqh+5J5YToAQ+8HNBNw0kZxVvCDwzhK2Nx6AKs7p+5/MbAh2PLgNW5Ym/ysbVAuqQ==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.8.2" + } + }, + "node_modules/jss-plugin-rule-value-function": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.8.2.tgz", + "integrity": "sha512-bW0EKAs+0HXpb6BKJhrn94IDdiWb0CnSluTkh0rGEgyzY/nmD1uV/Wf6KGlesGOZ9gmJzQy+9FFdxIUID1c9Ug==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.8.2", + "tiny-warning": "^1.0.2" + } + }, + "node_modules/jss-plugin-vendor-prefixer": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.8.2.tgz", + "integrity": "sha512-DeGv18QsSiYLSVIEB2+l0af6OToUe0JB+trpzUxyqD2QRC/5AzzDrCrYffO5AHZ81QbffYvSN/pkfZaTWpRXlg==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.8", + "jss": "10.8.2" + } + }, "node_modules/jwa": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", @@ -10503,6 +10839,11 @@ "node": ">=8" } }, + "node_modules/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==" + }, "node_modules/postcss": { "version": "8.3.8", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.8.tgz", @@ -11197,6 +11538,21 @@ "node": ">=0.10.0" } }, + "node_modules/react-collapse-pane": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/react-collapse-pane/-/react-collapse-pane-2.0.1.tgz", + "integrity": "sha512-6D95mymzY+NFKDkvjBGgsRNYbcSdLeY3Af7ll+IfIKh7dAmHyqKFh6cGj4sueVdxWoAgtbagiIeRgRcX/rYXUA==", + "dependencies": { + "@material-ui/core": "^4.11.4", + "styled-components": "^5.3.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16" + } + }, "node_modules/react-dom": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", @@ -11257,8 +11613,7 @@ "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "node_modules/react-property": { "version": "2.0.0", @@ -11330,6 +11685,21 @@ "node": "*" } }, + "node_modules/react-transition-group": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz", + "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -11927,6 +12297,11 @@ "node": ">=8" } }, + "node_modules/shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -12257,6 +12632,54 @@ "inline-style-parser": "0.1.1" } }, + "node_modules/styled-components": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz", + "integrity": "sha512-++4iHwBM7ZN+x6DtPPWkCI4vdtwumQ+inA/DdAsqYd4SVgUKJie5vXyzotA00ttcFdQkCng7zc6grwlfIfw+lw==", + "dependencies": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/traverse": "^7.4.5", + "@emotion/is-prop-valid": "^0.8.8", + "@emotion/stylis": "^0.8.4", + "@emotion/unitless": "^0.7.4", + "babel-plugin-styled-components": ">= 1.12.0", + "css-to-react-native": "^3.0.0", + "hoist-non-react-statics": "^3.0.0", + "shallowequal": "^1.1.0", + "supports-color": "^5.5.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0", + "react-is": ">= 16.8.0" + } + }, + "node_modules/styled-components/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "engines": { + "node": ">=4" + } + }, + "node_modules/styled-components/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/sumchecker": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", @@ -15179,6 +15602,34 @@ "sumchecker": "^3.0.1" } }, + "@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + }, + "@emotion/is-prop-valid": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", + "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "requires": { + "@emotion/memoize": "0.7.4" + } + }, + "@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" + }, + "@emotion/stylis": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", + "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==" + }, + "@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" + }, "@hookform/resolvers": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-2.8.1.tgz", @@ -15436,6 +15887,89 @@ "chalk": "^4.0.0" } }, + "@material-ui/core": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.3.tgz", + "integrity": "sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/styles": "^4.11.4", + "@material-ui/system": "^4.12.1", + "@material-ui/types": "5.1.0", + "@material-ui/utils": "^4.11.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 || ^17.0.0", + "react-transition-group": "^4.4.0" + } + }, + "@material-ui/styles": { + "version": "4.11.4", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.4.tgz", + "integrity": "sha512-KNTIZcnj/zprG5LW0Sao7zw+yG3O35pviHzejMdcSGCdWbiO8qzRgOYL8JAxAsWBKOKYwVZxXtHWaB5T2Kvxew==", + "requires": { + "@babel/runtime": "^7.4.4", + "@emotion/hash": "^0.8.0", + "@material-ui/types": "5.1.0", + "@material-ui/utils": "^4.11.2", + "clsx": "^1.0.4", + "csstype": "^2.5.2", + "hoist-non-react-statics": "^3.3.2", + "jss": "^10.5.1", + "jss-plugin-camel-case": "^10.5.1", + "jss-plugin-default-unit": "^10.5.1", + "jss-plugin-global": "^10.5.1", + "jss-plugin-nested": "^10.5.1", + "jss-plugin-props-sort": "^10.5.1", + "jss-plugin-rule-value-function": "^10.5.1", + "jss-plugin-vendor-prefixer": "^10.5.1", + "prop-types": "^15.7.2" + }, + "dependencies": { + "csstype": { + "version": "2.6.18", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.18.tgz", + "integrity": "sha512-RSU6Hyeg14am3Ah4VZEmeX8H7kLwEEirXe6aU2IPfKNvhXwTflK5HQRDNI0ypQXoqmm+QPyG2IaPuQE5zMwSIQ==" + } + } + }, + "@material-ui/system": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.1.tgz", + "integrity": "sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.11.2", + "csstype": "^2.5.2", + "prop-types": "^15.7.2" + }, + "dependencies": { + "csstype": { + "version": "2.6.18", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.18.tgz", + "integrity": "sha512-RSU6Hyeg14am3Ah4VZEmeX8H7kLwEEirXe6aU2IPfKNvhXwTflK5HQRDNI0ypQXoqmm+QPyG2IaPuQE5zMwSIQ==" + } + } + }, + "@material-ui/types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", + "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==", + "requires": {} + }, + "@material-ui/utils": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.2.tgz", + "integrity": "sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA==", + "requires": { + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0" + } + }, "@monaco-editor/loader": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.2.0.tgz", @@ -15970,6 +16504,14 @@ "@types/react": "*" } }, + "@types/react-transition-group": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.4.tgz", + "integrity": "sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug==", + "requires": { + "@types/react": "*" + } + }, "@types/scheduler": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", @@ -16697,6 +17239,17 @@ "@babel/helper-define-polyfill-provider": "^0.2.2" } }, + "babel-plugin-styled-components": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/babel-plugin-styled-components/-/babel-plugin-styled-components-1.13.3.tgz", + "integrity": "sha512-meGStRGv+VuKA/q0/jXxrPNWEm4LPfYIqxooDTdmh8kFsP/Ph7jJG5rUPwUPX3QHUvggwdbgdGpo88P/rRYsVw==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.15.4", + "@babel/helper-module-imports": "^7.15.4", + "babel-plugin-syntax-jsx": "^6.18.0", + "lodash": "^4.17.11" + } + }, "babel-plugin-syntax-flow": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz", @@ -17148,6 +17701,11 @@ "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==" }, + "camelize": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", + "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" + }, "caniuse-lite": { "version": "1.0.30001260", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001260.tgz", @@ -17355,6 +17913,11 @@ "mimic-response": "^1.0.0" } }, + "clsx": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", + "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==" + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -17639,6 +18202,11 @@ "source-map-resolve": "^0.6.0" } }, + "css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha1-/qJhbcZ2spYmhrOvjb2+GAskTgU=" + }, "css-color-names": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", @@ -17704,6 +18272,16 @@ "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz", "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==" }, + "css-to-react-native": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz", + "integrity": "sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ==", + "requires": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, "css-tree": { "version": "1.0.0-alpha.37", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz", @@ -17718,6 +18296,15 @@ "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz", "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==" }, + "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": "5.0.1", "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz", @@ -17951,6 +18538,15 @@ "utila": "~0.4" } }, + "dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "dom-serializer": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", @@ -19210,6 +19806,11 @@ "integrity": "sha512-8yKEWNX4z2YsofXAMT7KvA1g8p+GxtB1ffV8XtpAEGuXNAbCV5wdNKH+qTpw8SM9fh4aMPDR+yQuKfgnreyZlg==", "dev": true }, + "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==" + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -19492,6 +20093,11 @@ "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==" }, + "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-installed-globally": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", @@ -20438,6 +21044,84 @@ "graceful-fs": "^4.1.6" } }, + "jss": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.8.2.tgz", + "integrity": "sha512-FkoUNxI329CKQ9OQC8L72MBF9KPf5q8mIupAJ5twU7G7XREW7ahb+7jFfrjZ4iy1qvhx1HwIWUIvkZBDnKkEdQ==", + "requires": { + "@babel/runtime": "^7.3.1", + "csstype": "^3.0.2", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-camel-case": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.8.2.tgz", + "integrity": "sha512-2INyxR+1UdNuKf4v9It3tNfPvf7IPrtkiwzofeKuMd5D58/dxDJVUQYRVg/n460rTlHUfsEQx43hDrcxi9dSPA==", + "requires": { + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "10.8.2" + } + }, + "jss-plugin-default-unit": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.8.2.tgz", + "integrity": "sha512-UZ7cwT9NFYSG+SEy7noRU50s4zifulFdjkUNKE+u6mW7vFP960+RglWjTgMfh79G6OENZmaYnjHV/gcKV4nSxg==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.8.2" + } + }, + "jss-plugin-global": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.8.2.tgz", + "integrity": "sha512-UaYMSPsYZ7s/ECGoj4KoHC2jwQd5iQ7K+FFGnCAILdQrv7hPmvM2Ydg45ThT/sH46DqktCRV2SqjRuxeBH8nRA==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.8.2" + } + }, + "jss-plugin-nested": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.8.2.tgz", + "integrity": "sha512-acRvuPJOb930fuYmhkJaa994EADpt8TxI63Iyg96C8FJ9T2xRyU5T6R1IYKRwUiqZo+2Sr7fdGzRTDD4uBZaMA==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.8.2", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-props-sort": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.8.2.tgz", + "integrity": "sha512-wqdcjayKRWBZnNpLUrXvsWqh+5J5YToAQ+8HNBNw0kZxVvCDwzhK2Nx6AKs7p+5/MbAh2PLgNW5Ym/ysbVAuqQ==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.8.2" + } + }, + "jss-plugin-rule-value-function": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.8.2.tgz", + "integrity": "sha512-bW0EKAs+0HXpb6BKJhrn94IDdiWb0CnSluTkh0rGEgyzY/nmD1uV/Wf6KGlesGOZ9gmJzQy+9FFdxIUID1c9Ug==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.8.2", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-vendor-prefixer": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.8.2.tgz", + "integrity": "sha512-DeGv18QsSiYLSVIEB2+l0af6OToUe0JB+trpzUxyqD2QRC/5AzzDrCrYffO5AHZ81QbffYvSN/pkfZaTWpRXlg==", + "requires": { + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.8", + "jss": "10.8.2" + } + }, "jwa": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", @@ -21825,6 +22509,11 @@ "find-up": "^4.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==" + }, "postcss": { "version": "8.3.8", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.8.tgz", @@ -22315,6 +23004,15 @@ "object-assign": "^4.1.1" } }, + "react-collapse-pane": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/react-collapse-pane/-/react-collapse-pane-2.0.1.tgz", + "integrity": "sha512-6D95mymzY+NFKDkvjBGgsRNYbcSdLeY3Af7ll+IfIKh7dAmHyqKFh6cGj4sueVdxWoAgtbagiIeRgRcX/rYXUA==", + "requires": { + "@material-ui/core": "^4.11.4", + "styled-components": "^5.3.0" + } + }, "react-dom": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", @@ -22353,8 +23051,7 @@ "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "react-property": { "version": "2.0.0", @@ -22418,6 +23115,17 @@ } } }, + "react-transition-group": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz", + "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==", + "requires": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + } + }, "read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -22882,6 +23590,11 @@ "kind-of": "^6.0.2" } }, + "shallowequal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", + "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==" + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -23142,6 +23855,38 @@ "inline-style-parser": "0.1.1" } }, + "styled-components": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-5.3.3.tgz", + "integrity": "sha512-++4iHwBM7ZN+x6DtPPWkCI4vdtwumQ+inA/DdAsqYd4SVgUKJie5vXyzotA00ttcFdQkCng7zc6grwlfIfw+lw==", + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/traverse": "^7.4.5", + "@emotion/is-prop-valid": "^0.8.8", + "@emotion/stylis": "^0.8.4", + "@emotion/unitless": "^0.7.4", + "babel-plugin-styled-components": ">= 1.12.0", + "css-to-react-native": "^3.0.0", + "hoist-non-react-statics": "^3.0.0", + "shallowequal": "^1.1.0", + "supports-color": "^5.5.0" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "sumchecker": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", diff --git a/client/package.json b/client/package.json index 8c779cc..e82ebee 100644 --- a/client/package.json +++ b/client/package.json @@ -79,6 +79,7 @@ "node-watch": "^0.7.2", "nodemailer": "^6.7.0", "react": "^17.0.2", + "react-collapse-pane": "^2.0.1", "react-dom": "^17.0.2", "react-dropzone": "^11.4.2", "react-hook-form": "^7.16.1", diff --git a/client/src/app/components/editorPanel/UIEditorPanel.tsx b/client/src/app/components/editorPanel/UIEditorPanel.tsx index ff29c0f..86a0a4b 100644 --- a/client/src/app/components/editorPanel/UIEditorPanel.tsx +++ b/client/src/app/components/editorPanel/UIEditorPanel.tsx @@ -4,6 +4,7 @@ import { Editor } from './Editor'; import { Placeholder } from '../Placeholder'; import { NotificationArea } from '../NotificationArea'; import { Preview } from './Preview'; +import { SplitPane } from 'react-collapse-pane'; interface Props { text: string; @@ -18,9 +19,15 @@ export function UIEditorPanel({ text, setText }: Props) { {currentFile ? ( -
- - +
+ + + +
) : ( diff --git a/client/src/app/components/editorPanel/editor/UIEditor.tsx b/client/src/app/components/editorPanel/editor/UIEditor.tsx index 01f19c6..0ad2124 100644 --- a/client/src/app/components/editorPanel/editor/UIEditor.tsx +++ b/client/src/app/components/editorPanel/editor/UIEditor.tsx @@ -84,7 +84,7 @@ export function UIEditor({ unsaved, text, handleChange }: Props) { }; return ( -
+
diff --git a/client/src/app/components/editorPanel/preview/UIPreview.tsx b/client/src/app/components/editorPanel/preview/UIPreview.tsx index 3a66381..3e35504 100644 --- a/client/src/app/components/editorPanel/preview/UIPreview.tsx +++ b/client/src/app/components/editorPanel/preview/UIPreview.tsx @@ -7,7 +7,7 @@ interface Props { export function UIPreview({ content }: Props) { return ( -
+

Preview

From e26eb147556e28ffa1120bdcce57c05468daef7a Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Sat, 30 Oct 2021 11:49:08 -0400 Subject: [PATCH 39/45] Remove overflow for editor --- client/src/app/components/editorPanel/editor/UIEditor.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/app/components/editorPanel/editor/UIEditor.tsx b/client/src/app/components/editorPanel/editor/UIEditor.tsx index 0ad2124..f69fbcc 100644 --- a/client/src/app/components/editorPanel/editor/UIEditor.tsx +++ b/client/src/app/components/editorPanel/editor/UIEditor.tsx @@ -100,7 +100,7 @@ export function UIEditor({ unsaved, text, handleChange }: Props) { smoothScrolling: true, contextmenu: false, minimap: { enabled: false }, - wordWrap: 'on', + wordWrap: 'off', selectionHighlight: false, quickSuggestions: false, renderLineHighlight: 'none', From b295da56c33a8d7cac574da5a482be1cf877abab Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Sat, 30 Oct 2021 12:02:01 -0400 Subject: [PATCH 40/45] Add fixed width to embeds --- client/src/app/components/editorPanel/preview/usePreview.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/app/components/editorPanel/preview/usePreview.tsx b/client/src/app/components/editorPanel/preview/usePreview.tsx index 2f2673d..8de9f8d 100644 --- a/client/src/app/components/editorPanel/preview/usePreview.tsx +++ b/client/src/app/components/editorPanel/preview/usePreview.tsx @@ -76,7 +76,7 @@ export function usePreview(text: string) { found ? 'border-gray-800 hover:border-gray-700' : 'border-red-400 hover:border-red-500' - } p-2 my-2 cursor-pointer rounded-md min-w-min w-4/6 mr-auto'> + } p-2 my-2 cursor-pointer rounded-md min-w-min w-64 mr-auto'> ${render}
`; }, From 7d9946d9c63c6632f014c72f2f6705bd47ddc86e Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Sat, 30 Oct 2021 12:42:34 -0400 Subject: [PATCH 41/45] Add split pane for file explorer --- client/src/app/App.tsx | 9 +++++++-- client/src/app/components/editorPanel/UIEditorPanel.tsx | 2 +- .../src/app/components/fileExplorer/UIFileExplorer.tsx | 4 ++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/client/src/app/App.tsx b/client/src/app/App.tsx index b365016..0851e0a 100644 --- a/client/src/app/App.tsx +++ b/client/src/app/App.tsx @@ -12,6 +12,7 @@ import { useGoogleDrive } from './hooks/useGoogleDrive'; import { FileExplorer } from './components/FileExplorer'; import { Placeholder } from './components/Placeholder'; import { NotificationArea } from './components/NotificationArea'; +import { SplitPane } from 'react-collapse-pane'; export const editorReducer = (state: EditorState, action: EditorAction) => { switch (action.type) { @@ -41,10 +42,14 @@ export function App() { {notebook ? ( - <> + - + ) : (
diff --git a/client/src/app/components/editorPanel/UIEditorPanel.tsx b/client/src/app/components/editorPanel/UIEditorPanel.tsx index 86a0a4b..f7891f2 100644 --- a/client/src/app/components/editorPanel/UIEditorPanel.tsx +++ b/client/src/app/components/editorPanel/UIEditorPanel.tsx @@ -15,7 +15,7 @@ export function UIEditorPanel({ text, setText }: Props) { const [{ currentFile }] = useStore(); return ( -
+
{currentFile ? ( diff --git a/client/src/app/components/fileExplorer/UIFileExplorer.tsx b/client/src/app/components/fileExplorer/UIFileExplorer.tsx index 1004945..c461545 100644 --- a/client/src/app/components/fileExplorer/UIFileExplorer.tsx +++ b/client/src/app/components/fileExplorer/UIFileExplorer.tsx @@ -22,7 +22,7 @@ export function UIFileExplorer({ const [{ notebook }] = useStore(); return ( -
+

{getFileName(notebook!)} @@ -42,7 +42,7 @@ export function UIFileExplorer({

{items.map((item) => ( From 1b714dcdfe5349e3e239e8956b92f34ff0ded4ae Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Sat, 30 Oct 2021 13:40:41 -0400 Subject: [PATCH 42/45] Fix side menu display and match panes to color scheme --- client/src/app/App.tsx | 22 ++++++++++++------- client/src/app/components/SideMenu.tsx | 2 +- .../components/editorPanel/UIEditorPanel.tsx | 12 ++++++++-- .../fileExplorer/UIFileExplorer.tsx | 2 +- 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/client/src/app/App.tsx b/client/src/app/App.tsx index 0851e0a..da17469 100644 --- a/client/src/app/App.tsx +++ b/client/src/app/App.tsx @@ -42,14 +42,20 @@ export function App() { {notebook ? ( - - - - +
+ + + + +
) : (
diff --git a/client/src/app/components/SideMenu.tsx b/client/src/app/components/SideMenu.tsx index 1431e78..5a5c1b4 100644 --- a/client/src/app/components/SideMenu.tsx +++ b/client/src/app/components/SideMenu.tsx @@ -7,7 +7,7 @@ import { useStore } from '@hooks'; export function SideMenu() { const [{ notebook }] = useStore(); return ( -
+
{notebook && } diff --git a/client/src/app/components/editorPanel/UIEditorPanel.tsx b/client/src/app/components/editorPanel/UIEditorPanel.tsx index f7891f2..667fb04 100644 --- a/client/src/app/components/editorPanel/UIEditorPanel.tsx +++ b/client/src/app/components/editorPanel/UIEditorPanel.tsx @@ -15,15 +15,23 @@ export function UIEditorPanel({ text, setText }: Props) { const [{ currentFile }] = useStore(); return ( -
+
{currentFile ? (
diff --git a/client/src/app/components/fileExplorer/UIFileExplorer.tsx b/client/src/app/components/fileExplorer/UIFileExplorer.tsx index c461545..bf03c7e 100644 --- a/client/src/app/components/fileExplorer/UIFileExplorer.tsx +++ b/client/src/app/components/fileExplorer/UIFileExplorer.tsx @@ -22,7 +22,7 @@ export function UIFileExplorer({ const [{ notebook }] = useStore(); return ( -
+

{getFileName(notebook!)} From 7f47f5670a18cbd5709159ad16de4258b3355500 Mon Sep 17 00:00:00 2001 From: Olivier Goulet Date: Sat, 30 Oct 2021 14:18:10 -0400 Subject: [PATCH 43/45] Fix zindex issue with split panes --- client/src/app/App.tsx | 4 ++-- client/src/app/components/modalManager/Modal.tsx | 2 +- client/src/app/components/pageManager/page/UIPage.tsx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/client/src/app/App.tsx b/client/src/app/App.tsx index da17469..a596214 100644 --- a/client/src/app/App.tsx +++ b/client/src/app/App.tsx @@ -38,11 +38,11 @@ export function App() { return ( <> -

+
{notebook ? ( -
+
) { const handleClick = () => close(); return ( -
+
) { return (
From 7e4ac1b176c677debbe8e408ec9f5897c54e7dcb Mon Sep 17 00:00:00 2001 From: parsa111 <48108158+parsa111@users.noreply.github.com> Date: Mon, 1 Nov 2021 20:49:16 -0400 Subject: [PATCH 44/45] Add menu item to toggle preview visibility --- client/src/app/components/EditorPanel.tsx | 10 ++++- .../components/editorPanel/UIEditorPanel.tsx | 41 +++++++++++-------- .../components/editorPanel/useEditorPanel.ts | 14 ++++++- client/src/electron/menus/applicationMenu.ts | 7 ++++ 4 files changed, 52 insertions(+), 20 deletions(-) diff --git a/client/src/app/components/EditorPanel.tsx b/client/src/app/components/EditorPanel.tsx index 746e576..a0ca9f0 100644 --- a/client/src/app/components/EditorPanel.tsx +++ b/client/src/app/components/EditorPanel.tsx @@ -3,7 +3,13 @@ import { useEditorPanel } from './editorPanel/useEditorPanel'; import { UIEditorPanel } from './editorPanel/UIEditorPanel'; export function EditorPanel() { - const { text, setText } = useEditorPanel(); + const { text, setText, livePreviewVisiable } = useEditorPanel(); - return ; + return ( + + ); } diff --git a/client/src/app/components/editorPanel/UIEditorPanel.tsx b/client/src/app/components/editorPanel/UIEditorPanel.tsx index 667fb04..a51ff1b 100644 --- a/client/src/app/components/editorPanel/UIEditorPanel.tsx +++ b/client/src/app/components/editorPanel/UIEditorPanel.tsx @@ -7,11 +7,12 @@ import { Preview } from './Preview'; import { SplitPane } from 'react-collapse-pane'; interface Props { + livePreviewVisiable: boolean; text: string; setText: React.Dispatch; } -export function UIEditorPanel({ text, setText }: Props) { +export function UIEditorPanel({ text, setText, livePreviewVisiable }: Props) { const [{ currentFile }] = useStore(); return ( @@ -20,22 +21,30 @@ export function UIEditorPanel({ text, setText }: Props) { {currentFile ? (
- + {livePreviewVisiable ? ( + + + {livePreviewVisiable ? ( + + ) : ( +
+ )} +
+ ) : ( - -
+ )}
) : ( diff --git a/client/src/app/components/editorPanel/useEditorPanel.ts b/client/src/app/components/editorPanel/useEditorPanel.ts index c930eae..1dd28c5 100644 --- a/client/src/app/components/editorPanel/useEditorPanel.ts +++ b/client/src/app/components/editorPanel/useEditorPanel.ts @@ -10,6 +10,7 @@ import { import { useEditorStore } from '@hooks'; export function useEditorPanel() { + const [livePreviewVisiable, setLivePreviewVisiable] = useState(true); const [{ notebook, currentFile }, dispatch] = useStore(); const [{ primarySelection, secondarySelection }, editorDispatch] = useEditorStore(); @@ -31,6 +32,14 @@ export function useEditorPanel() { }); }); + ipcRenderer.removeAllListeners('toggleLivePreviewVisabilty'); + ipcRenderer.on('toggleLivePreviewVisabilty', () => { + if (!notebook) { + return; + } + setLivePreviewVisiable(!livePreviewVisiable); + }); + //ipcRenderer.removeAllListeners('toggleFileExplorer'); //ipcRenderer.on('toggleFileExplorer', () => { //if (!notebook) return; @@ -65,13 +74,14 @@ export function useEditorPanel() { }); }); }); - }, [notebook, primarySelection, secondarySelection]); + }, [notebook, primarySelection, secondarySelection, livePreviewVisiable]); return { primarySelection, secondarySelection, editorDispatch, text, - setText + setText, + livePreviewVisiable }; } diff --git a/client/src/electron/menus/applicationMenu.ts b/client/src/electron/menus/applicationMenu.ts index 7bbfce5..21d72f8 100644 --- a/client/src/electron/menus/applicationMenu.ts +++ b/client/src/electron/menus/applicationMenu.ts @@ -100,6 +100,13 @@ const template: MenuItemConstructorOptions[] = [ if (!window) return; window.webContents.send('toggleFileExplorer'); } + }, + { + label: 'Toggle Preview', + click: (_, window) => { + if (!window) return; + window.webContents.send('toggleLivePreviewVisabilty'); + } } ] } From 3a5a54119df19e70f453d4f753773f418886fb9e Mon Sep 17 00:00:00 2001 From: parsa111 <48108158+parsa111@users.noreply.github.com> Date: Mon, 1 Nov 2021 21:18:26 -0400 Subject: [PATCH 45/45] Add close button --- client/src/app/components/EditorPanel.tsx | 4 +++- client/src/app/components/editorPanel/Preview.tsx | 5 +++-- .../app/components/editorPanel/UIEditorPanel.tsx | 13 +++++++++++-- .../components/editorPanel/preview/UIPreview.tsx | 13 ++++++++++--- .../app/components/editorPanel/useEditorPanel.ts | 7 ++++++- 5 files changed, 33 insertions(+), 9 deletions(-) diff --git a/client/src/app/components/EditorPanel.tsx b/client/src/app/components/EditorPanel.tsx index a0ca9f0..e4f2911 100644 --- a/client/src/app/components/EditorPanel.tsx +++ b/client/src/app/components/EditorPanel.tsx @@ -3,13 +3,15 @@ import { useEditorPanel } from './editorPanel/useEditorPanel'; import { UIEditorPanel } from './editorPanel/UIEditorPanel'; export function EditorPanel() { - const { text, setText, livePreviewVisiable } = useEditorPanel(); + const { text, setText, handlePreviewClose, livePreviewVisiable } = + useEditorPanel(); return ( ); } diff --git a/client/src/app/components/editorPanel/Preview.tsx b/client/src/app/components/editorPanel/Preview.tsx index 09d45df..145355a 100644 --- a/client/src/app/components/editorPanel/Preview.tsx +++ b/client/src/app/components/editorPanel/Preview.tsx @@ -4,10 +4,11 @@ import { usePreview } from './preview/usePreview'; interface Props { text: string; + onClose: () => void; } -export function Preview({ text }: Props) { +export function Preview({ text, onClose }: Props) { const html = usePreview(text); - return ; + return ; } diff --git a/client/src/app/components/editorPanel/UIEditorPanel.tsx b/client/src/app/components/editorPanel/UIEditorPanel.tsx index a51ff1b..f3caba0 100644 --- a/client/src/app/components/editorPanel/UIEditorPanel.tsx +++ b/client/src/app/components/editorPanel/UIEditorPanel.tsx @@ -10,9 +10,15 @@ interface Props { livePreviewVisiable: boolean; text: string; setText: React.Dispatch; + handlePreviewClose: () => void; } -export function UIEditorPanel({ text, setText, livePreviewVisiable }: Props) { +export function UIEditorPanel({ + text, + setText, + livePreviewVisiable, + handlePreviewClose +}: Props) { const [{ currentFile }] = useStore(); return ( @@ -37,7 +43,10 @@ export function UIEditorPanel({ text, setText, livePreviewVisiable }: Props) { > {livePreviewVisiable ? ( - + ) : (
)} diff --git a/client/src/app/components/editorPanel/preview/UIPreview.tsx b/client/src/app/components/editorPanel/preview/UIPreview.tsx index 3e35504..d71a8a7 100644 --- a/client/src/app/components/editorPanel/preview/UIPreview.tsx +++ b/client/src/app/components/editorPanel/preview/UIPreview.tsx @@ -1,15 +1,22 @@ import React from 'react'; import './theme.css'; +import CloseIcon from '@assets/icons/close.svg'; interface Props { content: any; + handleClose: () => void; } -export function UIPreview({ content }: Props) { +export function UIPreview({ content, handleClose }: Props) { return (
-
-

Preview

+
+

Preview

{' '} +
{ + setLivePreviewVisiable(false); + }; + return { primarySelection, secondarySelection, editorDispatch, text, setText, - livePreviewVisiable + livePreviewVisiable, + handlePreviewClose }; }