client html / markdown exports

This commit is contained in:
davy-c 2019-12-03 18:01:49 +09:00 committed by Junyoung Choi
parent b33676bebb
commit 7ac3b9aad1
9 changed files with 332 additions and 90 deletions

View File

@ -23,5 +23,6 @@
"react": {
"version": "detect"
}
}
},
"exclude": ["dist", "node_modules"]
}

249
package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -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}
/>
<ToolbarSeparator />
<ToolbarExportButton note={this.props.note} />
<ToolbarIconButton onClick={() => {}} path={mdiFormatText} />
<ToolbarIconButton
className={splitMode ? 'active' : ''}

View File

@ -128,7 +128,8 @@ function rehypeCodeMirrorAttacher(options: Partial<RehypeCodeMirrorOptions>) {
}
}
}
const rehypeCodeMirror = rehypeCodeMirrorAttacher as Plugin<
export const rehypeCodeMirror = rehypeCodeMirrorAttacher as Plugin<
[Partial<RehypeCodeMirrorOptions>?]
>

View File

@ -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<HTMLButtonElement>) => {
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 (
<StyledButton
active={false}
onClick={openExportButtonContextMenu}
className={className}
>
<span>Export</span>
</StyledButton>
)
}
export default ToolbarExportButton

View File

@ -3,5 +3,6 @@
"module": "commonjs",
"target": "es5",
"esModuleInterop": true
}
},
"include": ["src/**/*.ts", "src/**/*.tsx", "./typings/**/*.d.ts"]
}

View File

@ -1,5 +1,6 @@
{
"include": ["src/**/*.ts", "src/**/*.tsx", "./typings/**/*.d.ts"],
"exclude": ["dist", "node_modules"],
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"target": "esnext",

View File

@ -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'