From 143c170ff7b17c5e4159547e4176e2175d847aa2 Mon Sep 17 00:00:00 2001 From: jongwon Date: Wed, 16 Dec 2020 02:01:22 +0900 Subject: [PATCH 1/5] Feat: add markdown editor --- frontend/package-lock.json | 353 +++++++++++++++++- frontend/package.json | 5 + .../container/MessageEditor/MessageEditor.js | 47 ++- 3 files changed, 389 insertions(+), 16 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index cb053d74..495d15c0 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -7775,6 +7775,14 @@ "warning": "^4.0.3" } }, + "cross-fetch": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.0.6.tgz", + "integrity": "sha512-KBPUbqgFjzWlVcURG+Svp9TlhA5uliYtiNx/0r8nv0pdypeQCRJ9IaSIc3q/x3q8t3F75cHuwxVql1HFGHCNJQ==", + "requires": { + "node-fetch": "2.6.1" + } + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -8178,6 +8186,11 @@ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" }, + "decorate-component-with-props": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decorate-component-with-props/-/decorate-component-with-props-1.1.0.tgz", + "integrity": "sha512-tTYQojixN64yK3/WBODMfvss/zbmyUx9HQXhzSxZiSiofeekVeRyyuToy9BCiTMrVEIKWxTcla2t3y5qdaUF7Q==" + }, "dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", @@ -8613,6 +8626,244 @@ } } }, + "draft": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/draft/-/draft-0.2.3.tgz", + "integrity": "sha1-9ELdhr1R2B87/Vtf3OD9mcxpzJ4=" + }, + "draft-js": { + "version": "0.11.7", + "resolved": "https://registry.npmjs.org/draft-js/-/draft-js-0.11.7.tgz", + "integrity": "sha512-ne7yFfN4sEL82QPQEn80xnADR8/Q6ALVworbC5UOSzOvjffmYfFsr3xSZtxbIirti14R7Y33EZC5rivpLgIbsg==", + "requires": { + "fbjs": "^2.0.0", + "immutable": "~3.7.4", + "object-assign": "^4.1.1" + } + }, + "draft-js-checkable-list-item": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/draft-js-checkable-list-item/-/draft-js-checkable-list-item-2.0.6.tgz", + "integrity": "sha512-YHnGr3rKSFfqXGcHqp8SGees5Y/KAsHoyknoDRM1Gyal3B+duiFjmYvxIZlSYnWIcHgH4pQpPDQJJ9aaPmsvNw==", + "requires": { + "draft-js-modifiers": "^0.1.5" + } + }, + "draft-js-markdown-plugin": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/draft-js-markdown-plugin/-/draft-js-markdown-plugin-3.0.5.tgz", + "integrity": "sha512-DNqKUJw2eHFGQL/GOKTrDqqe4pwOoH6wzJHkJ7APNQCoCHTrG4pD5ueiO9AuNMbaQTaeCtsj9QwUMs1YBwAQCg==", + "requires": { + "decorate-component-with-props": "^1.1.0", + "draft-js": "^0.10.4", + "draft-js-checkable-list-item": "^2.0.6", + "draft-js-prism-plugin": "^0.1.3", + "immutable": "~3.7.4", + "react-click-outside": "^3.0.1" + }, + "dependencies": { + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" + }, + "draft-js": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/draft-js/-/draft-js-0.10.5.tgz", + "integrity": "sha512-LE6jSCV9nkPhfVX2ggcRLA4FKs6zWq9ceuO/88BpXdNCS7mjRTgs0NsV6piUCJX9YxMsB9An33wnkMmU2sD2Zg==", + "requires": { + "fbjs": "^0.8.15", + "immutable": "~3.7.4", + "object-assign": "^4.1.0" + } + }, + "fbjs": { + "version": "0.8.17", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", + "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", + "requires": { + "core-js": "^1.0.0", + "isomorphic-fetch": "^2.1.1", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" + } + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "requires": { + "asap": "~2.0.3" + } + } + } + }, + "draft-js-markdown-shortcuts-plugin": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/draft-js-markdown-shortcuts-plugin/-/draft-js-markdown-shortcuts-plugin-0.6.1.tgz", + "integrity": "sha512-VZbq6WATsNNHH8wqUbYuY0ijHcb1o2V9cN2eeMEAHgr92RJmGGi2UfgxI9O7ycWhTwgS9KZ17AE76C1R/rYR6Q==", + "requires": { + "decorate-component-with-props": "^1.1.0", + "draft-js": "~0.11.5", + "draft-js-checkable-list-item": "^3.0.4", + "draft-js-prism-plugin": "^0.1.3", + "immutable": "~3.8.2" + }, + "dependencies": { + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" + }, + "draft-js-checkable-list-item": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/draft-js-checkable-list-item/-/draft-js-checkable-list-item-3.0.4.tgz", + "integrity": "sha512-rHTErKYTYoBRtSCxKfSz+PivbtXp0KqmjC2Ms3u9QHlx9c40qsbajdSz+1TfPXaWP8FAB5EeynZ2qYPRgltPeQ==", + "requires": { + "draft-js-modifiers": "~0.2.2", + "immutable": "~3.7.4" + }, + "dependencies": { + "immutable": { + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", + "integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks=" + } + } + }, + "draft-js-modifiers": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/draft-js-modifiers/-/draft-js-modifiers-0.2.2.tgz", + "integrity": "sha512-64zeY74S4um+NO5HI66scZAX6fufdpZlr6htI3ttvNkTw5Jx/3r7+ETKJ/PTnGWtzUTC7TVkeF6mP7oqtUBUQw==", + "requires": { + "draft-js": "~0.10.5", + "immutable": "~3.7.4" + }, + "dependencies": { + "draft-js": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/draft-js/-/draft-js-0.10.5.tgz", + "integrity": "sha512-LE6jSCV9nkPhfVX2ggcRLA4FKs6zWq9ceuO/88BpXdNCS7mjRTgs0NsV6piUCJX9YxMsB9An33wnkMmU2sD2Zg==", + "requires": { + "fbjs": "^0.8.15", + "immutable": "~3.7.4", + "object-assign": "^4.1.0" + } + }, + "immutable": { + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", + "integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks=" + } + } + }, + "fbjs": { + "version": "0.8.17", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", + "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", + "requires": { + "core-js": "^1.0.0", + "isomorphic-fetch": "^2.1.1", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" + } + }, + "immutable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=" + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "requires": { + "asap": "~2.0.3" + } + } + } + }, + "draft-js-modifiers": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/draft-js-modifiers/-/draft-js-modifiers-0.1.5.tgz", + "integrity": "sha512-UVbTvlbFSOlJ4LHNK68yflR1k6UyBge0o89DM0/YA8w5PXI+bExMTkByRcwhV5XIWYDgboHWLQSXjao02dW4mQ==", + "requires": { + "draft-js": "~0.10.0", + "immutable": "~3.7.4" + }, + "dependencies": { + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" + }, + "draft-js": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/draft-js/-/draft-js-0.10.5.tgz", + "integrity": "sha512-LE6jSCV9nkPhfVX2ggcRLA4FKs6zWq9ceuO/88BpXdNCS7mjRTgs0NsV6piUCJX9YxMsB9An33wnkMmU2sD2Zg==", + "requires": { + "fbjs": "^0.8.15", + "immutable": "~3.7.4", + "object-assign": "^4.1.0" + } + }, + "fbjs": { + "version": "0.8.17", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", + "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", + "requires": { + "core-js": "^1.0.0", + "isomorphic-fetch": "^2.1.1", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" + } + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "requires": { + "asap": "~2.0.3" + } + } + } + }, + "draft-js-plugins-editor": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/draft-js-plugins-editor/-/draft-js-plugins-editor-3.0.0.tgz", + "integrity": "sha512-bFEL0FUIPg9VK3KSeBZ3D+uMqQEVe4Cv7++LWCMASRH02jy6x2f87NRxSZLzTQES5+oL6Qg+OEUlaTn409145A==", + "requires": { + "immutable": "~3.7.4", + "prop-types": "^15.5.8" + } + }, + "draft-js-prism": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/draft-js-prism/-/draft-js-prism-1.0.6.tgz", + "integrity": "sha512-9iNPPr6/vaC9K60DtVes1JGDZ9uD0vZ7/8i6de5cZEzbftOj/ijIGplEV0dTFT/q8U+bY1uR1ikQevjRh2pEpQ==", + "requires": { + "extend": "^3.0.0", + "immutable": "*" + } + }, + "draft-js-prism-plugin": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/draft-js-prism-plugin/-/draft-js-prism-plugin-0.1.3.tgz", + "integrity": "sha512-w/agtisitO7SCHBBqa5vfkwy7DlhfKMCak6ivE4GpSV97MYLUIuRtafP1ei5tCMwGkJxJDKMv3Bgrd5miG55ZA==", + "requires": { + "draft-js-prism": "^1.0.6", + "react": "*" + } + }, "duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", @@ -8752,6 +9003,24 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "requires": { + "iconv-lite": "^0.6.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", + "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", @@ -9991,6 +10260,36 @@ "bser": "2.1.1" } }, + "fbjs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-2.0.0.tgz", + "integrity": "sha512-8XA8ny9ifxrAWlyhAbexXcs3rRMtxWcs3M0lctLfB49jRDHiaxj+Mo0XxbwE7nKZYzgCFoq64FS+WFd4IycPPQ==", + "requires": { + "core-js": "^3.6.4", + "cross-fetch": "^3.0.4", + "fbjs-css-vars": "^1.0.0", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" + }, + "dependencies": { + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "requires": { + "asap": "~2.0.3" + } + } + } + }, + "fbjs-css-vars": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", + "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==" + }, "figgy-pudding": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", @@ -11534,6 +11833,11 @@ "resolved": "https://registry.npmjs.org/immer/-/immer-7.0.9.tgz", "integrity": "sha512-Vs/gxoM4DqNAYR7pugIxi0Xc8XAun/uy7AQu4fLLqaTBHxjOP9pJ266Q9MWA/ly4z6rAFZbvViOtihxUZ7O28A==" }, + "immutable": { + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", + "integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks=" + }, "import-cwd": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", @@ -11620,9 +11924,9 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "inline-style-parser": { "version": "0.1.1", @@ -12134,6 +12438,26 @@ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" }, + "isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", + "requires": { + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" + }, + "dependencies": { + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "requires": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + } + } + }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -14183,8 +14507,7 @@ "node-fetch": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", - "dev": true + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" }, "node-forge": { "version": "0.10.0", @@ -16502,6 +16825,21 @@ "whatwg-fetch": "^3.4.1" } }, + "react-click-outside": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/react-click-outside/-/react-click-outside-3.0.1.tgz", + "integrity": "sha512-d0KWFvBt+esoZUF15rL2UBB7jkeAqLU8L/Ny35oLK6fW6mIbOv/ChD+ExF4sR9PD26kVx+9hNfD0FTIqRZEyRQ==", + "requires": { + "hoist-non-react-statics": "^2.1.1" + }, + "dependencies": { + "hoist-non-react-statics": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz", + "integrity": "sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==" + } + } + }, "react-color": { "version": "2.19.3", "resolved": "https://registry.npmjs.org/react-color/-/react-color-2.19.3.tgz", @@ -19962,6 +20300,11 @@ "is-typedarray": "^1.0.0" } }, + "ua-parser-js": { + "version": "0.7.23", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.23.tgz", + "integrity": "sha512-m4hvMLxgGHXG3O3fQVAyyAQpZzDOvwnhOTjYz5Xmr7r/+LpkNy3vJXdVRWgd1TkAb7NGROZuSy96CrlNVjA7KA==" + }, "unfetch": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 01166c21..819bf0d3 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -13,6 +13,11 @@ "@testing-library/react": "^11.1.0", "@testing-library/user-event": "^12.1.10", "axios": "^0.21.0", + "draft": "^0.2.3", + "draft-js": "^0.11.7", + "draft-js-markdown-plugin": "^3.0.5", + "draft-js-markdown-shortcuts-plugin": "^0.6.1", + "draft-js-plugins-editor": "^3.0.0", "emoji-mart": "^3.0.0", "qs": "^6.9.4", "react": "^17.0.1", diff --git a/frontend/src/container/MessageEditor/MessageEditor.js b/frontend/src/container/MessageEditor/MessageEditor.js index f2de8fcf..56dcbd9e 100644 --- a/frontend/src/container/MessageEditor/MessageEditor.js +++ b/frontend/src/container/MessageEditor/MessageEditor.js @@ -1,26 +1,51 @@ import React, { useState } from 'react' +import Editor from 'draft-js-plugins-editor' +import createMarkdownShortcutsPlugin from 'draft-js-markdown-shortcuts-plugin' +import { + ContentState, + EditorState, + getDefaultKeyBinding, + convertToRaw, +} from 'draft-js' -import Input from '../../presenter/Input' +const plugins = [createMarkdownShortcutsPlugin()] function MessageEditor({ channelTitle, sendMessage }) { - const [message, setMessage] = useState('') + const [message, setMessage] = useState(EditorState.createEmpty()) const handleInput = e => { - setMessage(e.target.value) + setMessage(e) } - const handleKey = e => { - if (e.key === 'Enter' && e.target.value) { - sendMessage(message) - setMessage('') + + const keyBindingFn = e => { + if (e.key === 'Enter') return 'send-message' + return getDefaultKeyBinding(e) + } + const handleKey = command => { + if (command === 'send-message' && message.getCurrentContent().hasText()) { + sendMessage(JSON.stringify(convertToRaw(message.getCurrentContent()))) + setMessage( + EditorState.moveFocusToEnd( + EditorState.push( + message, + ContentState.createFromText(''), + 'remove-range', + ), + ), + ) } } + return (
- + {/* TODO markdown, chat action 적용 필요 */}
) From 3d3877478f12bf93309c39532496a42903dd0542 Mon Sep 17 00:00:00 2001 From: jongwon Date: Wed, 16 Dec 2020 02:01:59 +0900 Subject: [PATCH 2/5] Feat: add markdown render --- .../src/presenter/ChatContent/ChatContent.js | 44 +++++++++++-------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/frontend/src/presenter/ChatContent/ChatContent.js b/frontend/src/presenter/ChatContent/ChatContent.js index caec6c80..d23953c3 100644 --- a/frontend/src/presenter/ChatContent/ChatContent.js +++ b/frontend/src/presenter/ChatContent/ChatContent.js @@ -1,24 +1,30 @@ -import React from 'react' +import React, { memo } from 'react' import styled from 'styled-components' +import { convertFromRaw, Editor, EditorState } from 'draft-js' import { COLOR } from '../../constant/style' -const ChatContent = ({ - displayName, - createdAt, - contents, - handleProfileModal, -}) => { - return ( - - - - {displayName} - - {createdAt} - - {contents} - - ) -} + +const ChatContent = memo( + ({ displayName, createdAt, contents, handleProfileModal }) => { + return ( + + + + {displayName} + + {createdAt} + + + + + + ) + }, +) const StyledChatContent = styled.div` width: 100%; display: flex; From 54b4af2ec0986efd4090493b94790d57ecd88065 Mon Sep 17 00:00:00 2001 From: jongwon Date: Wed, 16 Dec 2020 02:22:22 +0900 Subject: [PATCH 3/5] Refactor: update editor style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 실제 slack과 유사한 인풋 창으로 변경 --- .../container/MessageEditor/MessageEditor.js | 37 +++++++++++++------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/frontend/src/container/MessageEditor/MessageEditor.js b/frontend/src/container/MessageEditor/MessageEditor.js index 56dcbd9e..c4530c6a 100644 --- a/frontend/src/container/MessageEditor/MessageEditor.js +++ b/frontend/src/container/MessageEditor/MessageEditor.js @@ -7,6 +7,9 @@ import { getDefaultKeyBinding, convertToRaw, } from 'draft-js' +import styled from 'styled-components' +import 'draft-js/dist/Draft.css' +import { COLOR } from '../../constant/style' const plugins = [createMarkdownShortcutsPlugin()] @@ -36,19 +39,29 @@ function MessageEditor({ channelTitle, sendMessage }) { } return ( -
- + + + - {/* TODO markdown, chat action 적용 필요 */} -
+ {/* TODO markdown, chat action 적용 필요 */} + + ) } - +const MessageEditorContainer = styled.div` + padding: 20px; + background-color: ${COLOR.WHITE}; +` +const MessageEditorArea = styled.div` + border: 1px solid ${COLOR.LIGHT_GRAY}; + padding: 10px; + border-radius: 5px; +` export default MessageEditor From 895be7b15b895acdf1d3bb11c3f3a75d1c803b7e Mon Sep 17 00:00:00 2001 From: jongwon Date: Wed, 16 Dec 2020 06:11:21 +0900 Subject: [PATCH 4/5] Fix: Message editor losing focus bug --- .../src/container/MessageEditor/MessageEditor.js | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/frontend/src/container/MessageEditor/MessageEditor.js b/frontend/src/container/MessageEditor/MessageEditor.js index c4530c6a..813e0a32 100644 --- a/frontend/src/container/MessageEditor/MessageEditor.js +++ b/frontend/src/container/MessageEditor/MessageEditor.js @@ -1,4 +1,4 @@ -import React, { useState } from 'react' +import React, { useState, useRef } from 'react' import Editor from 'draft-js-plugins-editor' import createMarkdownShortcutsPlugin from 'draft-js-markdown-shortcuts-plugin' import { @@ -11,13 +11,9 @@ import styled from 'styled-components' import 'draft-js/dist/Draft.css' import { COLOR } from '../../constant/style' -const plugins = [createMarkdownShortcutsPlugin()] - function MessageEditor({ channelTitle, sendMessage }) { + const plugins = useRef([createMarkdownShortcutsPlugin()]) const [message, setMessage] = useState(EditorState.createEmpty()) - const handleInput = e => { - setMessage(e) - } const keyBindingFn = e => { if (e.key === 'Enter') return 'send-message' @@ -37,15 +33,14 @@ function MessageEditor({ channelTitle, sendMessage }) { ) } } - return ( From 5ea8dcace75b54ee3f3d4b7ece2f7193cb29b3a6 Mon Sep 17 00:00:00 2001 From: jongwon Date: Wed, 16 Dec 2020 20:49:30 +0900 Subject: [PATCH 5/5] Refactor: message editor and overall layout style --- .../container/ChannelHeader/ChannelHeader.js | 2 +- frontend/src/container/ChatRoom/ChatRoom.js | 1 + .../container/SideThreadBar/SideThreadBar.js | 24 +++++++------------ frontend/src/index.js | 13 ++-------- .../src/page/WorkspacePage/WorkspacePage.js | 4 ++-- .../src/presenter/GlobalStyle/GlobalStyle.js | 8 ++++++- 6 files changed, 22 insertions(+), 30 deletions(-) diff --git a/frontend/src/container/ChannelHeader/ChannelHeader.js b/frontend/src/container/ChannelHeader/ChannelHeader.js index 7753403c..352a5737 100644 --- a/frontend/src/container/ChannelHeader/ChannelHeader.js +++ b/frontend/src/container/ChannelHeader/ChannelHeader.js @@ -66,7 +66,7 @@ function ChannelHeader() { const ChannelHeaderStyle = styled.div` width: 100%; height: auto; - margin: auto 20px; + margin: 0 20px; display: flex; flex-direction: row; justify-content: space-between; diff --git a/frontend/src/container/ChatRoom/ChatRoom.js b/frontend/src/container/ChatRoom/ChatRoom.js index da52ecfa..1046ed83 100644 --- a/frontend/src/container/ChatRoom/ChatRoom.js +++ b/frontend/src/container/ChatRoom/ChatRoom.js @@ -180,6 +180,7 @@ const ChatHeader = styled.div` height: 60px; background: ${COLOR.BACKGROUND_CONTENTS}; border: 1px solid rgba(255, 255, 255, 0.1); + box-sizing: border-box; ` const ChatContents = styled.div` diff --git a/frontend/src/container/SideThreadBar/SideThreadBar.js b/frontend/src/container/SideThreadBar/SideThreadBar.js index 1c0373ee..b0a10206 100644 --- a/frontend/src/container/SideThreadBar/SideThreadBar.js +++ b/frontend/src/container/SideThreadBar/SideThreadBar.js @@ -103,9 +103,9 @@ function SideThreadBar() { const SideThreadBarStyle = styled.div` width: auto; - height: calc(100% - 1px); - background: ${COLOR.BACKGROUND_CONTENTS}; + height: 100%; border-bottom: 1px solid rgba(255, 255, 255, 0.1); + box-sizing: border-box; ` const SideBarHeader = styled.div` @@ -121,7 +121,9 @@ const SideBarHeader = styled.div` justify-content: flex-start; align-items: center; border: 1px solid rgba(255, 255, 255, 0.1); + box-sizing: border-box; border-right: 0; + background-color: ${COLOR.BACKGROUND_CONTENTS}; ` const CloseBtn = styled.div` @@ -132,33 +134,25 @@ const CloseBtn = styled.div` const SideBarContents = styled.div` width: auto; - height: calc(100% - 63px); - color: ${COLOR.LABEL_SELECT_TEXT}; + height: calc(100% - 60px); + overflow-y: auto; border: 1px solid rgba(255, 255, 255, 0.1); border-right: 0; + box-sizing: border-box; ` const ChatContent = styled.div` width: auto; - max-height: 30%; min-height: 20%; border: 1px solid rgba(255, 255, 255, 0.1); border-right: 0; overflow-y: auto; ` -const ReplyContents = styled.div` - height: 60%; - overflow-x: auto; - overflow-y: auto; -` +const ReplyContents = styled.div`` const MessageEditorArea = styled.div` - height: calc(10% - 3px); - - display: flex; - justify-content: center; - align-items: flex-end; + /* height: calc(10% - 3px); */ ` export default SideThreadBar diff --git a/frontend/src/index.js b/frontend/src/index.js index 045159d2..2a794c57 100644 --- a/frontend/src/index.js +++ b/frontend/src/index.js @@ -1,13 +1,13 @@ import React from 'react' import ReactDOM from 'react-dom' -import { createGlobalStyle } from 'styled-components' import './index.css' import WorkspacePage from './page/WorkspacePage' -import { BrowserRouter, Route, Switch } from 'react-router-dom' +import { BrowserRouter, Route } from 'react-router-dom' import reportWebVitals from './reportWebVitals' import LoginPage from './page/login/Login' import CreateWorkspace from './page/createWorkspace/CreateWorkspace' import SelectWorkspace from './page/selectWorkspace/SelectWorkspace' +import GlobalStyle from './presenter/GlobalStyle' import Auth from './hooks/Auth' import GithubOAuth from './hooks/GithubOAuth' import { RecoilRoot } from 'recoil' @@ -42,15 +42,6 @@ const App = () => { ) } -const GlobalStyle = createGlobalStyle` - body { - padding: 0px; - margin: 0px; - height: 100%; - width: 100%; - } -` - ReactDOM.render(, document.getElementById('root')) // If you want to start measuring performance in your app, pass a function // to log results (for example: reportWebVitals(console.log)) diff --git a/frontend/src/page/WorkspacePage/WorkspacePage.js b/frontend/src/page/WorkspacePage/WorkspacePage.js index 49b396f5..112b5f49 100644 --- a/frontend/src/page/WorkspacePage/WorkspacePage.js +++ b/frontend/src/page/WorkspacePage/WorkspacePage.js @@ -97,8 +97,7 @@ const ConstructionPage = SideBarWidth => { } const PageStyle = styled.div` - width: 100vw; - height: 100vh; + height: 100%; display: flex; flex-direction: column; ` @@ -129,6 +128,7 @@ const ChannelListHeaderArea = styled.div` background: ${COLOR.BACKGROUND_CHANNEL_LIST}; color: ${COLOR.LABEL_DEFAULT_TEXT}; border: 1px solid rgba(255, 255, 255, 0.1); + box-sizing: border-box; ` const ChannelListArea = styled.div` diff --git a/frontend/src/presenter/GlobalStyle/GlobalStyle.js b/frontend/src/presenter/GlobalStyle/GlobalStyle.js index bd626392..01ee2a53 100644 --- a/frontend/src/presenter/GlobalStyle/GlobalStyle.js +++ b/frontend/src/presenter/GlobalStyle/GlobalStyle.js @@ -1,12 +1,18 @@ import { createGlobalStyle } from 'styled-components' const GlobalStyle = createGlobalStyle` + html{ + height: 100%; + } body { padding: 0px; margin: 0px; height: 100%; width: 100%; - } + } + #root{ + height:100%; + } ` export default GlobalStyle