Merge pull request #1335 from hackmdio/feature/configurable-theme

Configurable editor color scheme (theme)
This commit is contained in:
Max Wu 2020-02-05 15:56:03 +08:00 committed by GitHub
commit 023161d00d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 232 additions and 27 deletions

View File

@ -0,0 +1,42 @@
/* Based on https://github.com/dempfi/ayu */
.cm-s-ayu-dark.CodeMirror { background: #0a0e14; color: #b3b1ad; }
.cm-s-ayu-dark div.CodeMirror-selected { background: #273747; }
.cm-s-ayu-dark .CodeMirror-line::selection, .cm-s-ayu-dark .CodeMirror-line > span::selection, .cm-s-ayu-dark .CodeMirror-line > span > span::selection { background: rgba(39, 55, 71, 99); }
.cm-s-ayu-dark .CodeMirror-line::-moz-selection, .cm-s-ayu-dark .CodeMirror-line > span::-moz-selection, .cm-s-ayu-dark .CodeMirror-line > span > span::-moz-selection { background: rgba(39, 55, 71, 99); }
.cm-s-ayu-dark .CodeMirror-gutters { background: #0a0e14; border-right: 0px; }
.cm-s-ayu-dark .CodeMirror-guttermarker { color: white; }
.cm-s-ayu-dark .CodeMirror-guttermarker-subtle { color: #3d424d; }
.cm-s-ayu-dark .CodeMirror-linenumber { color: #3d424d; }
.cm-s-ayu-dark .CodeMirror-cursor { border-left: 1px solid #e6b450; }
.cm-s-ayu-dark span.cm-comment { color: #626a73; }
.cm-s-ayu-dark span.cm-atom { color: #ae81ff; }
.cm-s-ayu-dark span.cm-number { color: #e6b450; }
.cm-s-ayu-dark span.cm-comment.cm-attribute { color: #ffb454; }
.cm-s-ayu-dark span.cm-comment.cm-def { color: rgba(57, 186, 230, 80); }
.cm-s-ayu-dark span.cm-comment.cm-tag { color: #39bae6; }
.cm-s-ayu-dark span.cm-comment.cm-type { color: #5998a6; }
.cm-s-ayu-dark span.cm-property, .cm-s-ayu-dark span.cm-attribute { color: #ffb454; }
.cm-s-ayu-dark span.cm-keyword { color: #ff8f40; }
.cm-s-ayu-dark span.cm-builtin { color: #e6b450; }
.cm-s-ayu-dark span.cm-string { color: #c2d94c; }
.cm-s-ayu-dark span.cm-variable { color: #b3b1ad; }
.cm-s-ayu-dark span.cm-variable-2 { color: #f07178; }
.cm-s-ayu-dark span.cm-variable-3 { color: #39bae6; }
.cm-s-ayu-dark span.cm-type { color: #ff8f40; }
.cm-s-ayu-dark span.cm-def { color: #ffee99; }
.cm-s-ayu-dark span.cm-bracket { color: #f8f8f2; }
.cm-s-ayu-dark span.cm-tag { color: rgba(57, 186, 230, 80); }
.cm-s-ayu-dark span.cm-header { color: #c2d94c; }
.cm-s-ayu-dark span.cm-link { color: #39bae6; }
.cm-s-ayu-dark span.cm-error { color: #ff3333; }
.cm-s-ayu-dark .CodeMirror-activeline-background { background: #01060e; }
.cm-s-ayu-dark .CodeMirror-matchingbracket {
text-decoration: underline;
color: white !important;
}

View File

@ -0,0 +1,43 @@
/* Based on https://github.com/dempfi/ayu */
.cm-s-ayu-mirage.CodeMirror { background: #1f2430; color: #cbccc6; }
.cm-s-ayu-mirage div.CodeMirror-selected { background: #34455a; }
.cm-s-ayu-mirage .CodeMirror-line::selection, .cm-s-ayu-mirage .CodeMirror-line > span::selection, .cm-s-ayu-mirage .CodeMirror-line > span > span::selection { background: #34455a; }
.cm-s-ayu-mirage .CodeMirror-line::-moz-selection, .cm-s-ayu-mirage .CodeMirror-line > span::-moz-selection, .cm-s-ayu-mirage .CodeMirror-line > span > span::-moz-selection { background: rgba(25, 30, 42, 99); }
.cm-s-ayu-mirage .CodeMirror-gutters { background: #1f2430; border-right: 0px; }
.cm-s-ayu-mirage .CodeMirror-guttermarker { color: white; }
.cm-s-ayu-mirage .CodeMirror-guttermarker-subtle { color: rgba(112, 122, 140, 66); }
.cm-s-ayu-mirage .CodeMirror-linenumber { color: rgba(61, 66, 77, 99); }
.cm-s-ayu-mirage .CodeMirror-cursor { border-left: 1px solid #ffcc66; }
.cm-s-ayu-mirage span.cm-comment { color: #5c6773; font-style:italic; }
.cm-s-ayu-mirage span.cm-atom { color: #ae81ff; }
.cm-s-ayu-mirage span.cm-number { color: #ffcc66; }
.cm-s-ayu-mirage span.cm-comment.cm-attribute { color: #ffd580; }
.cm-s-ayu-mirage span.cm-comment.cm-def { color: #d4bfff; }
.cm-s-ayu-mirage span.cm-comment.cm-tag { color: #5ccfe6; }
.cm-s-ayu-mirage span.cm-comment.cm-type { color: #5998a6; }
.cm-s-ayu-mirage span.cm-property { color: #f29e74; }
.cm-s-ayu-mirage span.cm-attribute { color: #ffd580; }
.cm-s-ayu-mirage span.cm-keyword { color: #ffa759; }
.cm-s-ayu-mirage span.cm-builtin { color: #ffcc66; }
.cm-s-ayu-mirage span.cm-string { color: #bae67e; }
.cm-s-ayu-mirage span.cm-variable { color: #cbccc6; }
.cm-s-ayu-mirage span.cm-variable-2 { color: #f28779; }
.cm-s-ayu-mirage span.cm-variable-3 { color: #5ccfe6; }
.cm-s-ayu-mirage span.cm-type { color: #ffa759; }
.cm-s-ayu-mirage span.cm-def { color: #ffd580; }
.cm-s-ayu-mirage span.cm-bracket { color: rgba(92, 207, 230, 80); }
.cm-s-ayu-mirage span.cm-tag { color: #5ccfe6; }
.cm-s-ayu-mirage span.cm-header { color: #bae67e; }
.cm-s-ayu-mirage span.cm-link { color: #5ccfe6; }
.cm-s-ayu-mirage span.cm-error { color: #ff3333; }
.cm-s-ayu-mirage .CodeMirror-activeline-background { background: #191e2a; }
.cm-s-ayu-mirage .CodeMirror-matchingbracket {
text-decoration: underline;
color: white !important;
}

View File

@ -0,0 +1,35 @@
/*
Name: Tomorrow Night - Bright
Author: Chris Kempson
Port done by Gerard Braad <me@gbraad.nl>
*/
.cm-s-tomorrow-night-bright.CodeMirror { background: #000000; color: #eaeaea; }
.cm-s-tomorrow-night-bright div.CodeMirror-selected { background: #424242; }
.cm-s-tomorrow-night-bright .CodeMirror-gutters { background: #000000; border-right: 0px; }
.cm-s-tomorrow-night-bright .CodeMirror-guttermarker { color: #e78c45; }
.cm-s-tomorrow-night-bright .CodeMirror-guttermarker-subtle { color: #777; }
.cm-s-tomorrow-night-bright .CodeMirror-linenumber { color: #424242; }
.cm-s-tomorrow-night-bright .CodeMirror-cursor { border-left: 1px solid #6A6A6A; }
.cm-s-tomorrow-night-bright span.cm-comment { color: #d27b53; }
.cm-s-tomorrow-night-bright span.cm-atom { color: #a16a94; }
.cm-s-tomorrow-night-bright span.cm-number { color: #a16a94; }
.cm-s-tomorrow-night-bright span.cm-property, .cm-s-tomorrow-night-bright span.cm-attribute { color: #99cc99; }
.cm-s-tomorrow-night-bright span.cm-keyword { color: #d54e53; }
.cm-s-tomorrow-night-bright span.cm-string { color: #e7c547; }
.cm-s-tomorrow-night-bright span.cm-variable { color: #b9ca4a; }
.cm-s-tomorrow-night-bright span.cm-variable-2 { color: #7aa6da; }
.cm-s-tomorrow-night-bright span.cm-def { color: #e78c45; }
.cm-s-tomorrow-night-bright span.cm-bracket { color: #eaeaea; }
.cm-s-tomorrow-night-bright span.cm-tag { color: #d54e53; }
.cm-s-tomorrow-night-bright span.cm-link { color: #a16a94; }
.cm-s-tomorrow-night-bright span.cm-error { background: #d54e53; color: #6A6A6A; }
.cm-s-tomorrow-night-bright .CodeMirror-activeline-background { background: #2a2a2a; }
.cm-s-tomorrow-night-bright .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }

View File

@ -0,0 +1,38 @@
/*
Name: Tomorrow Night - Eighties
Author: Chris Kempson
CodeMirror template by Jan T. Sott (https://github.com/idleberg/base16-codemirror)
Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16)
*/
.cm-s-tomorrow-night-eighties.CodeMirror { background: #000000; color: #CCCCCC; }
.cm-s-tomorrow-night-eighties div.CodeMirror-selected { background: #2D2D2D; }
.cm-s-tomorrow-night-eighties .CodeMirror-line::selection, .cm-s-tomorrow-night-eighties .CodeMirror-line > span::selection, .cm-s-tomorrow-night-eighties .CodeMirror-line > span > span::selection { background: rgba(45, 45, 45, 0.99); }
.cm-s-tomorrow-night-eighties .CodeMirror-line::-moz-selection, .cm-s-tomorrow-night-eighties .CodeMirror-line > span::-moz-selection, .cm-s-tomorrow-night-eighties .CodeMirror-line > span > span::-moz-selection { background: rgba(45, 45, 45, 0.99); }
.cm-s-tomorrow-night-eighties .CodeMirror-gutters { background: #000000; border-right: 0px; }
.cm-s-tomorrow-night-eighties .CodeMirror-guttermarker { color: #f2777a; }
.cm-s-tomorrow-night-eighties .CodeMirror-guttermarker-subtle { color: #777; }
.cm-s-tomorrow-night-eighties .CodeMirror-linenumber { color: #515151; }
.cm-s-tomorrow-night-eighties .CodeMirror-cursor { border-left: 1px solid #6A6A6A; }
.cm-s-tomorrow-night-eighties span.cm-comment { color: #d27b53; }
.cm-s-tomorrow-night-eighties span.cm-atom { color: #a16a94; }
.cm-s-tomorrow-night-eighties span.cm-number { color: #a16a94; }
.cm-s-tomorrow-night-eighties span.cm-property, .cm-s-tomorrow-night-eighties span.cm-attribute { color: #99cc99; }
.cm-s-tomorrow-night-eighties span.cm-keyword { color: #f2777a; }
.cm-s-tomorrow-night-eighties span.cm-string { color: #ffcc66; }
.cm-s-tomorrow-night-eighties span.cm-variable { color: #99cc99; }
.cm-s-tomorrow-night-eighties span.cm-variable-2 { color: #6699cc; }
.cm-s-tomorrow-night-eighties span.cm-def { color: #f99157; }
.cm-s-tomorrow-night-eighties span.cm-bracket { color: #CCCCCC; }
.cm-s-tomorrow-night-eighties span.cm-tag { color: #f2777a; }
.cm-s-tomorrow-night-eighties span.cm-link { color: #a16a94; }
.cm-s-tomorrow-night-eighties span.cm-error { background: #f2777a; color: #6A6A6A; }
.cm-s-tomorrow-night-eighties .CodeMirror-activeline-background { background: #343600; }
.cm-s-tomorrow-night-eighties .CodeMirror-matchingbracket { text-decoration: underline; color: white !important; }

View File

@ -0,0 +1,15 @@
export const availableThemes = [
{ name: 'Light', value: 'default' },
{ name: 'One Dark (Default)', value: 'one-dark' },
{ name: 'Monokai', value: 'monokai' },
{ name: 'Solarized Dark', value: 'solarized dark' },
{ name: 'Solarized Light', value: 'solarized light' },
{ name: 'Dracula', value: 'dracula' },
{ name: 'Material', value: 'material' },
{ name: 'Nord', value: 'nord' },
{ name: 'Panda', value: 'panda-syntax' },
{ name: 'Ayu Dark', value: 'ayu-dark' },
{ name: 'Ayu Mirage', value: 'ayu-mirage' },
{ name: 'Tomorror Night Bright', value: 'tomorrow-night-bright' },
{ name: 'Tomorror Night Eighties', value: 'tomorrow-night-eighties' }
]

View File

@ -1,11 +1,14 @@
/* global CodeMirror, $, editor, Cookies */
import { options, Alignment, FormatType } from '@susisu/mte-kernel'
import debounce from 'lodash/debounce'
import * as utils from './utils'
import config from './config'
import statusBarTemplate from './statusbar.html'
import toolBarTemplate from './toolbar.html'
import './markdown-lint'
import { initTableEditor } from './table-editor'
import { options, Alignment, FormatType } from '@susisu/mte-kernel'
import { availableThemes } from './constants'
/* config section */
const isMac = CodeMirror.keyMap.default === CodeMirror.keyMap.macDefault
@ -325,6 +328,8 @@ export default class Editor {
this.setSpellcheck()
this.setLinter()
this.setPreferences()
this.handleStatusBarResize()
}
updateStatusBar () {
@ -349,6 +354,21 @@ export default class Editor {
}
}
handleStatusBarResize () {
const onResize = debounce(() => {
if (!this.statusBar) {
return
}
const maxHeight = window.innerHeight - this.statusBar.height() - 50 /* navbar height */ - 10 /* spacing */
this.statusBar.find('.status-theme ul.dropdown-menu').css('max-height', `${maxHeight}px`)
}, 300)
$(window).resize(onResize)
onResize()
}
setIndent () {
var cookieIndentType = Cookies.get('indent_type')
var cookieTabSize = parseInt(Cookies.get('tab_size'))
@ -488,38 +508,37 @@ export default class Editor {
}
setTheme () {
var cookieTheme = Cookies.get('theme')
if (cookieTheme) {
this.editor.setOption('theme', cookieTheme)
this.statusIndicators.find('.status-theme ul.dropdown-menu').append(availableThemes.map(theme => {
return $(`<li value="${theme.value}"><a>${theme.name}</a></li>`)
}))
const activateThemeListItem = (theme) => {
this.statusIndicators.find('.status-theme li').removeClass('active')
this.statusIndicators.find(`.status-theme li[value="${theme}"]`).addClass('active')
}
var themeToggle = this.statusTheme.find('.ui-theme-toggle')
const checkTheme = () => {
var theme = this.editor.getOption('theme')
if (theme === 'one-dark') {
themeToggle.removeClass('active')
} else {
themeToggle.addClass('active')
}
}
themeToggle.click(() => {
var theme = this.editor.getOption('theme')
if (theme === 'one-dark') {
theme = 'default'
} else {
theme = 'one-dark'
}
const setTheme = theme => {
this.editor.setOption('theme', theme)
Cookies.set('theme', theme, {
expires: 365
})
this.statusIndicators.find('.status-theme li').removeClass('active')
this.statusIndicators.find(`.status-theme li[value="${theme}"]`).addClass('active')
}
checkTheme()
const cookieTheme = Cookies.get('theme')
if (cookieTheme && availableThemes.find(theme => cookieTheme === theme.value)) {
setTheme(cookieTheme)
activateThemeListItem(cookieTheme)
} else {
activateThemeListItem(this.editor.getOption('theme'))
}
this.statusIndicators.find('.status-theme li').click(function () {
const theme = $(this).attr('value')
setTheme(theme)
activateThemeListItem(theme)
})
checkTheme()
}
setSpellcheck () {

View File

@ -31,8 +31,12 @@
<div class="indent-width-label" title="Click to change indentation size">4</div>
<input class="indent-width-input hidden" type="number" min="1" max="10" maxlength="2" size="2">
</div>
<div class="status-theme">
<a class="ui-theme-toggle" title="Toggle editor theme"><i class="fa fa-sun-o fa-fw"></i></a>
<div class="status-theme dropup">
<a id="themeLabel" class="ui-theme-label text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Select theme">
<i class="fa fa-paint-brush fa-fw"></i>
</a>
<ul class="dropdown-menu" aria-labelledby="themeLabel" style="overflow: auto;">
</ul>
</div>
<div class="status-spellcheck">
<a class="ui-spellcheck-toggle" title="Toggle spellcheck"><i class="fa fa-check fa-fw"></i></a>

View File

@ -222,6 +222,15 @@ module.exports = {
path.join(__dirname, 'node_modules/@hackmd/codemirror/addon/search/matchesonscrollbar.css'),
path.join(__dirname, 'node_modules/@hackmd/codemirror/theme/monokai.css'),
path.join(__dirname, 'node_modules/@hackmd/codemirror/theme/one-dark.css'),
path.join(__dirname, 'node_modules/@hackmd/codemirror/theme/dracula.css'),
path.join(__dirname, 'node_modules/@hackmd/codemirror/theme/material.css'),
path.join(__dirname, 'node_modules/@hackmd/codemirror/theme/nord.css'),
path.join(__dirname, 'node_modules/@hackmd/codemirror/theme/panda-syntax.css'),
path.join(__dirname, 'node_modules/@hackmd/codemirror/theme/solarized.css'),
path.join(__dirname, 'public/css/codemirror-extend/ayu-dark.css'),
path.join(__dirname, 'public/css/codemirror-extend/ayu-mirage.css'),
path.join(__dirname, 'public/css/codemirror-extend/tomorrow-night-bright.css'),
path.join(__dirname, 'public/css/codemirror-extend/tomorrow-night-eighties.css'),
path.join(__dirname, 'node_modules/@hackmd/codemirror/mode/tiddlywiki/tiddlywiki.css'),
path.join(__dirname, 'node_modules/@hackmd/codemirror/mode/mediawiki/mediawiki.css'),
path.join(__dirname, 'public/css/github-extract.css'),