From 7ac3b9aad114f5be848effcd888d947aba6bad97 Mon Sep 17 00:00:00 2001 From: davy-c Date: Tue, 3 Dec 2019 18:01:49 +0900 Subject: [PATCH] client html / markdown exports --- .eslintrc | 3 +- package-lock.json | 249 ++++++++++++------ package.json | 4 +- .../NotePage/NoteDetail/NoteDetail.tsx | 2 + src/components/atoms/MarkdownPreviewer.tsx | 3 +- src/components/atoms/ToolbarExportButton.tsx | 154 +++++++++++ tsconfig-webpack.json | 3 +- tsconfig.json | 1 + typings/unified.d.ts | 3 + 9 files changed, 332 insertions(+), 90 deletions(-) create mode 100644 src/components/atoms/ToolbarExportButton.tsx diff --git a/.eslintrc b/.eslintrc index faaa1915f..bd28db39c 100644 --- a/.eslintrc +++ b/.eslintrc @@ -23,5 +23,6 @@ "react": { "version": "detect" } - } + }, + "exclude": ["dist", "node_modules"] } diff --git a/package-lock.json b/package-lock.json index 54df70956..f65e883c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2783,7 +2783,7 @@ }, "util": { "version": "0.10.3", - "resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", "dev": true, "requires": { @@ -3654,6 +3654,11 @@ "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.3.tgz", "integrity": "sha512-yB4oYSAa9yLcGyTbB4ItFwHw43QHdH129IJ5R+WvxOkWlyFnR5FAaBNnUq4mcxsTVZGh28bHoeTHMKXH1wZf3w==" }, + "character-entities-html4": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.3.tgz", + "integrity": "sha512-SwnyZ7jQBCRHELk9zf2CN5AnGEc2nA+uKMZLHvcqhpPprjkYhiLn0DywMHgN5ttFZuITMATbh68M6VIVKwJbcg==" + }, "character-entities-legacy": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.3.tgz", @@ -4865,6 +4870,11 @@ "esutils": "^2.0.2" } }, + "doctype": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/doctype/-/doctype-2.0.3.tgz", + "integrity": "sha512-e7TTDW7yJ3kRJIUdp/w2bkOI8QWVxer0lg0kuAYfM0jzquuL5ZJ0GVfUiIA63ec4mfeTz0vffuoM/jEPUb8v+w==" + }, "dom-converter": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", @@ -5804,14 +5814,6 @@ "resolved": "https://registry.npmjs.org/fastest-stable-stringify/-/fastest-stable-stringify-1.0.1.tgz", "integrity": "sha1-kSLUBtTJ2YvqZEpraFPVh0uHsCg=" }, - "fault": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.3.tgz", - "integrity": "sha512-sfFuP4X0hzrbGKjAUNXYvNqsZ5F6ohx/dZ9I0KQud/aiZNwg263r5L9yGB0clvXHCkzXh5W3t7RSHchggYIFmA==", - "requires": { - "format": "^0.2.2" - } - }, "faye-websocket": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", @@ -6080,11 +6082,6 @@ "mime-types": "^2.1.12" } }, - "format": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", - "integrity": "sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs=" - }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", @@ -6183,8 +6180,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -6205,14 +6201,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6227,20 +6221,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -6357,8 +6348,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -6370,7 +6360,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -6385,7 +6374,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -6393,14 +6381,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -6419,7 +6405,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -6500,8 +6485,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -6513,7 +6497,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -6599,8 +6582,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -6636,7 +6618,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -6656,7 +6637,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -6700,14 +6680,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -7064,6 +7042,30 @@ "xtend": "^4.0.1" } }, + "hast-util-to-html": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-6.0.2.tgz", + "integrity": "sha512-oiQzGHtjT6ZLhszCY89kCxGCo9O+YuPUHluv36fzp7Hv/E1W4428PgzcQAKlPUzbHAt3ELoPCSrYLWl8fQw7Ag==", + "requires": { + "ccount": "^1.0.0", + "comma-separated-tokens": "^1.0.1", + "hast-util-is-element": "^1.0.0", + "hast-util-whitespace": "^1.0.0", + "html-void-elements": "^1.0.0", + "property-information": "^5.2.0", + "space-separated-tokens": "^1.0.0", + "stringify-entities": "^2.0.0", + "unist-util-is": "^3.0.0", + "xtend": "^4.0.1" + }, + "dependencies": { + "unist-util-is": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz", + "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==" + } + } + }, "hast-util-to-parse5": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-5.1.1.tgz", @@ -7086,6 +7088,11 @@ "unist-util-find-after": "^2.0.3" } }, + "hast-util-whitespace": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-1.0.3.tgz", + "integrity": "sha512-AlkYiLTTwPOyxZ8axq2/bCwRUPjIPBfrHkXuCR92B38b3lSdU22R5F/Z4DL6a2kxWpekWq1w6Nj48tWat6GeRA==" + }, "hastscript": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-5.1.0.tgz", @@ -7658,6 +7665,11 @@ "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.3.tgz", "integrity": "sha512-eEMa6MKpHFzw38eKm56iNNi6GJ7lf6aLLio7Kr23sJPAECscgRtZvOBYybejWDQ2bM949Y++61PY+udzj5QMLA==" }, + "is-alphanumeric": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz", + "integrity": "sha1-Spzvcdr0wAHB2B1j0UDPU/1oifQ=" + }, "is-alphanumerical": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.3.tgz", @@ -8261,8 +8273,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -8283,14 +8294,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -8305,20 +8314,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -8435,8 +8441,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -8448,7 +8453,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -8463,7 +8467,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -8471,14 +8474,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -8497,7 +8498,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -8578,8 +8578,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -8591,7 +8590,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -8677,8 +8675,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -8714,7 +8711,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -8734,7 +8730,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -8778,14 +8773,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, @@ -9400,6 +9393,11 @@ "integrity": "sha512-p0b6mOGKcGa+7nnmKbpzR6qloPbrgLcnio++E+14Vo/XffOGwZtRpUhr8dTH/x2oCMmEoIU0Zwm3ZauhvYD17g==", "dev": true }, + "longest-streak": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.3.tgz", + "integrity": "sha512-9lz5IVdpwsKLMzQi0MQ+oD9EA0mIGcWYP7jXMTZVXP8D42PwuAk+M/HBFYQoxt1G5OR8m7aSIgb1UymfWGBWEw==" + }, "loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -9491,6 +9489,11 @@ "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.3.tgz", "integrity": "sha512-XUi5HJhhV5R74k8/0H2oCbCiYf/u4cO/rX8tnGkRvrqhsr5BRNU6Mg0yt/8UIx1iIS8220BNJsDb7XnILhLepw==" }, + "markdown-table": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-1.1.3.tgz", + "integrity": "sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==" + }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -9502,6 +9505,37 @@ "safe-buffer": "^5.1.2" } }, + "mdast-util-compact": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mdast-util-compact/-/mdast-util-compact-1.0.4.tgz", + "integrity": "sha512-3YDMQHI5vRiS2uygEFYaqckibpJtKq5Sj2c8JioeOQBU6INpKbdWzfyLqFFnDwEcEnRFIdMsguzs5pC1Jp4Isg==", + "requires": { + "unist-util-visit": "^1.1.0" + }, + "dependencies": { + "unist-util-is": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz", + "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==" + }, + "unist-util-visit": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.1.tgz", + "integrity": "sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==", + "requires": { + "unist-util-visit-parents": "^2.0.0" + } + }, + "unist-util-visit-parents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz", + "integrity": "sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==", + "requires": { + "unist-util-is": "^3.0.0" + } + } + } + }, "mdast-util-definitions": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-1.2.4.tgz", @@ -9792,7 +9826,7 @@ }, "minimist": { "version": "0.0.8", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "mississippi": { @@ -12081,6 +12115,16 @@ } } }, + "rehype-document": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/rehype-document/-/rehype-document-3.2.0.tgz", + "integrity": "sha512-TzlPvrIfZLT5w/CuQ+drqCTGoZ/e68nlZfXQH8/PGdauwQGHQ2+WyJ6EUt8tqmKuWR6Xc3gb8oyKtVWtHZGoJA==", + "requires": { + "doctype": "^2.0.0", + "hastscript": "^5.0.0", + "unist-builder": "^1.0.1" + } + }, "rehype-raw": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-4.0.1.tgz", @@ -12106,21 +12150,21 @@ "hast-util-sanitize": "^2.0.0" } }, + "rehype-stringify": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-6.0.1.tgz", + "integrity": "sha512-JfEPRDD4DiG7jet4md7sY07v6ACeb2x+9HWQtRPm2iA6/ic31hCv1SNBUtpolJASxQ/D8gicXiviW4TJKEMPKQ==", + "requires": { + "hast-util-to-html": "^6.0.0", + "xtend": "^4.0.0" + } + }, "relateurl": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", "dev": true }, - "remark-frontmatter": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-1.3.2.tgz", - "integrity": "sha512-2eayxITZ8rezsXdgcXnYB3iLivohm2V/ZT4Ne8uhua6A4pk6GdLE2ZzJnbnINtD1HRLaTdB7RwF9sgUbMptJZA==", - "requires": { - "fault": "^1.0.1", - "xtend": "^4.0.1" - } - }, "remark-parse": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-7.0.1.tgz", @@ -12151,6 +12195,27 @@ "mdast-util-to-hast": "^6.0.0" } }, + "remark-stringify": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-7.0.4.tgz", + "integrity": "sha512-qck+8NeA1D0utk1ttKcWAoHRrJxERYQzkHDyn+pF5Z4whX1ug98uCNPPSeFgLSaNERRxnD6oxIug6DzZQth6Pg==", + "requires": { + "ccount": "^1.0.0", + "is-alphanumeric": "^1.0.0", + "is-decimal": "^1.0.0", + "is-whitespace-character": "^1.0.0", + "longest-streak": "^2.0.1", + "markdown-escapes": "^1.0.0", + "markdown-table": "^1.1.0", + "mdast-util-compact": "^1.0.0", + "parse-entities": "^1.0.2", + "repeat-string": "^1.5.4", + "state-toggle": "^1.0.0", + "stringify-entities": "^2.0.0", + "unherit": "^1.0.4", + "xtend": "^4.0.1" + } + }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -12440,7 +12505,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true } @@ -13236,6 +13301,18 @@ "safe-buffer": "~5.1.0" } }, + "stringify-entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-2.0.0.tgz", + "integrity": "sha512-fqqhZzXyAM6pGD9lky/GOPq6V4X0SeTAFBl0iXb/BzOegl40gpf/bV3QQP7zULNYvjr6+Dx8SCaDULjVoOru0A==", + "requires": { + "character-entities-html4": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.2", + "is-hexadecimal": "^1.0.0" + } + }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", @@ -13415,7 +13492,7 @@ }, "readable-stream": { "version": "1.0.33", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz", "integrity": "sha1-OjYN1mwbHX/UcFOJhg7aHQ9hEmw=", "requires": { "core-util-is": "~1.0.0", diff --git a/package.json b/package.json index 6cf7d269c..188cbb514 100644 --- a/package.json +++ b/package.json @@ -119,12 +119,14 @@ "react-dom": "^16.9.0", "react-i18next": "^11.0.1", "react-use": "^12.10.0", + "rehype-document": "^3.2.0", "rehype-raw": "^4.0.1", "rehype-react": "^4.0.1", "rehype-sanitize": "^3.0.0", - "remark-frontmatter": "^1.3.2", + "rehype-stringify": "^6.0.1", "remark-parse": "^7.0.1", "remark-rehype": "^5.0.0", + "remark-stringify": "^7.0.4", "shortid": "^2.2.15", "styled-components": "^4.3.2", "typescript": "^3.6.3", diff --git a/src/components/NotePage/NoteDetail/NoteDetail.tsx b/src/components/NotePage/NoteDetail/NoteDetail.tsx index 576528db8..2793edcea 100644 --- a/src/components/NotePage/NoteDetail/NoteDetail.tsx +++ b/src/components/NotePage/NoteDetail/NoteDetail.tsx @@ -20,6 +20,7 @@ import { borderBottom, borderRight } from '../../../lib/styled/styleFunctions' +import ToolbarExportButton from '../../atoms/ToolbarExportButton' const StyledNoteDetailContainer = styled.div` ${secondaryBackgroundColor} @@ -347,6 +348,7 @@ export default class NoteDetail extends React.Component< onKeyDown={this.handleNewTagNameInputKeyDown} /> + {}} path={mdiFormatText} /> ) { } } } -const rehypeCodeMirror = rehypeCodeMirrorAttacher as Plugin< + +export const rehypeCodeMirror = rehypeCodeMirrorAttacher as Plugin< [Partial?] > diff --git a/src/components/atoms/ToolbarExportButton.tsx b/src/components/atoms/ToolbarExportButton.tsx new file mode 100644 index 000000000..6fc4d9b89 --- /dev/null +++ b/src/components/atoms/ToolbarExportButton.tsx @@ -0,0 +1,154 @@ +import React, { useCallback } from 'react' +import styled from '../../lib/styled' +import { iconColor } from '../../lib/styled/styleFunctions' +import { useContextMenu, MenuTypes } from '../../lib/contextMenu' +import { NoteDoc } from '../../lib/db/types' +import unified from 'unified' +import remarkParse from 'remark-parse' +import remarkRehype from 'remark-rehype' +import remarkStringify from 'remark-stringify' +import rehypeDocument from 'rehype-document' +import rehypeRaw from 'rehype-raw' +import rehypeSanitize from 'rehype-sanitize' +import rehypeStringify from 'rehype-stringify' +import { mergeDeepRight } from 'ramda' +import gh from 'hast-util-sanitize/lib/github.json' +import { usePreferences } from '../../lib/preferences' +import { rehypeCodeMirror } from './MarkdownPreviewer' +import { usePreviewStyle } from '../../lib/preview' + +const sanitizeSchema = mergeDeepRight(gh, { + attributes: { '*': ['className'] } +}) + +const StyledButton = styled.button<{ active: boolean }>` + background: transparent; + height: 32px; + box-sizing: border-box; + font-size: 14px; + outline: none; + border: none; + ${iconColor} + &:first-child { + margin-left: 0; + } + &:last-child { + margin-right: 0; + } +` + +interface ToolbarExportButtonProps { + note: NoteDoc + className?: string +} + +const ToolbarExportButton = ({ className, note }: ToolbarExportButtonProps) => { + const { popup } = useContextMenu() + const { preferences } = usePreferences() + const { previewStyle } = usePreviewStyle() + + const openExportButtonContextMenu = useCallback( + (event: React.MouseEvent) => { + event.preventDefault() + popup(event, [ + { + type: MenuTypes.Normal, + label: 'HTML export', + onClick: async () => await exportToHtml() + }, + { + type: MenuTypes.Normal, + label: 'Markdown export', + onClick: async () => await exportToMarkdown() + } + ]) + }, + [popup] + ) + + const downloadFile = ( + content: string, + fileName: string, + type: string = 'text/plain' + ) => { + const anchor = document.createElement('a') + anchor.style.display = 'none' + document.body.appendChild(anchor) + anchor.href = window.URL.createObjectURL(new Blob([content], { type })) + anchor.setAttribute('download', fileName) + anchor.click() + window.URL.revokeObjectURL(anchor.href) + document.body.removeChild(anchor) + } + + const exportToHtml = async () => { + await unified() + .use(remarkParse) + .use(remarkRehype, { allowDangerousHTML: false }) + .use(rehypeCodeMirror, { + ignoreMissing: true, + theme: preferences['markdown.codeBlockTheme'] + }) + .use(rehypeRaw) + .use(rehypeSanitize, sanitizeSchema) + .use(rehypeDocument, { + title: note.title, + style: previewStyle, + meta: { keywords: note.tags.join() } + }) + .use(rehypeStringify) + .process(note.content, (err, file) => { + if (err != null) { + /* TODO: Toast error */ + console.error(err) + return + } + + downloadFile( + String(file), + `${note.title.toLowerCase().replace(/\s+/g, '-')}.html`, + 'text/html' + ) + return + }) + } + + const exportToMarkdown = async () => { + console.log('export markdown') + await unified() + .use(remarkParse) + .use(remarkStringify) + .process(note.content, (err, file) => { + if (err != null) { + /* TODO: Toast error */ + console.error(err) + return + } + downloadFile( + [ + '---', + `title: "${note.title}"`, + `tags: "${note.tags.join()}"`, + '---', + String(file) + ].join('\n'), + `${note.title.toLowerCase().replace(/\s+/g, '-')}.md`, + 'text/markdown' + ) + return + }) + return + } + + return ( + + Export + + ) +} + +export default ToolbarExportButton diff --git a/tsconfig-webpack.json b/tsconfig-webpack.json index f4195027f..60a3c74b9 100644 --- a/tsconfig-webpack.json +++ b/tsconfig-webpack.json @@ -3,5 +3,6 @@ "module": "commonjs", "target": "es5", "esModuleInterop": true - } + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "./typings/**/*.d.ts"] } diff --git a/tsconfig.json b/tsconfig.json index 16041046a..b9046816e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,6 @@ { "include": ["src/**/*.ts", "src/**/*.tsx", "./typings/**/*.d.ts"], + "exclude": ["dist", "node_modules"], "compilerOptions": { "allowSyntheticDefaultImports": true, "target": "esnext", diff --git a/typings/unified.d.ts b/typings/unified.d.ts index c4164b0d6..af2e04fd1 100644 --- a/typings/unified.d.ts +++ b/typings/unified.d.ts @@ -1,7 +1,10 @@ declare module 'remark-rehype' +declare module 'remark-stringify' +declare module 'rehype-document' declare module 'rehype-raw' declare module 'rehype-sanitize' declare module 'rehype-react' +declare module 'rehype-stringify' declare module 'hast-util-sanitize/lib/github.json' declare module 'hast-util-to-text' declare module 'hastscript'