diff --git a/.eslintrc b/.eslintrc index faaa1915fc..bd28db39cc 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 54df709565..f65e883c78 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 6cf7d269c4..188cbb514a 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 576528db81..2793edcea5 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 0000000000..f55ff9d042 --- /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( + file.toString(), + `${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()}"`, + '---', + file.toString() + ].join('\n'), + `${note.title.toLowerCase().replace(/\s+/g, '-')}.md`, + 'text/markdown' + ) + return + }) + return + } + + return ( + + Export + + ) +} + +export default ToolbarExportButton diff --git a/src/lib/styled/styleFunctions_designfix.ts b/src/lib/styled/styleFunctions_designfix.ts new file mode 100644 index 0000000000..71cad74920 --- /dev/null +++ b/src/lib/styled/styleFunctions_designfix.ts @@ -0,0 +1,5 @@ +import { BaseThemeDesignfix } from './themes/types_designfix' + +interface StyledProps { + theme: BaseThemeDesignfix +} \ No newline at end of file diff --git a/src/lib/styled/themes/default_designfix.ts b/src/lib/styled/themes/default_designfix.ts new file mode 100644 index 0000000000..1da425e319 --- /dev/null +++ b/src/lib/styled/themes/default_designfix.ts @@ -0,0 +1,302 @@ +import { BaseThemeDesignfix } from './types_designfix' + +/* ———————————–———————————–———————————–——–—— + Colors +———————————–———————————–———————————–——–—— */ + +/*__ Setting _______________________*/ + +// Dark Base Colors +const baseColor01 = '#2C2D30' +const baseColor02 = '#1E2022' + +// Color Masks +const darkColor026 = 'rgba(0,0,0,0.26)' +const darkColor012 = 'rgba(0,0,0,0.12)' +const lightColor012 = 'rgba(255,255,255,0.12)' +const lightColor030 = 'rgba(255,255,255,0.3)' +const lightColor070 = 'rgba(255,255,255,0.7)' +const lightColor100 = 'rgba(255,255,255,1)' + +// System Colors +const primaryColor = '#03C588' +const errorColor = '#0FF6150' +const favColor = '#F1B81B' + + +/*__ Assign _______________________*/ + +// Text Colors +const baseTextColor = lightColor070 +const subtleTextColor = lightColor030 +const emphasizedTextColor = lightColor100 +const accentTextColor = primaryColor + +// Icon Colors +const baseIconColor = lightColor030 +const activeIconColor = lightColor070 +const errorIconColor = errorColor +const favIconColor = favColor + +// Background Colors +const baseBackgroundColor = baseColor01 +const lightBackgroundColor = lightColor012 +const preferenceBackgroundColor = baseColor02 +const formBackgroundColor = baseColor01 +const activeBackgroundColor = baseColor02 +const editorBackgroundColor = baseColor02 +const codeBackgroundColor = darkColor012 +const tagBackgroundColor = darkColor026 +const searchBackgroundColor = lightColor030 +const accentBackgroundColor = primaryColor + +// Border Color +const baseBorderColor = darkColor026 +const codeBorderColor = darkColor012 +const accentBorderColor = primaryColor +const lightBorderColor = lightColor030 +const subtleBorderColor = lightColor012 + + +/* ———————————–———————————–———————————–——–—— + Typography +———————————–———————————–———————————–——–—— */ + +/*__ Setting _______________________*/ + +// Font Family +const baseFontFamily = `-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Fira sans', Roboto, Helvetica, Arial, sans-serif 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'` + +// Font Sizes +const fontSize22 = 22 +const fontSize18 = 18 +const fontSize16 = 16 +const fontSize15 = 15 +const fontSize14 = 14 +const fontSize13 = 13 +const fontSize12 = 12 +const fontSize11 = 11 +const fontSize10 = 10 +const fontSize08 = 8 + +// Font Weights +const fontWeightBase = 400 +const fontWeightMedium = 500 + +// Line Heights +const lineHeightBase = 1.5 +const lineHeightNarrow = 1.2 +const lineHeightWide = 2 + + +/*__ Assign _______________________*/ + +// Font Sizes for Top +const topXLargeFontSize = fontSize16 +const topLargeFontSize = fontSize15 +const topMediumFontSize = fontSize14 +const topBaseFontSize = fontSize12 +const topSmallFontSize = fontSize10 +const topXSmallFontSize = fontSize08 + +// Font Sizes for Preference +const prefXLargeFontSize = fontSize22 +const prefLargeFontSize = fontSize18 +const prefMediumFontSize = fontSize14 +const prefBaseFontSize = fontSize13 +const prefSmallFontSize = fontSize12 +const prefXSmallFontSize = fontSize11 +const prefXXSmallFontSize = fontSize10 + +// Font Sizes for Add & Edit Storage +const storageLargeFontSize = fontSize22 +const storageMediumFontSize = fontSize18 +const storageBaseFontSize = fontSize13 +const storageSmallFontSize = fontSize12 +const storageXSmallFontSize = fontSize11 +const storageXXSmallFontSize = fontSize10 + + +/* ———————————–———————————–———————————–——–—— + Spacing +———————————–———————————–———————————–——–—— */ + +// Base Spacing +const space54 = 54 +const space48 = 48 +const space42 = 42 +const space36 = 36 +const space30 = 30 +const space24 = 24 +const space18 = 18 +const space12 = 12 +const space06 = 6 + + +/* ———————————–———————————–———————————–——–—— + Icon Sizes +———————————–———————————–———————————–——–—— */ + +// Size Setting +const iconSize32 = 32 +const iconSize28 = 28 +const iconSize24 = 24 +const iconSize20 = 20 +const iconSize18 = 18 +const iconSize16 = 16 + + +/* ———————————–———————————–———————————–——–—— + Border Radius +———————————–———————————–———————————–——–—— */ + +// Size Setting +const radius2 = 2 +const radius4 = 4 + + +/* ———————————–———————————–———————————–——–—— + Export Base Theme +———————————–———————————–———————————–——–—— */ + +export const defaultTheme: BaseThemeDesignfix = { + + /* ———————————–———————————–———————————–——–—— + Base Setting + ———————————–———————————–———————————–——–—— */ + + colors: { + text: baseTextColor, + link: accentTextColor, + icon: baseIconColor, + background: baseBackgroundColor, + border: baseBorderColor + }, + fontFamily: baseFontFamily, + fontSize: fontSize13, + fontWeight: fontWeightBase, + lineHeight: lineHeightBase, + + /* ———————————–———————————–———————————–——–—— + Atoms + ———————————–———————————–———————————–——–—— */ + + /*__ Icons _______________________*/ + + // Sidebar + preferenceIconWidth: iconSize28, + preferenceIconHeight: iconSize28, + preferenceIconColor: baseIconColor, + + listTitleIconWidth: iconSize20, + listTitleIconHeight: iconSize20, + listTitleIconColor: baseIconColor, + + listItemIconWidth: iconSize16, + listItemIconHeight: iconSize16, + listItemIconDefaultColor: baseIconColor, + listItemIconErrorColor: errorIconColor, + + // Search Bar + searchIconWidth: iconSize20, + searchIconHeight: iconSize20, + searchIconColor: baseIconColor, + + addNoteIconWidth: iconSize28, + addNoteIconHeight: iconSize28, + addNoteIconColor: baseIconColor, + + // Note Block + favIconWidth: iconSize24, + favIconHeight: iconSize24, + favIconDefaultColor: baseIconColor, + favIconActiveColor: favIconColor, + + // Toolbar + toolbarIconWidth: iconSize18, + toolbarIconHeight: iconSize18, + toolbarIconDefaultColor: baseIconColor, + toolbarIconActiveColor: activeIconColor, + + // Preference + refreshIconWidth: iconSize32, + refreshIconHeight: iconSize32, + refreshIconColor: baseIconColor, + + crossIconWidth: iconSize28, + crossIconHeight: iconSize28, + crossIconColor: baseIconColor, + + + /*__ Buttons _______________________*/ + + // Common + buttonBorderRadius: radius2, + buttonFontWeight: fontWeightBase, + buttonLineHeight: lineHeightNarrow, + + // Default Button + defaultButtonPaddingX: space18, + defaultButtonPaddingY: space12, + defaultButtonFontSize: fontSize13, + + // Small Button + smallButtonPaddingX: space12, + smallButtonPaddingY: space06, + smallButtonFontSize: fontSize11, + + // Primary Button + primaryButtonBackgroundColor: accentBackgroundColor, + primaryButtonBorderColor: accentBorderColor, + primaryButtonTextColor: emphasizedTextColor, + + // Secondary Button + secondaryButtonBackgroundColor: 'transparent', + secondaryButtonBorderColor: lightBorderColor, + secondaryButtonTextColor: emphasizedTextColor, + + // Subtle Button + subtleButtonBackgroundColor: 'transparent', + subtleButtonBorderColor: subtleBorderColor, + subtleButtonTextColor: subtleTextColor, + + + /*__ Forms _______________________*/ + + // Search Bar + searchbarPaddingX: space12, + searchbarPaddingY: space06, + searchbarBackgroundColor: searchBackgroundColor, + searchbarTextColor: emphasizedTextColor, + searchbarPlaceHolderColor: subtleTextColor, + searchbarBorderRadius: radius4, + searchbarFontSize: fontSize12, + searchbarFontWeight: fontWeightBase, + searchbarLineHeight: lineHeightNarrow, + searchbarIconColor: subtleTextColor, + searchbarIconRightMargin: 2, + + // Preference Label + preferenceLabelTextColor: emphasizedTextColor, + preferenceLabelFontSize: fontSize13, + preferenceLabelFontWeight: fontWeightBase, + preferenceLabelLineHeight: lineHeightNarrow, + + // Preference Form + preferenceFormPaddingX: space18, + preferenceFormPaddingY: space12, + preferenceFormBackgroundColor: formBackgroundColor, + preferenceFormTextColor: emphasizedTextColor, + preferenceFormPlaceHolderColor: subtleTextColor, + preferenceFormBorderRadius: radius2, + preferenceFormFontSize: fontSize12, + preferenceFormFontWeight: fontWeightBase, + preferenceFormLineHeight: lineHeightNarrow, + + + /*__ Scroll Bar _______________________*/ + + scrollBarTrackColor: baseBackgroundColor, + scrollBarThumbColor: lightBackgroundColor, + +} \ No newline at end of file diff --git a/src/lib/styled/themes/types_designfix.ts b/src/lib/styled/themes/types_designfix.ts new file mode 100644 index 0000000000..14de2b3a60 --- /dev/null +++ b/src/lib/styled/themes/types_designfix.ts @@ -0,0 +1,178 @@ +export interface BaseThemeDesignfix { + + /* ———————————–———————————–———————————–——–—— + Base Setting + ———————————–———————————–———————————–——–—— */ + + colors: any + fontFamily: string + fontSize: number + fontWeight: number + lineHeight: number + + + /* ———————————–———————————–———————————–——–—— + Atoms + ———————————–———————————–———————————–——–—— */ + + /*__ Icons _______________________*/ + + // Sidebar + preferenceIconWidth: number + preferenceIconHeight: number + preferenceIconColor: string + + listTitleIconWidth: number + listTitleIconHeight: number + listTitleIconColor: string + + listItemIconWidth: number + listItemIconHeight: number + listItemIconDefaultColor: string + listItemIconErrorColor: string + + // Search Bar + searchIconWidth: number + searchIconHeight: number + searchIconColor: string + + addNoteIconWidth: number + addNoteIconHeight: number + addNoteIconColor: string + + // Note Block + favIconWidth: number + favIconHeight: number + favIconDefaultColor: string + favIconActiveColor: string + + // Toolbar + toolbarIconWidth: number + toolbarIconHeight: number + toolbarIconDefaultColor: string + toolbarIconActiveColor: string + + // Preference + refreshIconWidth: number + refreshIconHeight: number + refreshIconColor: string + + crossIconWidth: number + crossIconHeight: number + crossIconColor: string + + + /*__ Buttons _______________________*/ + + // Common + buttonBorderRadius: number + buttonFontWeight: number + buttonLineHeight: number + + // Default Button + defaultButtonPaddingX: number + defaultButtonPaddingY: number + defaultButtonFontSize: number + + // Small Button + smallButtonPaddingX: number + smallButtonPaddingY: number + smallButtonFontSize: number + + // Primary Button + primaryButtonBackgroundColor: string + primaryButtonBorderColor: string + primaryButtonTextColor: string + + // Secondary Button + secondaryButtonBackgroundColor: string + secondaryButtonBorderColor: string + secondaryButtonTextColor: string + + // Subtle Button + subtleButtonBackgroundColor: string + subtleButtonBorderColor: string + subtleButtonTextColor: string + + + /*__ Forms _______________________*/ + + // Search Bar + searchbarPaddingX: number + searchbarPaddingY: number + searchbarBackgroundColor: string + searchbarTextColor: string + searchbarPlaceHolderColor: string + searchbarBorderRadius: number + searchbarFontSize: number + searchbarFontWeight: number + searchbarLineHeight: number + searchbarIconColor: string + searchbarIconRightMargin: number + + // Preference Label + preferenceLabelTextColor: string + preferenceLabelFontSize: number + preferenceLabelFontWeight: number + preferenceLabelLineHeight: number + + // Preference Form + preferenceFormPaddingX: number + preferenceFormPaddingY: number + preferenceFormBackgroundColor: string + preferenceFormTextColor: string + preferenceFormPlaceHolderColor: string + preferenceFormBorderRadius: number + preferenceFormFontSize: number + preferenceFormFontWeight: number + preferenceFormLineHeight: number + + + /*__ Scroll Bar _______________________*/ + + scrollBarTrackColor: string + scrollBarThumbColor: string + + + /* ———————————–———————————–———————————–——–—— + Molecules + ———————————–———————————–———————————–——–—— */ + + /*__ Top _______________________*/ + + // Context Menu + // Search Bar + // Note Block + // Toolbar + + /*__ Preferences _______________________*/ + + // Nav + // Account + // Account + + /* ———————————–———————————–———————————–——–—— + Organisms + ———————————–———————————–———————————–——–—— */ + + /*__ Top _______________________*/ + + // Side Bar + // Note List + // Editor + + /*__ Preference _______________________*/ + + // Navigator + // General + // Editor + // Markdown + // Hotkeys + // About + + /*__ Storage _______________________*/ + + // Add Storage + // Edit Storage + +} diff --git a/tsconfig-webpack.json b/tsconfig-webpack.json index f4195027f1..60a3c74b95 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 16041046ad..b9046816e4 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 c4164b0d64..af2e04fd17 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'