Merge branch 'master' of github.com:doocs/md

This commit is contained in:
yanglbme 2020-10-21 17:48:44 +08:00
commit 5ae6fd4b28
16 changed files with 1401 additions and 970 deletions

View File

@ -6,36 +6,38 @@
</template>
<script>
import Loading from './components/Loading'
import CodemirrorEditor from './view/CodemirrorEditor'
import Loading from "./components/Loading";
import CodemirrorEditor from "./view/CodemirrorEditor";
export default {
name: 'App',
name: "App",
components: {
Loading,
CodemirrorEditor
CodemirrorEditor,
},
data() {
return {
loading: true
}
loading: true,
};
},
mounted() {
setTimeout(() => {
this.loading = false
this.loading = false;
}, 100);
}
}
},
};
</script>
<style lang="scss" scoped>
.fade-enter, .fade-leave-to {
.fade-enter,
.fade-leave-to {
opacity: 0;
}
.fade-enter-to, .fade-leave {
.fade-enter-to,
.fade-leave {
opacity: 1;
}
.fade-enter-active, .fade-leave-active {
.fade-enter-active,
.fade-leave-active {
transition: all 1s;
}
</style>

View File

@ -1,4 +1,4 @@
@import './code-theme.less';
@import "./code-theme.less";
* {
box-sizing: border-box;
margin: 0;
@ -27,11 +27,12 @@ em {
html,
body {
height: 100%;
font-family: 'PingFang SC', BlinkMacSystemFont, Roboto, 'Helvetica Neue', sans-serif;
font-family: "PingFang SC", BlinkMacSystemFont, Roboto, "Helvetica Neue",
sans-serif;
}
.el-message__icon {
display: none
display: none;
}
.container {
@ -143,7 +144,8 @@ section {
font-size: 14px;
padding: 20px;
width: 100% !important;
font-family: 'PingFang SC', BlinkMacSystemFont, Roboto, 'Helvetica Neue', sans-serif !important;
font-family: "PingFang SC", BlinkMacSystemFont, Roboto, "Helvetica Neue",
sans-serif !important;
}
/* ele ui */
@ -158,7 +160,7 @@ section {
::-webkit-scrollbar {
width: 6px;
height: 6px;
background-color: #FFF;
background-color: #fff;
}
::-webkit-scrollbar-track {
@ -169,7 +171,7 @@ section {
::-webkit-scrollbar-thumb {
border-radius: 6px;
background-color: rgba(144, 146, 152, 0.5);
transition: background-color .3s;
transition: background-color 0.3s;
}
::-webkit-scrollbar-thumb:hover {

View File

@ -1,2 +1,2 @@
@import './codeTheme/wechat-code-block.less';
@import './codeTheme/github-code-block.less';
@import "./codeTheme/wechat-code-block.less";
@import "./codeTheme/github-code-block.less";

View File

@ -5,7 +5,7 @@
margin: 10px 8px;
position: relative;
height: auto;
background-color: rgba(27,31,35,.05);
background-color: rgba(27, 31, 35, 0.05);
.code-snippet__line-index {
display: none;

View File

@ -10,7 +10,7 @@
margin: 10px 8px;
color: #333;
position: relative;
background-color: rgba(27, 31, 35, .05);
background-color: rgba(27, 31, 35, 0.05);
border: 1px solid #f0f0f0;
border-radius: 2px;
display: flex;

View File

@ -1,2 +1,72 @@
/*! Color themes for Google Code Prettify | MIT License | github.com/jmblog/color-themes-for-google-code-prettify */
.prettyprint{font-family:Menlo,Bitstream Vera Sans Mono,DejaVu Sans Mono,Monaco,Consolas,monospace;border:0!important}.pln{color:#333}ol.linenums{margin-top:0;margin-bottom:0;color:#ccc}li.L0,li.L1,li.L2,li.L3,li.L4,li.L5,li.L6,li.L7,li.L8,li.L9{padding-left:1em;background-color:#fff;list-style-type:decimal}@media screen{.str{color:#183691}.kwd{color:#a71d5d}.com{color:#969896}.typ{color:#0086b3}.lit{color:#0086b3}.pun{color:#333}.opn{color:#333}.clo{color:#333}.tag{color:navy}.atn{color:#795da3}.atv{color:#183691}.dec{color:#333}.var{color:teal}.fun{color:#900}}
.prettyprint {
font-family: Menlo, Bitstream Vera Sans Mono, DejaVu Sans Mono, Monaco,
Consolas, monospace;
border: 0 !important;
}
.pln {
color: #333;
}
ol.linenums {
margin-top: 0;
margin-bottom: 0;
color: #ccc;
}
li.L0,
li.L1,
li.L2,
li.L3,
li.L4,
li.L5,
li.L6,
li.L7,
li.L8,
li.L9 {
padding-left: 1em;
background-color: #fff;
list-style-type: decimal;
}
@media screen {
.str {
color: #183691;
}
.kwd {
color: #a71d5d;
}
.com {
color: #969896;
}
.typ {
color: #0086b3;
}
.lit {
color: #0086b3;
}
.pun {
color: #333;
}
.opn {
color: #333;
}
.clo {
color: #333;
}
.tag {
color: navy;
}
.atn {
color: #795da3;
}
.atv {
color: #183691;
}
.dec {
color: #333;
}
.var {
color: teal;
}
.fun {
color: #900;
}
}

View File

@ -37,7 +37,8 @@
color: @nightWhiteColor!important;
background: rgb(30, 30, 30) !important;
}
.cm-s-xq-light span.cm-variable-2, .cm-s-style-mirror span.cm-tag {
.cm-s-xq-light span.cm-variable-2,
.cm-s-style-mirror span.cm-tag {
color: @nightFontColor;
}
.cm-s-xq-light .CodeMirror-activeline-background {
@ -57,7 +58,8 @@
background-color: @nightCodeMirrorColor;
border: 1px solid transparent;
}
.el-button.is-plain:focus, .el-button.is-plain:hover {
.el-button.is-plain:focus,
.el-button.is-plain:hover {
background: @nightButtonBg;
color: @nightWhiteColor;
border: 1px solid @nightWhiteColor;
@ -65,14 +67,18 @@
color: @nightWhiteColor;
}
}
.insert__dialog, .about__dialog, .reset__dialog, .upload__dialog {
.insert__dialog,
.about__dialog,
.reset__dialog,
.upload__dialog {
.el-dialog {
background-color: @nightBgColor;
}
.el-dialog__body {
color: @nightWhiteColor;
}
.el-dialog__title, .el-form-item__label {
.el-dialog__title,
.el-form-item__label {
color: @nightWhiteColor;
}
.el-tabs__item {
@ -85,7 +91,10 @@
background-color: @nightButtonBg;
}
}
::v-deep .el-icon-upload, .el-icon-download, .el-icon-refresh, .el-icon-s-grid {
::v-deep .el-icon-upload,
.el-icon-download,
.el-icon-refresh,
.el-icon-s-grid {
color: @nightWhiteColor;
}
::-webkit-scrollbar {

View File

@ -1,15 +1,35 @@
<template>
<el-dialog title="关于" class="about__dialog" :visible="value" @close="$emit('input', false)" width="30%" center>
<div style="text-align: center;">
<el-dialog
title="关于"
class="about__dialog"
:visible="value"
@close="$emit('input', false)"
width="30%"
center
>
<div style="text-align: center">
<h3>一款高度简洁的微信 Markdown 编辑器</h3>
</div>
<div style="text-align: center;margin-top:10px;">
<div style="text-align: center; margin-top: 10px">
<p>扫码关注我的公众号原创技术文章第一时间推送</p>
<img src="https://gitee.com/yanglbme/resource/raw/master/doocs-md/qrcode.png" style="width: 40%; display: block; margin: 20px auto 10px;">
<img
src="https://gitee.com/yanglbme/resource/raw/master/doocs-md/qrcode.png"
style="width: 40%; display: block; margin: 20px auto 10px"
/>
</div>
<span slot="footer" class="dialog-footer">
<el-button type="primary" @click="onRedirect('https://github.com/doocs/md')" plain>GitHub 仓库</el-button>
<el-button type="primary" @click="onRedirect('https://gitee.com/doocs/md')" plain>Gitee 仓库</el-button>
<el-button
type="primary"
@click="onRedirect('https://github.com/doocs/md')"
plain
>GitHub 仓库</el-button
>
<el-button
type="primary"
@click="onRedirect('https://gitee.com/doocs/md')"
plain
>Gitee 仓库</el-button
>
</span>
</el-dialog>
</template>
@ -19,16 +39,15 @@ export default {
props: {
value: {
type: Boolean,
default: false
}
default: false,
},
},
methods: {
onRedirect(url) {
window.open(url);
}
}
}
},
},
};
</script>
<style lang="less" scoped>
</style>
<style lang="less" scoped></style>

View File

@ -1,162 +1,278 @@
<template>
<el-container class="top is-dark">
<!-- 图片上传 -->
<el-tooltip :effect="effect" content="上传图片" placement="bottom-start">
<i class="el-icon-upload" size="medium" @click="$emit('showDialogUploadImg')"></i>
<el-tooltip
:effect="effect"
content="上传图片"
placement="bottom-start"
>
<i
class="el-icon-upload"
size="medium"
@click="$emit('showDialogUploadImg')"
></i>
</el-tooltip>
<!-- 下载文本文档 -->
<el-tooltip class="header__item" :effect="effect" content="下载编辑框Markdown文档" placement="bottom-start">
<i class="el-icon-download" size="medium" @click="$emit('downLoad')"></i>
<el-tooltip
class="header__item"
:effect="effect"
content="下载编辑框Markdown文档"
placement="bottom-start"
>
<i
class="el-icon-download"
size="medium"
@click="$emit('downLoad')"
></i>
</el-tooltip>
<!-- 页面重置 -->
<el-tooltip class="header__item" :effect="effect" content="重置页面" placement="bottom-start">
<i class="el-icon-refresh" size="medium" @click="showResetConfirm = true"></i>
<el-tooltip
class="header__item"
:effect="effect"
content="重置页面"
placement="bottom-start"
>
<i
class="el-icon-refresh"
size="medium"
@click="showResetConfirm = true"
></i>
</el-tooltip>
<!-- 插入表格 -->
<el-tooltip class="header__item header__item_last" :effect="effect" content="插入表格" placement="bottom-start">
<i class="el-icon-s-grid" size="medium" @click="$emit('showDialogForm')"></i>
<el-tooltip
class="header__item header__item_last"
:effect="effect"
content="插入表格"
placement="bottom-start"
>
<i
class="el-icon-s-grid"
size="medium"
@click="$emit('showDialogForm')"
></i>
</el-tooltip>
<el-form size="mini" class="ctrl" :inline=true>
<el-form size="mini" class="ctrl" :inline="true">
<el-form-item>
<el-select v-model="selectFont" size="mini" placeholder="选择字体" clearable @change="fontChanged">
<el-option v-for="font in config.builtinFonts" :style="{fontFamily: font.value}" :key="font.value"
:label="font.label" :value="font.value">
<el-select
v-model="selectFont"
size="mini"
placeholder="选择字体"
clearable
@change="fontChanged"
>
<el-option
v-for="font in config.builtinFonts"
:style="{ fontFamily: font.value }"
:key="font.value"
:label="font.label"
:value="font.value"
>
<span class="select-item-left">{{ font.label }}</span>
<span class="select-item-right">Abc</span>
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-select v-model="selectSize" size="mini" placeholder="选择段落字号" clearable @change="sizeChanged">
<el-option v-for="size in config.sizeOption" :key="size.value" :label="size.label" :value="size.value">
<el-select
v-model="selectSize"
size="mini"
placeholder="选择段落字号"
clearable
@change="sizeChanged"
>
<el-option
v-for="size in config.sizeOption"
:key="size.value"
:label="size.label"
:value="size.value"
>
<span class="select-item-left">{{ size.label }}</span>
<span class="select-item-right">{{ size.desc }}</span>
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-select v-model="selectColor" size="mini" placeholder="选择颜色" clearable @change="colorChanged">
<el-option v-for="color in config.colorOption" :key="color.value" :label="color.label" :value="color.value">
<el-select
v-model="selectColor"
size="mini"
placeholder="选择颜色"
clearable
@change="colorChanged"
>
<el-option
v-for="color in config.colorOption"
:key="color.value"
:label="color.label"
:value="color.value"
>
<span class="select-item-left">{{ color.label }}</span>
<span class="select-item-right">{{ color.desc }}</span>
</el-option>
</el-select>
</el-form-item>
<el-tooltip content="自定义颜色" :effect="effect" placement="top">
<el-color-picker v-model="selectColor" size="mini" show-alpha @change="colorChanged"></el-color-picker>
<el-color-picker
v-model="selectColor"
size="mini"
show-alpha
@change="colorChanged"
></el-color-picker>
</el-tooltip>
<el-tooltip content="微信外链自动转为文末引用" :effect="effect" placement="top">
<el-switch class="header__switch" v-model="citeStatus" active-color="#67c23a" inactive-color="#dcdfe6" @change="statusChanged">
<el-tooltip
content="微信外链自动转为文末引用"
:effect="effect"
placement="top"
>
<el-switch
class="header__switch"
v-model="citeStatus"
active-color="#67c23a"
inactive-color="#dcdfe6"
@change="statusChanged"
>
</el-switch>
</el-tooltip>
</el-form>
<el-tooltip class="item" :effect="effect" content="自定义CSS样式" placement="left">
<el-button :type="btnType" plain size="medium" icon="el-icon-setting" @click="customStyle"></el-button>
<el-tooltip
class="item"
:effect="effect"
content="自定义CSS样式"
placement="left"
>
<el-button
:type="btnType"
plain
size="medium"
icon="el-icon-setting"
@click="customStyle"
></el-button>
</el-tooltip>
<el-button :type="btnType" plain size="medium" @click="copy" placement="bottom-start">复制</el-button>
<el-button :type="btnType" plain size="medium" class="about" @click="$emit('showAboutDialog')">关于</el-button>
<el-tooltip :content="btnContent" :effect="effect" placement="bottom-start">
<div class="mode__switch mode__switch_black" v-if="nightMode" @click="themeChanged"></div>
<el-button
:type="btnType"
plain
size="medium"
@click="copy"
placement="bottom-start"
>复制</el-button
>
<el-button
:type="btnType"
plain
size="medium"
class="about"
@click="$emit('showAboutDialog')"
>关于</el-button
>
<el-tooltip
:content="btnContent"
:effect="effect"
placement="bottom-start"
>
<div
class="mode__switch mode__switch_black"
v-if="nightMode"
@click="themeChanged"
></div>
<div class="mode__switch" v-else @click="themeChanged"></div>
</el-tooltip>
<resetDialog :showResetConfirm="showResetConfirm" @confirm="confirmReset" @close="cancelReset"/>
<resetDialog
:showResetConfirm="showResetConfirm"
@confirm="confirmReset"
@close="cancelReset"
/>
</el-container>
</template>
<script>
import {
downLoadMD,
setFontSize,
fixCodeWhiteSpace,
setColorWithCustomTemplate
} from '../../assets/scripts/util'
import {
solveWeChatImage,
solveHtml
} from '../../assets/scripts/converter'
import config from '../../assets/scripts/config'
import DEFAULT_CSS_CONTENT from '../../assets/scripts/themes/default-theme-css'
import resetDialog from './resetDialog'
import {mapState, mapMutations} from 'vuex'
setColorWithCustomTemplate,
} from "../../assets/scripts/util";
import { solveWeChatImage, solveHtml } from "../../assets/scripts/converter";
import config from "../../assets/scripts/config";
import DEFAULT_CSS_CONTENT from "../../assets/scripts/themes/default-theme-css";
import resetDialog from "./resetDialog";
import { mapState, mapMutations } from "vuex";
export default {
name: 'editor-header',
name: "editor-header",
data() {
return {
config: config,
citeStatus: false,
showResetConfirm: false,
selectFont: '',
selectSize: '',
selectColor: '',
selectCodeTheme: 'github'
selectFont: "",
selectSize: "",
selectColor: "",
selectCodeTheme: "github",
};
},
components: {
resetDialog
resetDialog,
},
computed: {
effect() {
return this.nightMode ? 'dark' : 'light'
return this.nightMode ? "dark" : "light";
},
btnContent() {
return this.nightMode ? '浅色模式' : '暗黑模式'
return this.nightMode ? "浅色模式" : "暗黑模式";
},
btnType() {
return this.nightMode ? 'default' : 'primary';
return this.nightMode ? "default" : "primary";
},
...mapState({
output: state => state.output,
editor: state => state.editor,
cssEditor: state => state.cssEditor,
currentFont: state => state.currentFont,
currentSize: state => state.currentSize,
currentColor: state => state.currentColor,
codeTheme: state => state.codeTheme,
nightMode: state => state.nightMode
})
output: (state) => state.output,
editor: (state) => state.editor,
cssEditor: (state) => state.cssEditor,
currentFont: (state) => state.currentFont,
currentSize: (state) => state.currentSize,
currentColor: (state) => state.currentColor,
codeTheme: (state) => state.codeTheme,
nightMode: (state) => state.nightMode,
}),
},
methods: {
fontChanged(fonts) {
this.setWxRendererOptions({
fonts: fonts
fonts: fonts,
});
this.setCurrentFont(fonts);
this.$emit('refresh');
this.$emit("refresh");
},
sizeChanged(size) {
let theme = setFontSize(size.replace('px', ''))
theme = setColorWithCustomTemplate(theme, this.currentColor)
let theme = setFontSize(size.replace("px", ""));
theme = setColorWithCustomTemplate(theme, this.currentColor);
this.setWxRendererOptions({
size: size,
theme: theme
theme: theme,
});
this.setCurrentSize(size);
this.$emit('refresh');
this.$emit("refresh");
},
colorChanged(color) {
let theme = setFontSize(this.currentSize.replace('px', ''));
let theme = setFontSize(this.currentSize.replace("px", ""));
theme = setColorWithCustomTemplate(theme, color);
this.setWxRendererOptions({
theme: theme
theme: theme,
});
this.setCurrentColor(color);
this.$emit('refresh');
this.$emit("refresh");
},
codeThemeChanged(theme) {
this.setCurrentCodeTheme(theme);
this.$emit('refresh');
this.$emit("refresh");
},
statusChanged(val) {
this.setCiteStatus(val);
this.$emit('refresh');
this.$emit("refresh");
},
//
copy(e) {
this.$emit('startCopy');
this.$emit("startCopy");
setTimeout(() => {
let clipboardDiv = document.getElementById('output');
let clipboardDiv = document.getElementById("output");
solveWeChatImage();
fixCodeWhiteSpace();
solveHtml();
@ -167,36 +283,37 @@ export default {
range.setStartBefore(clipboardDiv.firstChild);
range.setEndAfter(clipboardDiv.lastChild);
window.getSelection().addRange(range);
document.execCommand('copy');
document.execCommand("copy");
window.getSelection().removeAllRanges();
fixCodeWhiteSpace('normal');
fixCodeWhiteSpace("normal");
clipboardDiv.innerHTML = this.output;
//
this.$notify({
showClose: true,
message: '已复制渲染后的文章到剪贴板,可直接到公众号后台粘贴',
message:
"已复制渲染后的文章到剪贴板,可直接到公众号后台粘贴",
offset: 80,
duration: 1600,
type: 'success'
type: "success",
});
this.$emit('refresh');
this.$emit('endCopy');
this.$emit("refresh");
this.$emit("endCopy");
}, 350);
e.target.blur();
},
// CSS
async customStyle() {
this.$emit('showCssEditor');
this.$emit("showCssEditor");
this.$nextTick(() => {
if (!this.cssEditor) {
this.cssEditor.refresh();
}
})
});
setTimeout(() => {
this.cssEditor.refresh();
},50)
let flag = await localStorage.getItem('__css_content');
}, 50);
let flag = await localStorage.getItem("__css_content");
if (!flag) {
this.setCssEditorValue(DEFAULT_CSS_CONTENT);
@ -204,15 +321,15 @@ export default {
},
//
confirmReset() {
localStorage.clear()
localStorage.clear();
this.clearEditorToDefault();
this.editor.focus()
this.editor.focus();
this.citeStatus = false;
this.statusChanged(false);
this.fontChanged(this.config.builtinFonts[0].value)
this.colorChanged(this.config.colorOption[1].value)
this.sizeChanged(this.config.sizeOption[2].value)
this.$emit('cssChanged')
this.fontChanged(this.config.builtinFonts[0].value);
this.colorChanged(this.config.colorOption[1].value);
this.sizeChanged(this.config.sizeOption[2].value);
this.$emit("cssChanged");
this.selectFont = this.currentFont;
this.selectSize = this.currentSize;
this.selectColor = this.currentColor;
@ -220,27 +337,27 @@ export default {
},
cancelReset() {
this.showResetConfirm = false;
this.editor.focus()
this.editor.focus();
},
...mapMutations([
'clearEditorToDefault',
'setCurrentColor',
'setCiteStatus',
'themeChanged',
'setCurrentFont',
'setCurrentSize',
'setCssEditorValue',
'setCurrentCodeTheme',
'setWxRendererOptions'
])
"clearEditorToDefault",
"setCurrentColor",
"setCiteStatus",
"themeChanged",
"setCurrentFont",
"setCurrentSize",
"setCssEditorValue",
"setCurrentCodeTheme",
"setWxRendererOptions",
]),
},
mounted() {
this.selectFont = this.currentFont;
this.selectSize = this.currentSize;
this.selectColor = this.currentColor;
this.selectCodeTheme = this.codeTheme;
}
}
},
};
</script>
<style lang="less" scoped>
@ -260,12 +377,12 @@ export default {
margin-left: 24px;
width: 24px;
height: 24px;
background: url('../../assets/images/night.png') no-repeat;
background: url("../../assets/images/night.png") no-repeat;
background-size: cover;
transition: all .3s;
transition: all 0.3s;
}
.mode__switch_black {
background: url('../../assets/images/light.png') no-repeat;
background: url("../../assets/images/light.png") no-repeat;
background-size: cover;
}
.top {

View File

@ -29,7 +29,11 @@
</el-col>
</el-row>
<table style="border-collapse: collapse" class="input-table">
<tr :class="{ 'head-style': row === 1 }" v-for="row in rowNum+1" :key="row">
<tr
:class="{ 'head-style': row === 1 }"
v-for="row in rowNum + 1"
:key="row"
>
<td v-for="col in colNum" :key="col">
<el-input
align="center"
@ -40,32 +44,33 @@
</tr>
</table>
<div slot="footer" class="dialog-footer">
<el-button :type="btnType" plain @click="$emit('input', false)"> </el-button>
<el-button :type="btnType" @click="insertTable" plain> </el-button>
<el-button :type="btnType" plain @click="$emit('input', false)"
> </el-button
>
<el-button :type="btnType" @click="insertTable" plain
> </el-button
>
</div>
</el-dialog>
</template>
<script>
import config from "../../assets/scripts/config";
import {createTable} from '../../assets/scripts/util';
import {
mapState,
mapMutations
} from "vuex";
import { createTable } from "../../assets/scripts/util";
import { mapState, mapMutations } from "vuex";
export default {
props: {
value: {
type: Boolean,
default: false
}
default: false,
},
},
data() {
return {
config: config,
rowNum: 3,
colNum: 3,
tableData: {}
tableData: {},
};
},
computed: {
@ -73,9 +78,9 @@ export default {
return this.nightMode ? "default" : "primary";
},
...mapState({
nightMode: state => state.nightMode,
editor: state => state.editor
})
nightMode: (state) => state.nightMode,
editor: (state) => state.editor,
}),
},
methods: {
//
@ -84,18 +89,18 @@ export default {
const table = createTable({
data: this.tableData,
rows: this.rowNum,
cols: this.colNum
cols: this.colNum,
});
this.tableData = {};
this.rowNum = 3;
this.colNum = 3;
this.editor.replaceSelection(`\n${table}\n`, "end");
this.$emit('input', false);
this.$emit("input", false);
this.editorRefresh();
},
...mapMutations(["editorRefresh"])
}
...mapMutations(["editorRefresh"]),
},
};
</script>

View File

@ -1,36 +1,42 @@
<template>
<el-dialog title="提示" class="reset__dialog" :visible="showResetConfirm" @close="$emit('close')">
<el-dialog
title="提示"
class="reset__dialog"
:visible="showResetConfirm"
@close="$emit('close')"
>
<div class="text">
此操作将丢失本地缓存的文本和自定义样式是否继续?
</div>
<div slot="footer" class="dialog-footer">
<el-button :type="btnType" plain @click="$emit('close')"> </el-button>
<el-button :type="btnType" @click="$emit('confirm')" plain> </el-button>
<el-button :type="btnType" plain @click="$emit('close')"
> </el-button
>
<el-button :type="btnType" @click="$emit('confirm')" plain
> </el-button
>
</div>
</el-dialog>
</template>
<script>
import {
mapState
} from 'vuex';
import { mapState } from "vuex";
export default {
props: {
showResetConfirm: {
type: Boolean,
default: false
}
default: false,
},
},
computed: {
btnType() {
return this.nightMode ? 'default' : 'primary';
return this.nightMode ? "default" : "primary";
},
...mapState({
nightMode: state => state.nightMode
})
}
}
nightMode: (state) => state.nightMode,
}),
},
};
</script>
<style lang="less" scoped>
@ -45,5 +51,4 @@
.dialog-footer {
text-align: center;
}
</style>

