diff --git a/.eslintrc.js b/.eslintrc.js index 49c2e6d..def4470 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,30 +1,28 @@ module.exports = { - root: true, - env: { - node: true - }, - 'extends': [ - 'plugin:vue/essential', - '@vue/standard' - ], - rules: { - 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', - 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', - 'camelcase': 'off', - 'eqeqeq': 'off' - }, - parserOptions: { - parser: 'babel-eslint' - }, - overrides: [ - { - files: [ - '**/__tests__/*.{j,t}s?(x)', - '**/tests/unit/**/*.spec.{j,t}s?(x)' - ], - env: { - jest: true - } - } - ] + root: true, + env: { + node: true + }, + 'extends': [ + 'plugin:vue/essential', + '@vue/standard' + ], + rules: { + 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', + 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', + 'camelcase': 'off', + 'eqeqeq': 'off' + }, + parserOptions: { + parser: 'babel-eslint' + }, + overrides: [{ + files: [ + '**/__tests__/*.{j,t}s?(x)', + '**/tests/unit/**/*.spec.{j,t}s?(x)' + ], + env: { + jest: true + } + }] } diff --git a/README.md b/README.md index 776c5c6..370462b 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,9 @@ Markdown 文档自动即时渲染为微信图文,让你不再为微信文章 - [x] 支持自定义 CSS 样式并实时渲染 - [x] 支持一键恢复至默认内容及样式 - [x] 支持打开或关闭引用链接的选项 +- [ ] 支持在编辑框右键弹出功能选项卡 +- [ ] 支持更加人性化的插入表格功能 + ![select-and-change-color-theme](https://imgkr.cn-bj.ufileos.com/32c05c23-6309-491f-bd0d-f22a62c944b4.gif) diff --git a/babel.config.js b/babel.config.js index e955840..c94e729 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,5 +1,5 @@ module.exports = { - presets: [ - '@vue/cli-plugin-babel/preset' - ] + presets: [ + '@vue/cli-plugin-babel/preset' + ] } diff --git a/jest.config.js b/jest.config.js index 0f95791..15e1b1e 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,3 +1,3 @@ module.exports = { - preset: '@vue/cli-plugin-unit-jest' + preset: '@vue/cli-plugin-unit-jest' } diff --git a/package.json b/package.json index af03cdd..6800eaa 100644 --- a/package.json +++ b/package.json @@ -1,42 +1,42 @@ { - "name": "vue-md", - "version": "1.3.2", - "private": true, - "homepage": "https://doocs.gitee.io/md", - "scripts": { - "serve": "vue-cli-service serve", - "build": "vue-cli-service build", - "lint": "vue-cli-service lint", - "test:unit": "vue-cli-service test:unit" - }, - "dependencies": { - "axios": "^0.19.1", - "codemirror": "^5.50.2", - "core-js": "^3.4.4", - "element-ui": "^2.13.0", - "jquery": "^3.4.1", - "juice": "^6.0.0", - "markdown": "^0.5.0", - "marked": "^0.8.0", - "prettier": "^2.0.5", - "prettify": "^0.1.7", - "vue": "^2.6.10", - "vue-router": "^3.1.3", - "vuex": "^3.1.2" - }, - "devDependencies": { - "@vue/cli-plugin-babel": "^4.1.0", - "@vue/cli-plugin-eslint": "^4.1.0", - "@vue/cli-plugin-unit-jest": "^4.1.0", - "@vue/cli-service": "^4.1.0", - "@vue/eslint-config-standard": "^4.0.0", - "@vue/test-utils": "1.0.0-beta.29", - "babel-eslint": "^10.0.3", - "eslint": "^5.16.0", - "eslint-plugin-vue": "^5.0.0", - "less-loader": "^6.0.0", - "node-sass": "^4.12.0", - "sass-loader": "^8.0.0", - "vue-template-compiler": "^2.6.10" - } -} + "name": "vue-md", + "version": "1.3.2", + "private": true, + "homepage": "https://doocs.gitee.io/md", + "scripts": { + "serve": "vue-cli-service serve", + "build": "vue-cli-service build", + "lint": "vue-cli-service lint", + "test:unit": "vue-cli-service test:unit" + }, + "dependencies": { + "axios": "^0.19.1", + "codemirror": "^5.50.2", + "core-js": "^3.4.4", + "element-ui": "^2.13.0", + "jquery": "^3.4.1", + "juice": "^6.0.0", + "markdown": "^0.5.0", + "marked": "^0.8.0", + "prettier": "^2.0.5", + "prettify": "^0.1.7", + "vue": "^2.6.10", + "vue-router": "^3.1.3", + "vuex": "^3.1.2" + }, + "devDependencies": { + "@vue/cli-plugin-babel": "^4.1.0", + "@vue/cli-plugin-eslint": "^4.1.0", + "@vue/cli-plugin-unit-jest": "^4.1.0", + "@vue/cli-service": "^4.1.0", + "@vue/eslint-config-standard": "^4.0.0", + "@vue/test-utils": "1.0.0-beta.29", + "babel-eslint": "^10.0.3", + "eslint": "^5.16.0", + "eslint-plugin-vue": "^5.0.0", + "less-loader": "^6.0.0", + "node-sass": "^4.12.0", + "sass-loader": "^8.0.0", + "vue-template-compiler": "^2.6.10" + } +} \ No newline at end of file diff --git a/public/assets/css/app.css b/public/assets/css/app.css index 2cfeade..e51d6cc 100644 --- a/public/assets/css/app.css +++ b/public/assets/css/app.css @@ -1,234 +1,245 @@ * { - box-sizing: border-box; - margin: 0; - padding: 0; + box-sizing: border-box; + margin: 0; + padding: 0; } -input, button, textarea { - font-family: inherit; +input, +button, +textarea { + font-family: inherit; } -h1, h2, h3, h4, h5, h6 { - font-weight: normal; +h1, +h2, +h3, +h4, +h5, +h6 { + font-weight: normal; } em { - font-style: normal !important; + font-style: normal !important; } -html, body { - height: 100%; - font-family: 'PingFang SC', BlinkMacSystemFont, Roboto, 'Helvetica Neue', sans-serif; +html, +body { + height: 100%; + font-family: 'PingFang SC', BlinkMacSystemFont, Roboto, 'Helvetica Neue', sans-serif; } .el-message__icon { - display: none + display: none } .container { - height: 100%; - display: flex; - flex-direction: column; + height: 100%; + display: flex; + flex-direction: column; } .top { - height: 60px; - padding: 10px 20px; - display: flex; - align-items: center; - margin-right: 20px; + height: 60px; + padding: 10px 20px; + display: flex; + align-items: center; + margin-right: 20px; } .web-title { - margin: 0 15px 0 5px; + margin: 0 15px 0 5px; } .web-icon { - width: auto; - height: 1.5rem; - vertical-align: middle; + width: auto; + height: 1.5rem; + vertical-align: middle; } #editor { - height: 100%; - display: block; - border: none; - width: 100%; - padding: 10px; + height: 100%; + display: block; + border: none; + width: 100%; + padding: 10px; } section { - height: 100%; + height: 100%; } .main-body { - display: flex; - flex-direction: column; - padding-top: 0; - padding-bottom: 10px; + display: flex; + flex-direction: column; + padding-top: 0; + padding-bottom: 10px; } .ctrl { - flex-basis: 60px; - flex-grow: 1; - flex-shrink: 1; - display: flex; - align-items: center; + flex-basis: 60px; + flex-grow: 1; + flex-shrink: 1; + display: flex; + align-items: center; } .preview-wrapper { - box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1); - padding: 0; - align-items: center; - justify-content: center; - display: flex; - overflow: scroll; - word-break: break-all; + box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1); + padding: 0; + align-items: center; + justify-content: center; + display: flex; + overflow: scroll; + word-break: break-all; } .main-section { - display: flex; - height: 100%; + display: flex; + height: 100%; } .hint { - opacity: 0.6; - margin: 20px 0; + opacity: 0.6; + margin: 20px 0; } .preview { - margin: 0 -20px; - width: 375px; - padding: 20px; - font-size: 14px; - box-sizing: border-box; - outline: none; - box-shadow: 0 0 60px rgba(0, 0, 0, 0.1); + margin: 0 -20px; + width: 375px; + padding: 20px; + font-size: 14px; + box-sizing: border-box; + outline: none; + box-shadow: 0 0 60px rgba(0, 0, 0, 0.1); } .preview table { - margin-bottom: 10px; - border-collapse: collapse; - display: table; - width: 100% !important; + margin-bottom: 10px; + border-collapse: collapse; + display: table; + width: 100% !important; } + /* .preview table tr:nth-child(even){ background: rgb(250, 250, 250); } */ .select-item-left { - float: left; + float: left; } .select-item-right { - float: right; - color: #8492a6; - font-size: 13px; + float: right; + color: #8492a6; + font-size: 13px; } .CodeMirror { - height: 100% !important; - box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1); - font-size: 14px; - padding: 20px; - width: 100% !important; - font-family: 'PingFang SC', BlinkMacSystemFont, Roboto, 'Helvetica Neue', sans-serif !important; + height: 100% !important; + box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1); + font-size: 14px; + padding: 20px; + width: 100% !important; + font-family: 'PingFang SC', BlinkMacSystemFont, Roboto, 'Helvetica Neue', sans-serif !important; } /* ele ui */ .el-form-item { - margin-bottom: 0 !important; + margin-bottom: 0 !important; } .el-tooltip { - cursor: pointer; + cursor: pointer; } /*wechat code block*/ -.rich_media_content .code-snippet *, .rich_media_content .code-snippet__fix * { - max-width: 1000% !important; +.rich_media_content .code-snippet *, +.rich_media_content .code-snippet__fix * { + max-width: 1000% !important; } .code-snippet__fix { - word-wrap: break-word !important; - font-size: 14px; - margin: 10px 8px; - color: #333; - position: relative; - background-color: rgb(238,238,238); - border: 1px solid #f0f0f0; - border-radius: 2px; - display: flex; - line-height: 24px; + word-wrap: break-word !important; + font-size: 14px; + margin: 10px 8px; + color: #333; + position: relative; + background-color: rgb(238, 238, 238); + border: 1px solid #f0f0f0; + border-radius: 2px; + display: flex; + line-height: 24px; } .code-snippet__fix .code-snippet__line-index { - counter-reset: line; - flex-shrink: 0; - height: 100%; - padding: 1em; - list-style-type: none; + counter-reset: line; + flex-shrink: 0; + height: 100%; + padding: 1em; + list-style-type: none; } .code-snippet__fix .code-snippet__line-index li { - list-style-type: none; - text-align: right; + list-style-type: none; + text-align: right; } .code-snippet__fix .code-snippet__line-index li::before { - min-width: 1.5em; - text-align: right; - left: -2.5em; - counter-increment: line; - content: counter(line); - display: inline; - color: rgba(0, 0, 0, 0.15); + min-width: 1.5em; + text-align: right; + left: -2.5em; + counter-increment: line; + content: counter(line); + display: inline; + color: rgba(0, 0, 0, 0.15); } .code-snippet__fix pre { - overflow-x: auto; - padding: 1em 1em 1em 1em; - white-space: normal; - flex: 1; - -webkit-overflow-scrolling: touch; + overflow-x: auto; + padding: 1em 1em 1em 1em; + white-space: normal; + flex: 1; + -webkit-overflow-scrolling: touch; } .code-snippet__fix code { - text-align: left; - font-size: 14px; - white-space: pre; - display: flex; - position: relative; - font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; + text-align: left; + font-size: 14px; + white-space: pre; + display: flex; + position: relative; + font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; } ::-webkit-scrollbar { - width: 6px; - height: 6px; - background-color: #FFF; + width: 6px; + height: 6px; + background-color: #FFF; } ::-webkit-scrollbar-track { - border-radius: 6px; - background-color: rgba(200, 200, 200, 0.3); + border-radius: 6px; + background-color: rgba(200, 200, 200, 0.3); } ::-webkit-scrollbar-thumb { - border-radius: 6px; - background-color: rgba(144, 146, 152, 0.5); - transition: background-color .3s; + border-radius: 6px; + background-color: rgba(144, 146, 152, 0.5); + transition: background-color .3s; } ::-webkit-scrollbar-thumb:hover { - background-color: rgba(144, 146, 152, 0.5); + background-color: rgba(144, 146, 152, 0.5); } .CodeMirror-vscrollbar:focus { outline: none; } -.CodeMirror-scroll, .preview-wrapper { +.CodeMirror-scroll, +.preview-wrapper { overflow: unset; overflow-y: scroll; } \ No newline at end of file diff --git a/public/assets/css/loading.css b/public/assets/css/loading.css index aea6b19..d0ede5b 100644 --- a/public/assets/css/loading.css +++ b/public/assets/css/loading.css @@ -1,47 +1,47 @@ .loading { - text-align: center; - position: fixed; - width: 100%; - height: 100%; - overflow: hidden; - z-index: 99999; - background-color: #f2f2f2; + text-align: center; + position: fixed; + width: 100%; + height: 100%; + overflow: hidden; + z-index: 99999; + background-color: #f2f2f2; } .loading_night { - background-color: #303133; + background-color: #303133; } .loading-wrapper { - position: fixed; - top: 50%; - left: 50%; - -webkit-transform: translateX(-50%) translateY(-50%); - -moz-transform: translateX(-50%) translateY(-50%); - -ms-transform: translateX(-50%) translateY(-50%); - transform: translateX(-50%) translateY(-50%); + position: fixed; + top: 50%; + left: 50%; + -webkit-transform: translateX(-50%) translateY(-50%); + -moz-transform: translateX(-50%) translateY(-50%); + -ms-transform: translateX(-50%) translateY(-50%); + transform: translateX(-50%) translateY(-50%); } .loading-text { - line-height: 1.4; - font-size: 1.2rem; - font-weight: bold; - margin-bottom: 1rem; + line-height: 1.4; + font-size: 1.2rem; + font-weight: bold; + margin-bottom: 1rem; } .loading-anim { - width: 35px; - height: 35px; - border: 5px solid rgba(189, 189, 189, 0.25); - border-left-color: rgba(66, 185, 131, 0.9); - border-top-color: rgba(66, 185, 131, 0.9); - border-radius: 50%; - display: inline-block; - animation: rotate 600ms infinite linear; + width: 35px; + height: 35px; + border: 5px solid rgba(189, 189, 189, 0.25); + border-left-color: rgba(66, 185, 131, 0.9); + border-top-color: rgba(66, 185, 131, 0.9); + border-radius: 50%; + display: inline-block; + animation: rotate 600ms infinite linear; } @keyframes rotate { - to { - transform: rotate(1turn) - } -} + to { + transform: rotate(1turn) + } +} \ No newline at end of file diff --git a/public/assets/css/style-mirror.css b/public/assets/css/style-mirror.css index bf98442..8c74dff 100644 --- a/public/assets/css/style-mirror.css +++ b/public/assets/css/style-mirror.css @@ -14,91 +14,111 @@ font-size: 16px; padding: 20px; line-height: 25px; - } - .cm-s-style-mirror div.CodeMirror-selected { +} + +.cm-s-style-mirror div.CodeMirror-selected { background: #e0e0e0; - } - .cm-s-style-mirror .CodeMirror-line::selection, - .cm-s-style-mirror .CodeMirror-line > span::selection, - .cm-s-style-mirror .CodeMirror-line > span > span::selection { +} + +.cm-s-style-mirror .CodeMirror-line::selection, +.cm-s-style-mirror .CodeMirror-line>span::selection, +.cm-s-style-mirror .CodeMirror-line>span>span::selection { background: #e0e0e0; - } - .cm-s-style-mirror .CodeMirror-line::-moz-selection, - .cm-s-style-mirror .CodeMirror-line > span::-moz-selection, - .cm-s-style-mirror .CodeMirror-line > span > span::-moz-selection { +} + +.cm-s-style-mirror .CodeMirror-line::-moz-selection, +.cm-s-style-mirror .CodeMirror-line>span::-moz-selection, +.cm-s-style-mirror .CodeMirror-line>span>span::-moz-selection { background: #e0e0e0; - } - .cm-s-style-mirror .CodeMirror-gutters { +} + +.cm-s-style-mirror .CodeMirror-gutters { background: #f5f5f5; border-right: 0px; - } - .cm-s-style-mirror .CodeMirror-guttermarker { +} + +.cm-s-style-mirror .CodeMirror-guttermarker { color: #ac4142; - } - .cm-s-style-mirror .CodeMirror-guttermarker-subtle { +} + +.cm-s-style-mirror .CodeMirror-guttermarker-subtle { color: #b0b0b0; - } - .cm-s-style-mirror .CodeMirror-linenumber { +} + +.cm-s-style-mirror .CodeMirror-linenumber { color: #b0b0b0; - } - .cm-s-style-mirror .CodeMirror-cursor { +} + +.cm-s-style-mirror .CodeMirror-cursor { border-left: 1px solid #505050; - } - - .cm-s-style-mirror span.cm-comment { - color:green; - } - .cm-s-style-mirror span.cm-atom { +} + +.cm-s-style-mirror span.cm-comment { + color: green; +} + +.cm-s-style-mirror span.cm-atom { color: #aa759f; - } - .cm-s-style-mirror span.cm-number { +} + +.cm-s-style-mirror span.cm-number { color: #aa759f; - } - - .cm-s-style-mirror span.cm-property, - .cm-s-style-mirror span.cm-attribute { +} + +.cm-s-style-mirror span.cm-property, +.cm-s-style-mirror span.cm-attribute { color: #90a959; - } - .cm-s-style-mirror span.cm-keyword { +} + +.cm-s-style-mirror span.cm-keyword { color: #023a52; - } - .cm-s-style-mirror span.cm-string { +} + +.cm-s-style-mirror span.cm-string { color: #e46918; - } - - .cm-s-style-mirror span.cm-variable { +} + +.cm-s-style-mirror span.cm-variable { color: #90a959; - } - .cm-s-style-mirror span.cm-variable-2 { +} + +.cm-s-style-mirror span.cm-variable-2 { color: #00695f; - } - .cm-s-style-mirror span.cm-variable-3 { +} + +.cm-s-style-mirror span.cm-variable-3 { color: #2e6e8a; - } - .cm-s-style-mirror span.cm-def { +} + +.cm-s-style-mirror span.cm-def { color: #d28445; - } - .cm-s-style-mirror span.cm-bracket { +} + +.cm-s-style-mirror span.cm-bracket { color: #202020; - } - .cm-s-style-mirror span.cm-tag { - color:#000; - } - .cm-s-style-mirror span.cm-link { +} + +.cm-s-style-mirror span.cm-tag { + color: #000; +} + +.cm-s-style-mirror span.cm-link { color: #b26a00; - } - .cm-s-style-mirror span.cm-error { +} + +.cm-s-style-mirror span.cm-error { /* background: #ac4142; color: #f5f5f5; */ text-decoration: underline; text-decoration-style: wavy; text-decoration-color: #df8d8e; - } - .cm-s-style-mirror .CodeMirror-activeline-background { +} + +.cm-s-style-mirror .CodeMirror-activeline-background { background: #dddcdc; - } - .cm-s-style-mirror .CodeMirror-matchingbracket { - color: rgb(32,32,32) !important; - background-color: rgba(0,0,0,0.1) !important; - } - \ No newline at end of file +} + +.cm-s-style-mirror .CodeMirror-matchingbracket { + color: rgb(32, 32, 32) !important; + background-color: rgba(0, 0, 0, 0.1) !important; +} \ No newline at end of file diff --git a/public/favicon.ico b/public/favicon.ico deleted file mode 100644 index df36fcf..0000000 Binary files a/public/favicon.ico and /dev/null differ diff --git a/public/index.html b/public/index.html index 091d43d..0c1058e 100644 --- a/public/index.html +++ b/public/index.html @@ -1,55 +1,28 @@ -
- - - - - -`) - return `
${text}` + this.setOptions = newOpts => { + this.opts = merge(this.opts, newOpts) } - renderer.code = (text, infoString) => { - text = text.replace(//g, '>') - let lines = text.split('\n') - let codeLines = [] - let numbers = [] + this.hasFootnotes = () => footnotes.length !== 0 - for (let i = 0; i < lines.length; i++) { - const line = lines[i] - codeLines.push(`
${(line || '
')}
`)
- numbers.push('')
- }
- let lang = infoString || ''
+ this.getRenderer = (status) => {
+ footnotes = []
+ footnoteIndex = 0
- return `
+ styleMapping = this.buildTheme(this.opts.theme)
+ let renderer = new marked.Renderer()
+
+ renderer.heading = (text, level) => {
+ switch (level) {
+ case 1:
+ return ``) + return `
${text}` + } + renderer.code = (text, infoString) => { + text = text.replace(//g, '>') + + let lines = text.split('\n') + let codeLines = [] + let numbers = [] + + for (let i = 0; i < lines.length; i++) { + const line = lines[i] + codeLines.push(`
${(line || '
')}
`)
+ numbers.push('')
+ }
+ let lang = infoString || ''
+
+ return `
@@ -145,53 +145,53 @@ const WxRenderer = function (opts) {
${text}
`
- renderer.listitem = text => `<%s/>${text}`
-
- renderer.list = (text, ordered, start) => {
- text = text.replace(/<\/*p.*?>/g, '')
- let segments = text.split(`<%s/>`)
- if (!ordered) {
- text = segments.join('•')
- return `${text}
` - } - text = segments[0] - for (let i = 1; i < segments.length; i++) { - text = text + i + '.' + segments[i] - } - return `${text}
` - } - renderer.image = (href, title, text) => { - let subText = '' - if (text) { - subText = `${text}
`
+ renderer.listitem = text => `<%s/>${text}`
+
+ renderer.list = (text, ordered, start) => {
+ text = text.replace(/<\/*p.*?>/g, '')
+ let segments = text.split(`<%s/>`)
+ if (!ordered) {
+ text = segments.join('•')
+ return `${text}
` + } + text = segments[0] + for (let i = 1; i < segments.length; i++) { + text = text + i + '.' + segments[i] + } + return `${text}
` + } + renderer.image = (href, title, text) => { + let subText = '' + if (text) { + subText = `