mirror of
https://github.com/doocs/md.git
synced 2024-11-28 13:36:32 +08:00
perf: rearrange the top layout (#163)
* perf: rearrange the top layout * chore: toggle selection style * chore: remove default option * chore: adjust the theme button position * feat: the MD import function is added * feat: add formatting function * perf: improved color picker experience * perf: added a format shortcut key * chore: reduce the margin difference
This commit is contained in:
parent
9c720a1662
commit
3d26b03430
@ -36,204 +36,259 @@
|
|||||||
</span>
|
</span>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<div class="left-side">
|
<div class="left-side">
|
||||||
<!-- 图片上传 -->
|
<el-dropdown>
|
||||||
<el-tooltip :effect="effect" content="上传图片" placement="bottom-start">
|
<span class="el-dropdown-link">
|
||||||
|
文件<i class="el-icon-arrow-down el-icon--right"></i>
|
||||||
|
</span>
|
||||||
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
<el-dropdown-item @click.native="refClick">
|
||||||
|
<i class="el-icon-upload2" size="medium"></i>
|
||||||
|
导入 .md
|
||||||
|
<input hidden type="file" ref="fileInput" accept=".md" />
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item @click.native="$emit('download')">
|
||||||
|
<i class="el-icon-download" size="medium"></i>
|
||||||
|
导出 .md
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item @click.native="$emit('export')">
|
||||||
|
<i class="el-icon-document" size="medium"></i>
|
||||||
|
导出 .html
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item divided @click.native="themeChanged">
|
||||||
<i
|
<i
|
||||||
class="el-icon-upload"
|
class="el-icon-check"
|
||||||
size="medium"
|
:style="{ opacity: nightMode ? 1 : 0 }"
|
||||||
@click="$emit('show-dialog-upload-img')"
|
|
||||||
></i>
|
></i>
|
||||||
</el-tooltip>
|
暗黑模式
|
||||||
<!-- 导出 Markdown 文档 -->
|
</el-dropdown-item>
|
||||||
<el-tooltip
|
</el-dropdown-menu>
|
||||||
class="header__item"
|
</el-dropdown>
|
||||||
:effect="effect"
|
|
||||||
content="导出 Markdown 文档"
|
<el-dropdown>
|
||||||
placement="bottom-start"
|
<span class="el-dropdown-link">
|
||||||
|
格式<i class="el-icon-arrow-down el-icon--right"></i>
|
||||||
|
</span>
|
||||||
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
<el-dropdown-item
|
||||||
|
class="format-item"
|
||||||
|
@click.native="$emit('addFormat', '**')"
|
||||||
>
|
>
|
||||||
|
加粗
|
||||||
|
<kbd> Ctrl + B </kbd>
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
class="format-item"
|
||||||
|
@click.native="$emit('addFormat', '*')"
|
||||||
|
>
|
||||||
|
斜体
|
||||||
|
<kbd> Ctrl + I </kbd>
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
class="format-item"
|
||||||
|
@click.native="$emit('addFormat', '~~')"
|
||||||
|
>
|
||||||
|
删除线
|
||||||
|
<kbd> Alt + Shift + U </kbd>
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
class="format-item"
|
||||||
|
@click.native="$emit('addFormat', '[', ']()')"
|
||||||
|
>
|
||||||
|
超链接
|
||||||
|
<kbd> Alt + Shift + K </kbd>
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
class="format-item"
|
||||||
|
@click.native="$emit('formatContent')"
|
||||||
|
>
|
||||||
|
格式化
|
||||||
|
<kbd> Ctrl + Alt + L </kbd>
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item divided @click.native="statusChanged">
|
||||||
<i
|
<i
|
||||||
class="el-icon-download"
|
class="el-icon-check"
|
||||||
size="medium"
|
:style="{ opacity: citeStatus ? 1 : 0 }"
|
||||||
@click="$emit('download')"
|
|
||||||
></i>
|
></i>
|
||||||
</el-tooltip>
|
微信外链转底部引用
|
||||||
<!-- 导出 HTML -->
|
</el-dropdown-item>
|
||||||
<el-tooltip
|
</el-dropdown-menu>
|
||||||
class="header__item"
|
</el-dropdown>
|
||||||
:effect="effect"
|
|
||||||
content="导出 HTML 页面"
|
<el-dropdown>
|
||||||
placement="bottom-start"
|
<span class="el-dropdown-link">
|
||||||
>
|
编辑<i class="el-icon-arrow-down el-icon--right"></i>
|
||||||
<i class="el-icon-document" size="medium" @click="$emit('export')"></i>
|
</span>
|
||||||
</el-tooltip>
|
<el-dropdown-menu slot="dropdown">
|
||||||
<!-- 样式重置 -->
|
<el-dropdown-item @click.native="$emit('show-dialog-upload-img')">
|
||||||
<el-tooltip
|
<i class="el-icon-upload" size="medium"></i>
|
||||||
class="header__item"
|
上传图片
|
||||||
:effect="effect"
|
</el-dropdown-item>
|
||||||
content="重置样式"
|
<el-dropdown-item @click.native="$emit('show-dialog-form')">
|
||||||
placement="bottom-start"
|
<i class="el-icon-s-grid" size="medium"></i>
|
||||||
>
|
插入表格
|
||||||
<i
|
</el-dropdown-item>
|
||||||
class="el-icon-refresh"
|
</el-dropdown-menu>
|
||||||
size="medium"
|
</el-dropdown>
|
||||||
@click="showResetConfirm = true"
|
|
||||||
></i>
|
<el-dropdown>
|
||||||
</el-tooltip>
|
<span class="el-dropdown-link">
|
||||||
<!-- 插入表格 -->
|
样式<i class="el-icon-arrow-down el-icon--right"></i>
|
||||||
<el-tooltip
|
</span>
|
||||||
class="header__item header__item_last"
|
<el-dropdown-menu slot="dropdown">
|
||||||
:effect="effect"
|
<el-dropdown-item class="padding-left-3">
|
||||||
content="插入表格"
|
<el-dropdown placement="right" class="style-option-menu">
|
||||||
placement="bottom-start"
|
<div class="el-dropdown-link">
|
||||||
>
|
字体
|
||||||
<i
|
<i class="el-icon-arrow-right el-icon--right"></i>
|
||||||
class="el-icon-s-grid"
|
</div>
|
||||||
size="medium"
|
<el-dropdown-menu slot="dropdown" style="width: 200px">
|
||||||
@click="$emit('show-dialog-form')"
|
<el-dropdown-item
|
||||||
></i>
|
|
||||||
</el-tooltip>
|
|
||||||
<el-select
|
|
||||||
v-model="selectFont"
|
|
||||||
size="mini"
|
|
||||||
placeholder="选择字体"
|
|
||||||
clearable
|
|
||||||
@change="fontChanged"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="font in config.builtinFonts"
|
v-for="font in config.builtinFonts"
|
||||||
:style="{ fontFamily: font.value }"
|
:style="{ fontFamily: font.value }"
|
||||||
:key="font.value"
|
:key="font.value"
|
||||||
:label="font.label"
|
:label="font.label"
|
||||||
:value="font.value"
|
:value="font.value"
|
||||||
|
@click.native="fontChanged(font.value)"
|
||||||
>
|
>
|
||||||
<span class="select-item-left">{{ font.label }}</span>
|
<i
|
||||||
|
class="el-icon-check"
|
||||||
|
:style="{ opacity: selectFont === font.value ? 1 : 0 }"
|
||||||
|
></i>
|
||||||
|
<span>{{ font.label }}</span>
|
||||||
<span class="select-item-right">Abc</span>
|
<span class="select-item-right">Abc</span>
|
||||||
</el-option>
|
</el-dropdown-item>
|
||||||
</el-select>
|
</el-dropdown-menu>
|
||||||
<el-select
|
</el-dropdown>
|
||||||
v-model="selectSize"
|
</el-dropdown-item>
|
||||||
size="mini"
|
<el-dropdown-item class="padding-left-3">
|
||||||
placeholder="选择段落字号"
|
<el-dropdown placement="right" class="style-option-menu">
|
||||||
clearable
|
<div class="el-dropdown-link">
|
||||||
@change="sizeChanged"
|
字号
|
||||||
>
|
<i class="el-icon-arrow-right el-icon--right"></i>
|
||||||
<el-option
|
</div>
|
||||||
|
<el-dropdown-menu slot="dropdown" style="width: 200px">
|
||||||
|
<el-dropdown-item
|
||||||
v-for="size in config.sizeOption"
|
v-for="size in config.sizeOption"
|
||||||
:key="size.value"
|
:key="size.value"
|
||||||
:label="size.label"
|
:label="size.label"
|
||||||
:value="size.value"
|
:value="size.value"
|
||||||
|
@click.native="sizeChanged(size.value)"
|
||||||
>
|
>
|
||||||
<span class="select-item-left">{{ size.label }}</span>
|
<i
|
||||||
|
class="el-icon-check"
|
||||||
|
:style="{ opacity: selectSize === size.value ? 1 : 0 }"
|
||||||
|
></i>
|
||||||
|
<span>{{ size.label }}</span>
|
||||||
<span class="select-item-right">{{ size.desc }}</span>
|
<span class="select-item-right">{{ size.desc }}</span>
|
||||||
</el-option>
|
</el-dropdown-item>
|
||||||
</el-select>
|
</el-dropdown-menu>
|
||||||
<el-select
|
</el-dropdown>
|
||||||
v-model="selectColor"
|
</el-dropdown-item>
|
||||||
size="mini"
|
<el-dropdown-item class="padding-left-3">
|
||||||
placeholder="选择颜色"
|
<el-dropdown placement="right" class="style-option-menu">
|
||||||
clearable
|
<div class="el-dropdown-link">
|
||||||
@change="colorChanged"
|
颜色
|
||||||
>
|
<i class="el-icon-arrow-right el-icon--right"></i>
|
||||||
<el-option
|
</div>
|
||||||
|
<el-dropdown-menu slot="dropdown" style="width: 200px">
|
||||||
|
<el-dropdown-item
|
||||||
v-for="color in config.colorOption"
|
v-for="color in config.colorOption"
|
||||||
:key="color.value"
|
:key="color.value"
|
||||||
:label="color.label"
|
:label="color.label"
|
||||||
:value="color.value"
|
:value="color.value"
|
||||||
|
@click.native="colorChanged(color.value)"
|
||||||
>
|
>
|
||||||
<span class="select-item-left">{{ color.label }}</span>
|
<i
|
||||||
|
class="el-icon-check"
|
||||||
|
:style="{ opacity: selectColor === color.value ? 1 : 0 }"
|
||||||
|
></i>
|
||||||
|
<span>{{ color.label }}</span>
|
||||||
<span class="select-item-right">{{ color.desc }}</span>
|
<span class="select-item-right">{{ color.desc }}</span>
|
||||||
</el-option>
|
</el-dropdown-item>
|
||||||
</el-select>
|
</el-dropdown-menu>
|
||||||
<el-select
|
</el-dropdown>
|
||||||
v-model="selectCodeTheme"
|
</el-dropdown-item>
|
||||||
size="mini"
|
<el-dropdown-item class="padding-left-3">
|
||||||
placeholder="代码主题"
|
<el-dropdown placement="right" class="style-option-menu">
|
||||||
@change="codeThemeChanged"
|
<div class="el-dropdown-link">
|
||||||
>
|
代码主题
|
||||||
<el-option
|
<i class="el-icon-arrow-right el-icon--right"></i>
|
||||||
|
</div>
|
||||||
|
<el-dropdown-menu slot="dropdown" style="width: 200px">
|
||||||
|
<el-dropdown-item
|
||||||
v-for="code in config.codeThemeOption"
|
v-for="code in config.codeThemeOption"
|
||||||
:key="code.value"
|
:key="code.value"
|
||||||
:label="code.label"
|
:label="code.label"
|
||||||
:value="code.value"
|
:value="code.value"
|
||||||
|
@click.native="codeThemeChanged(code.value)"
|
||||||
>
|
>
|
||||||
<span class="select-item-left">{{ code.label }}</span>
|
<i
|
||||||
|
class="el-icon-check"
|
||||||
|
:style="{ opacity: selectCodeTheme === code.value ? 1 : 0 }"
|
||||||
|
></i>
|
||||||
|
<span>{{ code.label }}</span>
|
||||||
<span class="select-item-right">{{ code.desc }}</span>
|
<span class="select-item-right">{{ code.desc }}</span>
|
||||||
</el-option>
|
</el-dropdown-item>
|
||||||
</el-select>
|
</el-dropdown-menu>
|
||||||
<el-tooltip content="自定义颜色" :effect="effect" placement="top">
|
</el-dropdown>
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
divided
|
||||||
|
class="padding-left-3"
|
||||||
|
@click.native="showPicker()"
|
||||||
|
>
|
||||||
|
自定义颜色
|
||||||
<el-color-picker
|
<el-color-picker
|
||||||
v-model="selectColor"
|
|
||||||
size="mini"
|
|
||||||
show-alpha
|
show-alpha
|
||||||
|
ref="colorPicker"
|
||||||
|
size="mini"
|
||||||
|
style="float: right; margin-top: 3px"
|
||||||
|
v-model="selectColor"
|
||||||
@change="colorChanged"
|
@change="colorChanged"
|
||||||
></el-color-picker>
|
></el-color-picker>
|
||||||
</el-tooltip>
|
</el-dropdown-item>
|
||||||
<el-tooltip
|
<el-dropdown-item class="padding-left-3" @click.native="customStyle">
|
||||||
content="微信外链自动转为文末引用"
|
自定义 CSS
|
||||||
:effect="effect"
|
</el-dropdown-item>
|
||||||
placement="top"
|
<el-dropdown-item
|
||||||
|
divided
|
||||||
|
class="padding-left-3"
|
||||||
|
@click.native="showResetConfirm = true"
|
||||||
>
|
>
|
||||||
<el-switch
|
重置
|
||||||
class="header__switch"
|
</el-dropdown-item>
|
||||||
v-model="citeStatus"
|
</el-dropdown-menu>
|
||||||
active-color="#67c23a"
|
</el-dropdown>
|
||||||
inactive-color="#dcdfe6"
|
|
||||||
@change="statusChanged"
|
<el-dropdown>
|
||||||
>
|
<span class="el-dropdown-link">
|
||||||
</el-switch>
|
帮助<i class="el-icon-arrow-down el-icon--right"></i>
|
||||||
</el-tooltip>
|
</span>
|
||||||
|
<el-dropdown-menu slot="dropdown">
|
||||||
|
<el-dropdown-item @click.native="$emit('show-about-dialog')">
|
||||||
|
关于
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</el-dropdown>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="right-side">
|
<div class="right-side">
|
||||||
<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
|
<el-button
|
||||||
:type="btnType"
|
:type="btnType"
|
||||||
plain
|
plain
|
||||||
size="medium"
|
size="medium"
|
||||||
@click="copy"
|
@click="copy"
|
||||||
placement="bottom-start"
|
placement="bottom-start"
|
||||||
>复制</el-button
|
>复制
|
||||||
>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
:type="btnType"
|
:type="btnType"
|
||||||
plain
|
plain
|
||||||
size="medium"
|
size="medium"
|
||||||
@click="prePost"
|
@click="prePost"
|
||||||
placement="bottom-start"
|
placement="bottom-start"
|
||||||
>发布</el-button
|
>发布
|
||||||
>
|
</el-button>
|
||||||
<el-button
|
|
||||||
:type="btnType"
|
|
||||||
plain
|
|
||||||
size="medium"
|
|
||||||
class="about"
|
|
||||||
@click="$emit('show-about-dialog')"
|
|
||||||
>关于</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>
|
|
||||||
</div>
|
</div>
|
||||||
<resetDialog
|
<resetDialog
|
||||||
:showResetConfirm="showResetConfirm"
|
:showResetConfirm="showResetConfirm"
|
||||||
@ -254,6 +309,7 @@ import config from '../../assets/scripts/config'
|
|||||||
import DEFAULT_CSS_CONTENT from '@/assets/example/theme-css.txt'
|
import DEFAULT_CSS_CONTENT from '@/assets/example/theme-css.txt'
|
||||||
import resetDialog from './resetDialog'
|
import resetDialog from './resetDialog'
|
||||||
import { mapState, mapMutations } from 'vuex'
|
import { mapState, mapMutations } from 'vuex'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: `editor-header`,
|
name: `editor-header`,
|
||||||
data() {
|
data() {
|
||||||
@ -300,6 +356,12 @@ export default {
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
refClick() {
|
||||||
|
this.$refs.fileInput.click()
|
||||||
|
},
|
||||||
|
showPicker() {
|
||||||
|
this.$refs.colorPicker.showPicker = true
|
||||||
|
},
|
||||||
prePost() {
|
prePost() {
|
||||||
let auto = {}
|
let auto = {}
|
||||||
try {
|
try {
|
||||||
@ -335,6 +397,7 @@ export default {
|
|||||||
fonts: fonts,
|
fonts: fonts,
|
||||||
})
|
})
|
||||||
this.setCurrentFont(fonts)
|
this.setCurrentFont(fonts)
|
||||||
|
this.selectFont = fonts
|
||||||
this.$emit(`refresh`)
|
this.$emit(`refresh`)
|
||||||
},
|
},
|
||||||
sizeChanged(size) {
|
sizeChanged(size) {
|
||||||
@ -345,6 +408,7 @@ export default {
|
|||||||
theme: theme,
|
theme: theme,
|
||||||
})
|
})
|
||||||
this.setCurrentSize(size)
|
this.setCurrentSize(size)
|
||||||
|
this.selectSize = size
|
||||||
this.$emit(`refresh`)
|
this.$emit(`refresh`)
|
||||||
},
|
},
|
||||||
colorChanged(color) {
|
colorChanged(color) {
|
||||||
@ -355,14 +419,17 @@ export default {
|
|||||||
theme: theme,
|
theme: theme,
|
||||||
})
|
})
|
||||||
this.setCurrentColor(color)
|
this.setCurrentColor(color)
|
||||||
|
this.selectColor = color
|
||||||
this.$emit(`refresh`)
|
this.$emit(`refresh`)
|
||||||
},
|
},
|
||||||
codeThemeChanged(theme) {
|
codeThemeChanged(theme) {
|
||||||
this.setCurrentCodeTheme(theme)
|
this.setCurrentCodeTheme(theme)
|
||||||
|
this.selectCodeTheme = theme
|
||||||
this.$emit(`refresh`)
|
this.$emit(`refresh`)
|
||||||
},
|
},
|
||||||
statusChanged(val) {
|
statusChanged() {
|
||||||
this.setCiteStatus(val)
|
this.citeStatus = !this.citeStatus
|
||||||
|
this.setCiteStatus(this.citeStatus)
|
||||||
this.$emit(`refresh`)
|
this.$emit(`refresh`)
|
||||||
},
|
},
|
||||||
// 复制到微信公众号
|
// 复制到微信公众号
|
||||||
@ -449,6 +516,19 @@ export default {
|
|||||||
this.selectColor = this.currentColor
|
this.selectColor = this.currentColor
|
||||||
this.selectCodeTheme = this.codeTheme
|
this.selectCodeTheme = this.codeTheme
|
||||||
this.citeStatus = this.currentCiteStatus
|
this.citeStatus = this.currentCiteStatus
|
||||||
|
|
||||||
|
const fileInput = this.$refs.fileInput
|
||||||
|
fileInput.onchange = () => {
|
||||||
|
const file = fileInput.files[0]
|
||||||
|
if (file == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const read = new FileReader()
|
||||||
|
read.readAsText(file)
|
||||||
|
read.onload = () => {
|
||||||
|
this.$emit(`import-md`, read.result)
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
@ -457,15 +537,11 @@ export default {
|
|||||||
.editor__header {
|
.editor__header {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.header__item {
|
|
||||||
margin: 0 3px;
|
|
||||||
}
|
|
||||||
.header__item_last {
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
.header__switch {
|
.header__switch {
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mode__switch {
|
.mode__switch {
|
||||||
margin-left: 24px;
|
margin-left: 24px;
|
||||||
margin-right: 24px;
|
margin-right: 24px;
|
||||||
@ -475,10 +551,12 @@ export default {
|
|||||||
background-size: cover;
|
background-size: cover;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mode__switch_black {
|
.mode__switch_black {
|
||||||
background: url('../../assets/images/light.png') no-repeat;
|
background: url('../../assets/images/light.png') no-repeat;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
.top {
|
.top {
|
||||||
height: 60px;
|
height: 60px;
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
@ -486,14 +564,17 @@ export default {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-select {
|
.el-select {
|
||||||
margin-right: 12px;
|
margin-right: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.left-side {
|
.left-side {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.right-side {
|
.right-side {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -513,4 +594,53 @@ export default {
|
|||||||
color: #8492a6;
|
color: #8492a6;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-dropdown {
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-dropdown-link {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.style-option-menu {
|
||||||
|
margin: 0;
|
||||||
|
width: 150px;
|
||||||
|
|
||||||
|
.el-dropdown-link {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.padding-left-3 {
|
||||||
|
padding-left: 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加边距影响了 divided 行的移入效果,此处做一个兼容处理
|
||||||
|
.el-dropdown-menu__item--divided.padding-left-3 {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 3em;
|
||||||
|
height: 6px;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.format-item {
|
||||||
|
.padding-left-3;
|
||||||
|
width: 180px;
|
||||||
|
|
||||||
|
kbd {
|
||||||
|
font-size: 0.75em;
|
||||||
|
float: right;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,11 +1,20 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container" :class="{ container_night: nightMode }">
|
<div
|
||||||
|
class="container"
|
||||||
|
:class="{ container_night: nightMode }"
|
||||||
|
@keydown.alt.shift.k="addFormat('[', ']()')"
|
||||||
|
@keydown.alt.shift.u="addFormat('~~')"
|
||||||
|
@keydown.ctrl.alt.l="formatContent()"
|
||||||
|
>
|
||||||
<el-container>
|
<el-container>
|
||||||
<el-header class="editor__header">
|
<el-header class="editor__header">
|
||||||
<editor-header
|
<editor-header
|
||||||
ref="header"
|
ref="header"
|
||||||
|
@addFormat="addFormat"
|
||||||
|
@formatContent="formatContent"
|
||||||
@refresh="onEditorRefresh"
|
@refresh="onEditorRefresh"
|
||||||
@cssChanged="cssChanged"
|
@cssChanged="cssChanged"
|
||||||
|
@import-md="importMD"
|
||||||
@download="downloadEditorContent"
|
@download="downloadEditorContent"
|
||||||
@export="exportEditorContent"
|
@export="exportEditorContent"
|
||||||
@showCssEditor="showCssEditor = !showCssEditor"
|
@showCssEditor="showCssEditor = !showCssEditor"
|
||||||
@ -110,12 +119,12 @@ import {
|
|||||||
customCssWithTemplate,
|
customCssWithTemplate,
|
||||||
checkImage,
|
checkImage,
|
||||||
} from '../assets/scripts/util'
|
} from '../assets/scripts/util'
|
||||||
|
|
||||||
import { toBase64 } from '../assets/scripts/util'
|
import { toBase64 } from '../assets/scripts/util'
|
||||||
import fileApi from '../api/file'
|
import fileApi from '../api/file'
|
||||||
|
import { mapState, mapMutations } from 'vuex'
|
||||||
|
|
||||||
require(`codemirror/mode/javascript/javascript`)
|
require(`codemirror/mode/javascript/javascript`)
|
||||||
import { mapState, mapMutations } from 'vuex'
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -446,6 +455,64 @@ export default {
|
|||||||
this.isCoping = false
|
this.isCoping = false
|
||||||
}, 800)
|
}, 800)
|
||||||
},
|
},
|
||||||
|
// 工具函数,添加格式
|
||||||
|
addFormat(before, after = before) {
|
||||||
|
const { head, anchor } = this.editor.doc.sel.ranges[0]
|
||||||
|
let start
|
||||||
|
let end
|
||||||
|
// 确定起始关系
|
||||||
|
if (head.line === anchor.line) {
|
||||||
|
if (head.ch < anchor.ch) {
|
||||||
|
start = head
|
||||||
|
end = anchor
|
||||||
|
} else {
|
||||||
|
start = anchor
|
||||||
|
end = head
|
||||||
|
}
|
||||||
|
} else if (head.line < anchor.line) {
|
||||||
|
start = head
|
||||||
|
end = anchor
|
||||||
|
} else {
|
||||||
|
start = head
|
||||||
|
end = anchor
|
||||||
|
}
|
||||||
|
|
||||||
|
const rows = []
|
||||||
|
let row = ``
|
||||||
|
for (const c of this.editor.getValue()) {
|
||||||
|
if (c === `\n`) {
|
||||||
|
rows.push(row)
|
||||||
|
row = ``
|
||||||
|
} else {
|
||||||
|
row += c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rows.push(row)
|
||||||
|
|
||||||
|
let txt = ``
|
||||||
|
for (let i = 0; i < rows.length; i++) {
|
||||||
|
const row = rows[i]
|
||||||
|
for (let j = 0; j < row.length; j++) {
|
||||||
|
if (i === start.line && j === start.ch) {
|
||||||
|
txt += before
|
||||||
|
}
|
||||||
|
if (i === end.line && j === end.ch) {
|
||||||
|
txt += after
|
||||||
|
}
|
||||||
|
txt += row[j]
|
||||||
|
}
|
||||||
|
//* 特殊情况,结束光标在末尾,无法遍历到
|
||||||
|
if (i === end.line && row.length === end.ch) {
|
||||||
|
txt += after
|
||||||
|
}
|
||||||
|
txt += `\n`
|
||||||
|
}
|
||||||
|
this.editor.setValue(txt)
|
||||||
|
},
|
||||||
|
importMD(md) {
|
||||||
|
this.editor.setValue(md)
|
||||||
|
this.onEditorRefresh()
|
||||||
|
},
|
||||||
// 导出编辑器内容到本地
|
// 导出编辑器内容到本地
|
||||||
downloadEditorContent() {
|
downloadEditorContent() {
|
||||||
downloadMD(this.editor.getValue(0))
|
downloadMD(this.editor.getValue(0))
|
||||||
@ -563,30 +630,37 @@ export default {
|
|||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-main {
|
.el-main {
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 20px;
|
margin: 20px;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.textarea-wrapper {
|
.textarea-wrapper {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.preview-wrapper_night {
|
.preview-wrapper_night {
|
||||||
overflow-y: inherit;
|
overflow-y: inherit;
|
||||||
position: relative;
|
position: relative;
|
||||||
left: -3px;
|
left: -3px;
|
||||||
|
|
||||||
.preview {
|
.preview {
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#output-wrapper {
|
#output-wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
user-select: text;
|
user-select: text;
|
||||||
}
|
}
|
||||||
|
|
||||||
.loading-mask {
|
.loading-mask {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
@ -598,6 +672,7 @@ export default {
|
|||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
color: gray;
|
color: gray;
|
||||||
background-color: #1e1e1e;
|
background-color: #1e1e1e;
|
||||||
|
|
||||||
.loading__img {
|
.loading__img {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
@ -608,6 +683,7 @@ export default {
|
|||||||
background: url('../assets/images/favicon.png') no-repeat;
|
background: url('../assets/images/favicon.png') no-repeat;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
span {
|
span {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
@ -615,11 +691,13 @@ export default {
|
|||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.bounceInRight {
|
.bounceInRight {
|
||||||
animation-name: bounceInRight;
|
animation-name: bounceInRight;
|
||||||
animation-duration: 1s;
|
animation-duration: 1s;
|
||||||
animation-fill-mode: both;
|
animation-fill-mode: both;
|
||||||
}
|
}
|
||||||
|
|
||||||
/deep/ .preview-table {
|
/deep/ .preview-table {
|
||||||
border-spacing: 0px;
|
border-spacing: 0px;
|
||||||
}
|
}
|
||||||
@ -650,6 +728,7 @@ export default {
|
|||||||
transform: none;
|
transform: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.codeMirror-wrapper {
|
.codeMirror-wrapper {
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user