mirror of
https://github.com/doocs/md.git
synced 2024-11-24 19:10:34 +08:00
refactor: customize theme (#368)
This commit is contained in:
parent
a744ecba68
commit
fed75b307e
@ -1,37 +1,29 @@
|
|||||||
interface Theme {
|
interface Theme {
|
||||||
BASE: Record<string, string | number>
|
base: Record<string, string | number>
|
||||||
block: Record<string, Record<string, string | number>>
|
block: Record<string, Record<string, string | number>>
|
||||||
inline: Record<string, Record<string, string | number>>
|
inline: Record<string, Record<string, string | number>>
|
||||||
}
|
}
|
||||||
|
|
||||||
const baseColor = `#3f3f3f`
|
const baseColor = `#3f3f3f`
|
||||||
|
|
||||||
function mergeTheme(defaultTheme: Theme, newTheme: Theme) {
|
function mergeTheme(defaultTheme: Theme, newTheme: Theme): Theme {
|
||||||
const res: Theme = {
|
const merge = (defaultObj: Record<string, any>, newObj: Record<string, any>) => {
|
||||||
BASE: {
|
const result: Record<string, any> = {}
|
||||||
...defaultTheme.BASE,
|
for (const key in defaultObj) {
|
||||||
...newTheme.BASE,
|
result[key] = { ...defaultObj[key], ...newObj?.[key] }
|
||||||
},
|
|
||||||
block: {},
|
|
||||||
inline: {},
|
|
||||||
}
|
|
||||||
for (const el in defaultTheme.block) {
|
|
||||||
res.block[el] = {
|
|
||||||
...defaultTheme.block[el],
|
|
||||||
...newTheme.block[el],
|
|
||||||
}
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
for (const el in defaultTheme.inline) {
|
|
||||||
res.inline[el] = {
|
return {
|
||||||
...defaultTheme.inline[el],
|
base: { ...defaultTheme.base, ...newTheme.base },
|
||||||
...newTheme.inline[el],
|
block: merge(defaultTheme.block, newTheme.block),
|
||||||
}
|
inline: merge(defaultTheme.inline, newTheme.inline),
|
||||||
}
|
}
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultTheme = {
|
const defaultTheme = {
|
||||||
BASE: {
|
base: {
|
||||||
'--md-primary-color': `#000000`,
|
'--md-primary-color': `#000000`,
|
||||||
'text-align': `left`,
|
'text-align': `left`,
|
||||||
'line-height': `1.75`,
|
'line-height': `1.75`,
|
||||||
@ -225,7 +217,7 @@ const defaultTheme = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const graceTheme = mergeTheme(defaultTheme, {
|
const graceTheme = mergeTheme(defaultTheme, {
|
||||||
BASE: {
|
base: {
|
||||||
},
|
},
|
||||||
block: {
|
block: {
|
||||||
h1: {
|
h1: {
|
||||||
|
@ -6,10 +6,10 @@ import { useDark, useStorage, useToggle } from '@vueuse/core'
|
|||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
|
||||||
import { altKey, codeBlockThemeOptions, colorOptions, fontFamilyOptions, fontSizeOptions, legendOptions, shiftKey, themeMap, themeOptions } from '@/config'
|
import { altKey, codeBlockThemeOptions, colorOptions, fontFamilyOptions, fontSizeOptions, legendOptions, shiftKey, themeMap, themeOptions } from '@/config'
|
||||||
import WxRenderer from '@/utils/wx-renderer'
|
import WxRenderer from '@/utils/renderer'
|
||||||
import DEFAULT_CONTENT from '@/assets/example/markdown.md?raw'
|
import DEFAULT_CONTENT from '@/assets/example/markdown.md?raw'
|
||||||
import DEFAULT_CSS_CONTENT from '@/assets/example/theme-css.txt?raw'
|
import DEFAULT_CSS_CONTENT from '@/assets/example/theme-css.txt?raw'
|
||||||
import { addPrefix, css2json, customCssWithTemplate, downloadMD, exportHTML, formatCss, formatDoc, setColorWithCustomTemplate, setFontSizeWithTemplate, setTheme } from '@/utils'
|
import { addPrefix, css2json, customCssWithTemplate, customizeTheme, downloadMD, exportHTML, formatCss, formatDoc } from '@/utils'
|
||||||
|
|
||||||
export const useStore = defineStore(`store`, () => {
|
export const useStore = defineStore(`store`, () => {
|
||||||
// 是否开启深色模式
|
// 是否开启深色模式
|
||||||
@ -46,7 +46,7 @@ export const useStore = defineStore(`store`, () => {
|
|||||||
const fontSizeNumber = fontSize.value.replace(`px`, ``)
|
const fontSizeNumber = fontSize.value.replace(`px`, ``)
|
||||||
|
|
||||||
const wxRenderer = new WxRenderer({
|
const wxRenderer = new WxRenderer({
|
||||||
theme: setTheme(themeMap[theme.value], fontSizeNumber, fontColor.value, theme.value === `default`),
|
theme: customizeTheme(themeMap[theme.value], { fontSize: fontSizeNumber, color: fontColor.value }),
|
||||||
fonts: fontFamily.value,
|
fonts: fontFamily.value,
|
||||||
size: fontSize.value,
|
size: fontSize.value,
|
||||||
})
|
})
|
||||||
@ -187,11 +187,9 @@ export const useStore = defineStore(`store`, () => {
|
|||||||
// 更新 CSS
|
// 更新 CSS
|
||||||
const updateCss = () => {
|
const updateCss = () => {
|
||||||
const json = css2json(cssEditor.value.getValue())
|
const json = css2json(cssEditor.value.getValue())
|
||||||
let t = setTheme(themeMap[theme.value], fontSizeNumber, fontColor.value, theme.value === `default`)
|
const newTheme = customCssWithTemplate(json, fontColor.value, customizeTheme(themeMap[theme.value], { fontSize: fontSizeNumber, color: fontColor.value }))
|
||||||
|
|
||||||
t = customCssWithTemplate(json, fontColor.value, t)
|
|
||||||
wxRenderer.setOptions({
|
wxRenderer.setOptions({
|
||||||
theme: t,
|
theme: newTheme,
|
||||||
})
|
})
|
||||||
editorRefresh()
|
editorRefresh()
|
||||||
}
|
}
|
||||||
@ -270,15 +268,15 @@ export const useStore = defineStore(`store`, () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getTheme = (size, color) => {
|
const getTheme = (size, color) => {
|
||||||
const t = setFontSizeWithTemplate(themeMap[theme.value])(size.replace(`px`, ``), theme.value === `default`)
|
const newTheme = themeMap[theme.value]
|
||||||
return setColorWithCustomTemplate(t, color, theme.value === `default`)
|
const fontSize = size.replace(`px`, ``)
|
||||||
|
return customizeTheme(newTheme, { fontSize, color })
|
||||||
}
|
}
|
||||||
|
|
||||||
const themeChanged = withAfterRefresh((newTheme) => {
|
const themeChanged = withAfterRefresh((newTheme) => {
|
||||||
wxRenderer.setOptions({
|
wxRenderer.setOptions({
|
||||||
theme: setTheme(themeMap[newTheme], fontSizeNumber, fontColor.value, newTheme === `default`),
|
theme: customizeTheme(themeMap[newTheme], { fontSize: fontSizeNumber, color: fontColor.value }),
|
||||||
})
|
})
|
||||||
|
|
||||||
theme.value = newTheme
|
theme.value = newTheme
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -9,86 +9,44 @@ export function addPrefix(str) {
|
|||||||
return `${prefix}__${str}`
|
return `${prefix}__${str}`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置自定义颜色
|
export function customizeTheme(theme, options) {
|
||||||
function createCustomTheme(theme, color) {
|
const newTheme = JSON.parse(JSON.stringify(theme))
|
||||||
const customTheme = JSON.parse(JSON.stringify(theme))
|
const { fontSize, color } = options
|
||||||
customTheme.BASE[`--md-primary-color`] = color
|
if (fontSize) {
|
||||||
return customTheme
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setColorWithCustomTemplate(theme, color, isDefault = true) {
|
|
||||||
return createCustomTheme(theme, color, isDefault)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置自定义字体大小
|
|
||||||
export function setFontSizeWithTemplate(template) {
|
|
||||||
return function (fontSize) {
|
|
||||||
const customTheme = JSON.parse(JSON.stringify(template))
|
|
||||||
for (let i = 1; i <= 4; i++) {
|
for (let i = 1; i <= 4; i++) {
|
||||||
const v = customTheme.block[`h${i}`][`font-size`]
|
const v = newTheme.block[`h${i}`][`font-size`]
|
||||||
customTheme.block[`h${i}`][`font-size`] = `${fontSize * Number.parseFloat(v)}px`
|
newTheme.block[`h${i}`][`font-size`] = `${fontSize * Number.parseFloat(v)}px`
|
||||||
}
|
}
|
||||||
return customTheme
|
|
||||||
}
|
}
|
||||||
}
|
if (color) {
|
||||||
|
newTheme.base[`--md-primary-color`] = color
|
||||||
export function setTheme(theme, fontSize, color, isDefault) {
|
}
|
||||||
return setColorWithCustomTemplate(setFontSizeWithTemplate(theme)(fontSize, isDefault), color, isDefault)
|
return newTheme
|
||||||
}
|
}
|
||||||
|
|
||||||
export function customCssWithTemplate(jsonString, color, theme) {
|
export function customCssWithTemplate(jsonString, color, theme) {
|
||||||
// block
|
const newTheme = customizeTheme(theme, { color });
|
||||||
const customTheme = createCustomTheme(theme, color)
|
|
||||||
|
|
||||||
customTheme.block.h1 = Object.assign(customTheme.block.h1, jsonString.h1)
|
const mergeProperties = (target, source, keys) => {
|
||||||
customTheme.block.h2 = Object.assign(customTheme.block.h2, jsonString.h2)
|
keys.forEach(key => {
|
||||||
customTheme.block.h3 = Object.assign(customTheme.block.h3, jsonString.h3)
|
if (source[key]) {
|
||||||
customTheme.block.h4 = Object.assign(customTheme.block.h4, jsonString.h4)
|
target[key] = Object.assign(target[key] || {}, source[key]);
|
||||||
customTheme.block.code = Object.assign(
|
}
|
||||||
customTheme.block.code,
|
});
|
||||||
jsonString.code,
|
};
|
||||||
)
|
|
||||||
customTheme.block.p = Object.assign(customTheme.block.p, jsonString.p)
|
|
||||||
customTheme.block.hr = Object.assign(customTheme.block.hr, jsonString.hr)
|
|
||||||
customTheme.block.blockquote = Object.assign(
|
|
||||||
customTheme.block.blockquote,
|
|
||||||
jsonString.blockquote,
|
|
||||||
)
|
|
||||||
customTheme.block.blockquote_p = Object.assign(
|
|
||||||
customTheme.block.blockquote_p,
|
|
||||||
jsonString.blockquote_p,
|
|
||||||
)
|
|
||||||
customTheme.block.image = Object.assign(
|
|
||||||
customTheme.block.image,
|
|
||||||
jsonString.image,
|
|
||||||
)
|
|
||||||
|
|
||||||
// inline
|
const blockKeys = [
|
||||||
customTheme.inline.strong = Object.assign(
|
'h1', 'h2', 'h3', 'h4', 'code', 'p', 'hr', 'blockquote',
|
||||||
customTheme.inline.strong,
|
'blockquote_p', 'image', 'ul', 'ol'
|
||||||
jsonString.strong,
|
];
|
||||||
)
|
const inlineKeys = ['strong', 'codespan', 'link', 'wx_link', 'listitem'];
|
||||||
customTheme.inline.codespan = Object.assign(
|
|
||||||
customTheme.inline.codespan,
|
mergeProperties(newTheme.block, jsonString, blockKeys);
|
||||||
jsonString.codespan,
|
mergeProperties(newTheme.inline, jsonString, inlineKeys);
|
||||||
)
|
return newTheme;
|
||||||
customTheme.inline.link = Object.assign(
|
|
||||||
customTheme.inline.link,
|
|
||||||
jsonString.link,
|
|
||||||
)
|
|
||||||
customTheme.inline.wx_link = Object.assign(
|
|
||||||
customTheme.inline.wx_link,
|
|
||||||
jsonString.wx_link,
|
|
||||||
)
|
|
||||||
customTheme.block.ul = Object.assign(customTheme.block.ul, jsonString.ul)
|
|
||||||
customTheme.block.ol = Object.assign(customTheme.block.ol, jsonString.ol)
|
|
||||||
customTheme.inline.listitem = Object.assign(
|
|
||||||
customTheme.inline.listitem,
|
|
||||||
jsonString.li,
|
|
||||||
)
|
|
||||||
return customTheme
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将 CSS 字符串转换为 JSON 对象
|
* 将 CSS 字符串转换为 JSON 对象
|
||||||
*
|
*
|
||||||
|
@ -28,7 +28,7 @@ class WxRenderer extends Renderer {
|
|||||||
merge = (base, extend) => ({ ...base, ...extend })
|
merge = (base, extend) => ({ ...base, ...extend })
|
||||||
|
|
||||||
buildTheme = (themeTpl) => {
|
buildTheme = (themeTpl) => {
|
||||||
const base = this.merge(themeTpl.BASE, {
|
const base = this.merge(themeTpl.base, {
|
||||||
'font-family': this.opts.fonts,
|
'font-family': this.opts.fonts,
|
||||||
'font-size': this.opts.size,
|
'font-size': this.opts.size,
|
||||||
})
|
})
|
Loading…
Reference in New Issue
Block a user