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