opti: rewrite TOC and remove hard code theme (#778)

* opti: prevent the duplicated header text error

* scroll error in toc

* delay the change event when init muya, so that the change event listener can handle change event.

* opti: style

* almost finished need last check

* style in table

* clear up some unused codes

* clear up theme hard code

* add no search data picture and new Folder new File

* move search and replace to top of editor

* add: no data image when there is no TOC

* update structure

* little bug fix

* update styles

* update un_draw icons

* update style of editor

* add animation when make open folder collapse.

* remove theme props in editor component, deprecated lightColor and darkColor

* add Ulysses Light

* theme: graphite

* update Ulysses blockquote

* update emoji style

* update titleBar height

* change theme color

* Support macOs dark mode

* update style of tooltip in editor

* update styles

* fix: TOC auto expand all

* patch added
This commit is contained in:
Ran Luo 2019-03-24 05:09:00 +08:00 committed by GitHub
parent 07d0bbb249
commit e1cfec6e3e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
60 changed files with 1368 additions and 1578 deletions

View File

@ -88,7 +88,8 @@
] ]
}, },
"mac": { "mac": {
"icon": "resources/icons/icon.icns" "icon": "resources/icons/icon.icns",
"darkModeSupport": true
}, },
"win": { "win": {
"icon": "resources/icons/icon.ico", "icon": "resources/icons/icon.ico",
@ -143,7 +144,7 @@
"chokidar": "^2.1.2", "chokidar": "^2.1.2",
"codemirror": "^5.44.0", "codemirror": "^5.44.0",
"command-exists": "^1.2.8", "command-exists": "^1.2.8",
"diacritics-map": "^0.1.0", "dayjs": "^1.8.10",
"dompurify": "^1.0.10", "dompurify": "^1.0.10",
"electron-is-accelerator": "^0.1.2", "electron-is-accelerator": "^0.1.2",
"element-resize-detector": "^1.2.0", "element-resize-detector": "^1.2.0",

View File

@ -1,10 +1,12 @@
import path from 'path' import path from 'path'
import { app } from 'electron' import { app, systemPreferences } from 'electron'
import appWindow from './window' import appWindow from './window'
import { isOsx } from './config' import { isOsx } from './config'
import { dockMenu } from './menus' import { dockMenu } from './menus'
import { isDirectory, isMarkdownFile } from './utils' import { isDirectory, isMarkdownFile, getMenuItemById } from './utils'
import { watchers } from './utils/imagePathAutoComplement' import { watchers } from './utils/imagePathAutoComplement'
import { selectTheme } from './actions/theme'
import preference from './preference'
class App { class App {
constructor () { constructor () {
@ -22,12 +24,12 @@ class App {
app.commandLine.appendSwitch('remote-debugging-port', '8315') app.commandLine.appendSwitch('remote-debugging-port', '8315')
} }
app.on('open-file', this.openFile.bind(this)) app.on('open-file', this.openFile)
app.on('ready', this.ready.bind(this)) app.on('ready', this.ready)
app.on('window-all-closed', () => { app.on('window-all-closed', () => {
app.removeListener('open-file', this.openFile.bind(this)) app.removeListener('open-file', this.openFile)
// close all the image path watcher // close all the image path watcher
for (const watcher of watchers.values()) { for (const watcher of watchers.values()) {
watcher.close() watcher.close()
@ -63,7 +65,7 @@ class App {
}) })
} }
ready () { ready = () => {
if (!isOsx && process.argv.length >= 2) { if (!isOsx && process.argv.length >= 2) {
for (const arg of process.argv) { for (const arg of process.argv) {
if (arg.startsWith('--')) { if (arg.startsWith('--')) {
@ -79,6 +81,32 @@ class App {
// Set dock on macOS // Set dock on macOS
if (process.platform === 'darwin') { if (process.platform === 'darwin') {
app.dock.setMenu(dockMenu) app.dock.setMenu(dockMenu)
// listen for system theme change and change Mark Text own `dark` and `light`,
// In macOS 10.14 Mojave,
// Apple introduced a new system-wide dark mode for all macOS computers.
systemPreferences.subscribeNotification(
'AppleInterfaceThemeChangedNotification',
() => {
const { theme } = preference.getAll()
let setedTheme = null
if (systemPreferences.isDarkMode() && theme !== 'dark') {
selectTheme('dark')
setedTheme = 'dark'
}
if (!systemPreferences.isDarkMode() && theme === 'dark') {
selectTheme('light')
setedTheme = 'light'
}
if (setedTheme) {
const themeMenu = getMenuItemById('themeMenu')
const menuItem = themeMenu.submenu.items.filter(item => (item.id === setedTheme))[0]
if (menuItem) {
menuItem.checked = true
}
}
}
)
} }
if (this.openFilesCache.length) { if (this.openFilesCache.length) {
@ -89,7 +117,7 @@ class App {
} }
} }
openFile (event, path) { openFile = (event, path) => {
const { openFilesCache } = this const { openFilesCache } = this
event.preventDefault() event.preventDefault()
if (app.isReady()) { if (app.isReady()) {

View File

@ -15,7 +15,7 @@ export const defaultWinOptions = {
useContentSize: true, useContentSize: true,
show: false, show: false,
frame: false, frame: false,
titleBarStyle: 'hidden' titleBarStyle: 'hiddenInset'
} }
export const EXTENSIONS = [ export const EXTENSIONS = [

View File

@ -5,19 +5,38 @@ const { theme } = userPreference.getAll()
export default { export default {
label: 'Theme', label: 'Theme',
id: 'themeMenu',
submenu: [{ submenu: [{
label: 'Dark', label: 'Mateial Dark',
type: 'radio', type: 'radio',
id: 'dark',
checked: theme === 'dark', checked: theme === 'dark',
click (menuItem, browserWindow) { click (menuItem, browserWindow) {
actions.selectTheme('dark') actions.selectTheme('dark')
} }
}, { }, {
label: 'Light', label: 'Cadmium Light',
type: 'radio', type: 'radio',
id: 'light',
checked: theme === 'light', checked: theme === 'light',
click (menuItem, browserWindow) { click (menuItem, browserWindow) {
actions.selectTheme('light') actions.selectTheme('light')
} }
}, {
label: 'Ulysses Light',
type: 'radio',
id: 'ulysses',
checked: theme === 'ulysses',
click (menuItem, browserWindow) {
actions.selectTheme('ulysses')
}
}, {
label: 'Graphite Light',
type: 'radio',
id: 'graphite',
checked: theme === 'graphite',
click (menuItem, browserWindow) {
actions.selectTheme('graphite')
}
}] }]
} }

View File

@ -1,22 +1,3 @@
/* Common CSS use by both light and dark themes */
:root {
--brandColor: #5b3cc4;
--successColor: rgb(23, 201, 100);
--warningColor: rgb(255, 130, 0);
--dangerColor: rgb(242, 19, 93);
--activeColor: #409eff;
--infoColor: #909399;
--primaryColor: #303133;
--regularColor: #606266;
--secondaryColor: #909399;
--placeholerColor: #C0C4CC;
--baseBorder: #DCDFE6;
--lightBorder: #E4E7ED;
--lighterBorder: #EBEEF5;
--extraLightBorder: #F2F6FC;
--editorAreaWidth: 700px;
}
html { html {
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
} }
@ -54,14 +35,14 @@ pre {
top: 0; top: 0;
left: -25px; left: -25px;
font-size: 14px; font-size: 14px;
color: var(--secondaryColor); color: var(--iconColor);
font-weight: 400; font-weight: 400;
font-style: italic; font-style: italic;
} }
div.ag-show-quick-insert-hint p.ag-paragraph.ag-active > span.ag-line:first-of-type:empty::after { div.ag-show-quick-insert-hint p.ag-paragraph.ag-active > span.ag-line:first-of-type:empty::after {
content: 'Type @ to insert'; content: 'Type @ to insert';
color: var(--placeholerColor); color: var(--editorColor10);
} }
.ag-paragraph:empty::after, .ag-paragraph:empty::after,
@ -81,7 +62,7 @@ div.ag-show-quick-insert-hint p.ag-paragraph.ag-active > span.ag-line:first-of-t
.ag-reference-marker { .ag-reference-marker {
font-size: .9em; font-size: .9em;
color: var(--secondaryColor); color: var(--editorColor10);
} }
.ag-reference-title { .ag-reference-title {
@ -94,19 +75,14 @@ div.ag-show-quick-insert-hint p.ag-paragraph.ag-active > span.ag-line:first-of-t
margin: 0 5px; margin: 0 5px;
} }
/* .ag-soft-line-break::after {
content: '↓';
opacity: .5;
} */
.ag-hard-line-break::after { .ag-hard-line-break::after {
content: '↩'; content: '↩';
opacity: .5; opacity: .5;
} }
*:not(.ag-hide)::selection, .ag-selection { *:not(.ag-hide)::selection, .ag-selection {
background: var(--baseBorder); background: var(--selectionColor);
color: var(--primaryColor); color: var(--editorColor);
} }
.ag-hide::selection { .ag-hide::selection {
@ -149,19 +125,18 @@ div.ag-function-html.ag-active .ag-html-preview {
animation-name: highlight; animation-name: highlight;
animation-duration: .25s; animation-duration: .25s;
display: inline-block; display: inline-block;
background: rgb(249, 226, 153); background: var(--highlightColor);
color: var(--primaryColor);
} }
span.ag-html-tag { span.ag-html-tag {
color: var(--secondaryColor); color: var(--editorColor50);
font-weight: 200; font-weight: 200;
font-family: monospace; font-family: monospace;
} }
span.ag-math { span.ag-math {
position: relative; position: relative;
color: rebeccapurple; color: var(--editorColor);
font-family: monospace; font-family: monospace;
display: inline-block; display: inline-block;
vertical-align: bottom; vertical-align: bottom;
@ -179,7 +154,7 @@ span.ag-math {
div.ag-empty { div.ag-empty {
text-align: center; text-align: center;
color: var(--regularColor); color: var(--editorColor50);
font-size: 14px; font-size: 14px;
font-style: italic; font-style: italic;
font-family: monospace; font-family: monospace;
@ -187,7 +162,7 @@ div.ag-empty {
div.ag-math-error, div.ag-math-error,
span.ag-math > .ag-math-render.ag-math-error { span.ag-math > .ag-math-render.ag-math-error {
color: var(--warningColor); color: var(--deleteColor);
font-size: 14px; font-size: 14px;
font-style: italic; font-style: italic;
font-family: monospace; font-family: monospace;
@ -268,11 +243,10 @@ figure {
display: flex; display: flex;
width: 20px; width: 20px;
height: 20px; height: 20px;
padding: 2px;
margin-right: 3px; margin-right: 3px;
cursor: pointer; cursor: pointer;
border-radius: 3px; border-radius: 3px;
color: var(--regularColor); color: var(--iconColor);
} }
.ag-tool-bar ul li[data-label=delete] { .ag-tool-bar ul li[data-label=delete] {
@ -281,23 +255,18 @@ figure {
} }
.ag-tool-bar ul li[data-label=delete] { .ag-tool-bar ul li[data-label=delete] {
color: var(--dangerColor); color: var(--deleteColor);
right: 0; right: 0;
} }
.ag-tool-bar ul li.active svg { .ag-tool-bar ul li.active svg {
fill: #409eff; fill: var(--themeColor);
} }
.ag-tool-bar ul li svg { .ag-tool-bar ul li svg {
width: 100%; width: 100%;
height: 100%; height: 100%;
will-change: transform; will-change: transform;
transition: transform .2s ease-in-out;
}
.ag-tool-bar ul li:hover svg {
transform: scale(1.1);
} }
figure.ag-active .ag-tool-bar { figure.ag-active .ag-tool-bar {
@ -313,7 +282,7 @@ figure.ag-active[data-role=HTML]::before {
top: 0; top: 0;
left: -45px; left: -45px;
font-size: 12px; font-size: 12px;
color: var(--secondaryColor); color: var(--editorColor50);
font-weight: 400; font-weight: 400;
font-style: italic; font-style: italic;
} }
@ -345,66 +314,56 @@ li.ag-task-list-item {
li.ag-task-list-item > input[type=checkbox] { li.ag-task-list-item > input[type=checkbox] {
position: absolute; position: absolute;
cursor: pointer; cursor: pointer;
width: 16px; width: 10px;
height: 16px; height: 10px;
margin: 4px 0px 0px; top: 5px;
top: 0;
left: -22px; left: -22px;
transform-origin: center; transform-origin: center;
transform: rotate(-90deg);
transition: all .2s ease; transition: all .2s ease;
} }
li.ag-task-list-item > input.ag-checkbox-checked {
transform: rotate(0);
}
li.ag-task-list-item > input.ag-checkbox-checked ~ * { li.ag-task-list-item > input.ag-checkbox-checked ~ * {
color: var(--regularColor); color: var(--editorColor50);
} }
li.ag-task-list-item > input.ag-checkbox-checked ~ p { li.ag-task-list-item > input.ag-checkbox-checked ~ p {
text-decoration: line-through; text-decoration: line-through;
color: var(--secondaryColor); color: var(--editorColor50);
} }
li.ag-task-list-item > input[type=checkbox]::before { li.ag-task-list-item > input[type=checkbox]::before {
content: ''; content: '';
width: 16px; width: 14px;
height: 16px; height: 14px;
box-sizing: border-box; box-sizing: border-box;
display: inline-block; display: inline-block;
border: 2px solid var(--infoColor); border: 1px solid var(--iconColor);
border-radius: 2px; border-radius: 50%;
background-color: #fff; background-color: var(--editorBgColor);
position: absolute; position: absolute;
top: 0; top: -2px;
left: 0; left: -2px;
transition: all .2s ease; transition: all .2s ease;
} }
li.ag-task-list-item > input.ag-checkbox-checked::before {
border: transparent;
background-color: var(--activeColor);
}
li.ag-task-list-item > input::after { li.ag-task-list-item > input::after {
content: ''; content: '';
transform: rotate(-45deg) scale(0); transform: rotate(-28deg) skew(0, -25deg) scale(0);
width: 9px; width: 8px;
height: 5px; height: 4px;
border: 2px solid #fff; border: 1px solid var(--iconColor);
border-top: none; border-top: none;
border-right: none; border-right: none;
position: absolute; position: absolute;
display: inline-block; display: inline-block;
top: 3px; top: 0px;
left: 3px; left: 2px;
transform-origin: bottom;
transition: all .2s ease; transition: all .2s ease;
} }
li.ag-task-list-item > input.ag-checkbox-checked::after { li.ag-task-list-item > input.ag-checkbox-checked::after {
transform: rotate(-45deg) scale(1); transform: rotate(-28deg) skew(0, -25deg) scale(1);
} }
/* li p .ag-hide:first-child { /* li p .ag-hide:first-child {
@ -419,8 +378,8 @@ p:not(.ag-active)[data-role="hr"] {
p:not(.ag-active)[data-role="hr"]::before { p:not(.ag-active)[data-role="hr"]::before {
content: ''; content: '';
width: 100%; width: 100%;
height: 5px; height: 2px;
background: gainsboro; background: var(--editorColor10);
position: absolute; position: absolute;
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
@ -433,7 +392,7 @@ p:not(.ag-active)[data-role="hr"] * {
pre.ag-multiple-math, pre.ag-multiple-math,
pre.ag-front-matter { pre.ag-front-matter {
position: relative; position: relative;
background: #f6f8fa; background: var(--selectionColor);
padding: .5rem; padding: .5rem;
border: 5px; border: 5px;
font-size: 14px; font-size: 14px;
@ -445,17 +404,17 @@ pre.ag-front-matter {
pre.ag-front-matter span.ag-code-line:first-of-type:empty::after { pre.ag-front-matter span.ag-code-line:first-of-type:empty::after {
content: 'Input YAML Front Matter...'; content: 'Input YAML Front Matter...';
color: var(--placeholerColor); color: var(--editorColor10);
} }
pre[data-role$='code'] span.ag-language-input:empty::after { pre[data-role$='code'] span.ag-language-input:empty::after {
content: 'Input Language...'; content: 'Input Language...';
color: var(--placeholerColor); color: var(--editorColor10);
} }
pre.ag-multiple-math span.ag-code-line:first-of-type:empty::after { pre.ag-multiple-math span.ag-code-line:first-of-type:empty::after {
content: 'Input Mathematical Formula...'; content: 'Input Mathematical Formula...';
color: var(--placeholerColor); color: var(--editorColor10);
} }
figure, figure,
@ -545,7 +504,7 @@ pre.ag-active.ag-indent-code::before,
pre.ag-active.ag-indent-code::after, pre.ag-active.ag-indent-code::after,
pre.ag-active.ag-multiple-math::before, pre.ag-active.ag-multiple-math::before,
pre.ag-active.ag-multiple-math::after { pre.ag-active.ag-multiple-math::after {
color: var(--regularColor); color: var(--editorColor30);
font-family: monospace; font-family: monospace;
position: absolute; position: absolute;
font-weight: 600; font-weight: 600;
@ -574,11 +533,6 @@ pre.ag-active.ag-indent-code::after {
bottom: -23px; bottom: -23px;
} }
span.ag-multiple-math-line {
color: purple;
font-family: monospace;
}
figure.ag-container-block div.ag-container-preview { figure.ag-container-block div.ag-container-preview {
width: 100%; width: 100%;
text-align: center; text-align: center;
@ -593,8 +547,8 @@ figure.ag-active.ag-container-block > div.ag-container-preview {
z-index: 10000; z-index: 10000;
transform: translateX(-50%); transform: translateX(-50%);
padding: .5rem; padding: .5rem;
background: #fff; background: var(--floatBgColor);
border: 1px solid var(--lightBorder); border: 1px solid var(--floatBorderColor);
border-radius: 4px; border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1); box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .1);
} }
@ -614,7 +568,7 @@ hr {
span.ag-emoji-marked-text { span.ag-emoji-marked-text {
position: relative; position: relative;
color: var(--regularColor); color: var(--themeColor);
text-decoration: none; text-decoration: none;
} }
@ -632,14 +586,14 @@ span.ag-emoji-marked-text {
.ag-emoji-marked-text::before { .ag-emoji-marked-text::before {
position: absolute; position: absolute;
content: attr(data-emoji); content: attr(data-emoji);
color: #000; color: var(--editorColor);
top: -6px; top: -6px;
left: -1.1em; left: -1.1em;
font-size: 1.5em; font-size: 1em;
} }
.ag-hide.ag-emoji-marked-text::before { .ag-hide.ag-emoji-marked-text::before {
top: -19px; top: -15px;
} }
.ag-html-escape { .ag-html-escape {
@ -653,7 +607,7 @@ span.ag-emoji-marked-text {
top: -2px; top: -2px;
left: -1rem; left: -1rem;
width: 1rem; width: 1rem;
color: var(--secondaryColor); color: var(--editorColor30);
height: 100%; height: 100%;
display: flex; display: flex;
justify-content: space-around; justify-content: space-around;
@ -670,14 +624,14 @@ span.ag-emoji-marked-text {
font-size: 14px; font-size: 14px;
font-family: monospace; font-family: monospace;
font-weight: 600; font-weight: 600;
color: var(--activeColor); color: var(--themeColor);
background: transparent; background: transparent;
border: none; border: none;
z-index: 10; z-index: 10;
} }
.ag-language-input::placeholder { .ag-language-input::placeholder {
color: var(--placeholerColor); color: var(--editorColor10);
} }
pre.ag-active .ag-language-input { pre.ag-active .ag-language-input {
@ -685,14 +639,14 @@ pre.ag-active .ag-language-input {
} }
.ag-language { .ag-language {
color: var(--activeColor); color: var(--themeColor);
font-weight: 600; font-weight: 600;
text-decoration: none; text-decoration: none;
font-family: monospace; font-family: monospace;
} }
span.ag-image-marked-text, span.ag-link-in-bracket, span.ag-link-in-bracket .ag-backlash { span.ag-image-marked-text, span.ag-link-in-bracket, span.ag-link-in-bracket .ag-backlash {
color: var(--regularColor); color: var(--editorColor50);
font-size: 16px; font-size: 16px;
text-decoration: none; text-decoration: none;
font-family: monospace; font-family: monospace;
@ -703,7 +657,7 @@ span.ag-image-marked-text, span.ag-link-in-bracket, span.ag-link-in-bracket .ag-
color: rgb(51, 51, 51); color: rgb(51, 51, 51);
} }
span.ag-warn.ag-emoji-marked-text { span.ag-warn.ag-emoji-marked-text {
color: var(--warningColor); color: var(--deleteColor);
text-decoration: none; text-decoration: none;
} }
@ -735,12 +689,12 @@ span.ag-warn.ag-emoji-marked-text {
} }
span[data-role="link"], a[data-role="link"], span[data-role="link"] .ag-backlash { span[data-role="link"], a[data-role="link"], span[data-role="link"] .ag-backlash {
color: #0366d6; color: var(--themeColor);
text-decoration: none; text-decoration: none;
} }
span.ag-reference-link { span.ag-reference-link {
color: var(--warningColor); color: var(--deleteColor);
} }
.ag-focus-mode p.ag-paragraph, .ag-focus-mode p.ag-paragraph,

View File

@ -218,7 +218,6 @@ export const EXPORT_DOMPURIFY_CONFIG = {
export const MUYA_DEFAULT_OPTION = { export const MUYA_DEFAULT_OPTION = {
focusMode: false, focusMode: false,
theme: 'light',
markdown: '', markdown: '',
preferLooseListItem: true, preferLooseListItem: true,
autoPairBracket: true, autoPairBracket: true,

View File

@ -22,6 +22,7 @@ import imagePathCtrl from './imagePathCtrl'
import htmlBlockCtrl from './htmlBlock' import htmlBlockCtrl from './htmlBlock'
import clickCtrl from './clickCtrl' import clickCtrl from './clickCtrl'
import inputCtrl from './inputCtrl' import inputCtrl from './inputCtrl'
import tocCtrl from './tocCtrl'
import importMarkdown from '../utils/importMarkdown' import importMarkdown from '../utils/importMarkdown'
const prototypes = [ const prototypes = [
@ -44,6 +45,7 @@ const prototypes = [
htmlBlockCtrl, htmlBlockCtrl,
clickCtrl, clickCtrl,
inputCtrl, inputCtrl,
tocCtrl,
importMarkdown importMarkdown
] ]

View File

@ -0,0 +1,24 @@
const tocCtrl = ContentState => {
ContentState.prototype.getTOC = function () {
const { blocks } = this
const toc = []
for (const block of blocks) {
if (/^h\d$/.test(block.type)) {
const { headingStyle, text, key, type } = block
const content = headingStyle === 'setext' ? text.trim() : text.replace(/^ *#{1,6} {1,}/, '').trim()
const lvl = +type.substring(1)
const slug = key
toc.push({
content,
lvl,
slug
})
}
}
return toc
}
}
export default tocCtrl

View File

@ -18,9 +18,8 @@ class Muya {
} }
constructor (container, options) { constructor (container, options) {
this.options = Object.assign({}, MUYA_DEFAULT_OPTION, options) this.options = Object.assign({}, MUYA_DEFAULT_OPTION, options)
const { focusMode, theme, markdown } = this.options const { focusMode, markdown } = this.options
this.focusMode = focusMode this.focusMode = focusMode
this.theme = theme
this.markdown = markdown this.markdown = markdown
this.container = getContainer(container, this.options) this.container = getContainer(container, this.options)
this.eventCenter = new EventCenter() this.eventCenter = new EventCenter()
@ -42,7 +41,7 @@ class Muya {
init () { init () {
const { container, contentState, eventCenter } = this const { container, contentState, eventCenter } = this
contentState.stateRender.setContainer(container.children[0]) contentState.stateRender.setContainer(container.children[0])
eventCenter.subscribe('stateChange', this.dispatchChange.bind(this)) eventCenter.subscribe('stateChange', this.dispatchChange)
eventCenter.attachDOMEvent(container, 'contextmenu', event => { eventCenter.attachDOMEvent(container, 'contextmenu', event => {
event.preventDefault() event.preventDefault()
event.stopPropagation() event.stopPropagation()
@ -61,19 +60,19 @@ class Muya {
eventCenter.dispatch('contextmenu', event, sectionChanges) eventCenter.dispatch('contextmenu', event, sectionChanges)
}) })
contentState.listenForPathChange() contentState.listenForPathChange()
const { theme, focusMode, markdown } = this const { focusMode, markdown } = this
this.setTheme(theme)
this.setMarkdown(markdown) this.setMarkdown(markdown)
this.setFocusMode(focusMode) this.setFocusMode(focusMode)
} }
dispatchChange () { dispatchChange = () => {
const { eventCenter } = this const { eventCenter } = this
const markdown = this.markdown = this.getMarkdown() const markdown = this.markdown = this.getMarkdown()
const wordCount = this.getWordCount(markdown) const wordCount = this.getWordCount(markdown)
const cursor = this.getCursor() const cursor = this.getCursor()
const history = this.getHistory() const history = this.getHistory()
eventCenter.dispatch('change', { markdown, wordCount, cursor, history }) const toc = this.getTOC()
eventCenter.dispatch('change', { markdown, wordCount, cursor, history, toc })
} }
getMarkdown () { getMarkdown () {
@ -85,6 +84,10 @@ class Muya {
return this.contentState.getHistory() return this.contentState.getHistory()
} }
getTOC () {
return this.contentState.getTOC()
}
setHistory (history) { setHistory (history) {
return this.contentState.setHistory(history) return this.contentState.setHistory(history)
} }
@ -119,7 +122,9 @@ class Muya {
this.contentState.importMarkdown(newMarkdown) this.contentState.importMarkdown(newMarkdown)
this.contentState.importCursor(cursor) this.contentState.importCursor(cursor)
this.contentState.render(isRenderCursor) this.contentState.render(isRenderCursor)
this.dispatchChange() setTimeout(() => {
this.dispatchChange()
}, 0)
} }
createTable (tableChecker) { createTable (tableChecker) {
@ -140,16 +145,6 @@ class Muya {
this.focusMode = bool this.focusMode = bool
} }
setTheme (name) {
if (!name) return
const { eventCenter } = this
this.theme = name
// Render cursor and refresh code block
this.contentState.render(true)
// notice the ui components to change theme
eventCenter.dispatch('theme-change', name)
}
setFont ({ fontSize, lineHeight }) { setFont ({ fontSize, lineHeight }) {
if (fontSize) this.contentState.fontSize = parseInt(fontSize, 10) if (fontSize) this.contentState.fontSize = parseInt(fontSize, 10)
if (lineHeight) this.contentState.lineHeight = lineHeight if (lineHeight) this.contentState.lineHeight = lineHeight

View File

@ -1,8 +1,7 @@
import katex from 'katex' import katex from 'katex'
import mermaid from 'mermaid' import mermaid from 'mermaid'
import prism, { loadedCache } from '../../../prism/' import prism, { loadedCache } from '../../../prism/'
import { slugify } from '../../../utils/dirtyToc' import { CLASS_OR_ID, DEVICE_MEMORY, PREVIEW_DOMPURIFY_CONFIG, HAS_TEXT_BLOCK_REG } from '../../../config'
import { CLASS_OR_ID, DEVICE_MEMORY, isInElectron, PREVIEW_DOMPURIFY_CONFIG, HAS_TEXT_BLOCK_REG } from '../../../config'
import { tokenizer } from '../../parse' import { tokenizer } from '../../parse'
import { snakeToCamel, sanitize, escapeHtml, getLongUniqueId, getImageInfo } from '../../../utils' import { snakeToCamel, sanitize, escapeHtml, getLongUniqueId, getImageInfo } from '../../../utils'
import { h, htmlToVNode } from '../snabbdom' import { h, htmlToVNode } from '../snabbdom'
@ -199,8 +198,7 @@ export default function renderLeafBlock (block, cursor, activeBlocks, matches, u
// TODO: This should be the best place to create and update the TOC. // TODO: This should be the best place to create and update the TOC.
// Cache `block.key` and title and update only if necessary. // Cache `block.key` and title and update only if necessary.
Object.assign(data.dataset, { Object.assign(data.dataset, {
head: type, head: type
id: isInElectron ? slugify(text.replace(/^#+\s(.*)/, (_, p1) => p1)) : ''
}) })
selector += `.${headingStyle}` selector += `.${headingStyle}`
} }

View File

@ -7,9 +7,9 @@
top: -1000px; top: -1000px;
right: -1000px; right: -1000px;
border-radius: 8px; border-radius: 8px;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.1); box-shadow: 0 4px 8px 0 var(--floatBorderColor);
border: 1px solid rgba(0, 0, 0, 0.1); border: 1px solid var(--floatBorderColor);
background-color: #ffffff; background-color: var(--floatBgColor);
transition: opacity .25s ease-in-out; transition: opacity .25s ease-in-out;
transform-origin: top; transform-origin: top;
box-sizing: border-box; box-sizing: border-box;
@ -17,11 +17,6 @@
overflow: hidden; overflow: hidden;
} }
.ag-float-wrapper.dark {
background: var(--primaryColor);
border-color: var(--primaryColor);
}
.ag-float-container::-webkit-scrollbar:vertical { .ag-float-container::-webkit-scrollbar:vertical {
width: 0px; width: 0px;
} }
@ -40,10 +35,6 @@
transform: rotate(45deg); transform: rotate(45deg);
} }
.dark[x-placement] .ag-popper-arrow {
border-color: var(--primaryColor);
}
[x-placement="bottom-start"] > .ag-popper-arrow { [x-placement="bottom-start"] > .ag-popper-arrow {
border-right: none; border-right: none;
border-bottom: none; border-bottom: none;

View File

@ -88,16 +88,6 @@ class BaseFloat {
} }
} }
const themeChange = theme => {
const { container, floatBox } = this
;[container, floatBox].forEach(ele => {
if (!ele.classList.contains(theme)) {
ele.classList.remove(theme === 'dark' ? 'light' : 'dark')
ele.classList.add(theme)
}
})
}
eventCenter.attachDOMEvent(document, 'click', this.hide.bind(this)) eventCenter.attachDOMEvent(document, 'click', this.hide.bind(this))
eventCenter.attachDOMEvent(floatBox, 'click', event => { eventCenter.attachDOMEvent(floatBox, 'click', event => {
event.stopPropagation() event.stopPropagation()
@ -105,7 +95,6 @@ class BaseFloat {
}) })
eventCenter.attachDOMEvent(container, 'keydown', keydownHandler) eventCenter.attachDOMEvent(container, 'keydown', keydownHandler)
eventCenter.attachDOMEvent(container, 'scroll', scrollHandler) eventCenter.attachDOMEvent(container, 'scroll', scrollHandler)
eventCenter.subscribe('theme-change', themeChange)
} }
hide () { hide () {

View File

@ -20,11 +20,14 @@
.ag-list-picker:hover .active { .ag-list-picker:hover .active {
background: transparent; background: transparent;
color: #606266;
} }
.ag-list-picker .item .language {
color: var(--editorColor);
}
.ag-list-picker .active, .ag-list-picker .item:hover { .ag-list-picker .active, .ag-list-picker .item:hover {
background-color: #ecf5ff; background-color: var(--floatHoverColor);
color: var(--activeColor);
} }
.ag-list-picker .item .icon-wrapper { .ag-list-picker .item .icon-wrapper {
@ -48,13 +51,4 @@
font-size: 14px; font-size: 14px;
line-height: 35px; line-height: 35px;
margin-left: 10px; margin-left: 10px;
}
.ag-list-picker.dark:hover .active {
background: transparent;
color: currentColor;
}
.ag-list-picker.dark .active, .ag-list-picker.dark .item:hover {
background-color: rgb(71, 72, 66);
color: var(--activeColor);
} }

View File

@ -6,7 +6,7 @@
} }
.ag-emoji-picker .title { .ag-emoji-picker .title {
color: rgba(55, 53, 47, 0.6); color: var(--editorColor);
line-height: 120%; line-height: 120%;
font-size: 11px; font-size: 11px;
padding: 10px 14px 12px 14px; padding: 10px 14px 12px 14px;
@ -16,7 +16,7 @@
font-weight: 600; font-weight: 600;
position: sticky; position: sticky;
top: 0; top: 0;
background: #fff; background: var(--floatBgColor);
z-index: 1001; z-index: 1001;
} }
@ -44,8 +44,7 @@
} }
.ag-emoji-picker .active, .ag-emoji-picker .item:hover { .ag-emoji-picker .active, .ag-emoji-picker .item:hover {
background-color: #ecf5ff; background-color: var(--floatHoverColor);
border: 1px solid var(--activeColor);
} }
.ag-emoji-picker section .emoji-wrapper .item span { .ag-emoji-picker section .emoji-wrapper .item span {
@ -58,23 +57,4 @@
transition: transform .2s ease-in; transition: transform .2s ease-in;
transform-origin: center; transform-origin: center;
} }
.ag-emoji-picker .active span, .ag-emoji-picker .item:hover span {
transform: scale(1.1);
}
.ag-emoji-picker.dark .title {
background: var(--primaryColor);
color: var(--placeholerColor);
}
.ag-emoji-picker.dark:hover .active {
background: transparent;
border-color: transparent;
}
.ag-emoji-picker.dark .active, .ag-emoji-picker.dark .item:hover {
background-color: rgb(72, 71, 66);
border: 1px solid var(--primaryColor);
}

View File

@ -26,7 +26,7 @@
} }
.ag-format-picker li.item:hover { .ag-format-picker li.item:hover {
background: rgb(243, 243, 243); background: var(--floatHoverColor);
} }
.ag-format-picker li.item:last-of-type { .ag-format-picker li.item:last-of-type {
@ -38,29 +38,20 @@
width: 2px; width: 2px;
position: absolute; position: absolute;
height: 18px; height: 18px;
background: #eee; background: var(--editorColor10);
left: -4px; left: -4px;
top: 6px; top: 6px;
} }
.ag-format-picker li.item svg { .ag-format-picker li.item svg {
fill: #666; fill: var(--iconColor);
} }
.ag-format-picker li.item.active svg { .ag-format-picker li.item.active svg {
fill: var(--activeColor); fill: var(--themeColor);
} }
.ag-format-picker li.item .icon-wrapper { .ag-format-picker li.item .icon-wrapper {
width: 16px; width: 16px;
height: 16px; height: 16px;
}
/* dark theme */
.ag-format-picker.dark li.item:hover {
background: rgb(60, 60, 60);
}
.ag-format-picker.dark li.item:last-of-type:before {
background: rgb(71, 71, 71);
} }

View File

@ -6,7 +6,7 @@
} }
.ag-quick-insert .title { .ag-quick-insert .title {
color: rgba(0, 0, 0, .6); color: var(--editorColor);
line-height: 120%; line-height: 120%;
font-size: 14px; font-size: 14px;
padding: 10px 14px 10px 14px; padding: 10px 14px 10px 14px;
@ -15,7 +15,7 @@
letter-spacing: 1px; letter-spacing: 1px;
position: sticky; position: sticky;
top: 0; top: 0;
background: #fff; background: var(--floatBgColor);
z-index: 1001; z-index: 1001;
} }
@ -32,20 +32,21 @@
} }
.ag-quick-insert .active, .ag-quick-insert .active,
.ag-quick-insert div.item:hover { .ag-quick-insert div.item:hover {
background-color: rgba(0, 0, 0, .04); background-color: var(--floatHoverColor);
} }
.ag-quick-insert .no-result { .ag-quick-insert .no-result {
margin-top: 20px; margin-top: 20px;
padding: 0 20px; padding: 0 20px;
font-size: 14px; font-size: 14px;
color: #999; text-align: center;
color: var(--themeColor);
} }
.ag-quick-insert .icon-container { .ag-quick-insert .icon-container {
width: 40px; width: 40px;
height: 40px; height: 40px;
border: 1px solid rgb(0, 0, 0, .1); border: 1px solid var(--floatBorderColor);
display: flex; display: flex;
justify-content: space-around; justify-content: space-around;
align-items: center; align-items: center;
@ -57,7 +58,7 @@
width: 20px; width: 20px;
height: 20px; height: 20px;
opacity: .6; opacity: .6;
fill: rgba(0, 0, 0, .6); fill: var(--iconColor);
} }
.ag-quick-insert .description { .ag-quick-insert .description {
@ -70,49 +71,21 @@
margin-right: 20px; margin-right: 20px;
flex-shrink: 1; flex-shrink: 1;
text-align: right; text-align: right;
color: rgba(0, 0, 0, .3); color: var(--editorColor50);
font-size: 14px; font-size: 14px;
letter-spacing: 1px; letter-spacing: 1px;
} }
.ag-quick-insert .big-title { .ag-quick-insert .big-title {
font-size: 14px; font-size: 14px;
color: rgba(0, 0, 0, .6); color: var(--editorColor);
} }
.ag-quick-insert .sub-title { .ag-quick-insert .sub-title {
font-size: 12px; font-size: 12px;
color: rgba(0, 0, 0, .4); color: var(--editorColor50);
} }
.ag-quick-insert .hide { .ag-quick-insert .hide {
display: none; display: none;
} }
.ag-quick-insert.dark .title {
background: var(--primaryColor);
color: var(--placeholerColor);
}
.ag-quick-insert.dark .big-title {
color: var(--lightBorder);
}
.ag-quick-insert.dark .sub-title {
color: rgba(255, 255, 255, .6);
}
.ag-quick-insert.dark .active,
.ag-quick-insert.dark div.item:hover {
background-color: rgb(71, 72, 66);
}
.ag-quick-insert.dark .icon-container > svg {
fill: rgba(255, 255, 255, .5);
}
.ag-quick-insert.dark .short-cut {
color: rgba(255, 255, 255, .5);
}

View File

@ -19,46 +19,54 @@
box-sizing: border-box; box-sizing: border-box;
margin-right: 1px; margin-right: 1px;
margin-bottom: 1px; margin-bottom: 1px;
border: 1px solid #ccc; border: 1px solid var(--editorColor10);
cursor: pointer; cursor: pointer;
} }
.ag-table-picker-header span { .ag-table-picker-header span {
background: #ddd; background: var(--editorColor10);
} }
.ag-table-picker-cell.current { .ag-table-picker-cell.current {
background: darkgray; background: var(--editorColor30);
} }
.ag-table-picker-header .current { .ag-table-picker-header .current {
background: #666; background: var(--editorColor50);
} }
.ag-table-picker-cell.selected { .ag-table-picker-cell.selected {
background: #ecf5ff; background: var(--selectionColor);
} }
.ag-table-picker-header .selected { .ag-table-picker-header .selected {
background: #ecf5ff; background: var(--selectionColor);
} }
.ag-table-picker-cell:last-of-type { .ag-table-picker-cell:last-of-type {
margin-right: 0; margin-right: 0;
} }
.ag-table-picker .footer { .ag-table-picker .footer {
padding-top: 5px; padding: 10px 0 0 0;
border-top: 1px solid #ccc; border-top: 1px solid var(--floatBorderColor);
text-align: center; text-align: center;
display: flex;
justify-content: space-around;
} }
.ag-table-picker .footer input { .ag-table-picker .footer input {
color: var(--editorColor);
background: var(--floatBorderColor);
outline: none;
border-radius: 3px;
text-align: center; text-align: center;
border: none; border: none;
box-sizing: border-box;
padding: 0; padding: 0;
height: 16px; height: 20px;
width: 16px; width: 30px;
border: none;
} }
.ag-table-picker .footer button { .ag-table-picker .footer button {
outline: none; outline: none;
cursor: pointer; cursor: pointer;
border-radius: 2px; border-radius: 3px;
line-height: 12px; line-height: 20px;
border: none; border: none;
height: 16px; height: 20px;
background: #409eff; background: var(--themeColor);
color: #fff; color: #fff;
} }

View File

@ -4,8 +4,11 @@
font-size: 12px; font-size: 12px;
padding: 5px 7px; padding: 5px 7px;
border-radius: 3px; border-radius: 3px;
background: rgb(50, 50, 50); background: var(--floatBgColor);
color: rgb(255, 255, 255); color: var(--editorColor);
box-shadow: 0 4px 8px 0 var(--floatBorderColor);
border: 1px solid var(--floatBorderColor);
box-sizing: border-box;
z-index: 1000; z-index: 1000;
opacity: 0; opacity: 0;
} }
@ -16,10 +19,13 @@
} }
.ag-tooltip:after { .ag-tooltip:after {
top: 0; top: -2px;
left: 50%; left: 50%;
content: ''; content: '';
background: inherit; background: inherit;
border: 1px solid var(--floatBorderColor);
border-right: none;
border-bottom: none;
width: 8px; width: 8px;
height: 8px; height: 8px;
position: absolute; position: absolute;

View File

@ -6,7 +6,7 @@ const position = (source, ele) => {
Object.assign(ele.style, { Object.assign(ele.style, {
top: `${top + height + 10}px`, top: `${top + height + 10}px`,
left: `${right - ele.offsetWidth / 2 - 3}px` left: `${right - ele.offsetWidth / 2 - 5}px`
}) })
} }

View File

@ -1,39 +0,0 @@
import { Lexer } from '../parser/marked'
import diacritics from 'diacritics-map'
export const getTocFromMarkdown = markdown => {
const tokens = new Lexer({ disableInline: true }).lex(markdown)
const toc = []
let token = null
while ((token = tokens.shift())) {
switch (token.type) {
case 'heading': {
const { depth, text } = token
toc.push({
content: text,
lvl: depth,
slug: slugify(text)
})
break
}
}
}
return toc
}
export const slugify = str => {
str = str.replace(/^\s+|\s+$/g, '').toLowerCase()
// replace accents
str = str.replace(/[À-ž]/g, c => {
return diacritics[c] || c
})
return str
.replace(/[^a-z0-9 -]/g, '') // remove invalid chars
.replace(/\t/g, '--') // collapse tabs and replace by --
.replace(/\s+/g, '-') // collapse whitespace and replace by -
.replace(/^-+/, '') // trim - from start of text
.replace(/-+$/, '') // trim - from end of text
.replace(/-+/g, '-') // collapse dashes
}

View File

@ -1,633 +0,0 @@
/*
* Open Sans
* https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i&subset=latin-ext
*/
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 300;
src: local('Open Sans Light'), local('OpenSans-Light'),
url('./fonts/open-sans-v15-latin_latin-ext-300.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 300;
src: local('Open Sans Light Italic'), local('OpenSans-LightItalic'),
url('./fonts/open-sans-v15-latin_latin-ext-300italic.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: local('Open Sans Regular'), local('OpenSans-Regular'),
url('./fonts/open-sans-v15-latin_latin-ext-regular.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 400;
src: local('Open Sans Italic'), local('OpenSans-Italic'),
url('./fonts/open-sans-v15-latin_latin-ext-italic.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 600;
src: local('Open Sans SemiBold'), local('OpenSans-SemiBold'),
url('./fonts/open-sans-v15-latin_latin-ext-600.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 600;
src: local('Open Sans SemiBold Italic'), local('OpenSans-SemiBoldItalic'),
url('./fonts/open-sans-v15-latin_latin-ext-600italic.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
src: local('Open Sans Bold'), local('OpenSans-Bold'),
url('./fonts/open-sans-v15-latin_latin-ext-700.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 700;
src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'),
url('./fonts/open-sans-v15-latin_latin-ext-700italic.woff') format('woff');
}
/*
* DejaVu Sans Mono
*/
@font-face {
font-family: "DejaVu Sans Mono";
src: local('DejaVu Sans Mono'), url('./fonts/DejaVuSansMono.ttf');
}
@font-face {
font-family: "DejaVu Sans Mono";
font-weight: bold;
src: url('./fonts/DejaVuSansMono-Bold.ttf');
}
@font-face {
font-family: "DejaVu Sans Mono";
font-style: oblique;
font-weight: bold;
src: url('./fonts/DejaVuSansMono-BoldOblique.ttf');
}
@font-face {
font-family: "DejaVu Sans Mono";
font-style: italic;
font-weight: bold;
src: url('./fonts/DejaVuSansMono-BoldOblique.ttf');
}
@font-face {
font-family: "DejaVu Sans Mono";
font-style: italic;
src: url('./fonts/DejaVuSansMono-Oblique.ttf');
}
@font-face {
font-family: "DejaVu Sans Mono";
font-style: oblique;
src: url('./fonts/DejaVuSansMono-Oblique.ttf');
}
html, body {
font-family: "Open Sans", "Clear Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 16px;
color: rgb(217, 217, 217);
line-height: 1.6;
background: rgb(45, 45, 45);
}
span code,
td code,
th code,
code,
code[class*="language-"],
.CodeMirror,
pre.ag-paragraph {
font-family: "DejaVu Sans Mono", "Source Code Pro", "Droid Sans Mono", Consolas, monospace;
font-size: 14px;
}
::-webkit-scrollbar {
background: rgb(43, 43, 43);
}
::-webkit-scrollbar:vertical {
width: 12px;
}
::-webkit-scrollbar-thumb {
background: rgb(55, 55, 55);
}
::-webkit-scrollbar-thumb:hover {
background: #3F3F3F;
}
#ag-editor-id {
max-width: var(--editorAreaWidth);
margin: 0 auto;
padding: 20px 50px 40px 50px;
padding-top: 20px;
padding-bottom: 100px;
}
#ag-editor-id, [contenteditable] {
outline: none;
caret-color: #efefef;
}
.ag-float-box {
background: #303133;
border: 1px solid #303133;
}
.ag-float-item {
color: #909399;
}
.ag-float-item-active {
background: #606266;
color: #C0C4CC;
}
.ag-table-picker {
background: #606266;
border: 1px solid #606266;
}
[x-placement] > .ag-popper-arrow {
border: 1px solid #606266;
border-right: none;
border-bottom: none;
}
figure.ag-active.ag-container-block > div.ag-container-preview {
background: rgb(50, 50, 50);
border: 1px solid rgb(43, 43, 43);
}
.ag-gray {
color: #909399;
text-decoration: none;
}
.el-dialog {
background: rgb(43, 43, 43);
}
.v-modal {
backdrop-filter: blur(5px);
background: rgba(0, 0, 0, .9);
}
body > *:first-child {
margin-top: 0 !important;
}
body>*:last-child {
margin-bottom: 0 !important;
}
a {
color: #4183C4;
}
h1,
h2,
h3,
h4,
h5,
h6 {
position: relative;
margin-top: 1rem;
margin-bottom: 1rem;
font-weight: bold;
line-height: 1.4;
cursor: text;
}
h1:hover a.anchor,
h2:hover a.anchor,
h3:hover a.anchor,
h4:hover a.anchor,
h5:hover a.anchor,
h6:hover a.anchor {
/*background: url("../../images/modules/styleguide/para.png") no-repeat 10px center;*/
text-decoration: none;
}
h1 tt,
h1 code {
font-size: inherit;
}
h2 tt,
h2 code {
font-size: inherit;
}
h3 tt,
h3 code {
font-size: inherit;
}
h4 tt,
h4 code {
font-size: inherit;
}
h5 tt,
h5 code {
font-size: inherit;
}
h6 tt,
h6 code {
font-size: inherit;
}
h1 {
padding-bottom: .3em;
font-size: 2.25em;
line-height: 1.2;
border-bottom: 1px solid #eee;
}
h2 {
padding-bottom: .3em;
font-size: 1.75em;
line-height: 1.225;
border-bottom: 1px solid #eee;
}
h3 {
font-size: 1.5em;
line-height: 1.43;
}
h4 {
font-size: 1.25em;
}
h5 {
font-size: 1em;
}
h6 {
font-size: 1em;
color: #777;
}
p,
blockquote,
ul,
ol,
dl,
table {
margin: 0.5em 0;
}
li>ol,
li>ul {
margin: 0 0;
}
hr {
height: 4px;
padding: 0;
margin: 16px 0;
background-color: #545454;
border: 0 none;
overflow: hidden;
box-sizing: content-box;
}
p:not(.ag-active)[data-role="hr"]::before {
background-color: #545454;
}
body>h2:first-child {
margin-top: 0;
padding-top: 0;
}
body>h1:first-child {
margin-top: 0;
padding-top: 0;
}
body>h1:first-child+h2 {
margin-top: 0;
padding-top: 0;
}
body>h3:first-child,
body>h4:first-child,
body>h5:first-child,
body>h6:first-child {
margin-top: 0;
padding-top: 0;
}
a:first-child h1,
a:first-child h2,
a:first-child h3,
a:first-child h4,
a:first-child h5,
a:first-child h6 {
margin-top: 0;
padding-top: 0;
}
h1 p,
h2 p,
h3 p,
h4 p,
h5 p,
h6 p {
margin-top: 0;
}
li p.first {
display: inline-block;
}
li.ag-tight-list-item > p {
padding: 0;
margin: 0;
}
ul,
ol {
padding-left: 30px;
}
ul:first-child,
ol:first-child {
margin-top: 0;
}
ul:last-child,
ol:last-child {
margin-bottom: 0;
}
blockquote {
border-left: 4px solid #606266;
padding: 0 15px;
color: #999999;
}
blockquote blockquote {
padding-right: 0;
}
table {
padding: 0;
word-break: initial;
}
table tr {
margin: 0;
padding: 0;
}
table thead tr,
table tr:nth-child(2n) {
background-color: #303133;
}
table tr th {
font-weight: bold;
border: 2px solid #606266;
text-align: left;
margin: 0;
padding: 6px 13px;
}
table tr td {
border: 1px solid #606266;
text-align: left;
margin: 0;
padding: 6px 13px;
}
table tr th:first-child,
table tr td:first-child {
margin-top: 0;
}
table tr th:last-child,
table tr td:last-child {
margin-bottom: 0;
}
/* custom add */
span.ag-line code,
th code,
td code {
border: none;
padding: 2px 4px;
border-radius: 3px;
font-size: 90%;
color: #efefef;
background-color: #606266;
border-radius: 4px;
/*font-family: Menlo, Monaco, Consolas, "Courier New", monospace;*/
}
@media print {
html {
font-size: 13px;
}
table,
pre {
page-break-inside: avoid;
}
pre {
word-wrap: break-word;
}
}
.ag-hide.ag-math > .ag-math-render {
color: #efefef;
}
blockquote .ag-hide.ag-math > .ag-math-render {
color: #999999;
}
.ag-gray.ag-math > .ag-math-render {
color: #333333;
background: #f6f8fa;
box-shadow: 0 2px 12px 0 rgba(255, 255, 255, 0.3);
}
.ag-gray.ag-math > .ag-math-render::before {
border-bottom-color: #f6f8fa;
}
#ag-editor-id pre.ag-html-block {
padding: 0 .5rem;
margin-top: 0;
}
#ag-editor-id pre.ag-front-matter {
background: transparent;
border-bottom: 1px dashed #efefef;
}
#ag-editor-id pre.ag-multiple-math {
background: transparent;
border: 1px solid #909399;
}
#ag-editor-id span.ag-math-text,
#ag-editor-id pre.ag-multiple-math span.ag-multiple-math-line {
color: lightsalmon;
}
#ag-editor-id div.ag-math-preview {
background: #303133;
border-color: #333;
}
#ag-editor-id pre.ag-html-block {
font-size: 90%;
line-height: 1.6;
background: var(--primaryColor);
color: #777777;
}
.ag-color-dark {
color: #c6c6c6;
}
/**
* okaidia theme for JavaScript, CSS and HTML
* Loosely based on Monokai textmate theme by http://www.monokai.nl/
* @author ocodia
*/
code[class*="language-"],
pre.ag-paragraph {
color: #f8f8f2;
/*font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;*/
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
overflow: visible;
}
/* Code blocks */
pre.ag-paragraph {
padding: 1em;
margin: 1em 0;
border-radius: 0.3em;
}
:not(pre) > code[class*="language-"],
pre.ag-paragraph {
background: #272822;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #f8f8f2;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.constant,
.token.symbol {
color: #f92672;
}
.token.boolean,
.token.number {
color: #ae81ff;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin {
color: #a6e22e;
}
.token.inserted {
color: #22863a;
background: #f0fff4;
}
.token.deleted {
color: #b31d28;
background: #ffeef0;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string,
.token.variable {
color: #f8f8f2;
}
.token.atrule,
.token.attr-value,
.token.function,
.token.class-name {
color: #e6db74;
}
.token.keyword {
color: #66d9ef;
}
.token.regex,
.token.important {
color: #fd971f;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}

View File

@ -99,7 +99,6 @@ html, body {
font-size: 16px; font-size: 16px;
color: #303133; color: #303133;
line-height: 1.6; line-height: 1.6;
background: rgb(252, 252, 252);
} }
span code, span code,
@ -113,19 +112,6 @@ pre.ag-paragraph {
font-size: 14px; font-size: 14px;
} }
::-webkit-scrollbar {
background: rgb(252, 252, 252);
}
::-webkit-scrollbar:vertical {
width: 12px;
}
::-webkit-scrollbar-thumb {
background: #EBEEF5;
}
::-webkit-scrollbar-thumb:hover {
background: #E1E4EA;
}
#ag-editor-id { #ag-editor-id {
max-width: var(--editorAreaWidth); max-width: var(--editorAreaWidth);
margin: 0 auto; margin: 0 auto;
@ -136,17 +122,16 @@ pre.ag-paragraph {
#ag-editor-id, [contenteditable] { #ag-editor-id, [contenteditable] {
outline: none; outline: none;
caret-color: #000000;
} }
.ag-gray { .ag-gray {
color: #C0C4CC; color: var(--editorColor30);
text-decoration: none; text-decoration: none;
} }
.v-modal { .v-modal {
backdrop-filter: blur(5px); backdrop-filter: blur(5px);
background: rgba(230, 230, 230, .9); background: var(--floatBorderColor);
} }
body>*:first-child { body>*:first-child {
@ -158,7 +143,7 @@ body>*:last-child {
} }
a { a {
color: #4183C4; color: var(--themeColor);
} }
h1, h1,
@ -216,35 +201,27 @@ h6 code {
} }
h1 { h1 {
padding-bottom: .3em; font-size: 40px;
font-size: 2.25em;
line-height: 1.2;
border-bottom: 1px solid #eee;
} }
h2 { h2 {
padding-bottom: .3em; font-size: 32px;
font-size: 1.75em;
line-height: 1.225;
border-bottom: 1px solid #eee;
} }
h3 { h3 {
font-size: 1.5em; font-size: 28px;
line-height: 1.43;
} }
h4 { h4 {
font-size: 1.25em; font-size: 24px;
} }
h5 { h5 {
font-size: 1em; font-size: 20px;
} }
h6 { h6 {
font-size: 1em; font-size: 16px;
color: #777;
} }
p, p,
@ -271,10 +248,6 @@ hr {
box-sizing: content-box; box-sizing: content-box;
} }
p:not(.ag-active)[data-role="hr"]::before {
background: gainsboro;
}
body>h2:first-child { body>h2:first-child {
margin-top: 0; margin-top: 0;
padding-top: 0; padding-top: 0;
@ -317,6 +290,14 @@ h6 p {
margin-top: 0; margin-top: 0;
} }
li.ag-paragraph {
color: var(--themeColor);
}
li > * {
color: var(--editorColor);
}
li p.first { li p.first {
display: inline-block; display: inline-block;
} }
@ -342,9 +323,20 @@ ol:last-child {
} }
blockquote { blockquote {
border-left: 4px solid #dddddd; position: relative;
padding: 0 15px; padding: 0 30px;
color: #777777; color: var(--editorColor50);
}
blockquote::before {
content: '';
display: block;
height: 100%;
width: 2px;
position: absolute;
left: 13px;
top: 0;
background: var(--themeColor);
} }
blockquote blockquote { blockquote blockquote {
@ -363,19 +355,19 @@ table tr {
table thead tr, table thead tr,
table tr:nth-child(2n) { table tr:nth-child(2n) {
background-color: #fafafa; background-color: var(--codeBlockBgColor);
} }
table tr th { table tr th {
font-weight: bold; font-weight: bold;
border: 1px solid #ebeef5; border: 1px solid var(--editorColor10);
text-align: left; text-align: left;
margin: 0; margin: 0;
padding: 6px 13px; padding: 6px 13px;
} }
table tr td { table tr td {
border: 1px solid #ebeef5; border: 1px solid var(--editorColor10);
text-align: left; text-align: left;
margin: 0; margin: 0;
padding: 6px 13px; padding: 6px 13px;
@ -394,7 +386,7 @@ table tr td:last-child {
span code, span code,
td code, td code,
th code { th code {
background-color: rgba(27, 31, 35, 0.05); background-color: var(--codeBlockBgColor);
border-radius: 3px; border-radius: 3px;
padding: 0; padding: 0;
/*font-family: Menlo, Monaco, Consolas, "Courier New", monospace;*/ /*font-family: Menlo, Monaco, Consolas, "Courier New", monospace;*/
@ -402,7 +394,7 @@ th code {
font-size: 85%; font-size: 85%;
margin: 0; margin: 0;
padding: 0.2em 0.4em; padding: 0.2em 0.4em;
color: #24292e; color: var(--editorColor);
} }
:not(pre) > code[class*="language-"], :not(pre) > code[class*="language-"],
@ -411,10 +403,10 @@ pre[class*="language-"] {
overflow: visible; overflow: visible;
font-size: 90%; font-size: 90%;
line-height: 1.6; line-height: 1.6;
background: #f6f8fa; background: var(--codeBlockBgColor);
border: 0; border: 0;
border-radius: 3px; border-radius: 3px;
color: #777777; color: var(--editorColor50);
} }
@media print { @media print {
@ -431,20 +423,20 @@ pre[class*="language-"] {
} }
.ag-hide.ag-math > .ag-math-render { .ag-hide.ag-math > .ag-math-render {
color: #333333; color: var(--editorColor);
} }
blockquote .ag-hide.ag-math > .ag-math-render { blockquote .ag-hide.ag-math > .ag-math-render {
color: #777777; color: var(--editorColor50);
} }
.ag-gray.ag-math > .ag-math-render { .ag-gray.ag-math > .ag-math-render {
color: #f6f8fa; color: var(--editorColor);
background: #333333; background: var(--floatBgColor);
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.3); box-shadow: 0 4px 8px 0 var(--floatBorderColor);
} }
.ag-gray.ag-math > .ag-math-render::before { .ag-gray.ag-math > .ag-math-render::before {
border-bottom-color: #333333; border-bottom-color: var(--floatBgColor);
} }
#ag-editor-id pre.ag-html-block { #ag-editor-id pre.ag-html-block {
@ -454,15 +446,7 @@ blockquote .ag-hide.ag-math > .ag-math-render {
} }
#ag-editor-id pre.ag-active.ag-html-block { #ag-editor-id pre.ag-active.ag-html-block {
background: #f6f8fa; background: var(--codeBlockBgColor);
}
p:not(.ag-active)[data-role="hr"]::before {
background: gainsboro;
}
.fg-color-dark {
color: #303133;
} }
/* prismjs default theme */ /* prismjs default theme */

View File

@ -2,18 +2,17 @@
<div <div
class="editor-container" class="editor-container"
> >
<title-bar <side-bar></side-bar>
:project="projectTree"
:pathname="pathname"
:filename="filename"
:active="windowActive"
:word-count="wordCount"
:theme="theme"
:platform="platform"
:is-saved="isSaved"
></title-bar>
<div class="editor-middle"> <div class="editor-middle">
<side-bar></side-bar> <title-bar
:project="projectTree"
:pathname="pathname"
:filename="filename"
:active="windowActive"
:word-count="wordCount"
:platform="platform"
:is-saved="isSaved"
></title-bar>
<recent <recent
v-if="!hasCurrentFile && init" v-if="!hasCurrentFile && init"
></recent> ></recent>
@ -22,34 +21,28 @@
:markdown="markdown" :markdown="markdown"
:filename="filename" :filename="filename"
:cursor="cursor" :cursor="cursor"
:theme="theme"
:source-code="sourceCode" :source-code="sourceCode"
:show-tab-bar="showTabBar" :show-tab-bar="showTabBar"
:text-direction="textDirection" :text-direction="textDirection"
></editor-with-tabs> ></editor-with-tabs>
<aidou></aidou>
<upload-image></upload-image>
<about-dialog></about-dialog>
<font></font>
<rename></rename>
<tweet></tweet>
<import-modal></import-modal>
</div> </div>
<bottom-bar
:source-code="sourceCode"
:theme="theme"
></bottom-bar>
<aidou></aidou>
<upload-image></upload-image>
<about-dialog></about-dialog>
<font></font>
<rename></rename>
<tweet></tweet>
<import-modal></import-modal>
</div> </div>
</template> </template>
<script> <script>
import { remote } from 'electron' import { remote } from 'electron'
import { addStyles } from '@/util/theme' import { addStyles, addThemeStyle } from '@/util/theme'
import Recent from '@/components/recent' import Recent from '@/components/recent'
import EditorWithTabs from '@/components/editorWithTabs' import EditorWithTabs from '@/components/editorWithTabs'
import TitleBar from '@/components/titleBar' import TitleBar from '@/components/titleBar'
import SideBar from '@/components/sideBar' import SideBar from '@/components/sideBar'
import BottomBar from '@/components/bottomBar'
import Aidou from '@/components/aidou/aidou' import Aidou from '@/components/aidou/aidou'
import UploadImage from '@/components/uploadImage' import UploadImage from '@/components/uploadImage'
import AboutDialog from '@/components/about' import AboutDialog from '@/components/about'
@ -69,7 +62,6 @@
EditorWithTabs, EditorWithTabs,
TitleBar, TitleBar,
SideBar, SideBar,
BottomBar,
UploadImage, UploadImage,
AboutDialog, AboutDialog,
Font, Font,
@ -104,6 +96,13 @@
return this.markdown !== undefined return this.markdown !== undefined
} }
}, },
watch: {
theme: function (value, oldValue) {
if (value !== oldValue) {
addThemeStyle(value)
}
}
},
created () { created () {
const { dispatch } = this.$store const { dispatch } = this.$store
// store/index.js // store/index.js
@ -182,7 +181,15 @@
<style scoped> <style scoped>
.editor-container { .editor-container {
padding-top: var(--titleBarHeight); display: flex;
flex-direction: row;
position: absolute;
width: 100vw;
height: 100vh;
top: 0;
left: 0;
right: 0;
bottom: 0;
} }
.editor-container .hide { .editor-container .hide {
z-index: -1; z-index: -1;
@ -192,7 +199,9 @@
} }
.editor-middle { .editor-middle {
display: flex; display: flex;
min-height: calc(100vh - var(--titleBarHeight)); flex: 1;
min-height: 100vh;
position: relative;
& > .editor { & > .editor {
flex: 1; flex: 1;
} }

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 48 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 34 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 19 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -1,19 +1,62 @@
/* Common CSS use by both light and dark themes */
:root { :root {
--primary: #409eff; --titleBarHeight: 32px;
--info: #909399;
--warning: rgb(255, 130, 0);
--error: rgb(242, 19, 93);
--lightBarColor: rgb(245, 245, 245);
--lightTabColor: rgb(243, 243, 243);
--darkBgColor: rgb(45, 45, 45);
--darkInputBgColor: rgb(54, 55, 49);
--darkInputColor: rgb(255, 255, 255);
--darkHoverColor: rgb(70, 70, 70);
--titleBarHeight: 25px;
--editorAreaWidth: 700px; --editorAreaWidth: 700px;
--lightBgHighlightColor: rgb(246, 248, 249); /*editor*/
--darkBgHighlightColor: rgb(40, 40, 40); --themeColor: rgba(33, 181, 111, 1);
--highlightColor: rgba(33, 181, 111, .7);
--selectionColor: rgba(33, 181, 111, .4);
--editorColor: rgba(0, 0, 0, .8);
--editorColor50: rgba(0, 0, 0, .5);
--editorColor30: rgba(0, 0, 0, .3);
--editorColor10: rgba(0, 0, 0, .1);
--editorBgColor: rgba(255, 255, 255, 1);
--deleteColor: #ff6969;
--iconColor: #333;
--codeBgColor: #d8d8d869;
--codeBlockBgColor: rgba(33, 181, 111, 0.08);
/*marktext*/
--sideBarColor: rgba(0, 0, 0, .6);
--sideBarTitleColor: rgba(0, 0, 0, 1);
--sideBarTextColor: rgba(0, 0, 0, .4);
--sideBarBgColor: rgba(242, 242, 242, 0.9);
--sideBarItemHoverBgColor: rgba(0, 0, 0, .03);
--itemBgColor: rgba(255, 255, 255, 0.6);
--floatBgColor: #fff;
--floatHoverColor: rgba(0, 0, 0, .04);
--floatBorderColor: rgba(0, 0, 0, .1);
} }
::-webkit-scrollbar {
background: var(--floatHoverColor);
}
::-webkit-scrollbar:vertical {
width: 12px;
}
::-webkit-scrollbar-thumb {
background: var(--editorColor10);
}
::-webkit-scrollbar-thumb:hover {
background: var(--editorColor30);
}
html, body {
margin: 0;
padding: 0;
background: transparent !important;
caret-color: var(--editorColor);
}
body {
position: fixed;
width: 100vw;
height: 100vh;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.icon { .icon {
width: 1em; height: 1em; width: 1em; height: 1em;
vertical-align: -0.15em; vertical-align: -0.15em;
@ -26,3 +69,35 @@
overflow: hidden; overflow: hidden;
white-space: nowrap; white-space: nowrap;
} }
/* cover Element style*/
.el-tooltip__popper.is-dark {
background: var(--floatBgColor);
color: var(--sideBarColor);
box-shadow: 0 4px 8px 0 var(--floatBorderColor);
border: solid 1px var(--floatBorderColor);
}
.el-tooltip__popper.is-dark .popper__arrow {
display: none;
}
.el-slider__button {
border-color: var(--themeColor);
}
.el-slider__bar {
background-color: var(--themeColor);
}
.ag-dialog-table {
border-radius: 8px;
box-shadow: 0 4px 8px 0 var(--floatBorderColor);
border: solid 1px var(--floatBorderColor);
background-color: var(--floatBgColor);
}
.ag-dialog-table .dialog-title svg {
width: 1.5em;
height: 1.5em;
}

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="about-dialog" :class="theme"> <div class="about-dialog">
<el-dialog <el-dialog
:visible.sync="showAboutDialog" :visible.sync="showAboutDialog"
:show-close="false" :show-close="false"
@ -10,7 +10,7 @@
<img class="logo" src="../../assets/images/logo.png" /> <img class="logo" src="../../assets/images/logo.png" />
<el-row> <el-row>
<el-col :span="24"> <el-col :span="24">
<h3 class="text fg-color-dark">{{ name }}</h3> <h3 class="title">{{ name }}</h3>
</el-col> </el-col>
<el-col :span="24"> <el-col :span="24">
<div class="text">{{ appVersion }}</div> <div class="text">{{ appVersion }}</div>
@ -37,8 +37,7 @@
}, },
computed: { computed: {
...mapState({ ...mapState({
'appVersion': state => state.appVersion, 'appVersion': state => state.appVersion
'theme': state => state.preferences.theme
}) })
}, },
created () { created () {
@ -62,15 +61,24 @@
display: block; display: block;
} }
.about-dialog .logo { .about-dialog img.logo {
width: 100px; width: 80px;
height: 100px; height: 80px;
display: inherit; display: inherit;
margin: 0 auto; margin: 0 auto;
} }
.about-dialog .title,
.about-dialog .text { .about-dialog .text {
text-align: center;
min-height: 32px; min-height: 32px;
text-align: center;
}
.about-dialog .title {
color: var(--sideBarTitleColor);
}
.about-dialog .text {
color: var(--sideBarTextColor);
} }
</style> </style>

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="aidou" :class="theme"> <div class="aidou">
<el-dialog <el-dialog
:visible.sync="showAiDou" :visible.sync="showAiDou"
:show-close="false" :show-close="false"
@ -105,9 +105,6 @@
'aiList': state => state.aidou.aiList, 'aiList': state => state.aidou.aiList,
'aiLoading': state => state.aidou.aiLoading 'aiLoading': state => state.aidou.aiLoading
}), }),
...mapState({
'theme': state => state.preferences.theme
}),
emojis () { emojis () {
return this.aiList.map(e => { return this.aiList.map(e => {
e.collected = this.collection.findIndex(c => c.link === e.link) > -1 e.collected = this.collection.findIndex(c => c.link === e.link) > -1
@ -253,14 +250,17 @@
align-items: center; align-items: center;
height: auto; height: auto;
padding: 5px; padding: 5px;
background: #fff; color: var(--editorColor);
box-shadow: 0 3px 8px rgba(0, 0, 0, .1); background: var(--floatBgColor);
border: 1px solid #eeeeee; box-shadow: 0 3px 8px 3px var(--floatHoverColor);
border: 1px solid var(--floatBorderColor);
border-radius: 3px; border-radius: 3px;
} }
.input-wrapper { .input-wrapper {
display: flex; display: flex;
width: 100%; width: 100%;
border: 1px solid var(--sideBarTextColor);
border-radius: 14px;
} }
.search { .search {
width: 100%; width: 100%;
@ -270,18 +270,19 @@
font-size: 14px; font-size: 14px;
padding: 0 8px; padding: 0 8px;
margin: 0 10px; margin: 0 10px;
color: #606266; color: var(--editorColor);
background: transparent;
} }
.search-wrapper svg { .search-wrapper svg {
cursor: pointer; cursor: pointer;
margin: 0 5px; margin: 0 5px;
width: 30px; width: 30px;
height: 30px; height: 30px;
color: #606266; color: var(--iconColor);
transition: all .3s ease-in-out; transition: all .3s ease-in-out;
} }
.search-wrapper svg:hover { .search-wrapper svg:hover {
color: var(--activeColor); color: var(--themeColor);
} }
ul.history { ul.history {
display: flex; display: flex;
@ -312,12 +313,12 @@
} }
ul.history .clear-history span { ul.history .clear-history span {
font-size: 12px; font-size: 12px;
color: #C0C4CC; color: var(--themeColor);
text-align: center; text-align: center;
cursor: pointer; cursor: pointer;
} }
ul.history li.active { ul.history li.active {
background: #EBEEF5; background: var(--floatHoverColor);
} }
ul.history:hover li { ul.history:hover li {
background: transparent; background: transparent;
@ -326,7 +327,7 @@
display: block; display: block;
} }
ul.history li:hover { ul.history li:hover {
background: #EBEEF5; background: var(--floatHoverColor);
} }
.image-container { .image-container {
height: 410px; height: 410px;
@ -358,7 +359,7 @@
display: none; display: none;
} }
.image-container .img-wrapper > svg.active { .image-container .img-wrapper > svg.active {
color: var(--activeColor); color: var(--themeColor);
} }
.image-container .img-wrapper:hover > svg { .image-container .img-wrapper:hover > svg {
display: block; display: block;
@ -378,20 +379,4 @@
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ { .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0; opacity: 0;
} }
/* style for dark theme */
.dark .search-wrapper {
background: var(--darkInputBgColor);
border-color: transparent;
& input {
background: transparent;
color: var(--darkInputColor);
}
}
.dark ul.history li.active {
background: rgb(39, 39, 39);
}
.dark ul.history li:hover {
background: rgb(39, 39, 39);
}
</style> </style>

View File

@ -50,15 +50,15 @@ export default {
animation: 3s infinite linear; animation: 3s infinite linear;
} }
.loader span:nth-child(1) { .loader span:nth-child(1) {
background: #F2F6FC; background: var(--themeColor);
animation: kiri 1.2s infinite linear; animation: kiri 1.2s infinite linear;
} }
.loader span:nth-child(2) { .loader span:nth-child(2) {
z-index: 100; z-index: 100;
background: #EBEEF5; background: var(--highlightColor);
} }
.loader span:nth-child(3) { .loader span:nth-child(3) {
background: #C0C4CC; background: var(--selectionColor);
animation: kanan 1.2s infinite linear; animation: kanan 1.2s infinite linear;
} }

View File

@ -1,36 +0,0 @@
<template>
<div class="bottom-bar" :class="theme">
<search
v-if="!sourceCode"
:theme="theme"
></search>
</div>
</template>
<script>
import Search from './search'
export default {
components: {
Search
},
props: {
sourceCode: Boolean,
theme: String
}
}
</script>
<style scoped>
.bottom-bar {
position: fixed;
left: 0;
right: 0;
bottom: 0;
background: rgb(245, 245, 245);
}
/* dark theme */
.dark {
background: rgb(43, 43, 43);
}
</style>

View File

@ -1,8 +1,8 @@
<template> <template>
<div <div
class="editor-wrapper" class="editor-wrapper"
:class="[{ 'typewriter': typewriter, 'focus': focus, 'source': sourceCode }, theme]" :class="[{ 'typewriter': typewriter, 'focus': focus, 'source': sourceCode }]"
:style="{ 'color': theme === 'dark' ? darkColor : lightColor, 'lineHeight': lineHeight, 'fontSize': fontSize, :style="{ 'lineHeight': lineHeight, 'fontSize': fontSize,
'font-family': editorFontFamily ? `${editorFontFamily}, ${defaultFontFamily}` : `${defaultFontFamily}` }" 'font-family': editorFontFamily ? `${editorFontFamily}, ${defaultFontFamily}` : `${defaultFontFamily}` }"
:dir="textDirection" :dir="textDirection"
> >
@ -20,9 +20,7 @@
dir='ltr' dir='ltr'
> >
<div slot="title" class="dialog-title"> <div slot="title" class="dialog-title">
<svg class="icon" aria-hidden="true"> Insert Table
<use xlink:href="#icon-table-3d"></use>
</svg>
</div> </div>
<el-form :model="tableChecker" :inline="true"> <el-form :model="tableChecker" :inline="true">
<el-form-item label="Rows"> <el-form-item label="Rows">
@ -47,17 +45,16 @@
</el-form> </el-form>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button @click="dialogTableVisible = false" size="mini"> <el-button @click="dialogTableVisible = false" size="mini">
<svg class="icon" aria-hidden="true"> Cancel
<use xlink:href="#icon-close"></use>
</svg>
</el-button> </el-button>
<el-button type="primary" @click="handleDialogTableConfirm" size="mini"> <el-button type="primary" @click="handleDialogTableConfirm" size="mini">
<svg class="icon" aria-hidden="true"> Ok
<use xlink:href="#icon-gou"></use>
</svg>
</el-button> </el-button>
</div> </div>
</el-dialog> </el-dialog>
<search
v-if="!sourceCode"
></search>
</div> </div>
</template> </template>
@ -71,23 +68,24 @@
import ImagePathPicker from 'muya/lib/ui/imagePicker' import ImagePathPicker from 'muya/lib/ui/imagePicker'
import FormatPicker from 'muya/lib/ui/formatPicker' import FormatPicker from 'muya/lib/ui/formatPicker'
import bus from '../../bus' import bus from '../../bus'
import Search from '../search.vue'
import { animatedScrollTo } from '../../util' import { animatedScrollTo } from '../../util'
import { showContextMenu } from '../../contextMenu/editor' import { showContextMenu } from '../../contextMenu/editor'
import Printer from '@/services/printService' import Printer from '@/services/printService'
import { DEFAULT_EDITOR_FONT_FAMILY } from '@/config' import { DEFAULT_EDITOR_FONT_FAMILY } from '@/config'
import { addThemeStyle } from '@/util/theme'
import 'muya/themes/light.css'
const STANDAR_Y = 320 const STANDAR_Y = 320
export default { export default {
components: {
Search
},
props: { props: {
filename: { filename: {
type: String type: String
}, },
theme: {
type: String,
required: true
},
markdown: String, markdown: String,
cursor: Object, cursor: Object,
textDirection: { textDirection: {
@ -138,13 +136,6 @@
focus: function (value) { focus: function (value) {
this.editor.setFocusMode(value) this.editor.setFocusMode(value)
}, },
theme: function (value, oldValue) {
const { editor } = this
if (value !== oldValue && editor) {
editor.setTheme(value)
addThemeStyle(value)
}
},
fontSize: function (value, oldValue) { fontSize: function (value, oldValue) {
const { editor } = this const { editor } = this
if (value !== oldValue && editor) { if (value !== oldValue && editor) {
@ -175,7 +166,6 @@
this.printer = new Printer() this.printer = new Printer()
const ele = this.$refs.editor const ele = this.$refs.editor
const { const {
theme,
focus: focusMode, focus: focusMode,
markdown, markdown,
preferLooseListItem, preferLooseListItem,
@ -196,7 +186,6 @@
Muya.use(ImagePathPicker) Muya.use(ImagePathPicker)
Muya.use(FormatPicker) Muya.use(FormatPicker)
const { container } = this.editor = new Muya(ele, { const { container } = this.editor = new Muya(ele, {
theme,
focusMode, focusMode,
markdown, markdown,
preferLooseListItem, preferLooseListItem,
@ -212,9 +201,6 @@
this.scrollToCursor() this.scrollToCursor()
} }
// the default theme is light write in the store
addThemeStyle(theme)
// listen for bus events. // listen for bus events.
bus.$on('file-loaded', this.setMarkdownToEditor) bus.$on('file-loaded', this.setMarkdownToEditor)
bus.$on('undo', this.handleUndo) bus.$on('undo', this.handleUndo)
@ -336,7 +322,7 @@
}, },
scrollToHeader (slug) { scrollToHeader (slug) {
return this.scrollToElement(`[data-id="${slug}"]`) return this.scrollToElement(`#${slug}`)
}, },
scrollToElement (selector) { scrollToElement (selector) {
@ -445,7 +431,6 @@
this.editor.copy(name) this.editor.copy(name)
} }
}, },
beforeDestroy () { beforeDestroy () {
bus.$off('file-loaded', this.setMarkdownToEditor) bus.$off('file-loaded', this.setMarkdownToEditor)
bus.$off('undo', this.handleUndo) bus.$off('undo', this.handleUndo)
@ -479,6 +464,31 @@
height: 100%; height: 100%;
position: relative; position: relative;
flex: 1; flex: 1;
color: var(--editorColor);
& .ag-dialog-table {
& .el-button {
width: 70px;
}
& .el-button:focus,
& .el-button:hover {
color: var(--themeColor);
border-color: var(--highlightColor);
background-color: var(--selectionColor);
}
& .el-button--primary {
color: #fff;
background: var(--themeColor);
border-color: var(--highlightColor);
}
& .el-input-number.is-controls-right .el-input__inner {
background: var(--itemBgColor);
color: var(--editorColor);
}
& .el-input-number.is-controls-right .el-input__inner:focus {
border-color: var(--themeColor);
}
}
} }
.editor-wrapper.source { .editor-wrapper.source {
position: absolute; position: absolute;
@ -496,26 +506,4 @@
padding-top: calc(50vh - 136px); padding-top: calc(50vh - 136px);
padding-bottom: calc(50vh - 54px); padding-bottom: calc(50vh - 54px);
} }
/* for dark theme */
.dark.editor-wrapper,
.dark.editor-wrapper #ag-editor-id {
background: var(--darkBgColor);
}
</style> </style>
<style>
.ag-dialog-table {
border-radius: 5px;
box-shadow: 0 1px 3px rgba(230, 230, 230, .3);
}
.dark .ag-dialog-table {
box-shadow: 0 1px 3px rgba(0, 0, 0, .3);
}
.ag-dialog-table .dialog-title svg {
width: 1.5em;
height: 1.5em;
}
</style>

View File

@ -5,7 +5,6 @@
<tabs v-show="showTabBar"></tabs> <tabs v-show="showTabBar"></tabs>
<div class="container"> <div class="container">
<editor <editor
:theme="theme"
:fileanme="filename" :fileanme="filename"
:markdown="markdown" :markdown="markdown"
:cursor="cursor" :cursor="cursor"
@ -13,7 +12,6 @@
></editor> ></editor>
<source-code <source-code
v-if="sourceCode" v-if="sourceCode"
:theme="theme"
:markdown="markdown" :markdown="markdown"
:cursor="cursor" :cursor="cursor"
:text-direction="textDirection" :text-direction="textDirection"
@ -29,10 +27,6 @@
export default { export default {
props: { props: {
theme: {
type: String,
required: true
},
filename: { filename: {
type: String type: String
}, },
@ -69,11 +63,15 @@
<style scoped> <style scoped>
.editor-with-tabs { .editor-with-tabs {
width: 100%;
height: 100%;
padding-top: var(--titleBarHeight);
flex: 1; flex: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: calc(100vh - var(--titleBarHeight));
overflow: hidden; overflow: hidden;
background: var(--editorBgColor);
& > .container { & > .container {
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;

View File

@ -1,7 +1,6 @@
<template> <template>
<div <div
class="source-code" class="source-code"
:class="[theme]"
ref="sourceCode" ref="sourceCode"
> >
</div> </div>
@ -10,15 +9,13 @@
<script> <script>
import codeMirror, { setMode, setCursorAtLastLine, setTextDirection } from '../../codeMirror' import codeMirror, { setMode, setCursorAtLastLine, setTextDirection } from '../../codeMirror'
import { wordCount as getWordCount } from 'muya/lib/utils' import { wordCount as getWordCount } from 'muya/lib/utils'
import { mapState } from 'vuex'
import { adjustCursor } from '../../util' import { adjustCursor } from '../../util'
import bus from '../../bus' import bus from '../../bus'
import { railscastsThemes } from '@/config'
export default { export default {
props: { props: {
theme: {
type: String,
required: true
},
markdown: String, markdown: String,
cursor: Object, cursor: Object,
textDirection: { textDirection: {
@ -27,6 +24,12 @@
} }
}, },
computed: {
...mapState({
'theme': state => state.preferences.theme
})
},
data () { data () {
return { return {
contentState: null, contentState: null,
@ -35,18 +38,6 @@
}, },
watch: { watch: {
theme: function (value, oldValue) {
const cm = this.$refs.sourceCode.querySelector('.CodeMirror')
if (value !== oldValue) {
if (value === 'dark') {
cm.classList.remove('cm-s-default')
cm.classList.add('cm-s-railscasts')
} else {
cm.classList.add('cm-s-default')
cm.classList.remove('cm-s-railscasts')
}
}
},
textDirection: function (value, oldValue) { textDirection: function (value, oldValue) {
const { editor } = this const { editor } = this
if (value !== oldValue && editor) { if (value !== oldValue && editor) {
@ -74,7 +65,9 @@
} }
} }
} }
if (theme === 'dark') codeMirrorConfig.theme = 'railscasts' if (railscastsThemes.includes(theme)) {
codeMirrorConfig.theme = 'railscasts'
}
const editor = this.editor = codeMirror(container, codeMirrorConfig) const editor = this.editor = codeMirror(container, codeMirrorConfig)
bus.$on('file-loaded', this.setMarkdown) bus.$on('file-loaded', this.setMarkdown)
bus.$on('file-changed', this.handleMarkdownChange) bus.$on('file-changed', this.handleMarkdownChange)
@ -147,6 +140,7 @@
.source-code .CodeMirror { .source-code .CodeMirror {
margin: 50px auto; margin: 50px auto;
max-width: var(--editorAreaWidth); max-width: var(--editorAreaWidth);
background: transparent;
} }
.source-code .CodeMirror-gutters { .source-code .CodeMirror-gutters {
border-right: none; border-right: none;
@ -154,14 +148,6 @@
} }
.source-code .CodeMirror-activeline-background, .source-code .CodeMirror-activeline-background,
.source-code .CodeMirror-activeline-gutter { .source-code .CodeMirror-activeline-gutter {
background: #F2F6FC; background: var(--floatHoverColor);
}
.source-code.dark,
.source-code.dark .CodeMirror {
background: var(--darkBgColor);
}
.dark.source-code .CodeMirror-activeline-background,
.dark.source-code .CodeMirror-activeline-gutter {
background: #333;
} }
</style> </style>

View File

@ -1,7 +1,6 @@
<template> <template>
<div <div
class="editor-tabs" class="editor-tabs"
:class="theme"
> >
<ul class="tabs-container"> <ul class="tabs-container">
<li <li
@ -37,7 +36,6 @@
mixins: [tabsMixins], mixins: [tabsMixins],
computed: { computed: {
...mapState({ ...mapState({
theme: state => state.preferences.theme,
currentFile: state => state.editor.currentFile, currentFile: state => state.editor.currentFile,
tabs: state => state.editor.tabs tabs: state => state.editor.tabs
}) })
@ -54,7 +52,6 @@
.editor-tabs { .editor-tabs {
width: 100%; width: 100%;
height: 35px; height: 35px;
background: var(--lightBarColor);
user-select: none; user-select: none;
} }
.tabs-container { .tabs-container {
@ -70,21 +67,13 @@
& > li { & > li {
position: relative; position: relative;
padding: 0 8px; padding: 0 8px;
color: var(--secondaryColor); color: var(--editorColor50);
font-size: 12px; font-size: 12px;
line-height: 35px; line-height: 35px;
height: 35px; height: 35px;
background: var(--lightTabColor); background: var(--floatBgColor);
display: flex; display: flex;
align-items: center; align-items: center;
&:not(:last-child):before {
content: '';
position: absolute;
top: 20%;
right: 0;
border-right: 1px solid #fff;
height: 60%;
}
& > svg { & > svg {
opacity: 0; opacity: 0;
} }
@ -99,7 +88,7 @@
} }
} }
& > li.active { & > li.active {
background: #fff; background: var(--itemBgColor);
&:not(:last-child):after { &:not(:last-child):after {
content: ''; content: '';
position: absolute; position: absolute;
@ -107,7 +96,7 @@
bottom: 0; bottom: 0;
right: 0; right: 0;
height: 2px; height: 2px;
background: var(--primary); background: var(--themeColor);
} }
& > svg { & > svg {
opacity: 1; opacity: 1;
@ -125,16 +114,4 @@
cursor: pointer; cursor: pointer;
} }
} }
.editor-tabs.dark {
background: var(--darkBgColor);
}
.editor-tabs.dark ul li {
background: var(--darkBgColor);
&:not(:last-child):before {
border-right-color: var(--darkHoverColor);
}
&.active {
color: var(--lightBorder);
}
}
</style> </style>

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="font" :class="theme"> <div class="font">
<el-dialog <el-dialog
:visible.sync="showFontSetting" :visible.sync="showFontSetting"
:show-close="false" :show-close="false"
@ -56,7 +56,6 @@
}, },
computed: { computed: {
...mapState({ ...mapState({
'theme': state => state.preferences.theme,
'fontSize': state => state.preferences.fontSize, 'fontSize': state => state.preferences.fontSize,
'lightColor': state => state.preferences.lightColor, 'lightColor': state => state.preferences.lightColor,
'darkColor': state => state.preferences.darkColor, 'darkColor': state => state.preferences.darkColor,

View File

@ -81,19 +81,20 @@ export default {
<style scoped> <style scoped>
.drop-container { .drop-container {
border-radius: 5px; border-radius: 5px;
border: 2px dashed #9c9c9c; color: var(--sideBarColor);
border: 1px dashed var(--sideBarTextColor);
& div, & div,
& p { & p {
text-align: center; text-align: center;
} }
&.active { &.active {
border: 2px dashed #409eff; border: 1px dashed var(--themeColor);
background-color: rgba(32, 159, 255, 0.06); background-color: var(--itemBgColor);
} }
} }
.img-wrapper { .img-wrapper {
width: 70px; width: 50px;
height: 100px; height: 70px;
margin: 40px auto 0 auto; margin: 40px auto 0 auto;
& img { & img {
width: 100%; width: 100%;
@ -107,12 +108,12 @@ export default {
& div { & div {
width: 70px; width: 70px;
height: 70px; height: 70px;
border: 1px solid #eee; border: 1px solid var(--sideBarTextColor);
border-radius: 3px; border-radius: 3px;
text-align: center; text-align: center;
font-size: 18px; font-size: 18px;
line-height: 70px; line-height: 70px;
color: #999; color: var(--sideBarTitleColor);
} }
} }
</style> </style>

View File

@ -1,20 +1,25 @@
<template> <template>
<div <div
class="recent-files-projects" class="recent-files-projects"
:class="theme"
@click="newFile"
> >
<div class="button-group">
<svg :viewBox="ContentIcon.viewBox" aria-hidden="true">
<use :xlink:href="ContentIcon.url" />
</svg>
<a href="javascript:;" @click="newFile">
New File
</a>
</div>
</div> </div>
</template> </template>
<script> <script>
import { mapState } from 'vuex' import ContentIcon from '@/assets/icons/undraw_content.svg'
export default { export default {
computed: { data () {
...mapState({ this.ContentIcon = ContentIcon
'theme': state => state.preferences.theme return {}
})
}, },
methods: { methods: {
newFile () { newFile () {
@ -26,12 +31,32 @@
<style scoped> <style scoped>
.recent-files-projects { .recent-files-projects {
background: var(--editorBgColor);
flex: 1; flex: 1;
} display: flex;
.dark.recent-files-projects { align-items: center;
background: var(--darkBgColor); justify-content: space-around;
& > div { & .button-group {
color: var(--baseBorder); display: flex;
flex-direction: column;
align-items: center;
& svg {
width: 200px;
fill: var(--themeColor);
}
& a {
text-decoration: none;
background: var(--themeColor);
box-shadow: 0 0 8px 0 var(--selectionColor);
display: block;
padding: 4px 10px;
border-radius: 5px;
margin-top: 20px;
color: #fff;
&:active {
opacity: .5;
}
}
} }
} }
</style> </style>

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="rename" :class="theme"> <div class="rename">
<el-dialog <el-dialog
:visible.sync="showRename" :visible.sync="showRename"
:show-close="false" :show-close="false"
@ -44,8 +44,7 @@
}, },
computed: { computed: {
...mapState({ ...mapState({
filename: state => state.editor.currentFile.filename, filename: state => state.editor.currentFile.filename
theme: state => state.preferences.theme
}) })
}, },
methods: { methods: {
@ -63,6 +62,10 @@
</script> </script>
<style> <style>
.rename .el-dialog__header {
height: 42px;
box-sizing: border-box;
}
.rename .el-dialog__body { .rename .el-dialog__body {
display: none; display: none;
} }
@ -84,13 +87,16 @@
align-items: center; align-items: center;
height: auto; height: auto;
padding: 5px; padding: 5px;
background: #fff; background: var(--floatBorderColor);
box-shadow: 0 3px 8px rgba(0, 0, 0, .1); box-shadow: 0 3px 8px var(--floatBorderColor);
border: 1px solid #eeeeee; border: 1px solid var(--floatBorderColor);
border-radius: 3px; border-radius: 3px;
& .input-wrapper { & .input-wrapper {
display: flex; display: flex;
width: 100%; width: 100%;
& input {
background: transparent;
}
} }
} }
.search { .search {
@ -101,28 +107,17 @@
font-size: 14px; font-size: 14px;
padding: 0 8px; padding: 0 8px;
margin: 0 10px; margin: 0 10px;
color: #606266; color: var(--sideBarColor);
} }
.search-wrapper svg { .search-wrapper svg {
cursor: pointer; cursor: pointer;
margin: 0 5px; margin: 0 5px;
width: 30px; width: 30px;
height: 30px; height: 30px;
color: #606266; color: var(--iconColor);
transition: all .3s ease-in-out; transition: all .3s ease-in-out;
} }
.search-wrapper svg:hover { .search-wrapper svg:hover {
color: var(--activeColor); color: var(--themeColor);
} }
/* style for dark theme */
.dark .search-wrapper {
background: var(--darkInputBgColor);
border-color: transparent;
& input {
background: transparent;
color: var(--darkInputColor);
}
}
</style> </style>

View File

@ -1,6 +1,5 @@
<template> <template>
<div class="search-bar" <div class="search-bar"
:class="theme"
@click.stop="noop" @click.stop="noop"
v-show="showSearch" v-show="showSearch"
> >
@ -29,7 +28,7 @@
:visible-arrow="false" :visible-arrow="false"
:open-delay="1000" :open-delay="1000"
> >
<button class="button" @click="caseClick" :class="{ 'active': caseSensitive }"> <button class="button left" @click="caseClick" :class="{ 'active': caseSensitive }">
<svg class="icon" aria-hidden="true"> <svg class="icon" aria-hidden="true">
<use xlink:href="#icon-case"></use> <use xlink:href="#icon-case"></use>
</svg> </svg>
@ -46,19 +45,19 @@
> >
<span class="search-result">{{`${highlightIndex + 1} / ${highlightCount}`}}</span> <span class="search-result">{{`${highlightIndex + 1} / ${highlightCount}`}}</span>
</div> </div>
<button class="button" @click="find('prev')"> <button class="button right" @click="find('prev')">
<svg class="icon" aria-hidden="true"> <svg class="icon" aria-hidden="true">
<use xlink:href="#icon-arrow-up"></use> <use xlink:href="#icon-arrow-up"></use>
</svg> </svg>
</button> </button>
<button class="button" @click="find('next')"> <button class="button right" @click="find('next')">
<svg class="icon" aria-hidden="true"> <svg class="icon" aria-hidden="true">
<use xlink:href="#icon-arrowdown"></use> <use xlink:href="#icon-arrowdown"></use>
</svg> </svg>
</button> </button>
</section> </section>
<section class="replace" v-if="type === 'replace'"> <section class="replace" v-if="type === 'replace'">
<button class="button active" @click="typeClick"> <button class="button active left" @click="typeClick">
<svg class="icon" aria-hidden="true"> <svg class="icon" aria-hidden="true">
<use xlink:href="#icon-findreplace"></use> <use xlink:href="#icon-findreplace"></use>
</svg> </svg>
@ -73,7 +72,7 @@
:visible-arrow="false" :visible-arrow="false"
:open-delay="1000" :open-delay="1000"
> >
<button class="button" @click="replace(false)"> <button class="button right" @click="replace(false)">
<svg class="icon" aria-hidden="true"> <svg class="icon" aria-hidden="true">
<use xlink:href="#icon-all-inclusive"></use> <use xlink:href="#icon-all-inclusive"></use>
</svg> </svg>
@ -86,7 +85,7 @@
:visible-arrow="false" :visible-arrow="false"
:open-delay="1000" :open-delay="1000"
> >
<button class="button" @click="replace(true)"> <button class="button right" @click="replace(true)">
<svg class="icon" aria-hidden="true"> <svg class="icon" aria-hidden="true">
<use xlink:href="#icon-replace"></use> <use xlink:href="#icon-replace"></use>
</svg> </svg>
@ -101,9 +100,6 @@
import { mapState } from 'vuex' import { mapState } from 'vuex'
export default { export default {
props: {
theme: String
},
data () { data () {
return { return {
showSearch: false, showSearch: false,
@ -219,8 +215,15 @@
<style scoped> <style scoped>
.search-bar { .search-bar {
width: 100%; position: absolute;
width: 400px;
padding: 5px; padding: 5px;
top: 0;
right: 20px;
box-shadow: 0 4px 8px 0 var(--floatBorderColor);
border: 1px solid var(--floatBorderColor);
border-radius: 5px;
background: var(--floatBgColor);
} }
.search { .search {
margin-bottom: 5px; margin-bottom: 5px;
@ -228,6 +231,7 @@
.search, .replace { .search, .replace {
height: 30px; height: 30px;
display: flex; display: flex;
padding: 0 10px;
} }
.search-bar .button { .search-bar .button {
outline: none; outline: none;
@ -236,65 +240,55 @@
background: transparent; background: transparent;
box-sizing: border-box; box-sizing: border-box;
height: 30px; height: 30px;
width: 50px; width: 30px;
text-align: center; text-align: center;
padding: 3px 5px; padding: 5px;
display: inline-block; display: inline-block;
margin-right: 5px;
font-weight: 500; font-weight: 500;
color: #606266; color: var(--iconColor);
&.left {
margin-right: 10px;
}
&.right {
margin-left: 10px;
}
} }
.button.active { .button.active {
color: rgb(242, 134, 94); color: var(--themeColor);
} }
.search-bar .button > svg { .search-bar .button > svg {
width: 1.6em; width: 20px;
height: 1.6em; height: 20px;
}
.search-bar .button:hover {
background: #EBEEF5;
} }
.search-bar .button:active { .search-bar .button:active {
background: #DCDFE6; opacity: .5;
} }
.input-wrapper { .input-wrapper {
display: flex; display: flex;
flex: 1; flex: 1;
position: relative; position: relative;
margin-right: 5px; margin-right: 5px;
background: var(--floatHoverColor);
border-radius: 4px;
overflow: hidden;
} }
.input-wrapper .search-result { .input-wrapper .search-result {
position: absolute; position: absolute;
top: 6px; top: 6px;
right: 5px; right: 10px;
font-size: 12px; font-size: 12px;
color: #C0C4CC; color: var(--sideBarTitleColor);
} }
.input-wrapper input { .input-wrapper input {
flex: 1; flex: 1;
padding: 0 8px;
height: 30px; height: 30px;
outline: none; outline: none;
border: none; border: none;
box-sizing: border-box; box-sizing: border-box;
font-size: 14px; font-size: 14px;
color: #606266; color: var(--editorColor);
padding: 0 8px; padding: 0 8px;
background: rgb(252, 252, 252); background: transparent;
}
/* css for dark theme*/
.dark {
caret-color: #efefef;
color: #606266;
}
.dark input {
background: rgb(54, 55, 49);
color: #C0C4CC;
}
.dark .button:hover {
background: rgb(71, 72, 66);
color: #C0C4CC;
}
.dark .button:active {
background: #303133;
} }
</style> </style>

View File

@ -4,7 +4,7 @@
class="side-bar-file" class="side-bar-file"
:style="{'padding-left': `${depth * 5 + 15}px`, 'opacity': file.isMarkdown ? 1 : 0.75 }" :style="{'padding-left': `${depth * 5 + 15}px`, 'opacity': file.isMarkdown ? 1 : 0.75 }"
@click="handleFileClick()" @click="handleFileClick()"
:class="[{'current': currentFile.pathname === file.pathname, 'active': file.id === activeItem.id }, theme]" :class="[{'current': currentFile.pathname === file.pathname, 'active': file.id === activeItem.id }]"
ref="file" ref="file"
> >
<file-icon <file-icon
@ -53,7 +53,6 @@
}, },
computed: { computed: {
...mapState({ ...mapState({
'theme': state => state.preferences.theme,
'renameCache': state => state.project.renameCache, 'renameCache': state => state.project.renameCache,
'activeItem': state => state.project.activeItem, 'activeItem': state => state.project.activeItem,
'clipboard': state => state.project.clipboard, 'clipboard': state => state.project.clipboard,
@ -103,7 +102,7 @@
box-sizing: border-box; box-sizing: border-box;
padding-right: 15px; padding-right: 15px;
&:hover { &:hover {
background: var(--extraLightBorder); background: var(--sideBarItemHoverBgColor);
} }
& > span { & > span {
overflow: hidden; overflow: hidden;
@ -115,7 +114,7 @@
position: absolute; position: absolute;
display: block; display: block;
left: 0; left: 0;
background: var(--activeColor); background: var(--themeColor);
width: 2px; width: 2px;
height: 0; height: 0;
top: 50%; top: 50%;
@ -126,19 +125,21 @@
.side-bar-file.current::before { .side-bar-file.current::before {
height: 100%; height: 100%;
} }
.side-bar-file.active { .side-bar-file.current > span {
background: var(--lightBorder); color: var(--themeColor);
}
.side-bar-file.active > span {
color: var(--sideBarTitleColor);
} }
input.rename { input.rename {
height: 22px; height: 22px;
outline: none; outline: none;
margin: 5px 0; margin: 5px 0;
border: 1px solid var(--lightBorder); padding: 0 8px;
color: var(--sideBarColor);
border: 1px solid var(--floatBorderColor);
background: var(--floatBorderColor);
width: 100%; width: 100%;
border-radius: 3px; border-radius: 3px;
} }
.dark.side-bar-file:hover {
background: var(--darkHoverColor);
color: var(--lightTabColor);
}
</style> </style>

View File

@ -1,7 +1,6 @@
<template> <template>
<div <div
class="side-bar-folder" class="side-bar-folder"
:class="theme"
> >
<div <div
class="folder-name" @click="folderNameClick" class="folder-name" @click="folderNameClick"
@ -80,7 +79,6 @@
}, },
computed: { computed: {
...mapState({ ...mapState({
'theme': state => state.preferences.theme,
'renameCache': state => state.project.renameCache, 'renameCache': state => state.project.renameCache,
'createCache': state => state.project.createCache, 'createCache': state => state.project.createCache,
'activeItem': state => state.project.activeItem, 'activeItem': state => state.project.activeItem,
@ -132,11 +130,11 @@
padding-right: 15px; padding-right: 15px;
& > svg { & > svg {
flex-shrink: 0; flex-shrink: 0;
color: darkgray; color: var(--iconColor);
margin-right: 5px; margin-right: 5px;
} }
&:hover { &:hover {
background: var(--extraLightBorder); background: var(--sideBarItemHoverBgColor);
} }
} }
} }
@ -144,12 +142,10 @@
outline: none; outline: none;
height: 22px; height: 22px;
margin: 5px 0; margin: 5px 0;
border: 1px solid var(--lightBorder); padding: 0 8px;
width: 100%; border: 1px solid var(--floatBorderColor);
background: var(--floatBorderColor);
width: 70%;
border-radius: 3px; border-radius: 3px;
} }
.dark.side-bar-folder > .folder-name:hover {
background-color: var(--darkHoverColor);
color: var(--lightTabColor);
}
</style> </style>

View File

@ -2,11 +2,10 @@
<div <div
v-show="showSideBar" v-show="showSideBar"
class="side-bar" class="side-bar"
:class="[theme]"
ref="sideBar" ref="sideBar"
:style="{ 'width': `${finalSideBarWidth}px` }" :style="{ 'width': `${finalSideBarWidth}px` }"
> >
<div class="title-bar-bg" :class="[theme]"></div> <div class="title-bar-bg"></div>
<div class="left-column"> <div class="left-column">
<ul> <ul>
<li <li
@ -75,7 +74,6 @@
}, },
computed: { computed: {
...mapState({ ...mapState({
'theme': state => state.preferences.theme,
'rightColumn': state => state.layout.rightColumn, 'rightColumn': state => state.layout.rightColumn,
'showSideBar': state => state.layout.showSideBar, 'showSideBar': state => state.layout.showSideBar,
'projectTree': state => state.project.projectTree, 'projectTree': state => state.project.projectTree,
@ -143,26 +141,13 @@
<style scoped> <style scoped>
.side-bar { .side-bar {
display: flex; display: flex;
height: calc(100vh - var(--titleBarHeight)); height: 100vh;
position: relative; position: relative;
color: var(--secondaryColor); color: var(--sideBarColor);
} }
.side-bar.light, .side-bar {
.title-bar-bg.light { background: var(--sideBarBgColor);
background: var(--lightBgHighlightColor); border-right: 1px solid var(--itemBgColor);
border-right: 1px solid rgb(242, 242, 242);
}
.side-bar.dark,
.title-bar-bg.dark {
background: var(--darkBgHighlightColor);
}
.title-bar-bg {
position: absolute;
top: calc(-1 * var(--titleBarHeight));
left: 0;
height: var(--titleBarHeight);
width: 100%;
} }
.left-column { .left-column {
@ -171,6 +156,8 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: space-between; justify-content: space-between;
padding-top: 40px;
box-sizing: border-box;
& > ul { & > ul {
opacity: 1; opacity: 1;
} }
@ -195,15 +182,14 @@
width: 18px; width: 18px;
height: 18px; height: 18px;
opacity: 1; opacity: 1;
color: var(--secondaryColor); color: var(--iconColor);
transition: transform .25s ease-in-out; transition: transform .25s ease-in-out;
} }
&:hover > svg { &:hover > svg {
color: var(--primary); color: var(--themeColor);
transform: scale(1.2);
} }
&.active > svg { &.active > svg {
color: var(--primary); color: var(--themeColor);
} }
} }
} }
@ -222,10 +208,10 @@
right: 0; right: 0;
bottom: 0; bottom: 0;
height: 100%; height: 100%;
width: 2px; width: 8px;
cursor: col-resize; cursor: col-resize;
&:hover { &:hover {
background: var(--secondaryColor); border-right: 2px solid var(--sideBarTextColor);
} }
} }
</style> </style>

View File

@ -2,15 +2,14 @@
<div <div
class="side-bar-list-file" class="side-bar-list-file"
@click="handleFileClick" @click="handleFileClick"
:class="[{ 'active': file.pathname === currentFile.pathname }, theme]" :class="[{ 'active': file.pathname === currentFile.pathname }]"
> >
<div class="title"> <div class="title">
<span class="filename">{{ filename }}</span> <span class="filename">{{ filename + extension }}</span>
<span>{{ extension }}</span> <span class="birth-time">{{ relativeTime }}</span>
</div> </div>
<div class="folder-date"> <div class="folder-date">
<span class="folder">{{parent}}</span> <span class="folder">{{parent}}</span>
<span class="birth-time">{{ new Date(file.birthTime).toLocaleString().split(/\s/)[0] }}</span>
</div> </div>
<div class="content"> <div class="content">
{{ file.data.markdown.substring(0, 50) }} {{ file.data.markdown.substring(0, 50) }}
@ -23,6 +22,7 @@
import { mapState } from 'vuex' import { mapState } from 'vuex'
import { fileMixins } from '../../mixins' import { fileMixins } from '../../mixins'
import { PATH_SEPARATOR } from '../../config' import { PATH_SEPARATOR } from '../../config'
import dayjs from '@/util/day'
export default { export default {
mixins: [fileMixins], mixins: [fileMixins],
@ -34,7 +34,6 @@
}, },
computed: { computed: {
...mapState({ ...mapState({
theme: state => state.preferences.theme,
tabs: state => state.editor.tabs, tabs: state => state.editor.tabs,
currentFile: state => state.editor.currentFile currentFile: state => state.editor.currentFile
}), }),
@ -44,6 +43,10 @@
return path.basename(this.file.name, path.extname(this.file.name)) return path.basename(this.file.name, path.extname(this.file.name))
}, },
relativeTime () {
return dayjs(+new Date(this.file.birthTime)).fromNow()
},
// Return the filename extension or null. // Return the filename extension or null.
extension () { extension () {
return path.extname(this.file.name) return path.extname(this.file.name)
@ -63,20 +66,20 @@
position: relative; position: relative;
user-select: none; user-select: none;
padding: 10px 20px; padding: 10px 20px;
color: var(--secondaryColor); color: var(--sideBarColor);
font-size: 14px; font-size: 14px;
& .title .filename { & .title .filename {
font-size: 15px; font-size: 15px;
} }
&:hover { &:hover {
background: var(--extraLightBorder); background: var(--sideBarItemHoverBgColor);
} }
&::before { &::before {
content: ''; content: '';
position: absolute; position: absolute;
display: block; display: block;
left: 0; left: 0;
background: var(--activeColor); background: var(--themeColor);
width: 2px; width: 2px;
height: 0; height: 0;
top: 50%; top: 50%;
@ -86,28 +89,33 @@
} }
.side-bar-list-file.active { .side-bar-list-file.active {
font-weight: 600; font-weight: 600;
color: var(--regularColor); .title {
color: var(--themeColor);
}
} }
.side-bar-list-file.active::before { .side-bar-list-file.active::before {
height: 100%; height: 100%;
} }
.title {
display: flex;
color: var(--sideBarTitleColor);
& .filename {
flex: 1;
}
& .birth-time {
color: var(--sideBarTextColor);
}
}
.folder-date { .folder-date {
margin-top: 5px; margin-top: 5px;
display: flex;
justify-content: space-between;
} }
.folder-date .folder,
.content { .content {
width: 100%; width: 100%;
margin-top: 5px; margin-top: 5px;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} color: var(--sideBarTextColor);
.dark.side-bar-list-file.active {
color: var(--lightTabColor);
}
.dark.side-bar-list-file:hover {
background: var(--darkHoverColor);
color: var(--lightTabColor);
} }
</style> </style>

View File

@ -3,7 +3,7 @@
class="opened-file" class="opened-file"
:title="file.pathname" :title="file.pathname"
@click="selectFile(file)" @click="selectFile(file)"
:class="[{'active': currentFile.id === file.id, 'unsaved': !file.isSaved }, theme]" :class="[{'active': currentFile.id === file.id, 'unsaved': !file.isSaved }]"
> >
<svg class="icon" aria-hidden="true" <svg class="icon" aria-hidden="true"
@click.stop="removeFileInTab(file)" @click.stop="removeFileInTab(file)"
@ -28,7 +28,6 @@
}, },
computed: { computed: {
...mapState({ ...mapState({
'theme': state => state.preferences.theme,
'currentFile': state => state.editor.currentFile 'currentFile': state => state.editor.currentFile
}) })
} }
@ -43,7 +42,7 @@
line-height: 28px; line-height: 28px;
padding-left: 30px; padding-left: 30px;
position: relative; position: relative;
color: var(--regularColor); color: var(--sideBarColor);
& > svg { & > svg {
display: none; display: none;
width: 10px; width: 10px;
@ -56,7 +55,7 @@
display: inline-block; display: inline-block;
} }
&:hover { &:hover {
background: var(--extraLightBorder); background: var(--sideBarItemHoverBgColor);
} }
& > span { & > span {
overflow: hidden; overflow: hidden;
@ -65,14 +64,14 @@
} }
} }
.opened-file.active { .opened-file.active {
color: var(--primary); color: var(--themeColor);
} }
.unsaved.opened-file::before { .unsaved.opened-file::before {
content: ''; content: '';
width: 7px; width: 7px;
height: 7px; height: 7px;
border-radius: 50%; border-radius: 50%;
background: var(--warning); background: var(--themeColor);
position: absolute; position: absolute;
top: 11px; top: 11px;
left: 12px; left: 12px;
@ -80,8 +79,4 @@
.unsaved.opened-file:hover::before { .unsaved.opened-file:hover::before {
content: none; content: none;
} }
.dark.opened-file:hover {
background: var(--darkHoverColor);
color: var(--lightTabColor);
}
</style> </style>

View File

@ -1,11 +1,11 @@
<template> <template>
<div class="side-bar-search" <div
:class="theme" class="side-bar-search"
> >
<div class="search-wrapper"> <div class="search-wrapper">
<input <input
type="text" v-model="keyword" type="text" v-model="keyword"
placeholder="Search in project..." placeholder="Search in folder..."
@keyup="search" @keyup="search"
> >
<svg class="icon" aria-hidden="true"> <svg class="icon" aria-hidden="true">
@ -20,17 +20,23 @@
></list-file> ></list-file>
</div> </div>
<div class="empty" v-else> <div class="empty" v-else>
<span>{{ !keyword ? 'Input search keyword' : 'No matched files' }}</span> <div class="no-data">
<svg :viewBox="EmptyIcon.viewBox" aria-hidden="true">
<use :xlink:href="EmptyIcon.url" />
</svg>
</div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { mapGetters, mapState } from 'vuex' import { mapGetters } from 'vuex'
import ListFile from './listFile.vue' import ListFile from './listFile.vue'
import EmptyIcon from '@/assets/icons/undraw_empty.svg'
export default { export default {
data () { data () {
this.EmptyIcon = EmptyIcon
return { return {
keyword: '', keyword: '',
searchResult: [] searchResult: []
@ -40,9 +46,6 @@
ListFile ListFile
}, },
computed: { computed: {
...mapState({
'theme': state => state.preferences.theme
}),
...mapGetters(['fileList']) ...mapGetters(['fileList'])
}, },
methods: { methods: {
@ -70,10 +73,14 @@
margin: 35px 20px; margin: 35px 20px;
border-radius: 3px; border-radius: 3px;
height: 30px; height: 30px;
border: 1px solid var(--lightBorder); border: 1px solid var(--floatBorderColor);
background: var(--floatBorderColor);
border-radius: 15px;
box-sizing: border-box; box-sizing: border-box;
align-items: center; align-items: center;
& > input { & > input {
color: var(--sideBarColor);
background: transparent;
height: 100%; height: 100%;
flex: 1; flex: 1;
border: none; border: none;
@ -87,16 +94,17 @@
flex-shrink: 0; flex-shrink: 0;
width: 20px; width: 20px;
height: 20px; height: 20px;
margin-right: 5px; margin-right: 10px;
&:hover { &:hover {
color: var(--brandColor); color: var(--iconColor);
} }
} }
} }
.empty, .empty,
.search-result { .search-result {
flex: 1; flex: 1;
overflow: auto; overflow-y: auto;
overflow-x: hidden;
&::-webkit-scrollbar:vertical { &::-webkit-scrollbar:vertical {
width: 5px; width: 5px;
} }
@ -104,14 +112,13 @@
.empty { .empty {
font-size: 14px; font-size: 14px;
text-align: center; text-align: center;
} display: flex;
.dark.side-bar-search .search-wrapper { flex-direction: column;
background: rgb(54, 55, 49); justify-content: space-around;
border-color: transparent; padding-bottom: 100px;
& > input, & .no-data svg {
& > svg { fill: var(--themeColor);
background: transparent; width: 120px;
color: #C0C4CC;
} }
} }
</style> </style>

View File

@ -1,56 +1,96 @@
<template> <template>
<ul class="side-bar-toc"> <div class="side-bar-toc">
<li v-for="(item, index) of toc" <div class="title">Table Of Content</div>
:key="index" <el-tree
:style="{'padding-left': `${(item.lvl - startLvl) * 20}px`}" v-if="toc.length"
@click="handleClick(item)" :data="toc"
:class="{ 'active': item.i === activeIndex }" :props="defaultProps"
> @node-click="handleClick"
{{ item.content }} :expand-on-click-node="false"
</li> :indent="10"
</ul> ></el-tree>
<div class="no-data" v-else>
<svg aria-hidden="true" :viewBox="EmptyIcon.viewBox">
<use :xlink:href="EmptyIcon.url"></use>
</svg>
</div>
</div>
</template> </template>
<script> <script>
import { mapGetters } from 'vuex' import { mapState } from 'vuex'
import bus from '../../bus' import bus from '../../bus'
import EmptyIcon from '@/assets/icons/undraw_toc_empty.svg'
export default { export default {
data () { data () {
this.EmptyIcon = EmptyIcon
return { return {
activeIndex: -1 defaultProps: {
children: 'children',
label: 'label'
}
} }
}, },
computed: { computed: {
...mapGetters(['toc']), ...mapState({
startLvl () { 'toc': state => state.editor.toc
return Math.min(...this.toc.map(h => h.lvl)) })
}
}, },
methods: { methods: {
handleClick (item) { handleClick ({ slug }) {
this.activeIndex = item.i bus.$emit('scroll-to-header', slug)
bus.$emit('scroll-to-header', item.slug)
} }
} }
} }
</script> </script>
<style scoped> <style>
.side-bar-toc { .side-bar-toc {
height: calc(100% - 35px); height: calc(100% - 35px);
margin: 0; margin: 0;
margin-top: 35px;
padding: 0; padding: 0;
list-style: none; list-style: none;
overflow: scroll; overflow: auto;
display: flex;
flex-direction: column;
& .title {
padding: 5px 0;
color: var(--sideBarTitleColor);
font-weight: 600px;
font-size: 16px;
margin: 20px 0;
text-align: center;
}
& .el-tree-node {
margin-top: 8px;
}
& .el-tree {
background: transparent;
color: var(--sideBarColor);
}
& .el-tree-node:focus > .el-tree-node__content {
background-color: var(--sideBarItemHoverBgColor);
}
& .el-tree-node__content:hover {
background: var(--sideBarItemHoverBgColor);
}
& > li { & > li {
font-size: 14px; font-size: 14px;
margin-bottom: 15px; margin-bottom: 15px;
cursor: pointer; cursor: pointer;
} }
& > li.active { & .no-data {
color: var(--primary); flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
padding-bottom: 50px;
& svg {
width: 120px;
fill: var(--themeColor);
}
} }
} }
</style> </style>

View File

@ -23,7 +23,7 @@
<!-- opened files --> <!-- opened files -->
<div class="opened-files"> <div class="opened-files">
<div class="title"> <div class="title">
<svg class="icon" aria-hidden="true" @click.stop="toggleOpenedFiles()"> <svg class="icon icon-arrow" :class="{'fold': !showOpenedFiles}" aria-hidden="true" @click.stop="toggleOpenedFiles()">
<use xlink:href="#icon-arrow"></use> <use xlink:href="#icon-arrow"></use>
</svg> </svg>
<span class="default-cursor text-overflow" @click.stop="toggleOpenedFiles()">Opened files</span> <span class="default-cursor text-overflow" @click.stop="toggleOpenedFiles()">Opened files</span>
@ -54,7 +54,7 @@
class="project-tree" v-if="projectTree" class="project-tree" v-if="projectTree"
> >
<div class="title"> <div class="title">
<svg class="icon" aria-hidden="true" @click.stop="toggleDirectories()"> <svg class="icon icon-arrow" :class="{'fold': !showDirectories}" aria-hidden="true" @click.stop="toggleDirectories()">
<use xlink:href="#icon-arrow"></use> <use xlink:href="#icon-arrow"></use>
</svg> </svg>
<span class="default-cursor text-overflow" @click.stop="toggleDirectories()">{{ projectTree.name }}</span> <span class="default-cursor text-overflow" @click.stop="toggleDirectories()">{{ projectTree.name }}</span>
@ -91,11 +91,14 @@
</div> </div>
</div> </div>
<div v-else class="open-project"> <div v-else class="open-project">
<a href="javascript:;" @click="openFolder" title="Open Folder"> <div class="button-group">
<svg class="icon" aria-hidden="true"> <svg aria-hidden="true" :viewBox="FolderIcon.viewBox">
<use xlink:href="#icon-create-project"></use> <use :xlink:href="FolderIcon.url"></use>
</svg> </svg>
</a> <a href="javascript:;" @click="openFolder">
Open Folder
</a>
</div>
</div> </div>
</div> </div>
</template> </template>
@ -108,11 +111,13 @@
import { mapState } from 'vuex' import { mapState } from 'vuex'
import bus from '../../bus' import bus from '../../bus'
import { createFileOrDirectoryMixins } from '../../mixins' import { createFileOrDirectoryMixins } from '../../mixins'
import FolderIcon from '@/assets/icons/undraw_folder.svg'
export default { export default {
mixins: [createFileOrDirectoryMixins], mixins: [createFileOrDirectoryMixins],
data () { data () {
this.depth = 0 this.depth = 0
this.FolderIcon = FolderIcon
return { return {
active: 'tree', // tree or list active: 'tree', // tree or list
showDirectories: true, showDirectories: true,
@ -199,6 +204,7 @@
display: inline-block; display: inline-block;
margin-right: 10px; margin-right: 10px;
} }
.list-enter-active, .list-leave-active { .list-enter-active, .list-leave-active {
transition: all .2s; transition: all .2s;
} }
@ -209,7 +215,7 @@
} }
.tree-view { .tree-view {
font-size: 14px; font-size: 14px;
color: var(--regularColor); color: var(--sideBarColor);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
@ -228,20 +234,31 @@
pointer-events: auto; pointer-events: auto;
cursor: pointer; cursor: pointer;
margin-left: 8px; margin-left: 8px;
color: var(--secondaryColor); color: var(--iconColor);
opacity: 0; opacity: 0;
} }
& > a:hover { & > a:hover {
color: var(--primary); color: var(--themeColor);
} }
& > a.active { & > a.active {
color: var(--primary); color: var(--themeColor);
} }
} }
.tree-view:hover .title a { .tree-view:hover .title a {
opacity: 1; opacity: 1;
} }
.icon-arrow {
margin-right: 5px;
transition: all .25s ease-out;
transform: rotate(90deg);
fill: var(--sideBarTextColor);
}
.icon-arrow.fold {
transform: rotate(0);
}
.opened-files, .opened-files,
.project-tree { .project-tree {
& > .title { & > .title {
@ -261,7 +278,7 @@
& > a { & > a {
display: none; display: none;
text-decoration: none; text-decoration: none;
color: var(--secondaryColor); color: var(--sideBarColor);
margin-left: 8px; margin-left: 8px;
} }
} }
@ -269,7 +286,7 @@
.opened-files div.title > a:hover { .opened-files div.title > a:hover {
display: block; display: block;
&:hover { &:hover {
color: var(--primary); color: var(--sideBarTitleColor);
} }
} }
.opened-files { .opened-files {
@ -277,7 +294,7 @@
flex-direction: column; flex-direction: column;
} }
.default-cursor { .default-cursor {
cursor: default; cursor: pointer;
} }
.opened-files .opened-files-list { .opened-files .opened-files-list {
max-height: 200px; max-height: 200px;
@ -308,26 +325,30 @@
.open-project { .open-project {
flex: 1; flex: 1;
display: flex; display: flex;
flex-direction: column;
justify-content: space-around; justify-content: space-around;
align-items: center; align-items: center;
margin-top: -100px; padding-bottom: 100px;
& > a { & .button-group {
width: 35px;
height: 35px;
border-radius: 50%;
text-decoration: none;
background: rgba(31, 116, 255, .5);
transition: all .3s ease;
display: flex; display: flex;
justify-content: space-around; flex-direction: column;
align-items: center; align-items: center;
& > svg { }
width: 18px; & svg {
height: 18px; width: 120px;
color: #fff; fill: var(--themeColor);
} }
&:hover { & a {
background: var(--primary); text-decoration: none;
background: var(--themeColor);
box-shadow: 0 0 8px 0 var(--selectionColor);
display: block;
padding: 4px 7px;
border-radius: 5px;
margin-top: 20px;
color: #fff;
&:active {
opacity: .5;
} }
} }
} }
@ -335,7 +356,7 @@
outline: none; outline: none;
height: 22px; height: 22px;
margin: 5px 0; margin: 5px 0;
border: 1px solid var(--lightBorder); border: 1px solid var(--themeColor);
width: calc(100% - 45px); width: calc(100% - 45px);
border-radius: 3px; border-radius: 3px;
} }
@ -352,7 +373,7 @@
padding-top: 40px; padding-top: 40px;
align-items: center; align-items: center;
& > a { & > a {
color: var(--primary); color: var(--themeColor);
text-align: center; text-align: center;
margin-top: 15px; margin-top: 15px;
text-decoration: none; text-decoration: none;

View File

@ -1,7 +1,7 @@
<template> <template>
<div <div
class="title-bar" class="title-bar"
:class="[{ 'active': active }, theme, { 'frameless': titleBarStyle === 'custom' }, { 'isOsx': platform === 'darwin' }]" :class="[{ 'active': active }, { 'frameless': titleBarStyle === 'custom' }, { 'isOsx': platform === 'darwin' }]"
> >
<div class="title"> <div class="title">
<span v-if="!filename">Mark Text</span> <span v-if="!filename">Mark Text</span>
@ -34,11 +34,20 @@
<el-tooltip <el-tooltip
v-if="wordCount" v-if="wordCount"
class="item" class="item"
effect="dark"
:content="`${wordCount[show]} ${HASH[show].full + (wordCount[show] > 1 ? 's' : '')}`" :content="`${wordCount[show]} ${HASH[show].full + (wordCount[show] > 1 ? 's' : '')}`"
:open-delay="500"
placement="bottom-end" placement="bottom-end"
> >
<div slot="content">
<div class="title-item">
<span class="front">Words:</span><span class="text">{{wordCount['word']}}</span>
</div>
<div class="title-item">
<span class="front">Characters:</span><span class="text">{{wordCount['character']}}</span>
</div>
<div class="title-item">
<span class="front">Paragraph:</span><span class="text">{{wordCount['paragraph']}}</span>
</div>
</div>
<div <div
v-if="wordCount" v-if="wordCount"
class="word-count" class="word-count"
@ -125,7 +134,6 @@
pathname: String, pathname: String,
active: Boolean, active: Boolean,
wordCount: Object, wordCount: Object,
theme: String,
platform: String, platform: String,
isSaved: Boolean isSaved: Boolean
}, },
@ -206,20 +214,20 @@
.title-bar { .title-bar {
-webkit-app-region: drag; -webkit-app-region: drag;
user-select: none; user-select: none;
background: var(--editorBgColor);
width: 100%; width: 100%;
height: var(--titleBarHeight); height: var(--titleBarHeight);
box-sizing: border-box; box-sizing: border-box;
color: #F2F6FC; color: var(--editorColor50);
position: fixed; position: absolute;
top: 0; top: 0;
left: 0;
right: 0; right: 0;
z-index: 1; z-index: 2;
transition: color .4s ease-in-out; transition: color .4s ease-in-out;
cursor: default; cursor: default;
} }
.active { .active {
color: #909399; color: var(--editorColor);
} }
img { img {
height: 90%; height: 90%;
@ -248,7 +256,7 @@
} }
.title-bar .title .filename.isOsx:hover { .title-bar .title .filename.isOsx:hover {
color: var(--primary); color: var(--themeColor);
} }
.active .save-dot { .active .save-dot {
@ -257,7 +265,7 @@
height: 7px; height: 7px;
display: inline-block; display: inline-block;
border-radius: 50%; border-radius: 50%;
background: var(--warning); background: var(--themeColor);
opacity: .7; opacity: .7;
visibility: hidden; visibility: hidden;
} }
@ -265,11 +273,9 @@
visibility: visible; visibility: visible;
} }
.title:hover { .title:hover {
color: #303133; color: var(sideBarTitleColor);
}
.title:hover .save-dot {
background: var(--warning);
} }
.right-toolbar { .right-toolbar {
padding: 0 10px; padding: 0 10px;
height: 100%; height: 100%;
@ -278,6 +284,7 @@
right: 0; right: 0;
width: 100px; width: 100px;
display: flex; display: flex;
align-items: center;
flex-direction: row-reverse; flex-direction: row-reverse;
} }
.left-toolbar { .left-toolbar {
@ -293,20 +300,19 @@
.word-count { .word-count {
cursor: pointer; cursor: pointer;
font-size: 14px; font-size: 14px;
color: #F2F6FC; color: var(--editorColor30);
height: 17px; height: 20px;
line-height: 17px; text-align: center;
margin-top: 4px; line-height: 24px;
padding: 1px 5px; padding: 0px 5px;
border-radius: 1px; box-sizing: border-box;
border-radius: 4px;
transition: all .25s ease-in-out; transition: all .25s ease-in-out;
} }
.active .word-count {
color: #DCDFE6;
}
.word-count:hover { .word-count:hover {
background: #F2F6FC; background: var(--sideBarBgColor);
color: #606266; color: var(--sideBarTitleColor);
} }
.title-no-drag { .title-no-drag {
-webkit-app-region: no-drag; -webkit-app-region: no-drag;
@ -326,7 +332,7 @@
transform: translateX(-50%) translateY(-50%); transform: translateX(-50%) translateY(-50%);
} }
.frameless-titlebar-menu { .frameless-titlebar-menu {
color: #606266; color: var(--sideBarColor);
} }
.frameless-titlebar-close:hover { .frameless-titlebar-close:hover {
background-color: rgb(228, 79, 79); background-color: rgb(228, 79, 79);
@ -341,26 +347,19 @@
.frameless-titlebar-close:hover svg { .frameless-titlebar-close:hover svg {
fill: #ffffff fill: #ffffff
} }
/* css for dark theme */
.dark {
background: var(--darkBgColor);
color: #909399;
}
.dark .title:hover {
color: #F2F6FC;
}
.dark .word-count:hover {
background: rgb(71, 72, 66);
color: #C0C4CC;
}
.dark .frameless-titlebar-button svg {
fill: #909399
}
.dark .frameless-titlebar-close:hover svg {
fill: #ffffff
}
/* exclude titlebar so we can apply a custom sidebar background color */
.title-bar.dark {
background: transparent;
}
</style> </style>
<style>
.title-item {
height: 28px;
line-height: 28px;
& .front {
color: var(--editorColor50);
}
& .text {
margin-left: 10px;
color: var(--editorColor30);
}
}
</style>

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="tweet-dialog" :class="theme"> <div class="tweet-dialog">
<el-dialog <el-dialog
:visible.sync="showTweetDialog" :visible.sync="showTweetDialog"
:show-close="false" :show-close="false"
@ -68,7 +68,6 @@
<script> <script>
import { shell } from 'electron' import { shell } from 'electron'
import { mapState } from 'vuex'
import bus from '../../bus' import bus from '../../bus'
export default { export default {
@ -79,11 +78,6 @@
selectedFace: 'smile' selectedFace: 'smile'
} }
}, },
computed: {
...mapState({
'theme': state => state.preferences.theme
})
},
created () { created () {
bus.$on('tweetDialog', this.showDialog) bus.$on('tweetDialog', this.showDialog)
}, },
@ -127,8 +121,7 @@
<style> <style>
.tweet-dialog { .tweet-dialog {
width: 450px; color: var(--sideBarColor);
color: var(--regularColor);
& .title { & .title {
font-size: 24px; font-size: 24px;
} }
@ -136,11 +129,14 @@
border-top-left-radius: 5px; border-top-left-radius: 5px;
border-top-right-radius: 5px; border-top-right-radius: 5px;
} }
& .el-dialog__body {
color: var(--sideBarColor);
}
} }
.feeling, .feedback { .tweet-dialog .feeling, .tweet-dialog .feedback {
font-size: 16px; font-size: 16px;
} }
.feeling { .tweet-dialog .feeling {
& ul { & ul {
display: flex; display: flex;
list-style: none; list-style: none;
@ -163,7 +159,7 @@
color: rgb(255, 204, 0); color: rgb(255, 204, 0);
} }
} }
.feedback { .tweet-dialog .feedback {
& > textarea { & > textarea {
width: 100%; width: 100%;
box-sizing: border-box; box-sizing: border-box;
@ -171,19 +167,21 @@
padding: .5rem; padding: .5rem;
resize: none; resize: none;
outline: none; outline: none;
border-color: var(--lightBorder); border: 1px solid var(--floatBorderColor);
background: var(--floatBorderColor);
color: var(--editorColor);
border-radius: 5px; border-radius: 5px;
font-size: 14px; font-size: 14px;
height: 80px; height: 80px;
} }
} }
.button { .tweet-dialog .button {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
} }
.button a.twitter { .tweet-dialog .button a.twitter {
color: var(--secondaryColor); color: var(--themeColor);
text-decoration: none; text-decoration: none;
width: auto; width: auto;
height: 30px; height: 30px;
@ -195,18 +193,18 @@
background: #eee; background: #eee;
cursor: not-allowed; cursor: not-allowed;
} }
.button a.active { .tweet-dialog .button a.active {
background: var(--primary); background: var(--themeColor);
color: #fff; color: #fff;
} }
.button a.active { .tweet-dialog .button a.active {
cursor: pointer; cursor: pointer;
} }
.button a.github { .tweet-dialog .button a.github {
color: var(--secondaryColor); color: var(--iconColor);
text-decoration: none; text-decoration: none;
&:hover { &:hover {
color: #1da1f2; color: var(--themeColor);
} }
& > svg { & > svg {
width: 1.4rem; width: 1.4rem;
@ -214,13 +212,8 @@
vertical-align: bottom; vertical-align: bottom;
} }
} }
.tweet-dialog.dark textarea { .tweet-dialog .el-dialog__header {
background: var(--darkInputBgColor); background: var(--themeColor);
border-color: transparent;
color: var(--darkInputColor);
}
.tweet-dialog.light .el-dialog__header {
background: var(--primary);
color: #fff; color: #fff;
} }
</style> </style>

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="aidou" :class="theme"> <div class="aidou">
<el-dialog <el-dialog
:visible.sync="showUpload" :visible.sync="showUpload"
:show-close="false" :show-close="false"
@ -27,7 +27,6 @@
</template> </template>
<script> <script>
import { mapState } from 'vuex'
import bus from '../../bus' import bus from '../../bus'
const msg = 'jpg | png | gif | jpeg only, max size 5M' const msg = 'jpg | png | gif | jpeg only, max size 5M'
@ -40,11 +39,6 @@
error: false error: false
} }
}, },
computed: {
...mapState({
'theme': state => state.preferences.theme
})
},
created () { created () {
this.$nextTick(() => { this.$nextTick(() => {
bus.$on('upload-image', this.handleUpload) bus.$on('upload-image', this.handleUpload)
@ -92,11 +86,21 @@
<style> <style>
.el-upload__tip { .el-upload__tip {
text-align: center; text-align: center;
color: var(--sideBarColor);
} }
.el-upload__tip.error { .el-upload__tip.error {
color: #E6A23C; color: #E6A23C;
} }
.dark .el-upload-dragger { .el-upload-dragger {
background: rgb(39, 39, 39); background: var(--itemBgColor);
& .el-upload__text {
color: var(--sideBarColor);
& em {
color: var(--themeColor);
}
}
}
.el-upload-dragger:hover {
border-color: var(--themeColor);
} }
</style> </style>

View File

@ -2,7 +2,7 @@ import path from 'path'
export const PATH_SEPARATOR = path.sep export const PATH_SEPARATOR = path.sep
export const THEME_LINK_ID = 'ag-theme' export const THEME_STYLE_ID = 'ag-theme'
export const COMMON_STYLE_ID = 'ag-common-style' export const COMMON_STYLE_ID = 'ag-common-style'
export const DEFAULT_EDITOR_FONT_FAMILY = '"Open Sans", "Clear Sans", "Helvetica Neue", Helvetica, Arial, sans-serif' export const DEFAULT_EDITOR_FONT_FAMILY = '"Open Sans", "Clear Sans", "Helvetica Neue", Helvetica, Arial, sans-serif'
@ -12,3 +12,5 @@ export const DEFAULT_STYLE = {
codeFontSize: '14px', codeFontSize: '14px',
theme: 'light' theme: 'light'
} }
export const railscastsThemes = ['dark']

View File

@ -6,7 +6,20 @@ import locale from 'element-ui/lib/locale'
import App from './app' import App from './app'
import store from './store' import store from './store'
import './assets/symbolIcon' import './assets/symbolIcon'
import { Dialog, Form, FormItem, InputNumber, Button, Tooltip, Upload, Slider, ColorPicker, Col, Row } from 'element-ui' import {
Dialog,
Form,
FormItem,
InputNumber,
Button,
Tooltip,
Upload,
Slider,
ColorPicker,
Col,
Row,
Tree
} from 'element-ui'
import services from './services' import services from './services'
import './assets/styles/index.css' import './assets/styles/index.css'
@ -54,6 +67,7 @@ Vue.use(Slider)
Vue.use(ColorPicker) Vue.use(ColorPicker)
Vue.use(Col) Vue.use(Col)
Vue.use(Row) Vue.use(Row)
Vue.use(Tree)
if (!process.env.IS_WEB) Vue.use(require('vue-electron')) if (!process.env.IS_WEB) Vue.use(require('vue-electron'))
Vue.http = Vue.prototype.$http = axios Vue.http = Vue.prototype.$http = axios

View File

@ -2,24 +2,16 @@ import { clipboard, ipcRenderer, shell } from 'electron'
import path from 'path' import path from 'path'
import bus from '../bus' import bus from '../bus'
import { hasKeys } from '../util' import { hasKeys } from '../util'
import listToTree from '../util/listToTree'
import { createDocumentState, getOptionsFromState, getSingleFileState, getBlankFileState } from './help' import { createDocumentState, getOptionsFromState, getSingleFileState, getBlankFileState } from './help'
import notice from '../services/notification' import notice from '../services/notification'
// HACK: When rewriting muya, create and update muya's TOC during heading parsing and pass it to the renderer process.
import { getTocFromMarkdown } from 'muya/lib/utils/dirtyToc'
const state = { const state = {
lineEnding: 'lf', lineEnding: 'lf',
currentFile: {}, currentFile: {},
tabs: [], tabs: [],
textDirection: 'ltr' textDirection: 'ltr',
} toc: []
const getters = {
toc: state => {
const { markdown } = state.currentFile
return getTocFromMarkdown(markdown)
}
} }
const mutations = { const mutations = {
@ -27,6 +19,9 @@ const mutations = {
SET_SEARCH (state, value) { SET_SEARCH (state, value) {
state.currentFile.searchMatches = value state.currentFile.searchMatches = value
}, },
SET_TOC (state, toc) {
state.toc = listToTree(toc)
},
SET_CURRENT_FILE (state, currentFile) { SET_CURRENT_FILE (state, currentFile) {
const oldCurrentFile = state.currentFile const oldCurrentFile = state.currentFile
if (!oldCurrentFile.id || oldCurrentFile.id !== currentFile.id) { if (!oldCurrentFile.id || oldCurrentFile.id !== currentFile.id) {
@ -463,7 +458,7 @@ const actions = {
// }, // },
// Content change from realtime preview editor and source code editor // Content change from realtime preview editor and source code editor
LISTEN_FOR_CONTENT_CHANGE ({ commit, state, rootState }, { markdown, wordCount, cursor, history }) { LISTEN_FOR_CONTENT_CHANGE ({ commit, state, rootState }, { markdown, wordCount, cursor, history, toc }) {
const { autoSave } = rootState.preferences const { autoSave } = rootState.preferences
const { projectTree } = rootState.project const { projectTree } = rootState.project
const { pathname, markdown: oldMarkdown, id } = state.currentFile const { pathname, markdown: oldMarkdown, id } = state.currentFile
@ -481,6 +476,8 @@ const actions = {
if (cursor) commit('SET_CURSOR', cursor) if (cursor) commit('SET_CURSOR', cursor)
// set history // set history
if (history) commit('SET_HISTORY', history) if (history) commit('SET_HISTORY', history)
// set toc
if (toc) commit('SET_TOC', toc)
// change save status/save to file only when the markdown changed! // change save status/save to file only when the markdown changed!
if (markdown !== oldMarkdown) { if (markdown !== oldMarkdown) {
@ -591,4 +588,4 @@ const actions = {
} }
} }
export default { state, getters, mutations, actions } export default { state, mutations, actions }

9
src/renderer/util/day.js Normal file
View File

@ -0,0 +1,9 @@
import dayjs from 'dayjs/esm'
import relativeTime from 'dayjs/esm/plugin/relativeTime'
import 'dayjs/esm/locale/en' // load on demand
dayjs.locale('en') // use Spanish locale globally
dayjs.extend(relativeTime)
export default dayjs

View File

@ -0,0 +1,30 @@
const listToTree = list => {
const result = []
let parent = null
let child = null
let tempLvl = 7 // any number great than 6
for (const { lvl, content, slug } of list) {
const item = {
lvl, label: content, slug, children: []
}
if (lvl < tempLvl) {
tempLvl = lvl
result.push(item)
parent = { children: result }
child = item
} else if (lvl === tempLvl) {
parent.children.push(item)
child = item
} else if (lvl > tempLvl) {
tempLvl = lvl
child.children.push(item)
parent = child
child = item
}
}
return result
}
export default listToTree

View File

@ -1,18 +1,42 @@
import { THEME_LINK_ID, COMMON_STYLE_ID, DEFAULT_CODE_FONT_FAMILY } from '../config' import { THEME_STYLE_ID, COMMON_STYLE_ID, DEFAULT_CODE_FONT_FAMILY, railscastsThemes } from '../config'
import { dark, ulysses, graphite } from './themeColor'
export const addThemeStyle = theme => { export const addThemeStyle = theme => {
const href = process.env.NODE_ENV !== 'production' let themeStyleEle = document.querySelector(`#${THEME_STYLE_ID}`)
? `./src/muya/themes/${theme}.css` if (!themeStyleEle) {
: `./static/themes/${theme}.css` themeStyleEle = document.createElement('style')
themeStyleEle.id = THEME_STYLE_ID
document.head.appendChild(themeStyleEle)
}
switch (theme) {
case 'light':
themeStyleEle.innerHTML = ''
break
case 'dark':
themeStyleEle.innerHTML = dark
break
case 'ulysses':
themeStyleEle.innerHTML = ulysses
break
case 'graphite':
themeStyleEle.innerHTML = graphite
break
default:
console.log('unknown theme')
break
}
let link = document.querySelector(`#${THEME_LINK_ID}`) // change codeMirror theme
if (!link) { const cm = document.querySelector('.CodeMirror')
link = document.createElement('link') if (cm) {
link.setAttribute('rel', 'stylesheet') if (railscastsThemes.includes(theme)) {
link.id = THEME_LINK_ID cm.classList.remove('cm-s-default')
document.head.appendChild(link) cm.classList.add('cm-s-railscasts')
} else {
cm.classList.add('cm-s-default')
cm.classList.remove('cm-s-railscasts')
} }
link.href = href }
} }
export const addCommonStyle = style => { export const addCommonStyle = style => {

View File

@ -0,0 +1,392 @@
// we can load custom theme from userData folder, we also can write this theme in userData folder.
export const dark = `
:root {
--themeColor: #f48237;
--highlightColor: rgba(244, 130, 55, .9);
--selectionColor: rgba(244, 130, 55, .4);
--editorColor: rgba(255, 255, 255, .8);
--editorColor50: rgba(255, 255, 255, .5);
--editorColor30: rgba(255, 255, 255, .3);
--editorColor10: rgba(255, 255, 255, .1);
--editorBgColor: #34393f;
--deleteColor: #ff6969;
--iconColor: rgba(255, 255, 255, .8);
--codeBgColor: #d8d8d869;
--codeBlockBgColor: rgba(244, 130, 55, .04);
--sideBarColor: rgba(255, 255, 255, .6);
--sideBarTitleColor: rgba(255, 255, 255, 1);
--sideBarTextColor: rgba(255, 255, 255, .4);
--sideBarBgColor: rgba(26, 33, 41, 0.9);
--sideBarItemHoverBgColor: rgba(255, 255, 255, .03);
--itemBgColor: rgba(71, 78, 86, 0.6);
--floatBgColor: #3c4650;
--floatHoverColor: rgba(255, 255, 255, .04);
--floatBorderColor: rgba(0, 0, 0, .03);
--editorAreaWidth: 700px;
}
div.title-bar .frameless-titlebar-button > div > svg {
fill: #ffffff;
}
/**
* okaidia theme for JavaScript, CSS and HTML
* Loosely based on Monokai textmate theme by http://www.monokai.nl/
* @author ocodia
*/
code[class*="language-"],
pre.ag-paragraph {
color: #f8f8f2;
/*font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;*/
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
overflow: visible;
}
/* Code blocks */
pre.ag-paragraph {
padding: 1em;
margin: 1em 0;
border-radius: 0.3em;
}
:not(pre) > code[class*="language-"],
pre.ag-paragraph {
/*background: #272822;*/
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}
.token.punctuation {
color: #f8f8f2;
}
.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.constant,
.token.symbol {
color: #f92672;
}
.token.boolean,
.token.number {
color: #ae81ff;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin {
color: #a6e22e;
}
.token.inserted {
color: #22863a;
background: #f0fff4;
}
.token.deleted {
color: #b31d28;
background: #ffeef0;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string,
.token.variable {
color: #f8f8f2;
}
.token.atrule,
.token.attr-value,
.token.function,
.token.class-name {
color: #e6db74;
}
.token.keyword {
color: #66d9ef;
}
.token.regex,
.token.important {
color: #fd971f;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
`
export const ulysses = `
:root {
--themeColor: rgb(12, 139, 186);
--highlightColor: rgba(12, 139, 186, .9);
--selectionColor: rgba(12, 139, 186, .4);
--editorColor: rgba(101, 101, 101, .8);
--editorColor50: rgba(101, 101, 101, .5);
--editorColor30: rgba(101, 101, 101, .3);
--editorColor10: rgba(101, 101, 101, .1);
--editorBgColor: #f3f3f3;
--deleteColor: #ff6969;
--iconColor: rgba(101, 101, 101, .8);
--codeBgColor: #d8d8d869;
--codeBlockBgColor: rgba(12, 139, 186, .04);
--sideBarColor: rgba(101, 101, 101, .6);
--sideBarTitleColor: rgba(101, 101, 101, 1);
--sideBarTextColor: rgba(101, 101, 101, .4);
--sideBarBgColor: rgba(248, 248, 248, 0.9);
--sideBarItemHoverBgColor: rgba(101, 101, 101, .03);
--itemBgColor: rgba(245, 245, 245, 0.6);
--floatBgColor: #ffffff;
--floatHoverColor: rgba(101, 101, 101, .04);
--floatBorderColor: rgba(0, 0, 0, .03);
--editorAreaWidth: 700px;
}
h1, h2, h3, h4, h5, h6 {
color: var(--themeColor);
text-align: center;
}
li.ag-bullet-list-item {
position: relative;
list-style: none;
}
li.ag-bullet-list-item::before {
content: '';
display: block;
position: absolute;
width: 5px;
height: 2px;
left: -18px;
top: 15px;
background: var(--editorColor);
}
blockquote.ag-paragraph {
background: rgb(233, 233, 233);
}
blockquote.ag-paragraph::before {
content: none;
}
li.ag-paragraph {
color: var(--editorColor);
}
/*task list*/
li.ag-task-list-item {
list-style-type: none;
position: relative;
}
li.ag-task-list-item > input[type=checkbox] {
position: absolute;
cursor: pointer;
width: 16px;
height: 16px;
margin: 4px 0px 0px;
top: 2px;
left: -22px;
transform-origin: center;
transform: rotate(-90deg);
transition: all .2s ease;
}
li.ag-task-list-item > input.ag-checkbox-checked {
transform: rotate(0);
opacity: .5;
}
li.ag-task-list-item > input[type=checkbox]::before {
content: '';
width: 16px;
height: 16px;
box-sizing: border-box;
display: inline-block;
border: 2px solid var(--editorColor);
border-radius: 2px;
background-color: var(--editorBgColor);
position: absolute;
top: 0;
left: 0;
transition: all .2s ease;
}
li.ag-task-list-item > input.ag-checkbox-checked::before {
border: transparent;
background-color: var(--editorColor);
}
li.ag-task-list-item > input::after {
content: '';
transform: rotate(-45deg) scale(0);
width: 9px;
height: 5px;
border: 2px solid #fff;
border-top: none;
border-right: none;
position: absolute;
display: inline-block;
top: 1px;
left: 5px;
transition: all .2s ease;
}
li.ag-task-list-item > input.ag-checkbox-checked::after {
transform: rotate(-45deg) scale(1);
}
/*horizontal line*/
p:not(.ag-active)[data-role="hr"]::before {
content: '';
position: absolute;
width: 50%;
display: block;
left: 50%;
top: 50%;
height: 2px;
box-sizing: border-box;
border-bottom: 2px dashed var(--editorColor50);
transform: translateX(-50%) translateY(-50%);
}
`
export const graphite = `
:root {
--themeColor: rgb(104, 134, 170);
--highlightColor: rgba(104, 134, 170, .9);
--selectionColor: rgba(104, 134, 170, .4);
--editorColor: rgba(43, 48, 50, .8);
--editorColor50: rgba(43, 48, 50, .5);
--editorColor30: rgba(43, 48, 50, .3);
--editorColor10: rgba(43, 48, 50, .1);
--editorBgColor: #f7f7f7;
--deleteColor: #ff6969;
--iconColor: rgba(135, 135, 135, .8);
--codeBgColor: #d8d8d869;
--codeBlockBgColor: rgba(104, 134, 170, .04);
--sideBarColor: rgba(188, 193, 197, .8);
--sideBarTitleColor: rgba(255, 255, 255, 1);
--sideBarTextColor: rgba(188, 193, 197, .4);
--sideBarBgColor: rgba(69, 75, 80, 1);
--sideBarItemHoverBgColor: rgba(255, 255, 255, .03);
--itemBgColor: rgba(43, 48, 50, .5);
--floatBgColor: rgb(237, 237, 238);
--floatHoverColor: rgba(43, 48, 50, .04);
--floatBorderColor: rgba(0, 0, 0, .03);
--editorAreaWidth: 700px;
}
li.ag-paragraph {
color: var(--editorColor);
}
/*task list*/
li.ag-task-list-item {
list-style-type: none;
position: relative;
}
li.ag-task-list-item > input[type=checkbox] {
position: absolute;
cursor: pointer;
width: 16px;
height: 16px;
margin: 4px 0px 0px;
top: 2px;
left: -22px;
transform-origin: center;
transform: rotate(-90deg);
transition: all .2s ease;
}
li.ag-task-list-item > input.ag-checkbox-checked {
transform: rotate(0);
opacity: .5;
}
li.ag-task-list-item > input[type=checkbox]::before {
content: '';
width: 16px;
height: 16px;
box-sizing: border-box;
display: inline-block;
border: 2px solid var(--editorColor);
border-radius: 2px;
background-color: var(--editorBgColor);
position: absolute;
top: 0;
left: 0;
transition: all .2s ease;
}
li.ag-task-list-item > input.ag-checkbox-checked::before {
border: transparent;
background-color: var(--editorColor);
}
li.ag-task-list-item > input::after {
content: '';
transform: rotate(-45deg) scale(0);
width: 9px;
height: 5px;
border: 2px solid #fff;
border-top: none;
border-right: none;
position: absolute;
display: inline-block;
top: 1px;
left: 5px;
transition: all .2s ease;
}
li.ag-task-list-item > input.ag-checkbox-checked::after {
transform: rotate(-45deg) scale(1);
}
/*horizontal line*/
p:not(.ag-active)[data-role="hr"]::before {
content: '';
position: absolute;
width: 100%;
display: block;
left: 50%;
top: 50%;
height: 2px;
box-sizing: border-box;
border-bottom: 2px dashed var(--editorColor50);
transform: translateX(-50%) translateY(-50%);
}
`

View File

@ -3168,6 +3168,11 @@ dateformat@^1.0.6:
get-stdin "^4.0.1" get-stdin "^4.0.1"
meow "^3.3.0" meow "^3.3.0"
dayjs@^1.8.10:
version "1.8.10"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.8.10.tgz#fc35a976ccac2a9c44b50485a06c4a5ecf5d1b37"
integrity sha512-U+7kBBkJzPWww0vNeMkaBeJwnkivTACoajm+bTfwparjFcPI6/5JSQN40WVnX6yCsm20oGf1SkMkIIp4m/boAw==
de-indent@^1.0.2: de-indent@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
@ -3397,11 +3402,6 @@ di@^0.0.1:
resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c"
integrity sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw= integrity sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=
diacritics-map@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/diacritics-map/-/diacritics-map-0.1.0.tgz#6dfc0ff9d01000a2edf2865371cac316e94977af"
integrity sha1-bfwP+dAQAKLt8oZTccrDFulJd68=
diff@3.5.0: diff@3.5.0:
version "3.5.0" version "3.5.0"
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"