diff --git a/package.json b/package.json index 4505ed6..5a17d74 100644 --- a/package.json +++ b/package.json @@ -75,6 +75,7 @@ "emmet-monaco-es": "^4.3.3", "feather-icons": "^4.25.0", "fs-extra": "^8.1.0", + "highlight.js": "^9.18.1", "interactjs": "^1.8.0-alpha.6", "junk": "^3.1.0", "lodash-es": "^4.17.15", @@ -86,6 +87,7 @@ "nedb": "^1.8.0", "perfect-scrollbar": "^1.4.0", "popper.js": "^1.16.0", + "prismjs": "^1.19.0", "rimraf": "^3.0.2", "sanitize-html": "^1.21.1", "shortid": "^2.2.15", diff --git a/src/renderer/components/editor/MarkdownPreview.vue b/src/renderer/components/editor/MarkdownPreview.vue index bfbec07..02bc5d8 100644 --- a/src/renderer/components/editor/MarkdownPreview.vue +++ b/src/renderer/components/editor/MarkdownPreview.vue @@ -13,6 +13,9 @@ import mila from 'markdown-it-link-attributes' import { shell } from 'electron' import PerfectScrollbar from 'perfect-scrollbar' import sanitizeHtml from 'sanitize-html' +import hljs from 'highlight.js' +import fs from 'fs' +import { mapState } from 'vuex' export default { name: 'MarkdownPreview', @@ -36,6 +39,7 @@ export default { }, computed: { + ...mapState(['app']), result () { const raw = this.md.render(this.model) return sanitizeHtml(raw, { @@ -49,7 +53,8 @@ export default { 'name', 'src', 'target', - 'width' + 'width', + 'class' ] } }) @@ -72,6 +77,9 @@ export default { watch: { model () { this.setLinksClass() + }, + 'app.theme' (v) { + this.toggleHljsStyles(v) } }, @@ -93,13 +101,31 @@ export default { init () { this.md = new MarkdownIt({ html: true, - langPrefix: 'language-' + langPrefix: 'language-', + highlight (str, lang) { + if (lang && hljs.getLanguage(lang)) { + try { + return `
${
+ hljs.highlight(lang, str, true).value
+ }`
+ } catch (err) {
+ console.log(err)
+ }
+ }
+ return `${MarkdownIt().utils.escapeHtml(
+ str
+ )}`
+ }
})
this.md.use(mila, {
attrs: {
class: 'external'
}
})
+
+ this.app.theme === 'dark'
+ ? this.toggleHljsStyles('dark')
+ : this.toggleHljsStyles('light')
},
// Добавляем класс ссылкам которые были созданы как HTML
setLinksClass () {
@@ -116,6 +142,25 @@ export default {
},
initPS () {
this.ps = new PerfectScrollbar(this.$refs.preview)
+ },
+ toggleHljsStyles (theme) {
+ const dark = fs.readFileSync(
+ __static + '/css/hljs/atom-one-dark.css',
+ 'utf8'
+ )
+ const light = fs.readFileSync(
+ __static + '/css/hljs/atom-one-light.css',
+ 'utf8'
+ )
+ const style = document.createElement('style')
+ style.setAttribute('name', 'hljs')
+
+ const existStyle = document.querySelector('style[name="hljs"]')
+
+ if (existStyle) existStyle.remove()
+
+ theme === 'dark' ? (style.innerHTML = dark) : (style.innerHTML = light)
+ document.head.appendChild(style)
}
}
}
diff --git a/static/css/hljs/atom-one-dark.css b/static/css/hljs/atom-one-dark.css
new file mode 100644
index 0000000..1616aaf
--- /dev/null
+++ b/static/css/hljs/atom-one-dark.css
@@ -0,0 +1,96 @@
+/*
+
+Atom One Dark by Daniel Gamage
+Original One Dark Syntax theme from https://github.com/atom/one-dark-syntax
+
+base: #282c34
+mono-1: #abb2bf
+mono-2: #818896
+mono-3: #5c6370
+hue-1: #56b6c2
+hue-2: #61aeee
+hue-3: #c678dd
+hue-4: #98c379
+hue-5: #e06c75
+hue-5-2: #be5046
+hue-6: #d19a66
+hue-6-2: #e6c07b
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ color: #abb2bf;
+ background: #282c34;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #5c6370;
+ font-style: italic;
+}
+
+.hljs-doctag,
+.hljs-keyword,
+.hljs-formula {
+ color: #c678dd;
+}
+
+.hljs-section,
+.hljs-name,
+.hljs-selector-tag,
+.hljs-deletion,
+.hljs-subst {
+ color: #e06c75;
+}
+
+.hljs-literal {
+ color: #56b6c2;
+}
+
+.hljs-string,
+.hljs-regexp,
+.hljs-addition,
+.hljs-attribute,
+.hljs-meta-string {
+ color: #98c379;
+}
+
+.hljs-built_in,
+.hljs-class .hljs-title {
+ color: #e6c07b;
+}
+
+.hljs-attr,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-type,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-number {
+ color: #d19a66;
+}
+
+.hljs-symbol,
+.hljs-bullet,
+.hljs-link,
+.hljs-meta,
+.hljs-selector-id,
+.hljs-title {
+ color: #61aeee;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-link {
+ text-decoration: underline;
+}
diff --git a/static/css/hljs/atom-one-light.css b/static/css/hljs/atom-one-light.css
new file mode 100644
index 0000000..d5bd1d2
--- /dev/null
+++ b/static/css/hljs/atom-one-light.css
@@ -0,0 +1,96 @@
+/*
+
+Atom One Light by Daniel Gamage
+Original One Light Syntax theme from https://github.com/atom/one-light-syntax
+
+base: #fafafa
+mono-1: #383a42
+mono-2: #686b77
+mono-3: #a0a1a7
+hue-1: #0184bb
+hue-2: #4078f2
+hue-3: #a626a4
+hue-4: #50a14f
+hue-5: #e45649
+hue-5-2: #c91243
+hue-6: #986801
+hue-6-2: #c18401
+
+*/
+
+.hljs {
+ display: block;
+ overflow-x: auto;
+ padding: 0.5em;
+ color: #383a42;
+ background: #fafafa;
+}
+
+.hljs-comment,
+.hljs-quote {
+ color: #a0a1a7;
+ font-style: italic;
+}
+
+.hljs-doctag,
+.hljs-keyword,
+.hljs-formula {
+ color: #a626a4;
+}
+
+.hljs-section,
+.hljs-name,
+.hljs-selector-tag,
+.hljs-deletion,
+.hljs-subst {
+ color: #e45649;
+}
+
+.hljs-literal {
+ color: #0184bb;
+}
+
+.hljs-string,
+.hljs-regexp,
+.hljs-addition,
+.hljs-attribute,
+.hljs-meta-string {
+ color: #50a14f;
+}
+
+.hljs-built_in,
+.hljs-class .hljs-title {
+ color: #c18401;
+}
+
+.hljs-attr,
+.hljs-variable,
+.hljs-template-variable,
+.hljs-type,
+.hljs-selector-class,
+.hljs-selector-attr,
+.hljs-selector-pseudo,
+.hljs-number {
+ color: #986801;
+}
+
+.hljs-symbol,
+.hljs-bullet,
+.hljs-link,
+.hljs-meta,
+.hljs-selector-id,
+.hljs-title {
+ color: #4078f2;
+}
+
+.hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs-strong {
+ font-weight: bold;
+}
+
+.hljs-link {
+ text-decoration: underline;
+}
diff --git a/yarn.lock b/yarn.lock
index 3d554e5..0ca573a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2288,6 +2288,15 @@ cli-width@^2.0.0:
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=
+clipboard@^2.0.0:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.6.tgz#52921296eec0fdf77ead1749421b21c968647376"
+ integrity sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==
+ dependencies:
+ good-listener "^1.2.2"
+ select "^1.1.2"
+ tiny-emitter "^2.0.0"
+
cliui@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
@@ -2973,6 +2982,11 @@ delayed-stream@~1.0.0:
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
+delegate@^3.1.2:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166"
+ integrity sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==
+
delegates@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
@@ -4484,6 +4498,13 @@ globule@^1.0.0:
lodash "~4.17.10"
minimatch "~3.0.2"
+good-listener@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50"
+ integrity sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=
+ dependencies:
+ delegate "^3.1.2"
+
got@^9.6.0:
version "9.6.0"
resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85"
@@ -4654,6 +4675,11 @@ helper-js@^1.0.47, helper-js@^1.2.0, helper-js@^1.3.7, helper-js@^1.4.5:
resolved "https://registry.yarnpkg.com/helper-js/-/helper-js-1.4.12.tgz#ae66e145e56963189227047d4c69ecef4f61f068"
integrity sha512-LcZ/z/eA/f/OMea9XYVBLRYv3jYQKDOQyI5m6uB80DyWwte4OLGFewYtguoDu+APFQKVoWs++ODGSYwzZmTSkg==
+highlight.js@^9.18.1:
+ version "9.18.1"
+ resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.18.1.tgz#ed21aa001fe6252bb10a3d76d47573c6539fe13c"
+ integrity sha512-OrVKYz70LHsnCgmbXctv/bfuvntIKDz177h0Co37DQ5jamGZLVmoCVMtjMtNZY3X9DrCcKfklHPNeA0uPZhSJg==
+
highlight.js@^9.3.0:
version "9.17.1"
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.17.1.tgz#14a4eded23fd314b05886758bb906e39dd627f9a"
@@ -7437,6 +7463,13 @@ pretty-error@^2.0.2:
renderkid "^2.0.1"
utila "~0.4"
+prismjs@^1.19.0:
+ version "1.19.0"
+ resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.19.0.tgz#713afbd45c3baca4b321569f2df39e17e729d4dc"
+ integrity sha512-IVFtbW9mCWm9eOIaEkNyo2Vl4NnEifis2GQ7/MLRG5TQe6t+4Sj9J5QWI9i3v+SS43uZBlCAOn+zYTVYQcPXJw==
+ optionalDependencies:
+ clipboard "^2.0.0"
+
private@^0.1.6, private@~0.1.5:
version "0.1.8"
resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
@@ -8177,6 +8210,11 @@ select-hose@^2.0.0:
resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=
+select@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d"
+ integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=
+
selfsigned@^1.10.7:
version "1.10.7"
resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.7.tgz#da5819fd049d5574f28e88a9bcc6dbc6e6f3906b"
@@ -8975,6 +9013,11 @@ timers-browserify@^2.0.4:
dependencies:
setimmediate "^1.0.4"
+tiny-emitter@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423"
+ integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==
+
title-case@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/title-case/-/title-case-2.1.1.tgz#3e127216da58d2bc5becf137ab91dae3a7cd8faa"