mirror of
https://github.com/doocs/md.git
synced 2024-11-28 13:36:32 +08:00
Merge pull request #17 from doocs/feature-night-mode
Feature night mode
This commit is contained in:
commit
32cd4f63d6
@ -155,7 +155,7 @@ section {
|
|||||||
margin: 10px 8px;
|
margin: 10px 8px;
|
||||||
color: #333;
|
color: #333;
|
||||||
position: relative;
|
position: relative;
|
||||||
background-color: rgba(0, 0, 0, 0.03);
|
background-color: rgb(238,238,238);
|
||||||
border: 1px solid #f0f0f0;
|
border: 1px solid #f0f0f0;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -228,6 +228,6 @@ section {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.CodeMirror-scroll, .preview-wrapper {
|
.CodeMirror-scroll, .preview-wrapper {
|
||||||
overflow: unset!important;
|
overflow: unset;
|
||||||
overflow-y: scroll!important;
|
overflow-y: scroll;
|
||||||
}
|
}
|
BIN
src/assets/images/favicon.png
Normal file
BIN
src/assets/images/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
@ -20,13 +20,18 @@
|
|||||||
background-color: @nightCodeMirrorColor;
|
background-color: @nightCodeMirrorColor;
|
||||||
box-shadow: inset 0 0 0 1px rgba(100, 37, 37, 0.102);
|
box-shadow: inset 0 0 0 1px rgba(100, 37, 37, 0.102);
|
||||||
}
|
}
|
||||||
.preview {
|
.output_night {
|
||||||
background-color: @nightPreviewColor;
|
.preview {
|
||||||
box-shadow: 0 0 70px rgba(0, 0, 0, 0.3);
|
background-color: @nightPreviewColor;
|
||||||
}
|
box-shadow: 0 0 70px rgba(0, 0, 0, 0.3);
|
||||||
.preview-wrapper {
|
}
|
||||||
background-color: @nightCodeMirrorColor;
|
.preview-wrapper {
|
||||||
box-shadow: inset 0 0 0 1px rgba(233, 231, 231, 0.102);
|
background-color: @nightCodeMirrorColor;
|
||||||
|
box-shadow: inset 0 0 0 1px rgba(233, 231, 231, 0.102);
|
||||||
|
}
|
||||||
|
.code-snippet__fix {
|
||||||
|
background-color: rgb(238,238,238);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.cm-s-style-mirror .CodeMirror-matchingbracket {
|
.cm-s-style-mirror .CodeMirror-matchingbracket {
|
||||||
color: @nightWhiteColor!important;
|
color: @nightWhiteColor!important;
|
||||||
@ -60,7 +65,7 @@
|
|||||||
color: @nightWhiteColor;
|
color: @nightWhiteColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.insert__dialog, .about__dialog {
|
.insert__dialog, .about__dialog, .reset__dialog {
|
||||||
.el-dialog {
|
.el-dialog {
|
||||||
background-color: @nightBgColor;
|
background-color: @nightBgColor;
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,7 @@
|
|||||||
<div class="mode__switch" v-if="!nightMode" @click="themeChanged"></div>
|
<div class="mode__switch" v-if="!nightMode" @click="themeChanged"></div>
|
||||||
<div class="mode__switch mode__switch_black" v-else @click="themeChanged"></div>
|
<div class="mode__switch mode__switch_black" v-else @click="themeChanged"></div>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
<resetDialog :showResetConfirm="showResetConfirm" @confirm="confirmReset" @close="cancelReset"/>
|
||||||
</el-container>
|
</el-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -81,6 +82,7 @@ import {
|
|||||||
} from '../../scripts/converter'
|
} from '../../scripts/converter'
|
||||||
import config from '../../scripts/config'
|
import config from '../../scripts/config'
|
||||||
import DEFAULT_CSS_CONTENT from '../../scripts/themes/default-theme-css'
|
import DEFAULT_CSS_CONTENT from '../../scripts/themes/default-theme-css'
|
||||||
|
import resetDialog from '../codeMirror/resetDialog'
|
||||||
import {mapState, mapMutations} from 'vuex'
|
import {mapState, mapMutations} from 'vuex'
|
||||||
export default {
|
export default {
|
||||||
name: 'editor-header',
|
name: 'editor-header',
|
||||||
@ -88,11 +90,15 @@ export default {
|
|||||||
return {
|
return {
|
||||||
config: config,
|
config: config,
|
||||||
citeStatus: false,
|
citeStatus: false,
|
||||||
|
showResetConfirm: false,
|
||||||
selectFont: '',
|
selectFont: '',
|
||||||
selectSize: '',
|
selectSize: '',
|
||||||
selectColor: ''
|
selectColor: ''
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
components: {
|
||||||
|
resetDialog
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
effect() {
|
effect() {
|
||||||
return this.nightMode ? 'dark' : 'light'
|
return this.nightMode ? 'dark' : 'light'
|
||||||
@ -165,28 +171,32 @@ export default {
|
|||||||
},
|
},
|
||||||
// 复制到微信公众号
|
// 复制到微信公众号
|
||||||
copy() {
|
copy() {
|
||||||
let clipboardDiv = document.getElementById('output')
|
this.$emit('startCopy');
|
||||||
solveWeChatImage()
|
setTimeout(() => {
|
||||||
this.setHtml(solveHtml())
|
let clipboardDiv = document.getElementById('output')
|
||||||
|
solveWeChatImage()
|
||||||
|
this.setHtml(solveHtml(this.nightMode))
|
||||||
|
|
||||||
clipboardDiv.focus()
|
clipboardDiv.focus()
|
||||||
window.getSelection().removeAllRanges()
|
window.getSelection().removeAllRanges()
|
||||||
let range = document.createRange()
|
let range = document.createRange()
|
||||||
|
|
||||||
range.setStartBefore(clipboardDiv.firstChild)
|
range.setStartBefore(clipboardDiv.firstChild)
|
||||||
range.setEndAfter(clipboardDiv.lastChild)
|
range.setEndAfter(clipboardDiv.lastChild)
|
||||||
window.getSelection().addRange(range)
|
window.getSelection().addRange(range)
|
||||||
document.execCommand('copy')
|
document.execCommand('copy')
|
||||||
// 输出提示
|
// 输出提示
|
||||||
this.$notify({
|
this.$notify({
|
||||||
showClose: true,
|
showClose: true,
|
||||||
message: '已复制渲染后的文章到剪贴板,可直接到公众号后台粘贴',
|
message: '已复制渲染后的文章到剪贴板,可直接到公众号后台粘贴',
|
||||||
offset: 80,
|
offset: 80,
|
||||||
duration: 1600,
|
duration: 1600,
|
||||||
type: 'success'
|
type: 'success'
|
||||||
})
|
})
|
||||||
clipboardDiv.innerHTML = this.output; // 恢复现场
|
clipboardDiv.innerHTML = this.output; // 恢复现场
|
||||||
this.$emit('refresh')
|
this.$emit('refresh');
|
||||||
|
this.$emit('endCopy');
|
||||||
|
}, 350);
|
||||||
},
|
},
|
||||||
// 自定义CSS样式
|
// 自定义CSS样式
|
||||||
async customStyle () {
|
async customStyle () {
|
||||||
@ -207,26 +217,22 @@ export default {
|
|||||||
},
|
},
|
||||||
// 重置页面
|
// 重置页面
|
||||||
reset() {
|
reset() {
|
||||||
this.$confirm('此操作将丢失本地缓存的文本和自定义样式,是否继续?', '提示', {
|
this.showResetConfirm = true;
|
||||||
confirmButtonText: '确定',
|
},
|
||||||
cancelButtonText: '取消',
|
confirmReset() {
|
||||||
confirmButtonClass: 'el-button--success',
|
localStorage.clear()
|
||||||
cancelButtonClass: 'el-button--success is-plain',
|
this.clearEditorToDefault();
|
||||||
type: 'warning',
|
this.editor.focus()
|
||||||
center: true
|
this.citeStatus = false;
|
||||||
}).then(() => {
|
this.statusChanged(false);
|
||||||
localStorage.clear()
|
this.fontChanged(this.config.builtinFonts[0].value)
|
||||||
this.clearEditorToDefault();
|
this.colorChanged(this.config.colorOption[1].value)
|
||||||
this.editor.focus()
|
this.sizeChanged(this.config.sizeOption[2].value)
|
||||||
this.citeStatus = false;
|
this.$emit('cssChanged')
|
||||||
this.statusChanged(false);
|
},
|
||||||
this.fontChanged(this.config.builtinFonts[0].value)
|
cancelReset() {
|
||||||
this.colorChanged(this.config.colorOption[1].value)
|
this.showResetConfirm = false;
|
||||||
this.sizeChanged(this.config.sizeOption[2].value)
|
this.editor.focus()
|
||||||
this.$emit('cssChanged')
|
|
||||||
}).catch(() => {
|
|
||||||
this.editor.focus()
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
// 下载编辑器内容到本地
|
// 下载编辑器内容到本地
|
||||||
downloadEditorContent () {
|
downloadEditorContent () {
|
||||||
|
43
src/components/codeMirror/resetDialog.vue
Normal file
43
src/components/codeMirror/resetDialog.vue
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<template>
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {mapState} from 'vuex';
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
showResetConfirm: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
btnType() {
|
||||||
|
return !this.nightMode ? 'success' : 'default';
|
||||||
|
},
|
||||||
|
...mapState({
|
||||||
|
nightMode: state=> state.nightMode
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.reset__dialog {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.text {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.dialog-footer {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
@ -13,9 +13,9 @@ export function solveWeChatImage() {
|
|||||||
image.style.height = height;
|
image.style.height = height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export function solveHtml() {
|
export function solveHtml(nightMode = false) {
|
||||||
const element = document.getElementById("output-wrapper");
|
const element = document.getElementById("output-wrapper");
|
||||||
let html = element.innerHTML;
|
let html = element.innerHTML
|
||||||
let res = "";
|
let res = "";
|
||||||
res = juice.inlineContent(
|
res = juice.inlineContent(
|
||||||
html,
|
html,
|
||||||
@ -25,4 +25,4 @@ export function solveHtml() {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container" :class="{'container_night': nightMode}">
|
<div class="container" :class="{'container_night': nightMode}">
|
||||||
<el-container>
|
<el-container>
|
||||||
<el-header class="editor__header is-dark">
|
<el-header class="editor__header">
|
||||||
<editor-header
|
<editor-header
|
||||||
@refresh="onEditorRefresh"
|
@refresh="onEditorRefresh"
|
||||||
@uploaded="uploaded"
|
@uploaded="uploaded"
|
||||||
@ -9,6 +9,8 @@
|
|||||||
@showBox="showBox = !showBox"
|
@showBox="showBox = !showBox"
|
||||||
@showAboutDialog="aboutDialogVisible = true"
|
@showAboutDialog="aboutDialogVisible = true"
|
||||||
@showDialogForm="dialogFormVisible = true"
|
@showDialogForm="dialogFormVisible = true"
|
||||||
|
@startCopy="isCoping = true, backLight = true"
|
||||||
|
@endCopy="endCopy"
|
||||||
/>
|
/>
|
||||||
</el-header>
|
</el-header>
|
||||||
<el-main class="main-body">
|
<el-main class="main-body">
|
||||||
@ -17,11 +19,15 @@
|
|||||||
<textarea id="editor" type="textarea" placeholder="Your markdown text here." v-model="source">
|
<textarea id="editor" type="textarea" placeholder="Your markdown text here." v-model="source">
|
||||||
</textarea>
|
</textarea>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12" class="preview-wrapper" id="preview">
|
<el-col :span="12" class="preview-wrapper" id="preview" :class="{'preview-wrapper_night': nightMode && isCoping}">
|
||||||
<section id="output-wrapper" >
|
<section id="output-wrapper" :class="{'output_night': nightMode && !backLight}">
|
||||||
<div class="preview">
|
<div class="preview">
|
||||||
<section id="output" v-html="output">
|
<section id="output" v-html="output">
|
||||||
</section>
|
</section>
|
||||||
|
<div class="loading-mask" v-if="nightMode && isCoping">
|
||||||
|
<div class="loading__img"></div>
|
||||||
|
<span>正在生成</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -77,6 +83,8 @@ export default {
|
|||||||
showBox: false,
|
showBox: false,
|
||||||
aboutDialogVisible: false,
|
aboutDialogVisible: false,
|
||||||
dialogFormVisible: false,
|
dialogFormVisible: false,
|
||||||
|
isCoping: false,
|
||||||
|
backLight: false,
|
||||||
timeout: null,
|
timeout: null,
|
||||||
changeTimer: null,
|
changeTimer: null,
|
||||||
source: ''
|
source: ''
|
||||||
@ -232,6 +240,12 @@ export default {
|
|||||||
this.editorRefresh();
|
this.editorRefresh();
|
||||||
setTimeout(()=> PR.prettyPrint(), 0);
|
setTimeout(()=> PR.prettyPrint(), 0);
|
||||||
},
|
},
|
||||||
|
endCopy() {
|
||||||
|
this.backLight = false;
|
||||||
|
setTimeout(()=> {
|
||||||
|
this.isCoping = false;
|
||||||
|
}, 800);
|
||||||
|
},
|
||||||
...mapMutations(['initEditorState', 'initEditorEntity', 'setWxRendererOptions',
|
...mapMutations(['initEditorState', 'initEditorEntity', 'setWxRendererOptions',
|
||||||
'editorRefresh', 'initCssEditorEntity'])
|
'editorRefresh', 'initCssEditorEntity'])
|
||||||
},
|
},
|
||||||
@ -258,4 +272,47 @@ export default {
|
|||||||
.container {
|
.container {
|
||||||
transition: all .3s;
|
transition: all .3s;
|
||||||
}
|
}
|
||||||
|
.preview {
|
||||||
|
transition: background 0s;
|
||||||
|
transition-delay: .2s;
|
||||||
|
}
|
||||||
|
.preview-wrapper_night {
|
||||||
|
overflow-y: inherit;
|
||||||
|
position: relative;
|
||||||
|
left: -3px;
|
||||||
|
.preview {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#output-wrapper {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.loading-mask {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
width: 376px;
|
||||||
|
height: 101%;
|
||||||
|
padding-top: 1px;
|
||||||
|
font-size: 15px;
|
||||||
|
color: gray;
|
||||||
|
background-color: #1e1e1e;
|
||||||
|
.loading__img {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 330px;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
background: url('../assets/images/favicon.png') no-repeat;
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 390px;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
Loading…
Reference in New Issue
Block a user