mirror of
https://github.com/doocs/md.git
synced 2025-02-11 17:20:11 +08:00
feat: support GFM
This commit is contained in:
parent
e946a55f0f
commit
014e4b4aea
@ -35,6 +35,7 @@ Markdown 文档自动即时渲染为微信图文,让你不再为微信文章
|
|||||||
|
|
||||||
- [x] 支持自定义 CSS 样式
|
- [x] 支持自定义 CSS 样式
|
||||||
- [x] 支持 Markdown 所有基础语法、代码块、LaTeX 公式
|
- [x] 支持 Markdown 所有基础语法、代码块、LaTeX 公式
|
||||||
|
- [x] 支持 [GFM 警告块](https://github.com/orgs/community/discussions/16925)
|
||||||
- [x] 支持浅色、深色两种编辑器外观
|
- [x] 支持浅色、深色两种编辑器外观
|
||||||
- [x] 支持 <kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>F</kbd> 快速格式化文档
|
- [x] 支持 <kbd>Alt</kbd> + <kbd>Shift</kbd> + <kbd>F</kbd> 快速格式化文档
|
||||||
- [x] 支持色盘取色,快速替换文章整体色调
|
- [x] 支持色盘取色,快速替换文章整体色调
|
||||||
|
@ -33,6 +33,27 @@ blockquote {
|
|||||||
/* 引用段落样式 */
|
/* 引用段落样式 */
|
||||||
blockquote_p {
|
blockquote_p {
|
||||||
}
|
}
|
||||||
|
/* GFM 警告块 */
|
||||||
|
markdown-alert {
|
||||||
|
}
|
||||||
|
/* GFM 警告块标题 */
|
||||||
|
markdown-alert-title {
|
||||||
|
}
|
||||||
|
/* GFM note */
|
||||||
|
markdown-alert-title-note {
|
||||||
|
}
|
||||||
|
/* GFM tip */
|
||||||
|
markdown-alert-title-tip {
|
||||||
|
}
|
||||||
|
/* GFM important */
|
||||||
|
markdown-alert-title-important {
|
||||||
|
}
|
||||||
|
/* GFM warning */
|
||||||
|
markdown-alert-title-warning {
|
||||||
|
}
|
||||||
|
/* GFM caution */
|
||||||
|
markdown-alert-title-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,15 +87,52 @@ 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': `rgb(80, 80, 80)`,
|
'color': `rgb(80, 80, 80)`,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// GFM 警告块
|
||||||
|
'markdown-alert': {
|
||||||
|
'font-style': `normal`,
|
||||||
|
'border-left': `none`,
|
||||||
|
'padding': `1em`,
|
||||||
|
'border-radius': `8px`,
|
||||||
|
'background': `#f7f7f7`,
|
||||||
|
'margin': `2em 8px`,
|
||||||
|
'--el-text-color-regular': `rgb(80, 80, 80) !important`,
|
||||||
|
},
|
||||||
|
|
||||||
|
// GFM 警告块标题
|
||||||
|
'markdown-alert-title': {
|
||||||
|
'display': `flex`,
|
||||||
|
'align-items': `center`,
|
||||||
|
},
|
||||||
|
|
||||||
|
'markdown-alert-title-note': {
|
||||||
|
color: `#478be6`,
|
||||||
|
},
|
||||||
|
|
||||||
|
'markdown-alert-title-tip': {
|
||||||
|
color: `#57ab5a`,
|
||||||
|
},
|
||||||
|
|
||||||
|
'markdown-alert-title-important': {
|
||||||
|
color: `#986ee2`,
|
||||||
|
},
|
||||||
|
|
||||||
|
'markdown-alert-title-warning': {
|
||||||
|
color: `#c69026`,
|
||||||
|
},
|
||||||
|
|
||||||
|
'markdown-alert-title-caution': {
|
||||||
|
color: `#e5534b`,
|
||||||
|
},
|
||||||
|
|
||||||
// 代码块
|
// 代码块
|
||||||
code_pre: {
|
'code_pre': {
|
||||||
'font-size': `14px`,
|
'font-size': `14px`,
|
||||||
'overflow-x': `auto`,
|
'overflow-x': `auto`,
|
||||||
'border-radius': `8px`,
|
'border-radius': `8px`,
|
||||||
@ -105,14 +142,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`,
|
||||||
@ -120,32 +157,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)`,
|
||||||
@ -230,43 +267,43 @@ const graceTheme = toMerged(defaultTheme, {
|
|||||||
base: {
|
base: {
|
||||||
},
|
},
|
||||||
block: {
|
block: {
|
||||||
h1: {
|
'h1': {
|
||||||
'padding': `0.5em 1em`,
|
'padding': `0.5em 1em`,
|
||||||
'border-bottom': `2px solid var(--md-primary-color)`,
|
'border-bottom': `2px solid var(--md-primary-color)`,
|
||||||
'font-size': `1.4em`,
|
'font-size': `1.4em`,
|
||||||
'text-shadow': `2px 2px 4px rgba(0,0,0,0.1)`,
|
'text-shadow': `2px 2px 4px rgba(0,0,0,0.1)`,
|
||||||
},
|
},
|
||||||
|
|
||||||
h2: {
|
'h2': {
|
||||||
'padding': `0.3em 1em`,
|
'padding': `0.3em 1em`,
|
||||||
'border-radius': `8px`,
|
'border-radius': `8px`,
|
||||||
'font-size': `1.3em`,
|
'font-size': `1.3em`,
|
||||||
'box-shadow': `0 4px 6px rgba(0,0,0,0.1)`,
|
'box-shadow': `0 4px 6px rgba(0,0,0,0.1)`,
|
||||||
},
|
},
|
||||||
|
|
||||||
h3: {
|
'h3': {
|
||||||
'padding-left': `12px`,
|
'padding-left': `12px`,
|
||||||
'font-size': `1.2em`,
|
'font-size': `1.2em`,
|
||||||
'border-left': `4px solid var(--md-primary-color)`,
|
'border-left': `4px solid var(--md-primary-color)`,
|
||||||
'border-bottom': `1px dashed var(--md-primary-color)`,
|
'border-bottom': `1px dashed var(--md-primary-color)`,
|
||||||
},
|
},
|
||||||
|
|
||||||
h4: {
|
'h4': {
|
||||||
'font-size': `1.1em`,
|
'font-size': `1.1em`,
|
||||||
},
|
},
|
||||||
|
|
||||||
h5: {
|
'h5': {
|
||||||
'font-size': `1em`,
|
'font-size': `1em`,
|
||||||
},
|
},
|
||||||
|
|
||||||
h6: {
|
'h6': {
|
||||||
'font-size': `1em`,
|
'font-size': `1em`,
|
||||||
},
|
},
|
||||||
|
|
||||||
p: {
|
'p': {
|
||||||
},
|
},
|
||||||
|
|
||||||
blockquote: {
|
'blockquote': {
|
||||||
'font-style': `italic`,
|
'font-style': `italic`,
|
||||||
'padding': `1em 1em 1em 2em`,
|
'padding': `1em 1em 1em 2em`,
|
||||||
'border-left': `4px solid var(--md-primary-color)`,
|
'border-left': `4px solid var(--md-primary-color)`,
|
||||||
@ -276,41 +313,51 @@ const graceTheme = toMerged(defaultTheme, {
|
|||||||
'box-shadow': `0 4px 6px rgba(0,0,0,0.05)`,
|
'box-shadow': `0 4px 6px rgba(0,0,0,0.05)`,
|
||||||
},
|
},
|
||||||
|
|
||||||
blockquote_p: {
|
'blockquote_p': {
|
||||||
},
|
},
|
||||||
|
|
||||||
code_pre: {
|
'markdown-alert': {
|
||||||
|
'font-style': `italic`,
|
||||||
|
'padding': `1em 1em 1em 2em`,
|
||||||
|
'border-left': `4px solid var(--md-primary-color)`,
|
||||||
|
'border-radius': `6px`,
|
||||||
|
'color': `rgba(0,0,0,0.6)`,
|
||||||
|
'background': `linear-gradient(to right, #f7f7f7, #ffffff)`,
|
||||||
|
'box-shadow': `0 4px 6px rgba(0,0,0,0.05)`,
|
||||||
|
},
|
||||||
|
|
||||||
|
'code_pre': {
|
||||||
'box-shadow': `inset 0 0 10px rgba(0,0,0,0.05)`,
|
'box-shadow': `inset 0 0 10px rgba(0,0,0,0.05)`,
|
||||||
},
|
},
|
||||||
|
|
||||||
code: {
|
'code': {
|
||||||
'white-space': `pre-wrap`,
|
'white-space': `pre-wrap`,
|
||||||
'font-family': `'Fira Code', Menlo, Operator Mono, Consolas, Monaco, monospace`,
|
'font-family': `'Fira Code', Menlo, Operator Mono, Consolas, Monaco, monospace`,
|
||||||
},
|
},
|
||||||
|
|
||||||
image: {
|
'image': {
|
||||||
'border-radius': `8px`,
|
'border-radius': `8px`,
|
||||||
'box-shadow': `0 4px 8px rgba(0,0,0,0.1)`,
|
'box-shadow': `0 4px 8px rgba(0,0,0,0.1)`,
|
||||||
},
|
},
|
||||||
|
|
||||||
ol: {
|
'ol': {
|
||||||
'padding-left': `1.5em`,
|
'padding-left': `1.5em`,
|
||||||
},
|
},
|
||||||
|
|
||||||
ul: {
|
'ul': {
|
||||||
'list-style': `none`,
|
'list-style': `none`,
|
||||||
'padding-left': `1.5em`,
|
'padding-left': `1.5em`,
|
||||||
},
|
},
|
||||||
|
|
||||||
footnotes: {
|
'footnotes': {
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
figure: {
|
'figure': {
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
hr: {
|
'hr': {
|
||||||
height: `1px`,
|
height: `1px`,
|
||||||
border: `none`,
|
border: `none`,
|
||||||
margin: `2em 0`,
|
margin: `2em 0`,
|
||||||
|
@ -2,6 +2,7 @@ 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 { altKey, codeBlockThemeOptions, colorOptions, fontFamilyOptions, fontSizeOptions, legendOptions, shiftKey, themeMap, themeOptions } from '@/config'
|
import { altKey, codeBlockThemeOptions, colorOptions, fontFamilyOptions, fontSizeOptions, legendOptions, shiftKey, themeMap, themeOptions } from '@/config'
|
||||||
import { addPrefix, css2json, customCssWithTemplate, customizeTheme, downloadMD, exportHTML, formatDoc } from '@/utils'
|
import { addPrefix, css2json, customCssWithTemplate, customizeTheme, downloadMD, exportHTML, formatDoc } from '@/utils'
|
||||||
|
import markedAlert from '@/utils/MDAlert'
|
||||||
import { initRenderer } from '@/utils/renderer'
|
import { initRenderer } from '@/utils/renderer'
|
||||||
import { useDark, useStorage, useToggle } from '@vueuse/core'
|
import { useDark, useStorage, useToggle } from '@vueuse/core'
|
||||||
|
|
||||||
@ -144,6 +145,7 @@ export const useStore = defineStore(`store`, () => {
|
|||||||
const editorRefresh = () => {
|
const editorRefresh = () => {
|
||||||
codeThemeChange()
|
codeThemeChange()
|
||||||
renderer.reset({ citeStatus: isCiteStatus.value, legend: legend.value, isUseIndent: isUseIndent.value })
|
renderer.reset({ citeStatus: isCiteStatus.value, legend: legend.value, isUseIndent: isUseIndent.value })
|
||||||
|
|
||||||
let outputTemp = marked.parse(editor.value!.getValue()) as string
|
let outputTemp = marked.parse(editor.value!.getValue()) as string
|
||||||
|
|
||||||
// 去除第一行的 margin-top
|
// 去除第一行的 margin-top
|
||||||
@ -184,6 +186,8 @@ export const useStore = defineStore(`store`, () => {
|
|||||||
renderer.setOptions({
|
renderer.setOptions({
|
||||||
theme: newTheme,
|
theme: newTheme,
|
||||||
})
|
})
|
||||||
|
marked.use(markedAlert({ theme: newTheme }))
|
||||||
|
|
||||||
editorRefresh()
|
editorRefresh()
|
||||||
}
|
}
|
||||||
// 初始化 CSS 编辑器
|
// 初始化 CSS 编辑器
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import type { PropertiesHyphen } from 'csstype'
|
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`
|
export type Block = `h1` | `h2` | `h3` | `h4` | `h5` | `h6` | `p` | `blockquote` | `blockquote_p` | `code_pre` | `code` | `image` | `ol` | `ul` | `footnotes` | `figure` | `hr`
|
||||||
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`
|
||||||
|
|
||||||
@ -12,8 +14,8 @@ export type ExtendedProperties = PropertiesHyphen & CustomCSSProperties
|
|||||||
|
|
||||||
export interface Theme {
|
export interface Theme {
|
||||||
base: ExtendedProperties
|
base: ExtendedProperties
|
||||||
block: Record<Block, PropertiesHyphen>
|
block: Record<Block | string, ExtendedProperties>
|
||||||
inline: Record<Inline, PropertiesHyphen>
|
inline: Record<Inline | string, ExtendedProperties>
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IOpts {
|
export interface IOpts {
|
||||||
@ -32,3 +34,39 @@ export interface IConfigOption<VT = string> {
|
|||||||
value: VT
|
value: VT
|
||||||
desc: string
|
desc: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options for the `markedAlert` extension.
|
||||||
|
*/
|
||||||
|
export interface AlertOptions {
|
||||||
|
className?: string
|
||||||
|
variants?: AlertVariantItem[]
|
||||||
|
theme?: Theme
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for an alert type.
|
||||||
|
*/
|
||||||
|
export interface AlertVariantItem {
|
||||||
|
type: string
|
||||||
|
icon: string
|
||||||
|
title?: string
|
||||||
|
titleClassName?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an alert token.
|
||||||
|
*/
|
||||||
|
export interface Alert {
|
||||||
|
type: `alert`
|
||||||
|
meta: {
|
||||||
|
className: string
|
||||||
|
variant: string
|
||||||
|
icon: string
|
||||||
|
title: string
|
||||||
|
titleClassName: string
|
||||||
|
}
|
||||||
|
raw: string
|
||||||
|
text: string
|
||||||
|
tokens: Token[]
|
||||||
|
}
|
||||||
|
155
src/utils/MDAlert.ts
Normal file
155
src/utils/MDAlert.ts
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
import type { AlertOptions, AlertVariantItem } from '@/types'
|
||||||
|
import type { MarkedExtension, Tokens } from 'marked'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://github.com/bent10/marked-extensions/tree/main/packages/alert
|
||||||
|
* To support theme, we need to modify the source code.
|
||||||
|
* A [marked](https://marked.js.org/) extension to support [GFM alerts](https://github.com/orgs/community/discussions/16925).
|
||||||
|
*/
|
||||||
|
export default function markedAlert(options: AlertOptions = {}): MarkedExtension {
|
||||||
|
const { className = `markdown-alert`, variants = [] } = options
|
||||||
|
const resolvedVariants = resolveVariants(variants)
|
||||||
|
|
||||||
|
return {
|
||||||
|
walkTokens(token) {
|
||||||
|
if (token.type !== `blockquote`)
|
||||||
|
return
|
||||||
|
|
||||||
|
const matchedVariant = resolvedVariants.find(({ type }) =>
|
||||||
|
new RegExp(createSyntaxPattern(type)).test(token.text),
|
||||||
|
)
|
||||||
|
|
||||||
|
if (matchedVariant) {
|
||||||
|
const {
|
||||||
|
type: variantType,
|
||||||
|
icon,
|
||||||
|
title = ucfirst(variantType),
|
||||||
|
titleClassName = `${className}-title`,
|
||||||
|
} = matchedVariant
|
||||||
|
const typeRegexp = new RegExp(createSyntaxPattern(variantType))
|
||||||
|
|
||||||
|
Object.assign(token, {
|
||||||
|
type: `alert`,
|
||||||
|
meta: {
|
||||||
|
className,
|
||||||
|
variant: variantType,
|
||||||
|
icon,
|
||||||
|
title,
|
||||||
|
titleClassName,
|
||||||
|
style: {
|
||||||
|
...options.theme?.block[className],
|
||||||
|
...options.theme?.block[`${className}-${variantType}`],
|
||||||
|
},
|
||||||
|
titleStyle: {
|
||||||
|
...options.theme?.block[titleClassName],
|
||||||
|
...options.theme?.block[`${titleClassName}-${variantType}`],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log({
|
||||||
|
...options.theme?.block[className],
|
||||||
|
...options.theme?.block[`${className}-${variantType}`],
|
||||||
|
}, `style`)
|
||||||
|
|
||||||
|
const firstLine = token.tokens?.[0] as Tokens.Paragraph
|
||||||
|
const firstLineText = firstLine.raw?.replace(typeRegexp, ``).trim()
|
||||||
|
|
||||||
|
if (firstLineText) {
|
||||||
|
const patternToken = firstLine.tokens[0] as Tokens.Text
|
||||||
|
|
||||||
|
Object.assign(patternToken, {
|
||||||
|
raw: patternToken.raw.replace(typeRegexp, ``),
|
||||||
|
text: patternToken.text.replace(typeRegexp, ``),
|
||||||
|
})
|
||||||
|
|
||||||
|
if (firstLine.tokens[1]?.type === `br`) {
|
||||||
|
firstLine.tokens.splice(1, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
token.tokens?.shift()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
extensions: [
|
||||||
|
{
|
||||||
|
name: `alert`,
|
||||||
|
level: `block`,
|
||||||
|
renderer({ meta, tokens = [] }) {
|
||||||
|
let tmpl = `<div class="${meta.className} ${meta.className}-${meta.variant}" style='${Object.entries(meta.style ?? {}).map(([key, value]) => `${key}: ${value}`).join(`; `)}'>\n`
|
||||||
|
tmpl += `<p class="${meta.titleClassName}" style='${Object.entries(meta.titleStyle ?? {}).map(([key, value]) => `${key}: ${value}`).join(`; `)}'>`
|
||||||
|
tmpl += meta.icon.replace(
|
||||||
|
`<svg`,
|
||||||
|
`<svg style="fill: ${meta.titleStyle?.color ?? `inherit`}"`,
|
||||||
|
)
|
||||||
|
tmpl += meta.title
|
||||||
|
tmpl += `</p>\n`
|
||||||
|
tmpl += this.parser.parse(tokens)
|
||||||
|
tmpl += `</div>\n`
|
||||||
|
|
||||||
|
return tmpl
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default configuration for alert variants.
|
||||||
|
*/
|
||||||
|
const defaultAlertVariant: AlertVariantItem[] = [
|
||||||
|
{
|
||||||
|
type: `note`,
|
||||||
|
icon: `<svg class="octicon octicon-info mr-2" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM6.5 7.75A.75.75 0 0 1 7.25 7h1a.75.75 0 0 1 .75.75v2.75h.25a.75.75 0 0 1 0 1.5h-2a.75.75 0 0 1 0-1.5h.25v-2h-.25a.75.75 0 0 1-.75-.75ZM8 6a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: `tip`,
|
||||||
|
icon: `<svg class="octicon octicon-light-bulb mr-2" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z"></path></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: `important`,
|
||||||
|
icon: `<svg class="octicon octicon-report mr-2" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v9.5A1.75 1.75 0 0 1 14.25 13H8.06l-2.573 2.573A1.458 1.458 0 0 1 3 14.543V13H1.75A1.75 1.75 0 0 1 0 11.25Zm1.75-.25a.25.25 0 0 0-.25.25v9.5c0 .138.112.25.25.25h2a.75.75 0 0 1 .75.75v2.19l2.72-2.72a.749.749 0 0 1 .53-.22h6.5a.25.25 0 0 0 .25-.25v-9.5a.25.25 0 0 0-.25-.25Zm7 2.25v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 9a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: `warning`,
|
||||||
|
icon: `<svg class="octicon octicon-alert mr-2" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M6.457 1.047c.659-1.234 2.427-1.234 3.086 0l6.082 11.378A1.75 1.75 0 0 1 14.082 15H1.918a1.75 1.75 0 0 1-1.543-2.575Zm1.763.707a.25.25 0 0 0-.44 0L1.698 13.132a.25.25 0 0 0 .22.368h12.164a.25.25 0 0 0 .22-.368Zm.53 3.996v2.5a.75.75 0 0 1-1.5 0v-2.5a.75.75 0 0 1 1.5 0ZM9 11a1 1 0 1 1-2 0 1 1 0 0 1 2 0Z"></path></svg>`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: `caution`,
|
||||||
|
icon: `<svg class="octicon octicon-stop mr-2" viewBox="0 0 16 16" width="16" height="16" aria-hidden="true"><path d="M4.47.22A.749.749 0 0 1 5 0h6c.199 0 .389.079.53.22l4.25 4.25c.141.14.22.331.22.53v6a.749.749 0 0 1-.22.53l-4.25 4.25A.749.749 0 0 1 11 16H5a.749.749 0 0 1-.53-.22L.22 11.53A.749.749 0 0 1 0 11V5c0-.199.079-.389.22-.53Zm.84 1.28L1.5 5.31v5.38l3.81 3.81h5.38l3.81-3.81V5.31L10.69 1.5ZM8 4a.75.75 0 0 1 .75.75v3.5a.75.75 0 0 1-1.5 0v-3.5A.75.75 0 0 1 8 4Zm0 8a1 1 0 1 1 0-2 1 1 0 0 1 0 2Z"></path></svg>`,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves the variants configuration, combining the provided variants with
|
||||||
|
* the default variants.
|
||||||
|
*/
|
||||||
|
export function resolveVariants(variants: AlertVariantItem[]) {
|
||||||
|
if (!variants.length)
|
||||||
|
return defaultAlertVariant
|
||||||
|
|
||||||
|
return Object.values(
|
||||||
|
[...defaultAlertVariant, ...variants].reduce(
|
||||||
|
(map, item) => {
|
||||||
|
map[item.type] = item
|
||||||
|
return map
|
||||||
|
},
|
||||||
|
{} as { [key: string]: AlertVariantItem },
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns regex pattern to match alert syntax.
|
||||||
|
*/
|
||||||
|
export function createSyntaxPattern(type: string) {
|
||||||
|
return `^(?:\\[!${type.toUpperCase()}])\\s*?\n*`
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Capitalizes the first letter of a string.
|
||||||
|
*/
|
||||||
|
export function ucfirst(str: string) {
|
||||||
|
return str.slice(0, 1).toUpperCase() + str.slice(1).toLowerCase()
|
||||||
|
}
|
@ -6,6 +6,7 @@ import hljs from 'highlight.js'
|
|||||||
|
|
||||||
import { marked } from 'marked'
|
import { marked } from 'marked'
|
||||||
import mermaid from 'mermaid'
|
import mermaid from 'mermaid'
|
||||||
|
import markedAlert from './MDAlert'
|
||||||
import { MDKatex } from './MDKatex'
|
import { MDKatex } from './MDKatex'
|
||||||
|
|
||||||
marked.use(MDKatex({ nonStandard: true }))
|
marked.use(MDKatex({ nonStandard: true }))
|
||||||
@ -103,6 +104,8 @@ export function initRenderer(opts: IOpts) {
|
|||||||
let listIndex: number = 0
|
let listIndex: number = 0
|
||||||
let isOrdered: boolean = false
|
let isOrdered: boolean = false
|
||||||
|
|
||||||
|
marked.use(markedAlert({ theme: opts.theme }))
|
||||||
|
|
||||||
function styles(tag: string, addition: string = ``): string {
|
function styles(tag: string, addition: string = ``): string {
|
||||||
return getStyles(styleMapping, tag, addition)
|
return getStyles(styleMapping, tag, addition)
|
||||||
}
|
}
|
||||||
|
@ -519,6 +519,17 @@ onMounted(() => {
|
|||||||
border-spacing: 0;
|
border-spacing: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:deep(.markdown-alert) {
|
||||||
|
display: block;
|
||||||
|
padding: 1em;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #f7f7f7;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.markdown-alert-title) {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
.codeMirror-wrapper,
|
.codeMirror-wrapper,
|
||||||
.preview-wrapper {
|
.preview-wrapper {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user