mirror of
https://github.com/doocs/md.git
synced 2025-02-10 16:55:49 +08:00
feat: support GFM styles to follow fonts changes & optimize custom style logic
This commit is contained in:
parent
2c26d59d7c
commit
0375954bfc
@ -33,29 +33,53 @@ blockquote {
|
|||||||
/* 引用段落样式 */
|
/* 引用段落样式 */
|
||||||
blockquote_p {
|
blockquote_p {
|
||||||
}
|
}
|
||||||
/* GFM 警告块 */
|
/* GFM note 样式 */
|
||||||
markdown-alert {
|
blockquote_note {
|
||||||
}
|
}
|
||||||
/* GFM 警告块标题 */
|
/* GFM tip 样式 */
|
||||||
markdown-alert-title {
|
blockquote_tip {
|
||||||
}
|
}
|
||||||
/* GFM 警告块内容,抵消 p 默认的 margin */
|
/* GFM important 样式 */
|
||||||
markdown-alert-content-wrapper {
|
blockquote_important {
|
||||||
}
|
}
|
||||||
/* GFM note */
|
/* GFM warning 样式 */
|
||||||
markdown-alert-title-note {
|
blockquote_warning {
|
||||||
}
|
}
|
||||||
/* GFM tip */
|
/* GFM caution 样式 */
|
||||||
markdown-alert-title-tip {
|
blockquote_caution {
|
||||||
}
|
}
|
||||||
/* GFM important */
|
/* GFM 通用标题 */
|
||||||
markdown-alert-title-important {
|
blockquote_title {
|
||||||
}
|
}
|
||||||
/* GFM warning */
|
/* GFM note 标题 */
|
||||||
markdown-alert-title-warning {
|
blockquote_title_note {
|
||||||
}
|
}
|
||||||
/* GFM caution */
|
/* GFM tip 标题 */
|
||||||
markdown-alert-title-caution {
|
blockquote_title_tip {
|
||||||
|
}
|
||||||
|
/* GFM important 标题 */
|
||||||
|
blockquote_title_important {
|
||||||
|
}
|
||||||
|
/* GFM warning 标题 */
|
||||||
|
blockquote_title_warning {
|
||||||
|
}
|
||||||
|
/* GFM caution 标题 */
|
||||||
|
blockquote_title_caution {
|
||||||
|
}
|
||||||
|
/* GFM note 段落样式 */
|
||||||
|
blockquote_p_note {
|
||||||
|
}
|
||||||
|
/* GFM tip 段落样式 */
|
||||||
|
blockquote_p_tip {
|
||||||
|
}
|
||||||
|
/* GFM important 段落样式 */
|
||||||
|
blockquote_p_important {
|
||||||
|
}
|
||||||
|
/* GFM warning 段落样式 */
|
||||||
|
blockquote_p_warning {
|
||||||
|
}
|
||||||
|
/* GFM caution 段落样式 */
|
||||||
|
blockquote_p_caution {
|
||||||
}
|
}
|
||||||
/* 段落样式 */
|
/* 段落样式 */
|
||||||
p {
|
p {
|
||||||
|
@ -10,7 +10,7 @@ const defaultTheme: Theme = {
|
|||||||
},
|
},
|
||||||
block: {
|
block: {
|
||||||
// 一级标题
|
// 一级标题
|
||||||
'h1': {
|
h1: {
|
||||||
'display': `table`,
|
'display': `table`,
|
||||||
'padding': `0 1em`,
|
'padding': `0 1em`,
|
||||||
'border-bottom': `2px solid var(--md-primary-color)`,
|
'border-bottom': `2px solid var(--md-primary-color)`,
|
||||||
@ -22,7 +22,7 @@ const defaultTheme: Theme = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 二级标题
|
// 二级标题
|
||||||
'h2': {
|
h2: {
|
||||||
'display': `table`,
|
'display': `table`,
|
||||||
'padding': `0 0.2em`,
|
'padding': `0 0.2em`,
|
||||||
'margin': `4em auto 2em`,
|
'margin': `4em auto 2em`,
|
||||||
@ -34,7 +34,7 @@ const defaultTheme: Theme = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 三级标题
|
// 三级标题
|
||||||
'h3': {
|
h3: {
|
||||||
'padding-left': `8px`,
|
'padding-left': `8px`,
|
||||||
'border-left': `3px solid var(--md-primary-color)`,
|
'border-left': `3px solid var(--md-primary-color)`,
|
||||||
'margin': `2em 8px 0.75em 0`,
|
'margin': `2em 8px 0.75em 0`,
|
||||||
@ -45,7 +45,7 @@ const defaultTheme: Theme = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 四级标题
|
// 四级标题
|
||||||
'h4': {
|
h4: {
|
||||||
'margin': `2em 8px 0.5em`,
|
'margin': `2em 8px 0.5em`,
|
||||||
'color': `var(--md-primary-color)`,
|
'color': `var(--md-primary-color)`,
|
||||||
'font-size': `1em`,
|
'font-size': `1em`,
|
||||||
@ -53,7 +53,7 @@ const defaultTheme: Theme = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 五级标题
|
// 五级标题
|
||||||
'h5': {
|
h5: {
|
||||||
'margin': `1.5em 8px 0.5em`,
|
'margin': `1.5em 8px 0.5em`,
|
||||||
'color': `var(--md-primary-color)`,
|
'color': `var(--md-primary-color)`,
|
||||||
'font-size': `1em`,
|
'font-size': `1em`,
|
||||||
@ -61,14 +61,14 @@ const defaultTheme: Theme = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 六级标题
|
// 六级标题
|
||||||
'h6': {
|
h6: {
|
||||||
'margin': `1.5em 8px 0.5em`,
|
'margin': `1.5em 8px 0.5em`,
|
||||||
'font-size': `1em`,
|
'font-size': `1em`,
|
||||||
'color': `var(--md-primary-color)`,
|
'color': `var(--md-primary-color)`,
|
||||||
},
|
},
|
||||||
|
|
||||||
// 段落
|
// 段落
|
||||||
'p': {
|
p: {
|
||||||
'margin': `1.5em 8px`,
|
'margin': `1.5em 8px`,
|
||||||
'letter-spacing': `0.1em`,
|
'letter-spacing': `0.1em`,
|
||||||
'color': `var(--el-text-color-regular)`,
|
'color': `var(--el-text-color-regular)`,
|
||||||
@ -76,7 +76,7 @@ const defaultTheme: Theme = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 引用
|
// 引用
|
||||||
'blockquote': {
|
blockquote: {
|
||||||
'font-style': `normal`,
|
'font-style': `normal`,
|
||||||
'border-left': `none`,
|
'border-left': `none`,
|
||||||
'padding': `1em`,
|
'padding': `1em`,
|
||||||
@ -87,57 +87,73 @@ const defaultTheme: Theme = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 引用内容
|
// 引用内容
|
||||||
'blockquote_p': {
|
blockquote_p: {
|
||||||
'display': `block`,
|
'display': `block`,
|
||||||
'font-size': `1em`,
|
'font-size': `1em`,
|
||||||
'letter-spacing': `0.1em`,
|
'letter-spacing': `0.1em`,
|
||||||
'color': `var(--el-text-color-regular)`,
|
'color': `var(--el-text-color-regular)`,
|
||||||
},
|
},
|
||||||
|
|
||||||
// GFM 警告块
|
blockquote_note: {
|
||||||
'markdown-alert': {
|
},
|
||||||
'font-style': `normal`,
|
|
||||||
'border-left': `none`,
|
blockquote_tip: {
|
||||||
'padding': `1em`,
|
},
|
||||||
'border-radius': `8px`,
|
|
||||||
'background': `var(--blockquote-background)`,
|
blockquote_important: {
|
||||||
'margin': `2em 8px`,
|
},
|
||||||
|
|
||||||
|
blockquote_warning: {
|
||||||
|
},
|
||||||
|
|
||||||
|
blockquote_caution: {
|
||||||
},
|
},
|
||||||
|
|
||||||
// GFM 警告块标题
|
// GFM 警告块标题
|
||||||
'markdown-alert-title': {
|
blockquote_title: {
|
||||||
'display': `flex`,
|
'display': `flex`,
|
||||||
'align-items': `center`,
|
'align-items': `center`,
|
||||||
'gap': `0.5em`,
|
'gap': `0.5em`,
|
||||||
|
'margin-bottom': `0.5em`,
|
||||||
},
|
},
|
||||||
|
|
||||||
// GFM 警告块内容,抵消 p 默认的 margin
|
blockquote_title_note: {
|
||||||
'markdown-alert-content-wrapper': {
|
|
||||||
margin: `-1em -8px -1.5em;`,
|
|
||||||
},
|
|
||||||
|
|
||||||
'markdown-alert-title-note': {
|
|
||||||
color: `#478be6`,
|
color: `#478be6`,
|
||||||
},
|
},
|
||||||
|
|
||||||
'markdown-alert-title-tip': {
|
blockquote_title_tip: {
|
||||||
color: `#57ab5a`,
|
color: `#57ab5a`,
|
||||||
},
|
},
|
||||||
|
|
||||||
'markdown-alert-title-important': {
|
blockquote_title_important: {
|
||||||
color: `#986ee2`,
|
color: `#986ee2`,
|
||||||
},
|
},
|
||||||
|
|
||||||
'markdown-alert-title-warning': {
|
blockquote_title_warning: {
|
||||||
color: `#c69026`,
|
color: `#c69026`,
|
||||||
},
|
},
|
||||||
|
|
||||||
'markdown-alert-title-caution': {
|
blockquote_title_caution: {
|
||||||
color: `#e5534b`,
|
color: `#e5534b`,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
blockquote_p_note: {
|
||||||
|
},
|
||||||
|
|
||||||
|
blockquote_p_tip: {
|
||||||
|
},
|
||||||
|
|
||||||
|
blockquote_p_important: {
|
||||||
|
},
|
||||||
|
|
||||||
|
blockquote_p_warning: {
|
||||||
|
},
|
||||||
|
|
||||||
|
blockquote_p_caution: {
|
||||||
|
},
|
||||||
|
|
||||||
// 代码块
|
// 代码块
|
||||||
'code_pre': {
|
code_pre: {
|
||||||
'font-size': `14px`,
|
'font-size': `14px`,
|
||||||
'overflow-x': `auto`,
|
'overflow-x': `auto`,
|
||||||
'border-radius': `8px`,
|
'border-radius': `8px`,
|
||||||
@ -147,14 +163,14 @@ const defaultTheme: Theme = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 行内代码
|
// 行内代码
|
||||||
'code': {
|
code: {
|
||||||
'margin': 0,
|
'margin': 0,
|
||||||
'white-space': `nowrap`,
|
'white-space': `nowrap`,
|
||||||
'font-family': `Menlo, Operator Mono, Consolas, Monaco, monospace`,
|
'font-family': `Menlo, Operator Mono, Consolas, Monaco, monospace`,
|
||||||
},
|
},
|
||||||
|
|
||||||
// 图片
|
// 图片
|
||||||
'image': {
|
image: {
|
||||||
'display': `block`,
|
'display': `block`,
|
||||||
'width': `100% !important`,
|
'width': `100% !important`,
|
||||||
'margin': `0.1em auto 0.5em`,
|
'margin': `0.1em auto 0.5em`,
|
||||||
@ -162,32 +178,32 @@ const defaultTheme: Theme = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 有序列表
|
// 有序列表
|
||||||
'ol': {
|
ol: {
|
||||||
'padding-left': `1em`,
|
'padding-left': `1em`,
|
||||||
'margin-left': `0`,
|
'margin-left': `0`,
|
||||||
'color': `var(--el-text-color-regular)`,
|
'color': `var(--el-text-color-regular)`,
|
||||||
},
|
},
|
||||||
|
|
||||||
// 无序列表
|
// 无序列表
|
||||||
'ul': {
|
ul: {
|
||||||
'list-style': `circle`,
|
'list-style': `circle`,
|
||||||
'padding-left': `1em`,
|
'padding-left': `1em`,
|
||||||
'margin-left': `0`,
|
'margin-left': `0`,
|
||||||
'color': `var(--el-text-color-regular)`,
|
'color': `var(--el-text-color-regular)`,
|
||||||
},
|
},
|
||||||
|
|
||||||
'footnotes': {
|
footnotes: {
|
||||||
'margin': `0.5em 8px`,
|
'margin': `0.5em 8px`,
|
||||||
'font-size': `80%`,
|
'font-size': `80%`,
|
||||||
'color': `var(--el-text-color-regular)`,
|
'color': `var(--el-text-color-regular)`,
|
||||||
},
|
},
|
||||||
|
|
||||||
'figure': {
|
figure: {
|
||||||
margin: `1.5em 8px`,
|
margin: `1.5em 8px`,
|
||||||
color: `var(--el-text-color-regular)`,
|
color: `var(--el-text-color-regular)`,
|
||||||
},
|
},
|
||||||
|
|
||||||
'hr': {
|
hr: {
|
||||||
'border-style': `solid`,
|
'border-style': `solid`,
|
||||||
'border-width': `1px 0 0`,
|
'border-width': `1px 0 0`,
|
||||||
'border-color': `rgba(0,0,0,0.1)`,
|
'border-color': `rgba(0,0,0,0.1)`,
|
||||||
|
@ -2,7 +2,8 @@ import type { PropertiesHyphen } from 'csstype'
|
|||||||
|
|
||||||
import type { Token } from 'marked'
|
import type { Token } from 'marked'
|
||||||
|
|
||||||
export type Block = `h1` | `h2` | `h3` | `h4` | `h5` | `h6` | `p` | `blockquote` | `blockquote_p` | `code_pre` | `code` | `image` | `ol` | `ul` | `footnotes` | `figure` | `hr`
|
type GFMBlock = `blockquote_note` | `blockquote_tip` | `blockquote_important` | `blockquote_warning` | `blockquote_caution` | `blockquote_title` | `blockquote_title_note` | `blockquote_title_tip` | `blockquote_title_important` | `blockquote_title_warning` | `blockquote_title_caution` | `blockquote_p` | `blockquote_p_note` | `blockquote_p_tip` | `blockquote_p_important` | `blockquote_p_warning` | `blockquote_p_caution`
|
||||||
|
export type Block = `h1` | `h2` | `h3` | `h4` | `h5` | `h6` | `p` | `blockquote` | `blockquote_p` | `code_pre` | `code` | `image` | `ol` | `ul` | `footnotes` | `figure` | `hr` | GFMBlock
|
||||||
export type Inline = `listitem` | `codespan` | `link` | `wx_link` | `strong` | `table` | `thead` | `td` | `footnote` | `figcaption` | `em`
|
export type Inline = `listitem` | `codespan` | `link` | `wx_link` | `strong` | `table` | `thead` | `td` | `footnote` | `figcaption` | `em`
|
||||||
|
|
||||||
interface CustomCSSProperties {
|
interface CustomCSSProperties {
|
||||||
@ -14,8 +15,8 @@ export type ExtendedProperties = PropertiesHyphen & CustomCSSProperties
|
|||||||
|
|
||||||
export interface Theme {
|
export interface Theme {
|
||||||
base: ExtendedProperties
|
base: ExtendedProperties
|
||||||
block: Record<Block | string, ExtendedProperties>
|
block: Record<Block, ExtendedProperties>
|
||||||
inline: Record<Inline | string, ExtendedProperties>
|
inline: Record<Inline, ExtendedProperties>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IOpts {
|
export interface IOpts {
|
||||||
@ -41,7 +42,7 @@ export interface IConfigOption<VT = string> {
|
|||||||
export interface AlertOptions {
|
export interface AlertOptions {
|
||||||
className?: string
|
className?: string
|
||||||
variants?: AlertVariantItem[]
|
variants?: AlertVariantItem[]
|
||||||
theme?: Theme
|
styles?: ThemeStyles
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,6 +29,8 @@ export default function markedAlert(options: AlertOptions = {}): MarkedExtension
|
|||||||
} = matchedVariant
|
} = matchedVariant
|
||||||
const typeRegexp = new RegExp(createSyntaxPattern(variantType), `i`)
|
const typeRegexp = new RegExp(createSyntaxPattern(variantType), `i`)
|
||||||
|
|
||||||
|
const { styles } = options
|
||||||
|
|
||||||
Object.assign(token, {
|
Object.assign(token, {
|
||||||
type: `alert`,
|
type: `alert`,
|
||||||
meta: {
|
meta: {
|
||||||
@ -37,16 +39,17 @@ export default function markedAlert(options: AlertOptions = {}): MarkedExtension
|
|||||||
icon,
|
icon,
|
||||||
title,
|
title,
|
||||||
titleClassName,
|
titleClassName,
|
||||||
style: {
|
wrapperStyle: {
|
||||||
...options.theme?.block[className],
|
...styles?.blockquote,
|
||||||
...options.theme?.block[`${className}-${variantType}`],
|
...styles?.[`blockquote_${variantType}` as keyof typeof styles],
|
||||||
},
|
},
|
||||||
titleStyle: {
|
titleStyle: {
|
||||||
...options.theme?.block[titleClassName],
|
...styles?.blockquote_title,
|
||||||
...options.theme?.block[`${titleClassName}-${variantType}`],
|
...styles?.[`blockquote_title_${variantType}` as keyof typeof styles],
|
||||||
},
|
},
|
||||||
contentWrapperStyle: {
|
contentStyle: {
|
||||||
margin: options.theme?.block[`${className}-content-wrapper`]?.margin,
|
...styles?.blockquote_p,
|
||||||
|
...styles?.[`blockquote_p_${variantType}` as keyof typeof styles],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -76,15 +79,17 @@ export default function markedAlert(options: AlertOptions = {}): MarkedExtension
|
|||||||
name: `alert`,
|
name: `alert`,
|
||||||
level: `block`,
|
level: `block`,
|
||||||
renderer({ meta, tokens = [] }) {
|
renderer({ meta, tokens = [] }) {
|
||||||
let tmpl = `<blockquote class="${meta.className} ${meta.className}-${meta.variant}" style='${getStyleString(meta.style)}'>\n`
|
let text = this.parser.parse(tokens)
|
||||||
tmpl += `<p class="${meta.titleClassName}" style='${getStyleString(meta.titleStyle)}'>`
|
text = text.replace(/<p .*?>/g, `<p style="${getStyleString(meta.contentStyle)}">`)
|
||||||
|
let tmpl = `<blockquote class="${meta.className} ${meta.className}-${meta.variant}" style="${getStyleString(meta.wrapperStyle)}">\n`
|
||||||
|
tmpl += `<p class="${meta.titleClassName}" style="${getStyleString(meta.titleStyle)}">`
|
||||||
tmpl += meta.icon.replace(
|
tmpl += meta.icon.replace(
|
||||||
`<svg`,
|
`<svg`,
|
||||||
`<svg style="fill: ${meta.titleStyle?.color ?? `inherit`}"`,
|
`<svg style="fill: ${meta.titleStyle?.color ?? `inherit`}"`,
|
||||||
)
|
)
|
||||||
tmpl += meta.title
|
tmpl += meta.title
|
||||||
tmpl += `</p>\n`
|
tmpl += `</p>\n`
|
||||||
tmpl += `<span style="${`${getStyleString(meta.contentWrapperStyle)} display: block;`}">${this.parser.parse(tokens)}</span>`
|
tmpl += text
|
||||||
tmpl += `</blockquote>\n`
|
tmpl += `</blockquote>\n`
|
||||||
|
|
||||||
return tmpl
|
return tmpl
|
||||||
|
@ -34,7 +34,7 @@ export function customizeTheme(theme: Theme, options: {
|
|||||||
export function customCssWithTemplate(jsonString: Partial<Record<Block | Inline, PropertiesHyphen>>, color: string, theme: Theme) {
|
export function customCssWithTemplate(jsonString: Partial<Record<Block | Inline, PropertiesHyphen>>, color: string, theme: Theme) {
|
||||||
const newTheme = customizeTheme(theme, { color })
|
const newTheme = customizeTheme(theme, { color })
|
||||||
|
|
||||||
const mergeProperties = <T extends Block | Inline | string = Block>(target: Record<T, PropertiesHyphen>, source: Partial<Record<Block | Inline | string, PropertiesHyphen>>, keys: T[]) => {
|
const mergeProperties = <T extends Block | Inline = Block>(target: Record<T, PropertiesHyphen>, source: Partial<Record<Block | Inline | string, PropertiesHyphen>>, keys: T[]) => {
|
||||||
keys.forEach((key) => {
|
keys.forEach((key) => {
|
||||||
if (source[key]) {
|
if (source[key]) {
|
||||||
target[key] = Object.assign(target[key] || {}, source[key])
|
target[key] = Object.assign(target[key] || {}, source[key])
|
||||||
@ -42,7 +42,7 @@ export function customCssWithTemplate(jsonString: Partial<Record<Block | Inline,
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const blockKeys: (Block | string)[] = [
|
const blockKeys: Block[] = [
|
||||||
`h1`,
|
`h1`,
|
||||||
`h2`,
|
`h2`,
|
||||||
`h3`,
|
`h3`,
|
||||||
@ -54,15 +54,23 @@ export function customCssWithTemplate(jsonString: Partial<Record<Block | Inline,
|
|||||||
`p`,
|
`p`,
|
||||||
`hr`,
|
`hr`,
|
||||||
`blockquote`,
|
`blockquote`,
|
||||||
|
`blockquote_note`,
|
||||||
|
`blockquote_tip`,
|
||||||
|
`blockquote_important`,
|
||||||
|
`blockquote_warning`,
|
||||||
|
`blockquote_caution`,
|
||||||
`blockquote_p`,
|
`blockquote_p`,
|
||||||
`markdown-alert`,
|
`blockquote_p_note`,
|
||||||
`markdown-alert-title`,
|
`blockquote_p_tip`,
|
||||||
`markdown-alert-content-wrapper`,
|
`blockquote_p_important`,
|
||||||
`markdown-alert-title-note`,
|
`blockquote_p_warning`,
|
||||||
`markdown-alert-title-tip`,
|
`blockquote_p_caution`,
|
||||||
`markdown-alert-title-important`,
|
`blockquote_title`,
|
||||||
`markdown-alert-title-warning`,
|
`blockquote_title_note`,
|
||||||
`markdown-alert-title-caution`,
|
`blockquote_title_tip`,
|
||||||
|
`blockquote_title_important`,
|
||||||
|
`blockquote_title_warning`,
|
||||||
|
`blockquote_title_caution`,
|
||||||
`image`,
|
`image`,
|
||||||
`ul`,
|
`ul`,
|
||||||
`ol`,
|
`ol`,
|
||||||
|
@ -126,7 +126,7 @@ export function initRenderer(opts: IOpts) {
|
|||||||
function setOptions(newOpts: Partial<IOpts>): void {
|
function setOptions(newOpts: Partial<IOpts>): void {
|
||||||
opts = { ...opts, ...newOpts }
|
opts = { ...opts, ...newOpts }
|
||||||
styleMapping = buildTheme(opts)
|
styleMapping = buildTheme(opts)
|
||||||
marked.use(markedAlert({ theme: opts.theme }))
|
marked.use(markedAlert({ styles: styleMapping }))
|
||||||
}
|
}
|
||||||
|
|
||||||
const buildFootnotes = () => {
|
const buildFootnotes = () => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user