mirror of https://github.com/YunYouJun/valaxy
refactor(md): with @mdit-vue plugins & ussOutline by document.querySelector
This commit is contained in:
parent
6d9bff1127
commit
49bbdb3fe1
|
@ -7,7 +7,7 @@
|
|||
"build": "npm run build:ssg && npm run rss",
|
||||
"build:spa": "valaxy build",
|
||||
"build:ssg": "valaxy build --ssg",
|
||||
"dev": "nodemon -w \"../../packages/valaxy/dist/*.js\" --exec \"valaxy .\"",
|
||||
"dev": "nodemon -w \"../../packages/valaxy/dist/*.cjs\" --exec \"valaxy .\"",
|
||||
"rss": "valaxy rss",
|
||||
"serve": "vite preview"
|
||||
},
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"build": "npm run build:ssg && npm run rss",
|
||||
"build:spa": "valaxy build",
|
||||
"build:ssg": "valaxy build --ssg",
|
||||
"dev": "nodemon -w \"../packages/valaxy/dist/*.js\" --exec \"valaxy .\"",
|
||||
"dev": "nodemon -w \"../packages/valaxy/dist/*.cjs\" --exec \"valaxy .\"",
|
||||
"rss": "valaxy rss",
|
||||
"serve": "vite preview"
|
||||
},
|
||||
|
|
|
@ -10,9 +10,9 @@ const { t } = useI18n()
|
|||
|
||||
<ul>
|
||||
<li>
|
||||
<a href="/docs" :title="t('docs.view_docs')">
|
||||
<router-link to="/docs" :title="t('docs.view_docs')">
|
||||
{{ t('docs.view_docs') }}
|
||||
</a>
|
||||
</router-link>
|
||||
</li>
|
||||
<li>
|
||||
<router-link class="flex justify-center" to="/examples">
|
||||
|
|
|
@ -64,7 +64,9 @@ const prevPost = computed(() => posts.value[findCurrentIndex() + 1])
|
|||
Next Article
|
||||
</h2>
|
||||
<div class="link">
|
||||
<a :href="nextPost.href">{{ nextPost.title }}</a>
|
||||
<router-link :to="nextPost.href">
|
||||
{{ nextPost.title }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="prevPost && prevPost.href" class="py-8">
|
||||
|
@ -72,11 +74,15 @@ const prevPost = computed(() => posts.value[findCurrentIndex() + 1])
|
|||
Previous Article
|
||||
</h2>
|
||||
<div class="link">
|
||||
<a :href="prevPost.href">{{ prevPost.title }}</a>
|
||||
<router-link :to="prevPost.href">
|
||||
{{ prevPost.title }}
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-8">
|
||||
<a class="link" href="/">← Back to Home</a>
|
||||
<router-link class="link" to="/">
|
||||
← Back to Home
|
||||
</router-link>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<script lang="ts" setup>
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useData, useFrontmatter } from 'valaxy'
|
||||
import { useFrontmatter } from 'valaxy'
|
||||
import { useAppStore } from 'valaxy/client/stores/app'
|
||||
import { provide, ref } from 'vue'
|
||||
|
||||
const frontmatter = useFrontmatter()
|
||||
const data = useData()
|
||||
const { t } = useI18n()
|
||||
const app = useAppStore()
|
||||
</script>
|
||||
|
@ -27,7 +27,7 @@ const app = useAppStore()
|
|||
{{ t('sidebar.toc') }}
|
||||
</h2>
|
||||
|
||||
<YunToc v-if="frontmatter.toc !== false" :headers="data.headers || []" />
|
||||
<YunOutline v-if="frontmatter.toc !== false" />
|
||||
|
||||
<div class="flex-grow" />
|
||||
|
||||
|
|
|
@ -1,28 +1,19 @@
|
|||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import type { Header } from 'valaxy'
|
||||
import { ref } from 'vue'
|
||||
import {
|
||||
resolveHeaders,
|
||||
useActiveAnchor,
|
||||
useFrontmatter,
|
||||
useOutline,
|
||||
} from 'valaxy'
|
||||
import { useThemeConfig } from '../composables'
|
||||
|
||||
const props = defineProps<{ headers: Header[] }>()
|
||||
|
||||
const frontmatter = useFrontmatter()
|
||||
const themeConfig = useThemeConfig()
|
||||
|
||||
const { locale } = useI18n()
|
||||
const container = ref()
|
||||
const marker = ref()
|
||||
|
||||
useActiveAnchor(container, marker)
|
||||
|
||||
const resolvedHeaders = computed(() => {
|
||||
return resolveHeaders(props.headers || [])
|
||||
})
|
||||
const { headers } = useOutline()
|
||||
|
||||
function handleClick({ target: el }: Event) {
|
||||
const id = `#${(el as HTMLAnchorElement).href!.split('#')[1]}`
|
||||
|
@ -45,26 +36,12 @@ function handleClick({ target: el }: Event) {
|
|||
Table of Contents for current page
|
||||
</span>
|
||||
|
||||
<ul class="va-toc relative z-1">
|
||||
<li
|
||||
v-for="{ text, link, children, hidden, lang } in resolvedHeaders"
|
||||
v-show="!hidden"
|
||||
:key="link"
|
||||
class="va-toc-item"
|
||||
:lang="lang || locale"
|
||||
>
|
||||
<a class="outline-link" :href="link" @click="handleClick">
|
||||
{{ text }}
|
||||
</a>
|
||||
<ul v-if="children && frontmatter.outline === 'deep'">
|
||||
<li v-for="item in children" v-show="!item.hidden" :key="item.link" :lang="lang || locale">
|
||||
<a class="outline-link" p="l-3" :href="link" @click="handleClick">
|
||||
{{ item.text }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<YunOutlineItem
|
||||
class="va-toc relative z-1"
|
||||
:headers="headers"
|
||||
:on-click="handleClick"
|
||||
root
|
||||
/>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -73,10 +50,6 @@ function handleClick({ target: el }: Event) {
|
|||
<style lang="scss" scoped>
|
||||
.va-toc {
|
||||
text-align: left;
|
||||
|
||||
.va-toc-item {
|
||||
color: var(--va-c-text-light);
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
|
@ -0,0 +1,48 @@
|
|||
<script setup lang="ts">
|
||||
import type { MenuItem } from 'valaxy'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
defineProps<{
|
||||
headers: MenuItem[]
|
||||
onClick: (e: MouseEvent) => void
|
||||
root?: boolean
|
||||
}>()
|
||||
|
||||
const { locale } = useI18n()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ul :class="root ? 'root' : 'nested'">
|
||||
<li v-for="{ children, link, title, lang } in headers" :key="link" class="va-toc-item" :lang="lang || locale">
|
||||
<a class="outline-link" :href="link" @click="onClick">{{ title }}</a>
|
||||
<template v-if="children?.length">
|
||||
<YunOutlineItem :headers="children" :on-click="onClick" />
|
||||
</template>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.va-toc {
|
||||
.va-toc-item {
|
||||
.outline-link {
|
||||
color: var(--va-c-text-light);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
transition: color 0.5s;
|
||||
|
||||
&:hover,
|
||||
&.active {
|
||||
color: var(--va-c-brand);
|
||||
transition: color 0.25s;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.nested {
|
||||
padding-left: 0.8rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -9,14 +9,14 @@ const router = useRouter()
|
|||
<template>
|
||||
<div class="sidebar-panel">
|
||||
<div class="site-info" m="t-6">
|
||||
<a class="site-author-avatar" href="/about">
|
||||
<router-link class="site-author-avatar" to="/about">
|
||||
<img class="rounded-full" :src="config.author.avatar" alt="avatar">
|
||||
<span class="site-author-status">{{ config.author.status.emoji }}</span>
|
||||
</a>
|
||||
</router-link>
|
||||
<div class="site-author-name">
|
||||
<a href="/about">
|
||||
<router-link to="/about">
|
||||
{{ config.author.name }}
|
||||
</a>
|
||||
</router-link>
|
||||
</div>
|
||||
<router-link v-if="router.hasRoute('about-site')" to="/about/site" class="site-name">
|
||||
{{ config.title }}
|
||||
|
|
|
@ -62,9 +62,9 @@ const sortedYears = computed(() => {
|
|||
<time v-if="post.date" class="post-time" font="mono" opacity="80">{{ formatDate(post.date, 'MM-DD') }}</time>
|
||||
</div>
|
||||
<h2 class="post-title" font="serif black">
|
||||
<a :href="post.path" class="post-title-link">
|
||||
<router-link :to="post.path || ''" class="post-title-link">
|
||||
{{ post.title }}
|
||||
</a>
|
||||
</router-link>
|
||||
</h2>
|
||||
</header>
|
||||
</article>
|
||||
|
|
|
@ -25,8 +25,13 @@ html.dark {
|
|||
}
|
||||
|
||||
ul {
|
||||
list-style: initial;
|
||||
li > p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
code {
|
||||
font-size: inherit;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
@use "./layout" as *;
|
||||
|
||||
@use "./common/button.scss" as *;
|
||||
@use "./common/markdown.scss" as *;
|
||||
|
||||
@forward "star-markdown-css/src/scss/theme/yun.scss" with (
|
||||
$colors: (
|
||||
"primary": $c-primary,
|
||||
)
|
||||
);
|
||||
|
||||
// override the default style of star-markdown-css
|
||||
@use "./common/markdown.scss" as *;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { computed, provide, ref } from 'vue'
|
||||
import { useHead } from '@vueuse/head'
|
||||
// @ts-expect-error virtual module
|
||||
import ValaxyUserApp from '/@valaxyjs/UserAppVue'
|
||||
|
@ -36,6 +36,9 @@ useHead({
|
|||
},
|
||||
],
|
||||
})
|
||||
|
||||
const onContentUpdated = ref()
|
||||
provide('onContentUpdated', onContentUpdated)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import type { Ref } from 'vue'
|
||||
import { inject, onMounted, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useAplayer, useCodePen, useCopyCode, wrapTable } from '..'
|
||||
import type { Post } from '../../types'
|
||||
|
@ -9,11 +10,14 @@ const props = defineProps<{
|
|||
excerpt?: string
|
||||
}>()
|
||||
|
||||
const onContentUpdated = inject('onContentUpdated') as Ref<() => void>
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const content = ref()
|
||||
function updateDom() {
|
||||
wrapTable(content.value)
|
||||
onContentUpdated.value()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
|
|
@ -1,51 +1,79 @@
|
|||
import type { Ref } from 'vue'
|
||||
import { onMounted, onUnmounted, onUpdated } from 'vue'
|
||||
import { computed, inject, onMounted, onUnmounted, onUpdated, ref } from 'vue'
|
||||
import { useFrontmatter } from '../composables'
|
||||
import { useThemeConfig } from '../../client'
|
||||
import { throttleAndDebounce } from '../utils'
|
||||
import type { Header } from '../../types'
|
||||
import type { DefaultThemeConfig, Header } from '../../types'
|
||||
|
||||
interface HeaderWithChildren extends Header {
|
||||
children?: Header[]
|
||||
hidden?: boolean
|
||||
export type MenuItem = Omit<Header, 'slug' | 'children'> & {
|
||||
children?: MenuItem[]
|
||||
}
|
||||
|
||||
interface MenuItemWithLinkAndChildren {
|
||||
text: string
|
||||
link: string
|
||||
children?: MenuItemWithLinkAndChildren[]
|
||||
hidden?: boolean
|
||||
lang?: string
|
||||
export function resolveHeaders(
|
||||
headers: MenuItem[],
|
||||
levelsRange: Exclude<DefaultThemeConfig['outline'], false> = [2, 4],
|
||||
) {
|
||||
const levels: [number, number]
|
||||
= typeof levelsRange === 'number'
|
||||
? [levelsRange, levelsRange]
|
||||
: levelsRange === 'deep'
|
||||
? [2, 6]
|
||||
: levelsRange
|
||||
|
||||
return groupHeaders(headers, levels)
|
||||
}
|
||||
|
||||
export function resolveHeaders(headers: Header[]) {
|
||||
return mapHeaders(groupHeaders(headers))
|
||||
function groupHeaders(headers: MenuItem[], levelsRange: [number, number]) {
|
||||
const result: MenuItem[] = []
|
||||
|
||||
headers = headers.map(h => ({ ...h }))
|
||||
headers.forEach((h, index) => {
|
||||
if (h.level >= levelsRange[0] && h.level <= levelsRange[1]) {
|
||||
if (addToParent(index, headers, levelsRange))
|
||||
result.push(h)
|
||||
}
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
function groupHeaders(headers: Header[]): HeaderWithChildren[] {
|
||||
headers = headers.map(h => Object.assign({}, h))
|
||||
// function mapHeaders(
|
||||
// headers: HeaderWithChildren[],
|
||||
// ): MenuItemWithLinkAndChildren[] {
|
||||
// return headers.map(header => ({
|
||||
// text: header.title,
|
||||
// link: `#${header.slug}`,
|
||||
// children: header.children ? mapHeaders(header.children) : undefined,
|
||||
// hidden: header.hidden,
|
||||
// lang: header.lang,
|
||||
// }))
|
||||
// }
|
||||
|
||||
let lastH2: HeaderWithChildren | undefined
|
||||
function addToParent(
|
||||
currIndex: number,
|
||||
headers: MenuItem[],
|
||||
levelsRange: [number, number],
|
||||
) {
|
||||
if (currIndex === 0)
|
||||
return true
|
||||
|
||||
for (const h of headers) {
|
||||
if (h.level === 2)
|
||||
lastH2 = h
|
||||
const currentHeader = headers[currIndex]
|
||||
for (let index = currIndex - 1; index >= 0; index--) {
|
||||
const header = headers[index]
|
||||
|
||||
else if (lastH2 && h.level <= 3)
|
||||
(lastH2.children || (lastH2.children = [])).push(h)
|
||||
if (
|
||||
header.level < currentHeader.level
|
||||
&& header.level >= levelsRange[0]
|
||||
&& header.level <= levelsRange[1]
|
||||
) {
|
||||
if (header.children == null)
|
||||
header.children = []
|
||||
header.children.push(currentHeader)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return headers.filter(h => h.level === 2)
|
||||
}
|
||||
|
||||
function mapHeaders(
|
||||
headers: HeaderWithChildren[],
|
||||
): MenuItemWithLinkAndChildren[] {
|
||||
return headers.map(header => ({
|
||||
text: header.title,
|
||||
link: `#${header.slug}`,
|
||||
children: header.children ? mapHeaders(header.children) : undefined,
|
||||
hidden: header.hidden,
|
||||
lang: header.lang,
|
||||
}))
|
||||
return true
|
||||
}
|
||||
|
||||
// magic number to avoid repeated retrieval
|
||||
|
@ -166,3 +194,40 @@ function isAnchorActive(
|
|||
|
||||
return [false, null]
|
||||
}
|
||||
|
||||
export const useOutline = () => {
|
||||
const frontmatter = useFrontmatter()
|
||||
const themeConfig = useThemeConfig()
|
||||
const headers = ref<MenuItem[]>([])
|
||||
const pageOutline = computed<DefaultThemeConfig['outline']>(
|
||||
() => frontmatter.value.outline ?? themeConfig.value.outline,
|
||||
)
|
||||
|
||||
const onContentUpdated = inject('onContentUpdated') as Ref<() => void>
|
||||
onContentUpdated.value = () => {
|
||||
headers.value = getHeaders(pageOutline.value)
|
||||
}
|
||||
|
||||
return {
|
||||
headers,
|
||||
}
|
||||
}
|
||||
|
||||
export function getHeaders(pageOutline: DefaultThemeConfig['outline']) {
|
||||
if (pageOutline === false)
|
||||
return []
|
||||
const updatedHeaders: MenuItem[] = []
|
||||
document
|
||||
.querySelectorAll<HTMLHeadingElement>('h2, h3, h4, h5, h6')
|
||||
.forEach((el) => {
|
||||
if (el.textContent && el.id) {
|
||||
updatedHeaders.push({
|
||||
level: Number(el.tagName[1]),
|
||||
title: el.innerText.replace(/\s+#\s*$/, ''),
|
||||
link: `#${el.id}`,
|
||||
lang: el.lang,
|
||||
})
|
||||
}
|
||||
})
|
||||
return resolveHeaders(updatedHeaders, pageOutline)
|
||||
}
|
||||
|
|
|
@ -22,6 +22,10 @@
|
|||
}
|
||||
|
||||
.markdown-body {
|
||||
code {
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
div[class*="language-"] {
|
||||
position: relative;
|
||||
background-color: var(--va-code-block-bg);
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
// ref vitepress src/node/markdown/env.ts
|
||||
import type { MarkdownSfcBlocks } from '@mdit-vue/plugin-sfc'
|
||||
import type { CleanUrlsMode, Header } from '../../types'
|
||||
|
||||
// Manually declaring all properties as rollup-plugin-dts
|
||||
// is unable to merge augmented module declarations
|
||||
|
||||
export interface MarkdownEnv {
|
||||
/**
|
||||
* The raw Markdown content without frontmatter
|
||||
*/
|
||||
content?: string
|
||||
/**
|
||||
* The excerpt that extracted by `@mdit-vue/plugin-frontmatter`
|
||||
*
|
||||
* - Would be the rendered HTML when `renderExcerpt` is enabled
|
||||
* - Would be the raw Markdown when `renderExcerpt` is disabled
|
||||
*/
|
||||
excerpt?: string
|
||||
/**
|
||||
* The frontmatter that extracted by `@mdit-vue/plugin-frontmatter`
|
||||
*/
|
||||
frontmatter?: Record<string, unknown>
|
||||
/**
|
||||
* The headers that extracted by `@mdit-vue/plugin-headers`
|
||||
*/
|
||||
headers?: Header[]
|
||||
/**
|
||||
* SFC blocks that extracted by `@mdit-vue/plugin-sfc`
|
||||
*/
|
||||
sfcBlocks?: MarkdownSfcBlocks
|
||||
/**
|
||||
* The title that extracted by `@mdit-vue/plugin-title`
|
||||
*/
|
||||
title?: string
|
||||
path: string
|
||||
relativePath: string
|
||||
cleanUrls: CleanUrlsMode
|
||||
links?: string[]
|
||||
}
|
|
@ -3,21 +3,37 @@ import MarkdownIt from 'markdown-it'
|
|||
import type { Theme } from 'shiki'
|
||||
|
||||
import anchorPlugin from 'markdown-it-anchor'
|
||||
import attrsPlugin from 'markdown-it-attrs'
|
||||
import emojiPlugin from 'markdown-it-emoji'
|
||||
import LinkAttributes from 'markdown-it-link-attributes'
|
||||
import TOC from 'markdown-it-table-of-contents'
|
||||
import TaskLists from 'markdown-it-task-lists'
|
||||
import attrs from 'markdown-it-attrs'
|
||||
|
||||
import type { KatexOptions } from 'katex'
|
||||
|
||||
import { componentPlugin } from '@mdit-vue/plugin-component'
|
||||
import {
|
||||
type FrontmatterPluginOptions,
|
||||
frontmatterPlugin,
|
||||
} from '@mdit-vue/plugin-frontmatter'
|
||||
import {
|
||||
type HeadersPluginOptions,
|
||||
headersPlugin,
|
||||
} from '@mdit-vue/plugin-headers'
|
||||
import { type SfcPluginOptions, sfcPlugin } from '@mdit-vue/plugin-sfc'
|
||||
import { titlePlugin } from '@mdit-vue/plugin-title'
|
||||
import { type TocPluginOptions, tocPlugin } from '@mdit-vue/plugin-toc'
|
||||
|
||||
import type { Header } from '../../types'
|
||||
import Katex from './markdown-it/katex'
|
||||
import { type Blocks, containerPlugin } from './markdown-it/container'
|
||||
import { headingPlugin } from './markdown-it/headings'
|
||||
import { slugify } from './slugify'
|
||||
import { highlight } from './highlight'
|
||||
import { highlightLinePlugin, preWrapperPlugin } from './markdown-it/highlightLines'
|
||||
|
||||
import { linkPlugin } from './plugins/link'
|
||||
|
||||
// import { lineNumberPlugin } from "./plugins/lineNumbers";
|
||||
|
||||
export * from './env'
|
||||
export type ThemeOptions = Theme | { light: Theme; dark: Theme }
|
||||
|
||||
export interface MarkdownParsedData {
|
||||
|
@ -25,11 +41,8 @@ export interface MarkdownParsedData {
|
|||
links?: string[]
|
||||
headers?: Header[]
|
||||
}
|
||||
export interface MarkdownRenderer extends MarkdownIt {
|
||||
__path: string
|
||||
__relativePath: string
|
||||
__data: MarkdownParsedData
|
||||
}
|
||||
|
||||
export type MarkdownRenderer = MarkdownIt
|
||||
|
||||
export interface MarkdownOptions {
|
||||
/**
|
||||
|
@ -40,14 +53,19 @@ export interface MarkdownOptions {
|
|||
* config markdown-it
|
||||
*/
|
||||
config?: (md: MarkdownIt) => void
|
||||
anchor?: {
|
||||
permalink?: anchorPlugin.AnchorOptions['permalink']
|
||||
}
|
||||
// https://github.com/Oktavilla/markdown-it-table-of-contents
|
||||
toc?: {
|
||||
includeLevel?: number[]
|
||||
[key: string]: any
|
||||
anchor?: anchorPlugin.AnchorOptions
|
||||
attrs?: {
|
||||
leftDelimiter?: string
|
||||
rightDelimiter?: string
|
||||
allowedAttributes?: string[]
|
||||
disable?: boolean
|
||||
}
|
||||
// mdit-vue plugins
|
||||
frontmatter?: FrontmatterPluginOptions
|
||||
headers?: HeadersPluginOptions
|
||||
sfc?: SfcPluginOptions
|
||||
toc?: TocPluginOptions
|
||||
|
||||
katex?: KatexOptions
|
||||
/**
|
||||
* shiki
|
||||
|
@ -57,30 +75,36 @@ export interface MarkdownOptions {
|
|||
* Custom block configurations
|
||||
*/
|
||||
blocks?: Blocks
|
||||
|
||||
externalLinks?: Record<string, string>
|
||||
}
|
||||
|
||||
export async function setupMarkdownPlugins(md: MarkdownIt, mdOptions: MarkdownOptions = {}, isExcerpt = false) {
|
||||
md
|
||||
.use(highlightLinePlugin)
|
||||
export async function setupMarkdownPlugins(
|
||||
md: MarkdownIt,
|
||||
mdOptions: MarkdownOptions = {},
|
||||
isExcerpt = false,
|
||||
base = '/',
|
||||
) {
|
||||
// custom plugins
|
||||
md.use(highlightLinePlugin)
|
||||
.use(preWrapperPlugin)
|
||||
.use(containerPlugin, mdOptions.blocks)
|
||||
// conflict with {% %}
|
||||
.use(attrs)
|
||||
|
||||
// generate toc in client
|
||||
if (!isExcerpt)
|
||||
md.use(headingPlugin, mdOptions?.toc?.includeLevel)
|
||||
// .use(lineNumberPlugin)
|
||||
// https://github.com/arve0/markdown-it-attrs
|
||||
// add classes
|
||||
md
|
||||
.use(LinkAttributes, {
|
||||
matcher: (link: string) => /^https?:\/\//.test(link),
|
||||
attrs: {
|
||||
.use(
|
||||
linkPlugin,
|
||||
{
|
||||
target: '_blank',
|
||||
rel: 'noopener',
|
||||
rel: 'noreferrer',
|
||||
...mdOptions.externalLinks,
|
||||
},
|
||||
})
|
||||
base,
|
||||
)
|
||||
|
||||
// conflict with {% %}
|
||||
// 3rd party plugins
|
||||
if (!mdOptions.attrs?.disable)
|
||||
md.use(attrsPlugin, mdOptions.attrs)
|
||||
|
||||
// .use(lineNumberPlugin)
|
||||
md.use(Katex, mdOptions.katex)
|
||||
md.use(emojiPlugin)
|
||||
|
||||
|
@ -90,24 +114,34 @@ export async function setupMarkdownPlugins(md: MarkdownIt, mdOptions: MarkdownOp
|
|||
permalink: anchorPlugin.permalink.ariaHidden({}),
|
||||
...mdOptions.anchor,
|
||||
})
|
||||
.use(TOC, {
|
||||
slugify,
|
||||
includeLevel: [2, 3, 4],
|
||||
...mdOptions.toc,
|
||||
})
|
||||
}
|
||||
|
||||
// mdit-vue plugins
|
||||
md.use(componentPlugin)
|
||||
.use(frontmatterPlugin, {
|
||||
...mdOptions.frontmatter,
|
||||
} as FrontmatterPluginOptions)
|
||||
.use(headersPlugin, {
|
||||
slugify,
|
||||
...mdOptions.headers,
|
||||
} as HeadersPluginOptions)
|
||||
.use(sfcPlugin, {
|
||||
...mdOptions.sfc,
|
||||
} as SfcPluginOptions)
|
||||
.use(titlePlugin)
|
||||
.use(tocPlugin, {
|
||||
slugify,
|
||||
...mdOptions.toc,
|
||||
} as TocPluginOptions)
|
||||
|
||||
md.use(TaskLists)
|
||||
|
||||
const originalRender = md.render
|
||||
md.render = (...args) => {
|
||||
(md as MarkdownRenderer).__data = {}
|
||||
return originalRender.call(md, ...args)
|
||||
}
|
||||
|
||||
if (mdOptions.config)
|
||||
mdOptions.config(md)
|
||||
|
||||
// if (options.lineNumbers)
|
||||
// md.use(lineNumberPlugin)
|
||||
|
||||
return md as MarkdownRenderer
|
||||
}
|
||||
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
// ref vitepress
|
||||
import { resolveTitleFromToken } from '@mdit-vue/shared'
|
||||
import type MarkdownIt from 'markdown-it'
|
||||
import type { MarkdownRenderer } from '..'
|
||||
import { slugify } from '../slugify'
|
||||
|
||||
export const headingPlugin = (md: MarkdownIt, include = [1, 2, 3, 4]) => {
|
||||
md.renderer.rules.heading_open = (tokens, i, options, env, self) => {
|
||||
const token = tokens[i]
|
||||
const tags = include.map(item => `h${item}`)
|
||||
if (tags.includes(token.tag)) {
|
||||
const content = tokens[i + 1].content
|
||||
const idAttr = token.attrs!.find(([name]) => name === 'id')
|
||||
const slug = idAttr && idAttr[1]
|
||||
const data = (md as MarkdownRenderer).__data
|
||||
const headers = data.headers || (data.headers = [])
|
||||
// remove {} after head
|
||||
const leftDeli = content.indexOf('{')
|
||||
const title = leftDeli === -1 ? content : content.slice(0, leftDeli).trim()
|
||||
|
||||
const matched = content.match(/\{lang=\"(.*)\"\}/)
|
||||
const lang = matched ? matched[1] : ''
|
||||
const titleToken = md.parseInline(title, {})[0]
|
||||
headers.push({
|
||||
level: parseInt(token.tag.slice(1), 10),
|
||||
title: resolveTitleFromToken(titleToken, {
|
||||
shouldAllowHtml: false,
|
||||
shouldEscapeText: false,
|
||||
}),
|
||||
slug: slug || slugify(title),
|
||||
lang,
|
||||
})
|
||||
}
|
||||
return self.renderToken(tokens, i, options)
|
||||
}
|
||||
}
|
|
@ -2,14 +2,13 @@
|
|||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
import c from 'picocolors'
|
||||
import matter from 'gray-matter'
|
||||
import LRUCache from 'lru-cache'
|
||||
import _debug from 'debug'
|
||||
import { resolveTitleFromToken } from '@mdit-vue/shared'
|
||||
import { EXTERNAL_URL_RE, getGitTimestamp, slash, transformObject } from '../utils'
|
||||
import type { HeadConfig, PageData } from '../../types'
|
||||
import type { CleanUrlsMode, HeadConfig, PageData } from '../../types'
|
||||
import { createMarkdownRenderer } from '.'
|
||||
import type { MarkdownOptions, MarkdownRenderer } from '.'
|
||||
import type { MarkdownEnv, MarkdownOptions, MarkdownRenderer } from '.'
|
||||
|
||||
const jsStringBreaker = '\u200B'
|
||||
const vueTemplateBreaker = '<wbr>'
|
||||
|
@ -101,6 +100,8 @@ export async function createMarkdownToVueRenderFn(
|
|||
userDefines: Record<string, any> | undefined,
|
||||
isBuild = false,
|
||||
includeLastUpdatedData = false,
|
||||
// https://vitepress.vuejs.org/config/app-configs#cleanurls-experimental
|
||||
cleanUrls: CleanUrlsMode = 'with-subfolders',
|
||||
) {
|
||||
const md = await createMarkdownRenderer(options)
|
||||
|
||||
|
@ -126,21 +127,33 @@ export async function createMarkdownToVueRenderFn(
|
|||
|
||||
// resolve includes
|
||||
const includes: string[] = []
|
||||
src = src.replace(includesRE, (_, m1) => {
|
||||
const includePath = path.join(dir, m1)
|
||||
const content = fs.readFileSync(includePath, 'utf-8')
|
||||
includes.push(slash(includePath))
|
||||
return content
|
||||
src = src.replace(includesRE, (m, m1) => {
|
||||
try {
|
||||
const includePath = path.join(dir, m1)
|
||||
const content = fs.readFileSync(includePath, 'utf-8')
|
||||
includes.push(slash(includePath))
|
||||
return content
|
||||
}
|
||||
catch (error) {
|
||||
return m // silently ignore error if file is not present
|
||||
}
|
||||
})
|
||||
|
||||
const { content, data: frontmatter } = matter(src)
|
||||
// reset env before render
|
||||
const env: MarkdownEnv = {
|
||||
path: file,
|
||||
relativePath,
|
||||
cleanUrls,
|
||||
}
|
||||
|
||||
// reset state before render
|
||||
md.__path = file
|
||||
md.__relativePath = relativePath
|
||||
|
||||
const html = md.render(content)
|
||||
const data = md.__data
|
||||
const html = md.render(src, env)
|
||||
const {
|
||||
frontmatter = {},
|
||||
headers = [],
|
||||
links = [],
|
||||
sfcBlocks,
|
||||
title = '',
|
||||
} = env
|
||||
|
||||
// validate data.links
|
||||
const deadLinks: string[] = []
|
||||
|
@ -157,9 +170,9 @@ export async function createMarkdownToVueRenderFn(
|
|||
deadLinks.push(url)
|
||||
}
|
||||
|
||||
if (data.links) {
|
||||
if (links) {
|
||||
const dir = path.dirname(file)
|
||||
for (let url of data.links) {
|
||||
for (let url of links) {
|
||||
if (/\.(?!html|md)\w+($|\?)/i.test(url))
|
||||
continue
|
||||
|
||||
|
@ -188,11 +201,11 @@ export async function createMarkdownToVueRenderFn(
|
|||
|
||||
// provide load
|
||||
const pageData: PageData = {
|
||||
title: inferTitle(md, frontmatter, ''),
|
||||
titleTemplate: frontmatter.titleTemplate,
|
||||
title: inferTitle(md, frontmatter, title),
|
||||
titleTemplate: frontmatter.titleTemplate as any,
|
||||
description: inferDescription(frontmatter),
|
||||
frontmatter,
|
||||
headers: data.headers || [],
|
||||
headers,
|
||||
relativePath,
|
||||
path: path.join(srcDir, relativePath),
|
||||
}
|
||||
|
@ -216,21 +229,30 @@ export async function createMarkdownToVueRenderFn(
|
|||
'aside',
|
||||
'aside-custom',
|
||||
]
|
||||
const slotsText = slots.map(s => `<template #${s}><slot name="${s}" /></template>`).join('')
|
||||
const slotsText = slots
|
||||
.map(s => `<template #${s}><slot name="${s}" /></template>`)
|
||||
.join('')
|
||||
return slotsText
|
||||
}
|
||||
|
||||
const vueSrc
|
||||
= [
|
||||
...injectPageDataCode(data.hoistedTags || [], pageData, replaceRegex),
|
||||
`<template><${pageComponent} :frontmatter="frontmatter" :data="data">`,
|
||||
`<template #main-content-md>${
|
||||
replaceConstants(html, replaceRegex, vueTemplateBreaker)
|
||||
}</template>`,
|
||||
generateSlots(),
|
||||
'<slot />',
|
||||
`</${pageComponent}></template>`,
|
||||
].join('\n')
|
||||
const vueSrc = [
|
||||
...injectPageDataCode(
|
||||
sfcBlocks?.scripts.map(item => item.content) ?? [],
|
||||
pageData,
|
||||
replaceRegex,
|
||||
),
|
||||
`<template><${pageComponent} :frontmatter="frontmatter" :data="data">`,
|
||||
`<template #main-content-md>${replaceConstants(
|
||||
html,
|
||||
replaceRegex,
|
||||
vueTemplateBreaker,
|
||||
)}</template>`,
|
||||
generateSlots(),
|
||||
'<slot />',
|
||||
`</${pageComponent}></template>`,
|
||||
...(sfcBlocks?.styles.map(item => item.content) ?? []),
|
||||
...(sfcBlocks?.customBlocks.map(item => item.content) ?? []),
|
||||
].join('\n')
|
||||
|
||||
debug(`[render] ${file} in ${Date.now() - start}ms.`)
|
||||
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
// ref vitepress
|
||||
|
||||
// markdown-it plugin for:
|
||||
// 1. adding target="_blank" to external links
|
||||
// 2. normalize internal links to end with `.html`
|
||||
|
||||
import { URL } from 'url'
|
||||
import type MarkdownIt from 'markdown-it'
|
||||
import type { MarkdownEnv } from '../env'
|
||||
import { EXTERNAL_URL_RE } from '../../utils'
|
||||
|
||||
const indexRE = /(^|.*\/)index.md(#?.*)$/i
|
||||
|
||||
export const linkPlugin = (
|
||||
md: MarkdownIt,
|
||||
externalAttrs: Record<string, string>,
|
||||
base: string,
|
||||
) => {
|
||||
md.renderer.rules.link_open = (
|
||||
tokens,
|
||||
idx,
|
||||
options,
|
||||
env: MarkdownEnv,
|
||||
self,
|
||||
) => {
|
||||
const token = tokens[idx]
|
||||
const hrefIndex = token.attrIndex('href')
|
||||
if (hrefIndex >= 0) {
|
||||
const hrefAttr = token.attrs![hrefIndex]
|
||||
const url = hrefAttr[1]
|
||||
const isExternal = EXTERNAL_URL_RE.test(url)
|
||||
if (isExternal) {
|
||||
Object.entries(externalAttrs).forEach(([key, val]) => {
|
||||
token.attrSet(key, val)
|
||||
})
|
||||
// catch localhost links as dead link
|
||||
if (url.replace(EXTERNAL_URL_RE, '').startsWith('//localhost:'))
|
||||
pushLink(url, env)
|
||||
}
|
||||
else if (
|
||||
// internal anchor links
|
||||
!url.startsWith('#')
|
||||
// mail links
|
||||
&& !url.startsWith('mailto:')
|
||||
// links to files (other than html/md)
|
||||
&& !/\.(?!html|md)\w+($|\?)/i.test(url)
|
||||
) {
|
||||
normalizeHref(hrefAttr, env)
|
||||
}
|
||||
|
||||
// encode vite-specific replace strings in case they appear in URLs
|
||||
// this also excludes them from build-time replacements (which injects
|
||||
// <wbr/> and will break URLs)
|
||||
hrefAttr[1] = hrefAttr[1]
|
||||
.replace(/\bimport\.meta/g, 'import%2Emeta')
|
||||
.replace(/\bprocess\.env/g, 'process%2Eenv')
|
||||
}
|
||||
return self.renderToken(tokens, idx, options)
|
||||
}
|
||||
|
||||
function normalizeHref(hrefAttr: [string, string], env: MarkdownEnv) {
|
||||
let url = hrefAttr[1]
|
||||
|
||||
const indexMatch = url.match(indexRE)
|
||||
if (indexMatch) {
|
||||
const [, path, hash] = indexMatch
|
||||
url = path + hash
|
||||
}
|
||||
else {
|
||||
let cleanUrl = url.replace(/[?#].*$/, '')
|
||||
// transform foo.md -> foo[.html]
|
||||
if (cleanUrl.endsWith('.md')) {
|
||||
cleanUrl = cleanUrl.replace(
|
||||
/\.md$/,
|
||||
env.cleanUrls === 'disabled' ? '.html' : '',
|
||||
)
|
||||
}
|
||||
// transform ./foo -> ./foo[.html]
|
||||
if (
|
||||
env.cleanUrls === 'disabled'
|
||||
&& !cleanUrl.endsWith('.html')
|
||||
&& !cleanUrl.endsWith('/')
|
||||
)
|
||||
cleanUrl += '.html'
|
||||
|
||||
const parsed = new URL(url, 'http://a.com')
|
||||
url = cleanUrl + parsed.search + parsed.hash
|
||||
}
|
||||
|
||||
// ensure leading . for relative paths
|
||||
if (!url.startsWith('/') && !/^\.\//.test(url))
|
||||
url = `./${url}`
|
||||
|
||||
// export it for existence check
|
||||
pushLink(url.replace(/\.html$/, ''), env)
|
||||
|
||||
// append base to internal (non-relative) urls
|
||||
if (url.startsWith('/'))
|
||||
url = `${base}${url}`.replace(/\/+/g, '/')
|
||||
|
||||
// markdown-it encodes the uri
|
||||
hrefAttr[1] = decodeURI(url)
|
||||
}
|
||||
|
||||
function pushLink(link: string, env: MarkdownEnv) {
|
||||
const links = env.links || (env.links = [])
|
||||
links.push(link)
|
||||
}
|
||||
}
|
|
@ -90,7 +90,7 @@ export async function resolveOptions(options: ValaxyEntryOptions, mode: Resolved
|
|||
// supported in Node 12+, which is required by Vite.
|
||||
const pages = (
|
||||
await fg(['**.md'], {
|
||||
cwd: userRoot,
|
||||
cwd: resolve(userRoot, 'pages'),
|
||||
ignore: ['**/node_modules'],
|
||||
})
|
||||
).sort()
|
||||
|
|
|
@ -133,10 +133,6 @@ export function createValaxyPlugin(options: ResolvedValaxyOptions, serverOptions
|
|||
markdownToVue = await createMarkdownToVueRenderFn(
|
||||
options.userRoot,
|
||||
valaxyConfig.markdown || {
|
||||
toc: {
|
||||
includeLevel: [1, 2, 3, 4],
|
||||
listType: 'ol',
|
||||
},
|
||||
katex: {},
|
||||
},
|
||||
options.pages,
|
||||
|
@ -200,19 +196,6 @@ export function createValaxyPlugin(options: ResolvedValaxyOptions, serverOptions
|
|||
code.replace('{%', '\{\%')
|
||||
code.replace('%}', '\%\}')
|
||||
|
||||
// const scripts = [
|
||||
// '<script setup>',
|
||||
// 'import { useRoute } from "vue-router"',
|
||||
// 'const route = useRoute()',
|
||||
// `route.meta.headers = ${JSON.stringify(_md.__data)}`,
|
||||
// `export const data = JSON.parse(${JSON.stringify(JSON.stringify(pageData))})`,
|
||||
// `frontmatter.data = JSON.parse(${JSON.stringify(JSON.stringify(pageData))})`,
|
||||
// '</script>',
|
||||
// ]
|
||||
|
||||
// const li = code.lastIndexOf('</script>')
|
||||
// code = code.slice(0, li) + scripts.join('\n') + code.slice(li + 9)
|
||||
|
||||
// transform .md files into vueSrc so plugin-vue can handle it
|
||||
const { vueSrc, deadLinks, includes } = await markdownToVue(
|
||||
code,
|
||||
|
|
|
@ -85,7 +85,6 @@
|
|||
"markdown-it-attrs": "^4.1.4",
|
||||
"markdown-it-container": "^3.0.0",
|
||||
"markdown-it-emoji": "^2.0.2",
|
||||
"markdown-it-link-attributes": "^4.0.1",
|
||||
"markdown-it-table-of-contents": "^0.6.0",
|
||||
"markdown-it-task-lists": "^2.1.1",
|
||||
"nprogress": "^0.2.0",
|
||||
|
@ -109,12 +108,17 @@
|
|||
"yargs": "^17.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mdit-vue/plugin-component": "^0.11.1",
|
||||
"@mdit-vue/plugin-frontmatter": "^0.11.1",
|
||||
"@mdit-vue/plugin-headers": "^0.11.1",
|
||||
"@mdit-vue/plugin-sfc": "^0.11.1",
|
||||
"@mdit-vue/plugin-title": "^0.11.1",
|
||||
"@mdit-vue/plugin-toc": "^0.11.1",
|
||||
"@mdit-vue/shared": "^0.11.0",
|
||||
"@types/cross-spawn": "^6.0.2",
|
||||
"@types/ejs": "^3.1.1",
|
||||
"@types/katex": "^0.14.0",
|
||||
"@types/markdown-it": "^12.2.3",
|
||||
"@types/markdown-it-link-attributes": "^3.0.1",
|
||||
"@types/nprogress": "^0.2.0",
|
||||
"@types/yargs": "^17.0.13",
|
||||
"debug": "^4.3.4",
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
export type DefaultThemeConfig = Record<string, any>
|
||||
export type DefaultThemeConfig = {
|
||||
/**
|
||||
* Custom header levels of outline in the aside component.
|
||||
*
|
||||
* @default 2
|
||||
*/
|
||||
outline?: number | [number, number] | 'deep' | false
|
||||
} & Record<string, any>
|
||||
|
||||
export interface SocialLink {
|
||||
/**
|
||||
|
|
|
@ -1,9 +1,33 @@
|
|||
import type { Post } from './posts'
|
||||
|
||||
export type CleanUrlsMode =
|
||||
| 'disabled'
|
||||
| 'without-subfolders'
|
||||
| 'with-subfolders'
|
||||
|
||||
export interface Header {
|
||||
/**
|
||||
* The level of the header
|
||||
*
|
||||
* `1` to `6` for `<h1>` to `<h6>`
|
||||
*/
|
||||
level: number
|
||||
/**
|
||||
* The title of the header
|
||||
*/
|
||||
title: string
|
||||
/**
|
||||
* The slug of the header
|
||||
*
|
||||
* Typically the `id` attr of the header anchor
|
||||
*/
|
||||
slug: string
|
||||
/**
|
||||
* Link of the header
|
||||
*
|
||||
* Typically using `#${slug}` as the anchor hash
|
||||
*/
|
||||
link: string
|
||||
/**
|
||||
* i18n
|
||||
*/
|
||||
|
|
|
@ -94,12 +94,17 @@ importers:
|
|||
'@iconify-json/carbon': ^1.1.8
|
||||
'@iconify-json/ri': ^1.1.3
|
||||
'@intlify/vite-plugin-vue-i18n': ^6.0.3
|
||||
'@mdit-vue/plugin-component': ^0.11.1
|
||||
'@mdit-vue/plugin-frontmatter': ^0.11.1
|
||||
'@mdit-vue/plugin-headers': ^0.11.1
|
||||
'@mdit-vue/plugin-sfc': ^0.11.1
|
||||
'@mdit-vue/plugin-title': ^0.11.1
|
||||
'@mdit-vue/plugin-toc': ^0.11.1
|
||||
'@mdit-vue/shared': ^0.11.0
|
||||
'@types/cross-spawn': ^6.0.2
|
||||
'@types/ejs': ^3.1.1
|
||||
'@types/katex': ^0.14.0
|
||||
'@types/markdown-it': ^12.2.3
|
||||
'@types/markdown-it-link-attributes': ^3.0.1
|
||||
'@types/nprogress': ^0.2.0
|
||||
'@types/yargs': ^17.0.13
|
||||
'@vitejs/plugin-vue': ^3.1.2
|
||||
|
@ -127,7 +132,6 @@ importers:
|
|||
markdown-it-attrs: ^4.1.4
|
||||
markdown-it-container: ^3.0.0
|
||||
markdown-it-emoji: ^2.0.2
|
||||
markdown-it-link-attributes: ^4.0.1
|
||||
markdown-it-table-of-contents: ^0.6.0
|
||||
markdown-it-task-lists: ^2.1.1
|
||||
nprogress: ^0.2.0
|
||||
|
@ -177,7 +181,6 @@ importers:
|
|||
markdown-it-attrs: 4.1.4_markdown-it@13.0.1
|
||||
markdown-it-container: 3.0.0
|
||||
markdown-it-emoji: 2.0.2
|
||||
markdown-it-link-attributes: 4.0.1
|
||||
markdown-it-table-of-contents: 0.6.0
|
||||
markdown-it-task-lists: 2.1.1
|
||||
nprogress: 0.2.0
|
||||
|
@ -200,12 +203,17 @@ importers:
|
|||
vue-router: 4.1.5_vue@3.2.40
|
||||
yargs: 17.6.0
|
||||
devDependencies:
|
||||
'@mdit-vue/plugin-component': 0.11.1
|
||||
'@mdit-vue/plugin-frontmatter': 0.11.1
|
||||
'@mdit-vue/plugin-headers': 0.11.1
|
||||
'@mdit-vue/plugin-sfc': 0.11.1
|
||||
'@mdit-vue/plugin-title': 0.11.1
|
||||
'@mdit-vue/plugin-toc': 0.11.1
|
||||
'@mdit-vue/shared': 0.11.0
|
||||
'@types/cross-spawn': 6.0.2
|
||||
'@types/ejs': 3.1.1
|
||||
'@types/katex': 0.14.0
|
||||
'@types/markdown-it': 12.2.3
|
||||
'@types/markdown-it-link-attributes': 3.0.1
|
||||
'@types/nprogress': 0.2.0
|
||||
'@types/yargs': 17.0.13
|
||||
debug: 4.3.4
|
||||
|
@ -859,6 +867,57 @@ packages:
|
|||
'@jridgewell/sourcemap-codec': 1.4.14
|
||||
dev: false
|
||||
|
||||
/@mdit-vue/plugin-component/0.11.1:
|
||||
resolution: {integrity: sha512-fCqyYPwEXFa182/Vz6g8McDi3SCIwm3yHWkWddHx+QNn0gMGFqkhJVcz/wjCIA3oCoWUBWM80aZ09ZuoQiOmvQ==}
|
||||
dependencies:
|
||||
'@types/markdown-it': 12.2.3
|
||||
markdown-it: 13.0.1
|
||||
dev: true
|
||||
|
||||
/@mdit-vue/plugin-frontmatter/0.11.1:
|
||||
resolution: {integrity: sha512-AdZJInjD1pTJXlfhuoBS5ycuIQ3ewBfY0R/XHM3TRDEaDHQJHxouUCpCyijZmpdljTU45lFetIowaKtAi7GBog==}
|
||||
dependencies:
|
||||
'@mdit-vue/types': 0.11.0
|
||||
'@types/markdown-it': 12.2.3
|
||||
gray-matter: 4.0.3
|
||||
markdown-it: 13.0.1
|
||||
dev: true
|
||||
|
||||
/@mdit-vue/plugin-headers/0.11.1:
|
||||
resolution: {integrity: sha512-eBUonsEkXP2Uf2MIXSWZGCcLCIMSA1XfThJwhzSAosoa7fO5aw52LKCweddmn7zLQvgQh7p7382sFAhCc2KXog==}
|
||||
dependencies:
|
||||
'@mdit-vue/shared': 0.11.0
|
||||
'@mdit-vue/types': 0.11.0
|
||||
'@types/markdown-it': 12.2.3
|
||||
markdown-it: 13.0.1
|
||||
dev: true
|
||||
|
||||
/@mdit-vue/plugin-sfc/0.11.1:
|
||||
resolution: {integrity: sha512-3AjQXqExzT9FWGNOeTBqK1pbt1UA5anrZvjo7OO2PJ3lrfZd0rbjionFkmW/VW1912laHUraIP6n74mUNqPuWw==}
|
||||
dependencies:
|
||||
'@mdit-vue/types': 0.11.0
|
||||
'@types/markdown-it': 12.2.3
|
||||
markdown-it: 13.0.1
|
||||
dev: true
|
||||
|
||||
/@mdit-vue/plugin-title/0.11.1:
|
||||
resolution: {integrity: sha512-lvgR1pSgwX5D3tmLGyYBsfd3GbEoscqYsLTE8Vg+rCY8LfSrHdwrOD3Eg+SM2KyS5+gn+Zw4nS0S1yxOIVZBCQ==}
|
||||
dependencies:
|
||||
'@mdit-vue/shared': 0.11.0
|
||||
'@mdit-vue/types': 0.11.0
|
||||
'@types/markdown-it': 12.2.3
|
||||
markdown-it: 13.0.1
|
||||
dev: true
|
||||
|
||||
/@mdit-vue/plugin-toc/0.11.1:
|
||||
resolution: {integrity: sha512-1tkGb1092ZgLhoSmE5hkC6U0IRGG5bWhUY4p14npV4cwqntciXEoXRqPA1jGEDh5hnofZC0bHbeS3uKxsmAEew==}
|
||||
dependencies:
|
||||
'@mdit-vue/shared': 0.11.0
|
||||
'@mdit-vue/types': 0.11.0
|
||||
'@types/markdown-it': 12.2.3
|
||||
markdown-it: 13.0.1
|
||||
dev: true
|
||||
|
||||
/@mdit-vue/shared/0.11.0:
|
||||
resolution: {integrity: sha512-eiGe42y7UYpjO6/8Lg6OpAtzZrRU9k8dhpX1e/kJMTcL+tn+XkqRMJJ8I2pdrOQMSkgvIva5FNAriykqFzkdGg==}
|
||||
dependencies:
|
||||
|
@ -961,12 +1020,6 @@ packages:
|
|||
/@types/linkify-it/3.0.2:
|
||||
resolution: {integrity: sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==}
|
||||
|
||||
/@types/markdown-it-link-attributes/3.0.1:
|
||||
resolution: {integrity: sha512-K8RnNb1q8j7rDOJbMF7AnlhCC/45BjrQ8z3WZWOrvkBIl8u9RXvmBdG/hfpnmK1JhhEZcmFEKWt+ilW1Mly+2Q==}
|
||||
dependencies:
|
||||
'@types/markdown-it': 12.2.3
|
||||
dev: true
|
||||
|
||||
/@types/markdown-it/12.2.3:
|
||||
resolution: {integrity: sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==}
|
||||
dependencies:
|
||||
|
@ -1781,7 +1834,6 @@ packages:
|
|||
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
|
||||
dependencies:
|
||||
sprintf-js: 1.0.3
|
||||
dev: false
|
||||
|
||||
/argparse/2.0.1:
|
||||
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
|
||||
|
@ -3428,7 +3480,6 @@ packages:
|
|||
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
|
||||
engines: {node: '>=4'}
|
||||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/esquery/1.4.0:
|
||||
resolution: {integrity: sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==}
|
||||
|
@ -3550,7 +3601,6 @@ packages:
|
|||
engines: {node: '>=0.10.0'}
|
||||
dependencies:
|
||||
is-extendable: 0.1.1
|
||||
dev: false
|
||||
|
||||
/extract-comments/1.1.0:
|
||||
resolution: {integrity: sha512-dzbZV2AdSSVW/4E7Ti5hZdHWbA+Z80RJsJhr5uiL10oyjl/gy7/o+HI1HwK4/WSZhlq4SNKU3oUzXlM13Qx02Q==}
|
||||
|
@ -3911,7 +3961,6 @@ packages:
|
|||
kind-of: 6.0.3
|
||||
section-matter: 1.0.0
|
||||
strip-bom-string: 1.0.0
|
||||
dev: false
|
||||
|
||||
/gzip-size/6.0.0:
|
||||
resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==}
|
||||
|
@ -4231,7 +4280,6 @@ packages:
|
|||
/is-extendable/0.1.1:
|
||||
resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/is-extglob/2.1.1:
|
||||
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
||||
|
@ -4408,7 +4456,6 @@ packages:
|
|||
dependencies:
|
||||
argparse: 1.0.10
|
||||
esprima: 4.0.1
|
||||
dev: false
|
||||
|
||||
/js-yaml/4.1.0:
|
||||
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
|
||||
|
@ -4526,7 +4573,6 @@ packages:
|
|||
/kind-of/6.0.3:
|
||||
resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/kleur/3.0.3:
|
||||
resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==}
|
||||
|
@ -4733,10 +4779,6 @@ packages:
|
|||
resolution: {integrity: sha512-zLftSaNrKuYl0kR5zm4gxXjHaOI3FAOEaloKmRA5hijmJZvSjmxcokOLlzycb/HXlUFWzXqpIEoyEMCE4i9MvQ==}
|
||||
dev: false
|
||||
|
||||
/markdown-it-link-attributes/4.0.1:
|
||||
resolution: {integrity: sha512-pg5OK0jPLg62H4k7M9mRJLT61gUp9nvG0XveKYHMOOluASo9OEF13WlXrpAp2aj35LbedAy3QOCgQCw0tkLKAQ==}
|
||||
dev: false
|
||||
|
||||
/markdown-it-table-of-contents/0.6.0:
|
||||
resolution: {integrity: sha512-jHvEjZVEibyW97zEYg19mZCIXO16lHbvRaPDkEuOfMPBmzlI7cYczMZLMfUvwkhdOVQpIxu3gx6mgaw46KsNsQ==}
|
||||
engines: {node: '>6.4.0'}
|
||||
|
@ -5703,7 +5745,6 @@ packages:
|
|||
dependencies:
|
||||
extend-shallow: 2.0.1
|
||||
kind-of: 6.0.3
|
||||
dev: false
|
||||
|
||||
/select-hose/2.0.0:
|
||||
resolution: {integrity: sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==}
|
||||
|
@ -5932,7 +5973,6 @@ packages:
|
|||
|
||||
/sprintf-js/1.0.3:
|
||||
resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==}
|
||||
dev: false
|
||||
|
||||
/stable/0.1.8:
|
||||
resolution: {integrity: sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==}
|
||||
|
@ -6018,7 +6058,6 @@ packages:
|
|||
/strip-bom-string/1.0.0:
|
||||
resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/strip-bom/3.0.0:
|
||||
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
|
||||
|
|
Loading…
Reference in New Issue