From fed75b307ec71cce173d6b34a96e024f8bc8fe66 Mon Sep 17 00:00:00 2001 From: Libin YANG Date: Thu, 29 Aug 2024 19:43:06 +0800 Subject: [PATCH] refactor: customize theme (#368) --- src/config/theme.ts | 36 ++++----- src/stores/index.js | 20 +++-- src/utils/index.js | 98 +++++++---------------- src/utils/{wx-renderer.js => renderer.js} | 2 +- 4 files changed, 52 insertions(+), 104 deletions(-) rename src/utils/{wx-renderer.js => renderer.js} (99%) diff --git a/src/config/theme.ts b/src/config/theme.ts index 4fb0cec..0c06a51 100644 --- a/src/config/theme.ts +++ b/src/config/theme.ts @@ -1,37 +1,29 @@ interface Theme { - BASE: Record + base: Record block: Record> inline: Record> } const baseColor = `#3f3f3f` -function mergeTheme(defaultTheme: Theme, newTheme: Theme) { - const res: Theme = { - BASE: { - ...defaultTheme.BASE, - ...newTheme.BASE, - }, - block: {}, - inline: {}, - } - for (const el in defaultTheme.block) { - res.block[el] = { - ...defaultTheme.block[el], - ...newTheme.block[el], +function mergeTheme(defaultTheme: Theme, newTheme: Theme): Theme { + const merge = (defaultObj: Record, newObj: Record) => { + const result: Record = {} + for (const key in defaultObj) { + result[key] = { ...defaultObj[key], ...newObj?.[key] } } + return result } - for (const el in defaultTheme.inline) { - res.inline[el] = { - ...defaultTheme.inline[el], - ...newTheme.inline[el], - } + + return { + base: { ...defaultTheme.base, ...newTheme.base }, + block: merge(defaultTheme.block, newTheme.block), + inline: merge(defaultTheme.inline, newTheme.inline), } - return res } const defaultTheme = { - BASE: { + base: { '--md-primary-color': `#000000`, 'text-align': `left`, 'line-height': `1.75`, @@ -225,7 +217,7 @@ const defaultTheme = { } const graceTheme = mergeTheme(defaultTheme, { - BASE: { + base: { }, block: { h1: { diff --git a/src/stores/index.js b/src/stores/index.js index 2646160..a24bff8 100644 --- a/src/stores/index.js +++ b/src/stores/index.js @@ -6,10 +6,10 @@ import { useDark, useStorage, useToggle } from '@vueuse/core' import { ElMessage, ElMessageBox } from 'element-plus' 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_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`, () => { // 是否开启深色模式 @@ -46,7 +46,7 @@ export const useStore = defineStore(`store`, () => { const fontSizeNumber = fontSize.value.replace(`px`, ``) 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, size: fontSize.value, }) @@ -187,11 +187,9 @@ export const useStore = defineStore(`store`, () => { // 更新 CSS const updateCss = () => { const json = css2json(cssEditor.value.getValue()) - let t = setTheme(themeMap[theme.value], fontSizeNumber, fontColor.value, theme.value === `default`) - - t = customCssWithTemplate(json, fontColor.value, t) + const newTheme = customCssWithTemplate(json, fontColor.value, customizeTheme(themeMap[theme.value], { fontSize: fontSizeNumber, color: fontColor.value })) wxRenderer.setOptions({ - theme: t, + theme: newTheme, }) editorRefresh() } @@ -270,15 +268,15 @@ export const useStore = defineStore(`store`, () => { } const getTheme = (size, color) => { - const t = setFontSizeWithTemplate(themeMap[theme.value])(size.replace(`px`, ``), theme.value === `default`) - return setColorWithCustomTemplate(t, color, theme.value === `default`) + const newTheme = themeMap[theme.value] + const fontSize = size.replace(`px`, ``) + return customizeTheme(newTheme, { fontSize, color }) } const themeChanged = withAfterRefresh((newTheme) => { wxRenderer.setOptions({ - theme: setTheme(themeMap[newTheme], fontSizeNumber, fontColor.value, newTheme === `default`), + theme: customizeTheme(themeMap[newTheme], { fontSize: fontSizeNumber, color: fontColor.value }), }) - theme.value = newTheme }) diff --git a/src/utils/index.js b/src/utils/index.js index 664ffd1..2165d79 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -9,86 +9,44 @@ export function addPrefix(str) { return `${prefix}__${str}` } -// 设置自定义颜色 -function createCustomTheme(theme, color) { - const customTheme = JSON.parse(JSON.stringify(theme)) - customTheme.BASE[`--md-primary-color`] = color - 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)) +export function customizeTheme(theme, options) { + const newTheme = JSON.parse(JSON.stringify(theme)) + const { fontSize, color } = options + if (fontSize) { for (let i = 1; i <= 4; i++) { - const v = customTheme.block[`h${i}`][`font-size`] - customTheme.block[`h${i}`][`font-size`] = `${fontSize * Number.parseFloat(v)}px` + const v = newTheme.block[`h${i}`][`font-size`] + newTheme.block[`h${i}`][`font-size`] = `${fontSize * Number.parseFloat(v)}px` } - return customTheme } -} - -export function setTheme(theme, fontSize, color, isDefault) { - return setColorWithCustomTemplate(setFontSizeWithTemplate(theme)(fontSize, isDefault), color, isDefault) + if (color) { + newTheme.base[`--md-primary-color`] = color + } + return newTheme } export function customCssWithTemplate(jsonString, color, theme) { - // block - const customTheme = createCustomTheme(theme, color) + const newTheme = customizeTheme(theme, { color }); - customTheme.block.h1 = Object.assign(customTheme.block.h1, jsonString.h1) - customTheme.block.h2 = Object.assign(customTheme.block.h2, jsonString.h2) - customTheme.block.h3 = Object.assign(customTheme.block.h3, jsonString.h3) - customTheme.block.h4 = Object.assign(customTheme.block.h4, jsonString.h4) - 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, - ) + const mergeProperties = (target, source, keys) => { + keys.forEach(key => { + if (source[key]) { + target[key] = Object.assign(target[key] || {}, source[key]); + } + }); + }; - // inline - customTheme.inline.strong = Object.assign( - customTheme.inline.strong, - jsonString.strong, - ) - customTheme.inline.codespan = Object.assign( - customTheme.inline.codespan, - jsonString.codespan, - ) - 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 + const blockKeys = [ + 'h1', 'h2', 'h3', 'h4', 'code', 'p', 'hr', 'blockquote', + 'blockquote_p', 'image', 'ul', 'ol' + ]; + const inlineKeys = ['strong', 'codespan', 'link', 'wx_link', 'listitem']; + + mergeProperties(newTheme.block, jsonString, blockKeys); + mergeProperties(newTheme.inline, jsonString, inlineKeys); + return newTheme; } + /** * 将 CSS 字符串转换为 JSON 对象 * diff --git a/src/utils/wx-renderer.js b/src/utils/renderer.js similarity index 99% rename from src/utils/wx-renderer.js rename to src/utils/renderer.js index fdad49f..1a03260 100644 --- a/src/utils/wx-renderer.js +++ b/src/utils/renderer.js @@ -28,7 +28,7 @@ class WxRenderer extends Renderer { merge = (base, extend) => ({ ...base, ...extend }) buildTheme = (themeTpl) => { - const base = this.merge(themeTpl.BASE, { + const base = this.merge(themeTpl.base, { 'font-family': this.opts.fonts, 'font-size': this.opts.size, })