View File

@ -1,62 +1,70 @@
<template>
<ul v-show="value" id="menu" class="menu" :style="`left: ${left}px;top: ${top}px;`">
<li v-for="item of list" :key="item.key" class="menu_item" @mousedown="onMouseDown(item.key)">
<ul
v-show="value"
id="menu"
class="menu"
:style="`left: ${left}px;top: ${top}px;`"
>
<li
v-for="item of list"
:key="item.key"
class="menu_item"
@mousedown="onMouseDown(item.key)"
>
<span>{{ item.text }}</span>
</li>
</ul>
</template>
<script>
import {
uploadImgFile,
} from '../../assets/scripts/uploadImageFile';
import { uploadImgFile } from "../../assets/scripts/uploadImageFile";
export default {
props: {
value: {
type: Boolean,
default: false
default: false,
},
top: {
type: Number,
default: 0
default: 0,
},
left: {
type: Number,
default: 0
}
default: 0,
},
},
data() {
return {
list: [
{
text: '上传图片',
key: 'insertPic'
text: "上传图片",
key: "insertPic",
},
{
text: '插入表格',
key: 'insertTable'
text: "插入表格",
key: "insertTable",
},
{
text: '页面重置',
key: 'pageReset'
text: "页面重置",
key: "pageReset",
},
{
text: '下载MD文档',
key: 'downLoad'
}
]
}
text: "下载MD文档",
key: "downLoad",
},
],
};
},
methods: {
closeCB() {
this.$emit('input', false);
this.$emit("input", false);
},
onMouseDown(key) {
this.$emit('menuTick', key)
this.$emit('closeMenu', false)
}
this.$emit("menuTick", key);
this.$emit("closeMenu", false);
},
}
},
};
</script>
<style lang="less" scoped>
@ -83,7 +91,8 @@ export default {
color: white;
background: rgb(139, 146, 148);
}
span,.btn-upload {
span,
.btn-upload {
text-align: center;
display: inline-block;
padding: 4px 0;
@ -104,7 +113,6 @@ export default {
}
}
li:hover {
background-color: #1790ff;
color: white;
@ -114,5 +122,4 @@ li {
font-size: 15px;
list-style: none;
}
</style>

View File

@ -1,14 +1,37 @@
<template>
<el-dialog title="本地上传" class="upload__dialog" :visible="value" @close="$emit('close')">
<el-dialog
title="本地上传"
class="upload__dialog"
:visible="value"
@close="$emit('close')"
>
<el-tabs type="card" :value="'upload'">
<el-tab-pane class="upload-panel" label="选择上传" name="upload">
<el-select v-model="imgHost" @change="changeImgHost" placeholder="请选择" size="small">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
<el-select
v-model="imgHost"
@change="changeImgHost"
placeholder="请选择"
size="small"
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
<el-upload drag action :headers="{'Content-Type': 'multipart/form-data'}" :show-file-list="false"
:multiple="true" accept=".jpg, .jpeg, .png, .gif" name="file" :before-upload="beforeUpload"
v-loading="uploadingImg">
<el-upload
drag
action
:headers="{ 'Content-Type': 'multipart/form-data' }"
:show-file-list="false"
:multiple="true"
accept=".jpg, .jpeg, .png, .gif"
name="file"
:before-upload="beforeUpload"
v-loading="uploadingImg"
>
<i class="el-icon-upload"></i>
<div class="el-upload__text">
将图片拖到此处
@ -17,88 +40,164 @@
</el-upload>
</el-tab-pane>
<el-tab-pane class="github-panel" label="GitHub 图床" name="github">
<el-form class="setting-form" ref="form" :model="formGitHub" label-position="right" label-width="140px">
<el-form
class="setting-form"
ref="form"
:model="formGitHub"
label-position="right"
label-width="140px"
>
<el-form-item label="GitHub 仓库" :required="true">
<el-input v-model.trim="formGitHub.repo" placeholder="如github.com/yanglbme/resource"></el-input>
<el-input
v-model.trim="formGitHub.repo"
placeholder="如github.com/yanglbme/resource"
></el-input>
</el-form-item>
<el-form-item label="分支">
<el-input v-model.trim="formGitHub.branch" placeholder="如release可不填默认 master"></el-input>
<el-input
v-model.trim="formGitHub.branch"
placeholder="如release可不填默认 master"
></el-input>
</el-form-item>
<el-form-item label="Token" :required="true">
<el-input v-model.trim="formGitHub.accessToken" show-password
placeholder="如cc1d0c1426d0fd0902bd2d7184b14da61b8abc46"></el-input>
<el-link type="primary"
<el-input
v-model.trim="formGitHub.accessToken"
show-password
placeholder="如cc1d0c1426d0fd0902bd2d7184b14da61b8abc46"
></el-input>
<el-link
type="primary"
href="https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token"
target="_blank">如何获取 GitHub Token</el-link>
target="_blank"
>如何获取 GitHub Token</el-link
>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="saveGitHubConfiguration">保存配置</el-button>
<el-button
type="primary"
@click="saveGitHubConfiguration"
>保存配置</el-button
>
</el-form-item>
</el-form>
</el-tab-pane>
<el-tab-pane class="github-panel" label="阿里云 OSS" name="aliOSS">
<el-form class="setting-form" ref="form" :model="formAliOSS" label-position="right" label-width="140px">
<el-form
class="setting-form"
ref="form"
:model="formAliOSS"
label-position="right"
label-width="140px"
>
<el-form-item label="AccessKey ID" :required="true">
<el-input v-model.trim="formAliOSS.accessKeyId" placeholder="如LTAI4GdoocsmdoxUf13ylbaNHk"></el-input>
<el-input
v-model.trim="formAliOSS.accessKeyId"
placeholder="如LTAI4GdoocsmdoxUf13ylbaNHk"
></el-input>
</el-form-item>
<el-form-item label="AccessKey Secret" :required="true">
<el-input v-model.trim="formAliOSS.accessKeySecret" show-password
placeholder="如cc1d0c142doocs0902bd2d7md4b14da6ylbabc46"></el-input>
<el-input
v-model.trim="formAliOSS.accessKeySecret"
show-password
placeholder="如cc1d0c142doocs0902bd2d7md4b14da6ylbabc46"
></el-input>
</el-form-item>
<el-form-item label="Bucket" :required="true">
<el-input v-model.trim="formAliOSS.bucket"
placeholder="如doocs"></el-input>
<el-input
v-model.trim="formAliOSS.bucket"
placeholder="如doocs"
></el-input>
</el-form-item>
<el-form-item label="Bucket 所在区域" :required="true">
<el-input v-model.trim="formAliOSS.region"
placeholder="如oss-cn-shenzhen"></el-input>
<el-input
v-model.trim="formAliOSS.region"
placeholder="如oss-cn-shenzhen"
></el-input>
</el-form-item>
<el-form-item label="自定义 CDN 域名" :required="false">
<el-input v-model.trim="formAliOSS.cdnHost"
placeholder="如https://imagecdn.alidaodao.com可不填"></el-input>
<el-input
v-model.trim="formAliOSS.cdnHost"
placeholder="如https://imagecdn.alidaodao.com可不填"
></el-input>
</el-form-item>
<el-form-item label="存储路径">
<el-input v-model.trim="formAliOSS.path"
placeholder="如img可不填默认为根目录"></el-input>
<el-link type="primary"
<el-input
v-model.trim="formAliOSS.path"
placeholder="如img可不填默认为根目录"
></el-input>
<el-link
type="primary"
href="https://help.aliyun.com/document_detail/31883.html"
target="_blank">如何使用阿里云 OSS</el-link>
target="_blank"
>如何使用阿里云 OSS</el-link
>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="saveAliOSSConfiguration">保存配置</el-button>
<el-button
type="primary"
@click="saveAliOSSConfiguration"
>保存配置</el-button
>
</el-form-item>
</el-form>
</el-tab-pane>
<el-tab-pane class="github-panel" label="腾讯云 COS" name="txCOS">
<el-form class="setting-form" ref="form" :model="formTxCOS" label-position="right" label-width="140px">
<el-form
class="setting-form"
ref="form"
:model="formTxCOS"
label-position="right"
label-width="140px"
>
<el-form-item label="SecretId" :required="true">
<el-input v-model.trim="formTxCOS.secretId" placeholder="如AKIDnQp1w3DOOCSs8F5MDp9tdoocsmdUPonW3"></el-input>
<el-input
v-model.trim="formTxCOS.secretId"
placeholder="如AKIDnQp1w3DOOCSs8F5MDp9tdoocsmdUPonW3"
></el-input>
</el-form-item>
<el-form-item label="SecretKey" :required="true">
<el-input v-model.trim="formTxCOS.secretKey" show-password
placeholder="如ukLmdtEJ9271f3DOocsMDsCXdS3YlbW0"></el-input>
<el-input
v-model.trim="formTxCOS.secretKey"
show-password
placeholder="如ukLmdtEJ9271f3DOocsMDsCXdS3YlbW0"
></el-input>
</el-form-item>
<el-form-item label="Bucket" :required="true">
<el-input v-model.trim="formTxCOS.bucket"
placeholder="如doocs-3212520134"></el-input>
<el-input
v-model.trim="formTxCOS.bucket"
placeholder="如doocs-3212520134"
></el-input>
</el-form-item>
<el-form-item label="Bucket 所在区域" :required="true">
<el-input v-model.trim="formTxCOS.region"
placeholder="如ap-guangzhou"></el-input>
<el-input
v-model.trim="formTxCOS.region"
placeholder="如ap-guangzhou"
></el-input>
</el-form-item>
<el-form-item label="自定义 CDN 域名" :required="false">
<el-input v-model.trim="formTxCOS.cdnHost"
placeholder="如https://imagecdn.alidaodao.com可不填"></el-input>
<el-input
v-model.trim="formTxCOS.cdnHost"
placeholder="如https://imagecdn.alidaodao.com可不填"
></el-input>
</el-form-item>
<el-form-item label="存储路径">
<el-input v-model.trim="formTxCOS.path"
placeholder="如img可不填默认根目录"></el-input>
<el-link type="primary"
<el-input
v-model.trim="formTxCOS.path"
placeholder="如img可不填默认根目录"
></el-input>
<el-link
type="primary"
href="https://cloud.tencent.com/document/product/436/38484"
target="_blank">如何使用腾讯云 COS</el-link>
target="_blank"
>如何使用腾讯云 COS</el-link
>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="saveTxCOSConfiguration">保存配置</el-button>
<el-button
type="primary"
@click="saveTxCOSConfiguration"
>保存配置</el-button
>
</el-form-item>
</el-form>
</el-tab-pane>
@ -107,9 +206,7 @@
</template>
<script>
import {
uploadImgFile
} from "../../assets/scripts/uploadImageFile";
import { uploadImgFile } from "../../assets/scripts/uploadImageFile";
export default {
props: {
@ -141,7 +238,8 @@ export default {
path: "",
cdnHost: "",
},
options: [{
options: [
{
value: "default",
label: "默认图床",
},
@ -151,12 +249,12 @@ export default {
},
{
value: "aliOSS",
label: "阿里云"
label: "阿里云",
},
{
value: "txCOS",
label: "腾讯云"
}
label: "腾讯云",
},
],
imgHost: "default",
uploadingImg: false,
@ -181,13 +279,15 @@ export default {
localStorage.setItem("imgHost", this.imgHost);
this.$message({
showClose: true,
message: '已成功切换图床',
message: "已成功切换图床",
type: "success",
});
},
saveGitHubConfiguration() {
if (!(this.formGitHub.repo && this.formGitHub.accessToken)) {
const blankElement = this.formGitHub.repo ? "token" : "GitHub 仓库"
const blankElement = this.formGitHub.repo
? "token"
: "GitHub 仓库";
this.$message({
showClose: true,
message: `参数「​${blankElement}」不能为空`,
@ -195,14 +295,24 @@ export default {
});
return;
}
localStorage.setItem("githubConfig", JSON.stringify(this.formGitHub));
localStorage.setItem(
"githubConfig",
JSON.stringify(this.formGitHub)
);
this.$message({
message: "保存成功",
type: "success",
});
},
saveAliOSSConfiguration() {
if (!(this.formAliOSS.accessKeyId && this.formAliOSS.accessKeySecret && this.formAliOSS.bucket && this.formAliOSS.region)) {
if (
!(
this.formAliOSS.accessKeyId &&
this.formAliOSS.accessKeySecret &&
this.formAliOSS.bucket &&
this.formAliOSS.region
)
) {
this.$message({
showClose: true,
message: `阿里云 OSS 参数配置不全`,
@ -210,7 +320,10 @@ export default {
});
return;
}
localStorage.setItem("aliOSSConfig", JSON.stringify(this.formAliOSS));
localStorage.setItem(
"aliOSSConfig",
JSON.stringify(this.formAliOSS)
);
this.$message({
message: "保存成功",
type: "success",
@ -218,7 +331,14 @@ export default {
},
saveTxCOSConfiguration() {
if (!(this.formTxCOS.secretId && this.formTxCOS.secretKey && this.formTxCOS.bucket && this.formTxCOS.region)) {
if (
!(
this.formTxCOS.secretId &&
this.formTxCOS.secretKey &&
this.formTxCOS.bucket &&
this.formTxCOS.region
)
) {
this.$message({
showClose: true,
message: `腾讯云 COS 参数配置不全`,
@ -241,11 +361,11 @@ export default {
this.uploadingImg = true;
uploadImgFile(file)
.then(res => {
.then((res) => {
this.$emit("uploaded", res);
this.uploadingImg = false;
})
.catch(err => {
.catch((err) => {
this.uploadingImg = false;
this.$message({
showClose: true,
@ -256,20 +376,30 @@ export default {
return false;
},
validateConfig() {
let checkRes = true, errMessage = '';
let checkRes = true,
errMessage = "";
switch (localStorage.getItem('imgHost')) {
case 'github':
checkRes = this.formGitHub.repo && this.formGitHub.accessToken;
errMessage = checkRes ? '' : '请先配置 GitHub 图床参数';
switch (localStorage.getItem("imgHost")) {
case "github":
checkRes =
this.formGitHub.repo && this.formGitHub.accessToken;
errMessage = checkRes ? "" : "请先配置 GitHub 图床参数";
break;
case 'aliOSS':
checkRes = this.formAliOSS.accessKeyId && this.formAliOSS.accessKeySecret && this.formAliOSS.bucket && this.formAliOSS.region;
errMessage = checkRes ? '' : '请先配置阿里云 OSS 参数';
case "aliOSS":
checkRes =
this.formAliOSS.accessKeyId &&
this.formAliOSS.accessKeySecret &&
this.formAliOSS.bucket &&
this.formAliOSS.region;
errMessage = checkRes ? "" : "请先配置阿里云 OSS 参数";
break;
case 'txCOS':
checkRes = this.formTxCOS.secretId && this.formTxCOS.secretKey && this.formTxCOS.bucket && this.formTxCOS.region;
errMessage = checkRes ? '' : '请先配置腾讯云 COS 参数';
case "txCOS":
checkRes =
this.formTxCOS.secretId &&
this.formTxCOS.secretKey &&
this.formTxCOS.bucket &&
this.formTxCOS.region;
errMessage = checkRes ? "" : "请先配置腾讯云 COS 参数";
break;
}
errMessage && this.$message.error(errMessage);
@ -319,5 +449,4 @@ export default {
text-align: right;
}
}
</style>

View File

@ -7,8 +7,7 @@
</div>
</template>
<script>
</script>
<script></script>
<style lang="less" scoped>
.loading-wrapper {
@ -42,7 +41,7 @@
display: inline-block;
width: 100px;
height: 100px;
background: url('../assets/images/favicon.png') no-repeat;
background: url("../assets/images/favicon.png") no-repeat;
background-size: cover;
}
</style>

View File

@ -1,5 +1,5 @@
<template>
<div class="container" :class="{'container_night': nightMode}">
<div class="container" :class="{ container_night: nightMode }">
<el-container>
<el-header class="editor__header">
<editor-header
@ -11,38 +11,70 @@
@showAboutDialog="aboutDialogVisible = true"
@showDialogForm="dialogFormVisible = true"
@showDialogUploadImg="dialogUploadImgVisible = true"
@startCopy="isCoping = true, backLight = true"
@startCopy="(isCoping = true), (backLight = true)"
@endCopy="endCopy"
/>
</el-header>
<el-main class="main-body">
<el-row class="main-section">
<el-col :span="12" @contextmenu.prevent.native="openMenu($event)">
<textarea id="editor" type="textarea" placeholder="Your markdown text here." v-model="source">
<el-col
:span="12"
@contextmenu.prevent.native="openMenu($event)"
>
<textarea
id="editor"
type="textarea"
placeholder="Your markdown text here."
v-model="source"
>
</textarea>
</el-col>
<el-col :span="12" class="preview-wrapper" id="preview" ref="preview" :class="{'preview-wrapper_night': nightMode && isCoping}">
<section id="output-wrapper" :class="{'output_night': nightMode && !backLight}">
<el-col
:span="12"
class="preview-wrapper"
id="preview"
ref="preview"
:class="{
'preview-wrapper_night': nightMode && isCoping,
}"
>
<section
id="output-wrapper"
:class="{ output_night: nightMode && !backLight }"
>
<div class="preview">
<section id="output" v-html="output">
</section>
<div class="loading-mask" v-if="nightMode && isCoping">
<section id="output" v-html="output"></section>
<div
class="loading-mask"
v-if="nightMode && isCoping"
>
<div class="loading__img"></div>
<span>正在生成</span>
</div>
</div>
</section>
</el-col>
<transition name="custom-classes-transition" enter-active-class="bounceInRight">
<transition
name="custom-classes-transition"
enter-active-class="bounceInRight"
>
<el-col id="cssBox" :span="12" v-show="showCssEditor">
<textarea id="cssEditor" type="textarea" placeholder="Your custom css here.">
<textarea
id="cssEditor"
type="textarea"
placeholder="Your custom css here."
>
</textarea>
</el-col>
</transition>
</el-row>
</el-main>
</el-container>
<upload-img-dialog v-model="dialogUploadImgVisible" @close="dialogUploadImgVisible = false" @uploaded="uploaded" />
<upload-img-dialog
v-model="dialogUploadImgVisible"
@close="dialogUploadImgVisible = false"
@uploaded="uploaded"
/>
<about-dialog v-model="aboutDialogVisible" />
<insert-form-dialog v-model="dialogFormVisible" />
<right-click-menu
@ -55,23 +87,23 @@
</div>
</template>
<script>
import editorHeader from '../components/CodemirrorEditor/header';
import aboutDialog from '../components/CodemirrorEditor/aboutDialog';
import insertFormDialog from '../components/CodemirrorEditor/insertForm';
import rightClickMenu from '../components/CodemirrorEditor/rightClickMenu';
import uploadImgDialog from '../components/CodemirrorEditor/uploadImgDialog';
import editorHeader from "../components/CodemirrorEditor/header";
import aboutDialog from "../components/CodemirrorEditor/aboutDialog";
import insertFormDialog from "../components/CodemirrorEditor/insertForm";
import rightClickMenu from "../components/CodemirrorEditor/rightClickMenu";
import uploadImgDialog from "../components/CodemirrorEditor/uploadImgDialog";
import {
css2json,
downLoadMD,
setFontSize,
saveEditorContent,
customCssWithTemplate
} from '../assets/scripts/util'
import {uploadImgFile} from '../assets/scripts/uploadImageFile';
customCssWithTemplate,
} from "../assets/scripts/util";
import { uploadImgFile } from "../assets/scripts/uploadImageFile";
require('codemirror/mode/javascript/javascript')
import {mapState, mapMutations} from 'vuex';
require("codemirror/mode/javascript/javascript");
import { mapState, mapMutations } from "vuex";
export default {
data() {
return {
@ -84,29 +116,29 @@ export default {
backLight: false,
timeout: null,
changeTimer: null,
source: '',
source: "",
mouseLeft: 0,
mouseTop: 0
}
mouseTop: 0,
};
},
components: {
editorHeader,
aboutDialog,
insertFormDialog,
rightClickMenu,
uploadImgDialog
uploadImgDialog,
},
computed: {
...mapState({
wxRenderer: state => state.wxRenderer,
output: state => state.output,
editor: state => state.editor,
cssEditor: state => state.cssEditor,
currentSize: state => state.currentSize,
currentColor: state => state.currentColor,
nightMode: state => state.nightMode,
rightClickMenuVisible: state => state.rightClickMenuVisible
})
wxRenderer: (state) => state.wxRenderer,
output: (state) => state.output,
editor: (state) => state.editor,
cssEditor: (state) => state.cssEditor,
currentSize: (state) => state.currentSize,
currentColor: (state) => state.currentColor,
nightMode: (state) => state.nightMode,
rightClickMenuVisible: (state) => state.rightClickMenuVisible,
}),
},
created() {
this.initEditorState();
@ -119,43 +151,56 @@ export default {
methods: {
initEditor() {
this.initEditorEntity();
this.editor.on('change', (cm, e) => {
this.editor.on("change", (cm, e) => {
if (this.changeTimer) clearTimeout(this.changeTimer);
this.changeTimer = setTimeout(() => {
this.onEditorRefresh();
saveEditorContent(this.editor, '__editor_content');
saveEditorContent(this.editor, "__editor_content");
}, 300);
});
//
this.editor.on('paste', (cm, e) => {
if (!(e.clipboardData && e.clipboardData.items) || this.isImgLoading) {
this.editor.on("paste", (cm, e) => {
if (
!(e.clipboardData && e.clipboardData.items) ||
this.isImgLoading
) {
return;
}
for (let i = 0, len = e.clipboardData.items.length; i < len; ++i) {
for (
let i = 0, len = e.clipboardData.items.length;
i < len;
++i
) {
let item = e.clipboardData.items[i];
if (item.kind === 'file') {
if (item.kind === "file") {
//
const imgHost = localStorage.getItem('imgHost') || 'default';
if (imgHost != 'default' && !localStorage.getItem(`${imgHost}Config`)) {
const imgHost =
localStorage.getItem("imgHost") || "default";
if (
imgHost != "default" &&
!localStorage.getItem(`${imgHost}Config`)
) {
this.$message({
showClose: true,
message: '请先配置好图床参数',
type: 'error'
message: "请先配置好图床参数",
type: "error",
});
continue;
}
this.isImgLoading = true;
const pasteFile = item.getAsFile()
uploadImgFile(pasteFile).then(res => {
this.uploaded(res)
}).catch(err => {
const pasteFile = item.getAsFile();
uploadImgFile(pasteFile)
.then((res) => {
this.uploaded(res);
})
.catch((err) => {
this.$message({
showClose: true,
message: err,
type: 'error'
type: "error",
});
});
this.isImgLoading = false;
@ -163,38 +208,37 @@ export default {
}
});
this.editor.on('mousedown', () => {
this.$store.commit('setRightClickMenuVisible', false);
this.editor.on("mousedown", () => {
this.$store.commit("setRightClickMenuVisible", false);
});
this.editor.on('blur', () => {
this.editor.on("blur", () => {
//!mousedown
this.$store.commit('setRightClickMenuVisible', false);
this.$store.commit("setRightClickMenuVisible", false);
});
this.editor.on('scroll', () => {
this.$store.commit('setRightClickMenuVisible', false);
this.editor.on("scroll", () => {
this.$store.commit("setRightClickMenuVisible", false);
});
},
initCssEditor() {
this.initCssEditorEntity();
//
this.cssEditor.on('keyup', (cm, e) => {
this.cssEditor.on("keyup", (cm, e) => {
if ((e.keyCode >= 65 && e.keyCode <= 90) || e.keyCode === 189) {
cm.showHint(e);
}
});
this.cssEditor.on('update', (instance) => {
this.cssEditor.on("update", (instance) => {
this.cssChanged();
saveEditorContent(this.cssEditor, '__css_content');
})
saveEditorContent(this.cssEditor, "__css_content");
});
},
cssChanged() {
let json = css2json(this.cssEditor.getValue(0));
let theme = setFontSize(this.currentSize.replace('px', ''));
let theme = setFontSize(this.currentSize.replace("px", ""));
theme = customCssWithTemplate(json, this.currentColor, theme);
this.setWxRendererOptions({
theme: theme
theme: theme,
});
this.onEditorRefresh();
},
@ -203,8 +247,8 @@ export default {
if (!response) {
this.$message({
showClose: true,
message: '上传图片未知异常',
type: 'error'
message: "上传图片未知异常",
type: "error",
});
return;
}
@ -217,47 +261,66 @@ export default {
this.editor.replaceSelection(`\n${markdownImage}\n`, cursor);
this.$message({
showClose: true,
message: '图片上传成功',
type: 'success'
message: "图片上传成功",
type: "success",
});
this.onEditorRefresh();
},
//
leftAndRightScroll() {
const scrollCB = text => {
const scrollCB = (text) => {
let source, target;
clearTimeout(this.timeout);
if (text === 'preview') {
if (text === "preview") {
source = this.$refs.preview.$el;
target = document.getElementsByClassName('CodeMirror-scroll')[0];
this.editor.off('scroll', editorScrollCB);
target = document.getElementsByClassName(
"CodeMirror-scroll"
)[0];
this.editor.off("scroll", editorScrollCB);
this.timeout = setTimeout(() => {
this.editor.on('scroll', editorScrollCB);
this.editor.on("scroll", editorScrollCB);
}, 300);
} else if (text === 'editor') {
source = document.getElementsByClassName('CodeMirror-scroll')[0];
} else if (text === "editor") {
source = document.getElementsByClassName(
"CodeMirror-scroll"
)[0];
target = this.$refs.preview.$el;
target.removeEventListener("scroll", previewScrollCB, false);
target.removeEventListener(
"scroll",
previewScrollCB,
false
);
this.timeout = setTimeout(() => {
target.addEventListener("scroll", previewScrollCB, false);
target.addEventListener(
"scroll",
previewScrollCB,
false
);
}, 300);
}
let percentage = source.scrollTop / (source.scrollHeight - source.offsetHeight);
let height = percentage * (target.scrollHeight - target.offsetHeight);
let percentage =
source.scrollTop /
(source.scrollHeight - source.offsetHeight);
let height =
percentage * (target.scrollHeight - target.offsetHeight);
target.scrollTo(0, height);
};
const editorScrollCB = () => {
scrollCB('editor');
scrollCB("editor");
};
const previewScrollCB = () => {
scrollCB('preview');
scrollCB("preview");
};
this.$refs.preview.$el.addEventListener("scroll", previewScrollCB, false);
this.editor.on('scroll', editorScrollCB);
this.$refs.preview.$el.addEventListener(
"scroll",
previewScrollCB,
false
);
this.editor.on("scroll", editorScrollCB);
},
//
onEditorRefresh() {
@ -284,43 +347,43 @@ export default {
const left = e.clientX - offsetLeft;
this.mouseLeft = Math.min(maxLeft, left);
this.mouseTop = e.clientY + 10;
this.$store.commit('setRightClickMenuVisible', true);
this.$store.commit("setRightClickMenuVisible", true);
},
closeRightClickMenu() {
this.$store.commit('setRightClickMenuVisible', false);
this.$store.commit("setRightClickMenuVisible", false);
},
onMenuEvent(type, info = {}) {
switch (type) {
case 'pageReset':
case "pageReset":
this.$refs.header.showResetConfirm = true;
break;
case 'insertPic':
this.dialogUploadImgVisible = true
case "insertPic":
this.dialogUploadImgVisible = true;
break;
case 'downLoad':
case "downLoad":
this.downloadEditorContent();
break;
case 'insertTable':
case "insertTable":
this.dialogFormVisible = true;
default:
break;
}
},
...mapMutations([
'initEditorState',
'initEditorEntity',
'setWxRendererOptions',
'editorRefresh',
'initCssEditorEntity'])
"initEditorState",
"initEditorEntity",
"setWxRendererOptions",
"editorRefresh",
"initCssEditorEntity",
]),
},
mounted() {
setTimeout(() => {
this.leftAndRightScroll();
PR.prettyPrint();
}, 300);
}
}
},
};
</script>
<style lang="less" scoped>
.main-body {
@ -328,17 +391,17 @@ export default {
overflow: hidden;
}
.el-main {
transition: all .3s;
transition: all 0.3s;
padding: 0;
margin: 20px;
margin-top: 0;
}
.container {
transition: all .3s;
transition: all 0.3s;
}
.preview {
transition: background 0s;
transition-delay: .2s;
transition-delay: 0.2s;
}
.preview-wrapper_night {
overflow-y: inherit;
@ -369,7 +432,7 @@ export default {
width: 50px;
height: 50px;
transform: translate(-50%, -50%);
background: url('../assets/images/favicon.png') no-repeat;
background: url("../assets/images/favicon.png") no-repeat;
background-size: cover;
}
span {
@ -385,30 +448,34 @@ export default {
animation-fill-mode: both;
}
@keyframes bounceInRight {
0%,60%,75%,90%,100% {
transition-timing-function: cubic-bezier(0.215,.610,.355,1.000)
0%,
60%,
75%,
90%,
100% {
transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
0% {
opacity: 0;
transform:translate3d(3000px,0,0)}
transform: translate3d(3000px, 0, 0);
}
60% {
opacity: 1;
transform:translate3d(-25px,0,0)
transform: translate3d(-25px, 0, 0);
}
75% {
transform:translate3d(10px,0,0)
transform: translate3d(10px, 0, 0);
}
90% {
transform:translate3d(-5px,0,0)
transform: translate3d(-5px, 0, 0);
}
100% {
transform:none
transform: none;
}
}
</style>
<style lang="less">
@import url('../assets/less/app.less');
@import url('../assets/less/style-mirror.css');
@import url('../assets/less/github-v2.min.css');
@import url("../assets/less/app.less");
@import url("../assets/less/style-mirror.css");
@import url("../assets/less/github-v2.min.css");
</style>