diff --git a/README.md b/README.md index f1bd3b3..3f85f23 100644 --- a/README.md +++ b/README.md @@ -17,16 +17,23 @@ Markdown 文档自动即时渲染为微信图文,让你不再为微信文章排版而发愁!只要你会基本的 Markdown 语法,就能做出一篇样式简洁而又美观大方的微信图文。 ## 在线编辑器地址 -- GitHub Page:https://doocs.github.io/md -- Gitee Page:https://doocs.gitee.io/md +- Netlify: https://mdmd.netlify.app +- Gitee Pages:https://doocs.gitee.io/md +- GitHub Pages:https://doocs.github.io/md -注:推荐使用 Chrome 浏览器,效果最佳。另外,对于国内(中国)的朋友,访问 [Gitee Page](https://doocs.gitee.io/md) 速度会相对快一些。 +注:推荐使用 Chrome 浏览器,效果最佳。另外,对于国内(中国)的朋友,访问 [Gitee Pages](https://doocs.gitee.io/md) 速度会相对快一些。 ## 为何二次开发 现有的开源微信 Markdown 编辑器,样式繁杂,也不符合我个人的审美需求。在我使用它们进行文章排版的时候,经常还要自己做一些改动,费时费力,因此动手做了二次开发。 欢迎各位朋友随时提交 PR,让这款微信 Markdown 编辑器变得更好!如果你有新的想法,也欢迎在 Issues 区反馈。 +注:目前在非 master 分支上对项目进行重构,更多新特性,敬请期待! + +- [Vue 分支](https://github.com/doocs/md/tree/m_create_vue) +- [React 分支](https://github.com/doocs/md/tree/chore-webpack) + + ## 功能特性 - [x] 支持 Markdown 所有基础语法 - [x] 支持单独进行字体、字号设置 @@ -57,8 +64,55 @@ Markdown 文档自动即时渲染为微信图文,让你不再为微信文章 ![doocs-md-upload-image](https://imgkr.cn-bj.ufileos.com/97db3cd6-bddc-4eff-8635-472631b0a642.gif) +## 谁在使用 + + + + + + + + + +
+ +
+ Doocs开源社区 +
+
+ +
+ 掘墓人的小铲子 +
+
+ +
+ 全网重点 +
+
+ +
+ 爱码士的内心独白 +
+
+ +
+ 乐玩nodejs npm工具库 +
+
+ +
+ 简静慢 +
+
+ +注:如果你使用了本 Markdown 编辑器进行文章排版,并且希望在本项目 README 中展示你的公众号,请到 [#5](https://github.com/doocs/md/issues/5) 留言。 + ## 示例文章 -- [ES6 特性快速扫盲](https://mp.weixin.qq.com/s/I3EzOO0skf8xDCGtyYM5Lg) +- [全网首发!GPU 驱动自升级原理详解](https://mp.weixin.qq.com/s/7UG24ZugfI5ZnhUpo8vfvQ) +- [Quick Start - 天下武功,唯快不破!效率工具,老少皆宜](https://mp.weixin.qq.com/s/SFde8OsZ8FzNGMHwpmDtrg) +- [死磕JavaScript系列之原来你是对象(一)](https://mp.weixin.qq.com/s/oc5Z2t9ykbu_Dezjnw5mfQ) +- [一文多发神器--ArtiPub&OpenWrite](https://mp.weixin.qq.com/s/FpGIX9viQR6Z9iSCEPH86g) - [免费且好用的图床,就你了,「图壳」!](https://mp.weixin.qq.com/s/0HhgHLo_tTRFZcC-CVjDbw) - [GitHub 项目持续本地化,交给它来做,准没错!](https://mp.weixin.qq.com/s/KO4xHr4EI0YfjF0hiT3pbw) - [阿里又一个 20k+ stars 开源项目诞生,恭喜 fastjson!](https://mp.weixin.qq.com/s/RNKDCK2KoyeuMeEs6GUrow) @@ -66,8 +120,6 @@ Markdown 文档自动即时渲染为微信图文,让你不再为微信文章 - [刷掉 90 % 候选人的海量数据面试题(附题解+方法总结)](https://mp.weixin.qq.com/s/rjGqxUvrEqJNlo09GrT1Dw) - [GitHub 标星 11.5k 的一款开源工具,助你轻松查看 Git 历史](https://mp.weixin.qq.com/s/PK-ikENqF13Lmqy2pcMhYQ) -注:如果你使用了本 Markdown 编辑器进行文章排版,并且希望将你的文章加入示例列表,欢迎随时提交 PR。 - ## 项目维护者 diff --git a/src/api/fetch.js b/src/api/fetch.js new file mode 100644 index 0000000..206de7f --- /dev/null +++ b/src/api/fetch.js @@ -0,0 +1,32 @@ +import axios from 'axios'; + +// 创建axios实例 +const service = axios.create({ + baseURL: '', + timeout: 10 * 1000 // 请求超时时间 +}); + +service.interceptors.request.use( + config => { + if (/^(post)|(put)|(delete)$/i.test(config.method)) { + if (config.data && config.data.upload) { + config.headers['Content-Type'] = 'multipart/form-data'; + config.headers['Access-Control-Allow-Origin'] = 'http://192.168.0.106:8080'; + } + } + return config; + }, error => { + Promise.reject(error); + } +); + +service.interceptors.response.use(res => { + if (res.data.success) { + return res.data; + } else { + console.log(res); + } + return Promise.reject(res.data); +}, error => Promise.reject(error)); + +export default service; \ No newline at end of file diff --git a/src/api/file.js b/src/api/file.js new file mode 100644 index 0000000..f20fad7 --- /dev/null +++ b/src/api/file.js @@ -0,0 +1,15 @@ +import fetch from './fetch'; + + +function fileUpload(data) { + return fetch({ + url: 'https://imgkr.com/api/files/upload', + method: 'post', + data: data + }) +} + + +export default { + fileUpload +}; \ No newline at end of file diff --git a/src/components/CodemirrorEditor.vue b/src/components/CodemirrorEditor.vue index 85d24f2..bde61bf 100644 --- a/src/components/CodemirrorEditor.vue +++ b/src/components/CodemirrorEditor.vue @@ -4,61 +4,61 @@ - + :show-file-list="false" :multiple="true" accept=".jpg,.jpeg,.png,.gif" name="file" + :before-upload="beforeUpload" :on-success="uploaded"> +   - + -   +   -   +   -   +   - + - {{ font.label }} Abc - + - - + + - + {{ size.label }} {{ size.desc }} - + - - + + - + {{ color.label }} {{ color.hex }} - + - - + + - -    - + +    + - + - + 复制 关于 @@ -71,7 +71,7 @@
-
+
@@ -105,12 +105,12 @@ - + - + - + diff --git a/src/components/codeMirror/header.vue b/src/components/codeMirror/header.vue new file mode 100644 index 0000000..6f83a02 --- /dev/null +++ b/src/components/codeMirror/header.vue @@ -0,0 +1,77 @@ + + + + + \ No newline at end of file diff --git a/src/scripts/config.js b/src/scripts/config.js new file mode 100644 index 0000000..2a623c5 --- /dev/null +++ b/src/scripts/config.js @@ -0,0 +1,60 @@ +export default { + builtinFonts: [ + { + label: '无衬线', + value: '-apple-system-font,BlinkMacSystemFont, Helvetica Neue, PingFang SC, Hiragino Sans GB , Microsoft YaHei UI , Microsoft YaHei ,Arial,sans-serif' + }, + { + label: '衬线', + value: "Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif" + } + ], + sizeOption: [ + { + label: '12px', + value: '12px', + desc: '更小' + }, + { + label: '13px', + value: '13px', + desc: '稍小' + }, + { + label: '14px', + value: '14px', + desc: '推荐' + }, + { + label: '15px', + value: '15px', + desc: '稍大' + }, + { + label: '16px', + value: '16px', + desc: '更大' + } + ], + colorOption: [ + { + label: '经典蓝', + value: 'rgba(15, 76, 129, 1)', + hex: '最新流行' + }, + { + label: '翡翠绿', + value: 'rgba(0, 152, 116, 1)', + hex: '优雅清新' + }, + { + label: '活力橘', + value: 'rgba(250, 81, 81, 1)', + hex: '热情活泼' + } + ], + form: { + rows: 1, + cols: 1 + } +}; \ No newline at end of file diff --git a/src/scripts/util.js b/src/scripts/util.js index fe6ce62..d7f8893 100644 --- a/src/scripts/util.js +++ b/src/scripts/util.js @@ -167,3 +167,29 @@ export function css2json (css) { // 返回JSON形式的结果串 return json } + + +/** + * 将编辑器内容保存到 LocalStorage + * @param {*} editor + * @param {*} name + */ +export function saveEditorContent(editor, name) { + const content = editor.getValue(0) + + if (content) { + localStorage.setItem(name, content) + } else { + localStorage.removeItem(name) + } +} + +export function checkImage(file) { + if (!/\.(gif|jpg|jpeg|png|GIF|JPG|PNG)$/.test(file.name)) { + return '请上传 JPG/PNG/GIF 格式的图片'; + } + if (file.size > 5 * 1024 * 1024) { + return '由于公众号限制,图片大小不能超过 5.0M'; + } + return false; +} \ No newline at end of file diff --git a/src/store/index.js b/src/store/index.js index 332b916..8689f0a 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -1,15 +1,136 @@ import Vue from 'vue' import Vuex from 'vuex' +import config from '../scripts/config'; +import WxRenderer from '../scripts/renderers/wx-renderer' +import marked from 'marked' +import CodeMirror from 'codemirror/lib/codemirror' +import DEFAULT_CONTENT from '../scripts/default-content' +import DEFAULT_CSS_CONTENT from '../scripts/themes/default-theme-css' +import { + setColor +} from '../scripts/util' Vue.use(Vuex) +const state = { + wxRenderer: null, + output: '', + editor: null, + cssEditor: null, + html: '', + currentFont: {}, + currentSize: {}, + currentColor: {} +}; +const mutations = { + setEditorValue(state, data) { + state.editor.setValue(data) + }, + setCssEditorValue(state, data) { + state.cssEditor.setValue(data) + }, + setWxRendererOptions(state, data) { + state.wxRenderer.setOptions(data); + }, + setCurrentFont(state, data) { + state.currentFont = data; + localStorage.setItem('fonts', data) + }, + setCurrentSize(state, data) { + state.currentSize = data; + localStorage.setItem('size', data) + }, + setCurrentColor(state, data) { + state.currentColor = data; + localStorage.setItem('color', data) + }, + initEditorState(state) { + state.currentFont = localStorage.getItem('fonts') || config.builtinFonts[0].value + state.currentColor = localStorage.getItem('color') || config.colorOption[1].value + state.currentSize = localStorage.getItem('size') || config.sizeOption[2].value + state.status = localStorage.getItem('status') === 'true' + state.wxRenderer = new WxRenderer({ + theme: setColor(state.currentColor), + fonts: state.currentFont, + size: state.currentSize, + status: state.status + }) + }, + initEditorEntity(state) { + state.editor = CodeMirror.fromTextArea( + document.getElementById('editor'), + { + value: '', + mode: 'text/x-markdown', + theme: 'xq-light', + lineNumbers: false, + lineWrapping: true, + styleActiveLine: true, + autoCloseBrackets: true + } + ) + // 如果有编辑器内容被保存则读取,否则加载默认内容 + if (localStorage.getItem('__editor_content')) { + state.editor.setValue(localStorage.getItem('__editor_content')) + } else { + state.editor.setValue(DEFAULT_CONTENT) + } + }, + initCssEditorEntity(state) { + state.cssEditor = CodeMirror.fromTextArea( + document.getElementById('cssEditor'), { + value: '', + mode: 'css', + theme: 'style-mirror', + lineNumbers: false, + lineWrapping: true, + matchBrackets: true, + autofocus: true, + extraKeys: { + 'Ctrl-F': function autoFormat(editor) { + const totalLines = editor.lineCount() + editor.autoFormatRange({ + line: 0, + ch: 0 + }, { + line: totalLines + }) + } + } + } + ) + + // 如果有编辑器内容被保存则读取,否则加载默认内容 + if (localStorage.getItem('__css_content')) { + state.cssEditor.setValue(localStorage.getItem('__css_content')) + } else { + state.cssEditor.setValue(DEFAULT_CSS_CONTENT) + } + }, + editorRefresh(state) { + let output = marked(state.editor.getValue(0), { + renderer: state.wxRenderer.getRenderer(state.status) + }) + // 去除第一行的 margin-top + output = output.replace(/(style=".*?)"/, '$1;margin-top: 0"') + if (state.status) { + // 引用脚注 + output += state.wxRenderer.buildFootnotes() + // 附加的一些 style + output += state.wxRenderer.buildAddition() + } + + state.output = output + }, + clearEditorToDefault(state) { + state.editor.setValue(DEFAULT_CONTENT) + state.cssEditor.setValue(DEFAULT_CSS_CONTENT) + } +} + export default new Vuex.Store({ - state: { - }, - mutations: { - }, - actions: { - }, - modules: { - } + state, + mutations, + actions: {}, + modules: {} }) diff --git a/src/views/Home.vue b/src/views/Home.vue index 02d9ab5..7d00042 100644 --- a/src/views/Home.vue +++ b/src/views/Home.vue @@ -1,17 +1,14 @@