forked from marktext/marktext
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy paththeme.js
More file actions
176 lines (159 loc) · 4.99 KB
/
theme.js
File metadata and controls
176 lines (159 loc) · 4.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
import { THEME_STYLE_ID, COMMON_STYLE_ID, DEFAULT_CODE_FONT_FAMILY, oneDarkThemes, railscastsThemes } from '../config'
import { dark, graphite, materialDark, oneDark, ulysses } from './themeColor'
import { isLinux } from './index'
import elementStyle from 'element-ui/lib/theme-chalk/index.css'
const ORIGINAL_THEME = '#409EFF'
const patchTheme = css => {
return `@media not print {\n${css}\n}`
}
const getEmojiPickerPatch = () => {
return isLinux
? '.ag-emoji-picker section .emoji-wrapper .item span { font-family: sans-serif, "Noto Color Emoji"; }'
: ''
}
const getThemeCluster = themeColor => {
const tintColor = (color, tint) => {
let red = parseInt(color.slice(1, 3), 16)
let green = parseInt(color.slice(3, 5), 16)
let blue = parseInt(color.slice(5, 7), 16)
if (tint === 0) { // when primary color is in its rgb space
return [red, green, blue].join(',')
} else {
red += Math.round(tint * (255 - red))
green += Math.round(tint * (255 - green))
blue += Math.round(tint * (255 - blue))
red = red.toString(16)
green = green.toString(16)
blue = blue.toString(16)
return `#${red}${green}${blue}`
}
}
const clusters = [{
color: themeColor,
variable: 'var(--themeColor)'
}]
for (let i = 9; i >= 1; i--) {
clusters.push({
color: tintColor(themeColor, Number((i / 10).toFixed(2))),
variable: `var(--themeColor${10 - i}0)`
})
}
return clusters
}
export const addThemeStyle = theme => {
const isCmRailscasts = railscastsThemes.includes(theme)
const isCmOneDark = oneDarkThemes.includes(theme)
const isDarkTheme = isCmOneDark || isCmRailscasts
let themeStyleEle = document.querySelector(`#${THEME_STYLE_ID}`)
if (!themeStyleEle) {
themeStyleEle = document.createElement('style')
themeStyleEle.id = THEME_STYLE_ID
document.head.appendChild(themeStyleEle)
}
switch (theme) {
case 'light':
themeStyleEle.innerHTML = ''
break
case 'dark':
themeStyleEle.innerHTML = patchTheme(dark())
break
case 'material-dark':
themeStyleEle.innerHTML = patchTheme(materialDark())
break
case 'ulysses':
themeStyleEle.innerHTML = patchTheme(ulysses())
break
case 'graphite':
themeStyleEle.innerHTML = patchTheme(graphite())
break
case 'one-dark':
themeStyleEle.innerHTML = patchTheme(oneDark())
break
default:
console.log('unknown theme')
break
}
// workaround: use dark icons
document.body.classList.remove('dark')
if (isDarkTheme) {
document.body.classList.add('dark')
}
// change CodeMirror theme
const cm = document.querySelector('.CodeMirror')
if (cm) {
cm.classList.remove('cm-s-default')
cm.classList.remove('cm-s-one-dark')
cm.classList.remove('cm-s-railscasts')
if (isCmOneDark) {
cm.classList.add('cm-s-one-dark')
} else if (isCmRailscasts) {
cm.classList.add('cm-s-railscasts')
} else {
cm.classList.add('cm-s-default')
}
}
}
export const setEditorWidth = value => {
const EDITOR_WIDTH_STYLE_ID = 'editor-width'
let result = ''
if (value && /^[0-9]+(?:ch|px|%)$/.test(value)) {
// Overwrite the theme value and add 100px for padding.
result = `:root { --editorAreaWidth: calc(100px + ${value}); }`
}
let styleEle = document.querySelector(`#${EDITOR_WIDTH_STYLE_ID}`)
if (!styleEle) {
styleEle = document.createElement('style')
styleEle.setAttribute('id', EDITOR_WIDTH_STYLE_ID)
document.head.appendChild(styleEle)
}
styleEle.innerHTML = result
}
export const addCommonStyle = options => {
const { codeFontFamily, codeFontSize, hideScrollbar } = options
let sheet = document.querySelector(`#${COMMON_STYLE_ID}`)
if (!sheet) {
sheet = document.createElement('style')
sheet.id = COMMON_STYLE_ID
document.head.appendChild(sheet)
}
let scrollbarStyle = ''
if (hideScrollbar) {
scrollbarStyle = '::-webkit-scrollbar {display: none;}'
}
sheet.innerHTML = `${scrollbarStyle}
span code,
td code,
th code,
code,
code[class*="language-"],
.CodeMirror,
pre.ag-paragraph {
font-family: ${codeFontFamily}, ${DEFAULT_CODE_FONT_FAMILY};
font-size: ${codeFontSize}px;
}
${getEmojiPickerPatch()}
`
}
export const addElementStyle = () => {
const ID = 'mt-el-style'
let sheet = document.querySelector(`#${ID}`)
if (sheet) {
return
}
const themeCluster = getThemeCluster(ORIGINAL_THEME)
let newElementStyle = elementStyle
for (const { color, variable } of themeCluster) {
newElementStyle = newElementStyle.replace(new RegExp(color, 'ig'), variable)
}
sheet = document.createElement('style')
sheet.id = ID
// NOTE: Prepend element UI style, otherwise we cannot overwrite the style with the default light theme.
document.head.insertBefore(sheet, document.head.firstChild)
sheet.innerHTML = newElementStyle
}
// Append common sheet and theme at the end of head - order is important.
export const addStyles = options => {
const { theme } = options
addThemeStyle(theme)
addCommonStyle(options)
}