Merge pull request #15 from doocs/feature-night-mode

night mode
This commit is contained in:
JimQing 2020-05-17 18:29:31 +08:00 committed by GitHub
commit bdbc322f76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 169 additions and 89 deletions

View File

@ -41,6 +41,7 @@ Markdown 文档自动即时渲染为微信图文,让你不再为微信文章
- [x] 支持自定义 CSS 样式并实时渲染 - [x] 支持自定义 CSS 样式并实时渲染
- [x] 支持一键恢复至默认内容及样式 - [x] 支持一键恢复至默认内容及样式
- [x] 支持打开或关闭引用链接的选项 - [x] 支持打开或关闭引用链接的选项
- [x] 支持夜间模式展示
![select-and-change-color-theme](https://imgkr.cn-bj.ufileos.com/32c05c23-6309-491f-bd0d-f22a62c944b4.gif) ![select-and-change-color-theme](https://imgkr.cn-bj.ufileos.com/32c05c23-6309-491f-bd0d-f22a62c944b4.gif)

View File

@ -1,6 +1,6 @@
{ {
"name": "vue-md", "name": "vue-md",
"version": "0.1.0", "version": "1.3.0",
"private": true, "private": true,
"homepage": "https://doocs.gitee.io/md", "homepage": "https://doocs.gitee.io/md",
"scripts": { "scripts": {

View File

@ -8,6 +8,10 @@
background-color: #f2f2f2; background-color: #f2f2f2;
} }
.loading_night {
background-color: #303133;
}
.loading-wrapper { .loading-wrapper {
position: fixed; position: fixed;
top: 50%; top: 50%;

View File

@ -5,7 +5,7 @@
<script> <script>
import Loading from './components/Loading' import Loading from './components/Loading'
import CodemirrorEditor from './components/CodemirrorEditor' import CodemirrorEditor from './view/CodemirrorEditor'
export default { export default {
name: 'App', name: 'App',
components: { components: {

BIN
src/assets/images/light.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
src/assets/images/night.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -0,0 +1,80 @@
@nightBgColor: #333333;
@nightPreviewColor: #1e1e1e;
@nightHeaderColor: #3c3c3c;
@nightCodeMirrorColor: #1e1e1e;
@nightActiveCodeMirrorColor: gray;
@nightFontColor: gray;
@nightLinkColor: #8e9eb9;
@nightLinkTextColor: #84868b;
@nightWhiteColor: #ffffff;
@nightButtonBg: #1e1e1e;
@nightButtonHoverColor: #84868b;
.container_night {
background-color: @nightBgColor;
.el-main {
background-color: @nightBgColor;
}
.CodeMirror {
caret-color: @nightFontColor;
color: @nightFontColor;
background-color: @nightCodeMirrorColor;
box-shadow: inset 0 0 0 1px rgba(100, 37, 37, 0.102);
}
.preview {
background-color: @nightPreviewColor;
box-shadow: 0 0 70px rgba(0, 0, 0, 0.3);
}
.preview-wrapper {
background-color: @nightCodeMirrorColor;
box-shadow: inset 0 0 0 1px rgba(233, 231, 231, 0.102);
}
.cm-s-style-mirror .CodeMirror-matchingbracket {
color: @nightWhiteColor!important;
background: rgb(30, 30, 30)!important;
}
.cm-s-xq-light span.cm-variable-2, .cm-s-style-mirror span.cm-tag {
color: @nightFontColor;
}
.cm-s-xq-light .CodeMirror-activeline-background {
background-color: transparent;
}
.cm-s-xq-light span.cm-string {
color: @nightLinkColor;
}
.cm-s-xq-light span.cm-link {
color: @nightLinkTextColor;
}
.editor__header {
background-color: @nightHeaderColor;
}
.el-button {
color: @nightWhiteColor;
background-color: @nightCodeMirrorColor;
border: 1px solid transparent;
}
.el-button.is-plain:focus, .el-button.is-plain:hover {
background: @nightButtonBg;
color: @nightWhiteColor;
border: 1px solid @nightWhiteColor;
i {
color: @nightWhiteColor;
}
}
.insert__dialog, .about__dialog {
.el-dialog {
background-color: @nightBgColor;
}
.el-dialog__body {
color: @nightWhiteColor;
}
.el-dialog__title, .el-form-item__label {
color: @nightWhiteColor;
}
}
i {
color: @nightWhiteColor;
}
::-webkit-scrollbar {
background-color: @nightCodeMirrorColor;
}
}

View File

@ -1,5 +1,5 @@
<template> <template>
<el-dialog title="关于" :visible="aboutDialogVisible" @close="$emit('close')" width="30%" center> <el-dialog title="关于" class="about__dialog" :visible="aboutDialogVisible" @close="$emit('close')" width="30%" center>
<div style="text-align: center;"> <div style="text-align: center;">
<h3>一款高度简洁的微信 Markdown 编辑器</h3> <h3>一款高度简洁的微信 Markdown 编辑器</h3>
</div> </div>

View File

@ -1,24 +1,24 @@
<template> <template>
<el-container class="top"> <el-container class="top is-dark">
<!-- 图片上传 --> <!-- 图片上传 -->
<el-upload class="header__item" action="https://imgkr.com/api/files/upload" <el-upload class="header__item" action="https://imgkr.com/api/files/upload"
:headers="{'Content-Type': 'multipart/form-data'}" :headers="{'Content-Type': 'multipart/form-data'}"
:show-file-list="false" :multiple="true" accept=".jpg,.jpeg,.png,.gif" name="file" :show-file-list="false" :multiple="true" accept=".jpg,.jpeg,.png,.gif" name="file"
:before-upload="beforeUpload"> :before-upload="beforeUpload">
<el-tooltip effect="dark" content="上传图片" placement="bottom-start"> <el-tooltip :effect="effect" content="上传图片" placement="bottom-start">
<i class="el-icon-upload" size="medium"></i> <i class="el-icon-upload" size="medium"></i>
</el-tooltip> </el-tooltip>
</el-upload> </el-upload>
<!-- 下载文本文档 --> <!-- 下载文本文档 -->
<el-tooltip class="header__item" effect="dark" content="下载编辑框Markdown文档" placement="bottom-start"> <el-tooltip class="header__item" :effect="effect" content="下载编辑框Markdown文档" placement="bottom-start">
<i class="el-icon-download" size="medium" @click="downloadEditorContent"></i> <i class="el-icon-download" size="medium" @click="downloadEditorContent"></i>
</el-tooltip> </el-tooltip>
<!-- 页面重置 --> <!-- 页面重置 -->
<el-tooltip class="header__item" effect="dark" content="重置页面" placement="bottom-start"> <el-tooltip class="header__item" :effect="effect" content="重置页面" placement="bottom-start">
<i class="el-icon-refresh" size="medium" @click="reset"></i> <i class="el-icon-refresh" size="medium" @click="reset"></i>
</el-tooltip> </el-tooltip>
<!-- 插入表格 --> <!-- 插入表格 -->
<el-tooltip class="header__item header__item_last" effect="dark" content="插入表格" placement="bottom-start"> <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> <i class="el-icon-s-grid" size="medium" @click="$emit('showDialogForm')"></i>
</el-tooltip> </el-tooltip>
<el-form size="mini" class="ctrl" :inline=true> <el-form size="mini" class="ctrl" :inline=true>
@ -47,19 +47,23 @@
</el-option> </el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-tooltip content="自定义颜色" placement="top"> <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>
<el-tooltip content="微信外链自动转为文末引用" placement="top"> <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 class="header__switch" v-model="citeStatus" active-color="#67c23a" inactive-color="#dcdfe6" @change="statusChanged">
</el-switch> </el-switch>
</el-tooltip> </el-tooltip>
</el-form> </el-form>
<el-tooltip class="item" effect="dark" content="自定义CSS样式" placement="left"> <el-tooltip class="item" :effect="effect" content="自定义CSS样式" placement="left">
<el-button type="success" plain size="medium" icon="el-icon-setting" @click="customStyle"></el-button> <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">复制</el-button>
<el-button :type="btnType" plain size="medium" class="about" @click="$emit('showAboutDialog')">关于</el-button>
<el-tooltip content="夜间模式" placement="bottom-start">
<div class="mode__switch" v-if="!nightMode" @click="themeChanged"></div>
<div class="mode__switch mode__switch_black" v-else @click="themeChanged"></div>
</el-tooltip> </el-tooltip>
<el-button type="success" plain size="medium" @click="copy">复制</el-button>
<el-button type="success" plain size="medium" class="about" @click="$emit('showAboutDialog')">关于</el-button>
</el-container> </el-container>
</template> </template>
@ -90,13 +94,20 @@ export default {
}; };
}, },
computed: { computed: {
effect() {
return this.nightMode ? 'dark' : 'light'
},
btnType() {
return !this.nightMode ? 'success' : 'default';
},
...mapState({ ...mapState({
output: state=> state.output, output: state=> state.output,
editor: state=> state.editor, editor: state=> state.editor,
cssEditor: state=> state.cssEditor, cssEditor: state=> state.cssEditor,
currentFont: state=> state.currentFont, currentFont: state=> state.currentFont,
currentSize: state=> state.currentSize, currentSize: state=> state.currentSize,
currentColor: state=> state.currentColor currentColor: state=> state.currentColor,
nightMode: state=> state.nightMode
}) })
}, },
methods: { methods: {
@ -228,7 +239,7 @@ export default {
downLink.click() downLink.click()
document.body.removeChild(downLink) document.body.removeChild(downLink)
}, },
...mapMutations(['clearEditorToDefault','setCurrentColor', 'setCiteStatus', ...mapMutations(['clearEditorToDefault','setCurrentColor', 'setCiteStatus', 'themeChanged',
'setHtml', 'setCurrentFont', 'setCurrentSize', 'setCssEditorValue', 'setWxRendererOptions']) 'setHtml', 'setCurrentFont', 'setCurrentSize', 'setCssEditorValue', 'setWxRendererOptions'])
}, },
mounted() { mounted() {
@ -252,4 +263,19 @@ export default {
.header__switch { .header__switch {
margin-left: 8px; margin-left: 8px;
} }
.mode__switch {
margin-left: 24px;
width: 24px;
height: 24px;
background: url('../../assets/images/night.png') no-repeat;
background-size: cover;
transition: all .3s;
}
.mode__switch_black {
background: url('../../assets/images/light.png') no-repeat;
background-size: cover;
}
.top {
margin-right: 0;
}
</style> </style>

View File

@ -1,6 +1,6 @@
<template> <template>
<el-dialog title="插入表格" :visible="dialogFormVisible" @close="$emit('close')"> <el-dialog title="插入表格" class="insert__dialog" :visible="dialogFormVisible" @close="$emit('close')">
<el-form :model="config.form"> <el-form class="insert__form" :model="config.form">
<el-form-item label="行数(表头不计入行数)"> <el-form-item label="行数(表头不计入行数)">
<el-input v-model="config.form.rows"></el-input> <el-input v-model="config.form.rows"></el-input>
</el-form-item> </el-form-item>
@ -9,8 +9,8 @@
</el-form-item> </el-form-item>
</el-form> </el-form>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button type="success" plain @click="$emit('close')"> </el-button> <el-button :type="btnType" plain @click="$emit('close')"> </el-button>
<el-button type="success" @click="insertTable"> </el-button> <el-button :type="btnType" @click="insertTable" plain> </el-button>
</div> </div>
</el-dialog> </el-dialog>
</template> </template>
@ -31,7 +31,11 @@ export default {
} }
}, },
computed: { computed: {
btnType() {
return !this.nightMode ? 'success' : 'default';
},
...mapState({ ...mapState({
nightMode: state=> state.nightMode,
editor: state=> state.editor editor: state=> state.editor
}) })
}, },

View File

@ -1,6 +1,5 @@
import Vue from 'vue' import Vue from 'vue'
import App from './App.vue' import App from './App.vue'
import router from './router'
import store from './store' import store from './store'
import ElementUI from 'element-ui' import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css' import 'element-ui/lib/theme-chalk/index.css'
@ -9,12 +8,12 @@ import 'codemirror/lib/codemirror.css';
import "codemirror/theme/ambiance.css"; import "codemirror/theme/ambiance.css";
import "codemirror/addon/hint/show-hint.css"; import "codemirror/addon/hint/show-hint.css";
import "codemirror/theme/xq-light.css"; import "codemirror/theme/xq-light.css";
import "./assets/less/theme.less";
Vue.use(ElementUI) Vue.use(ElementUI)
Vue.config.productionTip = false Vue.config.productionTip = false
new Vue({ new Vue({
router,
store, store,
render: h => h(App) render: h => h(App)
}).$mount('#app') }).$mount('#app')

View File

@ -1,29 +0,0 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
export default router

View File

@ -21,7 +21,8 @@ const state = {
currentFont: '', currentFont: '',
currentSize: '', currentSize: '',
currentColor: '', currentColor: '',
citeStatus: 0 citeStatus: 0,
nightMode: true
}; };
const mutations = { const mutations = {
setHtml(state, data) { setHtml(state, data) {
@ -52,6 +53,9 @@ const mutations = {
state.currentColor = data; state.currentColor = data;
localStorage.setItem('color', data) localStorage.setItem('color', data)
}, },
themeChanged(state) {
state.nightMode = !state.nightMode;
},
initEditorState(state) { initEditorState(state) {
state.currentFont = localStorage.getItem('fonts') || config.builtinFonts[0].value state.currentFont = localStorage.getItem('fonts') || config.builtinFonts[0].value
state.currentColor = localStorage.getItem('color') || config.colorOption[1].value state.currentColor = localStorage.getItem('color') || config.colorOption[1].value

View File

@ -1,7 +1,7 @@
<template> <template>
<div id="app" class="container"> <div class="container" :class="{'container_night': nightMode}">
<el-container> <el-container>
<el-header class="top editor__header"> <el-header class="editor__header is-dark">
<editor-header <editor-header
@refresh="onEditorRefresh" @refresh="onEditorRefresh"
@uploaded="uploaded" @uploaded="uploaded"
@ -53,9 +53,9 @@ import 'codemirror/addon/hint/css-hint.js'
import '../scripts/format.js' import '../scripts/format.js'
import fileApi from '../api/file'; import fileApi from '../api/file';
import editorHeader from './codeMirror/header'; import editorHeader from '../components/codeMirror/header';
import aboutDialog from './codeMirror/aboutDialog'; import aboutDialog from '../components/codeMirror/aboutDialog';
import insertFormDialog from './codeMirror/insertForm'; import insertFormDialog from '../components/codeMirror/insertForm';
import { import {
setFontSize, setFontSize,
css2json, css2json,
@ -93,7 +93,8 @@ export default {
cssEditor: state=> state.cssEditor, cssEditor: state=> state.cssEditor,
currentSize: state=> state.currentSize, currentSize: state=> state.currentSize,
currentColor: state=> state.currentColor, currentColor: state=> state.currentColor,
html: state=> state.html html: state=> state.html,
nightMode: state=> state.nightMode
}) })
}, },
created() { created() {
@ -207,7 +208,7 @@ export default {
}, },
// //
leftAndRightScroll() { leftAndRightScroll() {
$('div.CodeMirror-scroll, #preview').on('scroll', function callback() { $('#preview').on('scroll', function callback() {
clearTimeout(this.timeout) clearTimeout(this.timeout)
let source = $(this) let source = $(this)
@ -246,6 +247,15 @@ export default {
<style lang="less" scoped> <style lang="less" scoped>
@import url('../scripts/google-code-prettify/prettify.css'); @import url('../scripts/google-code-prettify/prettify.css');
.main-body { .main-body {
padding-top: 0; padding-top: 12px;
overflow: hidden;
}
.el-main {
transition: all .3s;
padding: 0;
margin: 20px;
}
.container {
transition: all .3s;
} }
</style> </style>

View File

@ -1,5 +0,0 @@
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>

View File

@ -1,14 +0,0 @@
<template>
<div class="home">
</div>
</template>
<script>
// @ is an alias to /src
export default {
name: 'home',
components: {
}
}
</script>