Skip to content

Commit 8633f26

Browse files
committed
fix: bring back CodeBlockFile component
1 parent 87f6e01 commit 8633f26

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+4117
-30
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<script setup lang="ts">
2+
import { transformContent } from '../../transformers'
3+
import { useAsyncData } from '#imports'
4+
5+
const props = defineProps<{
6+
path: string
7+
language?: string
8+
filename?: string
9+
}>()
10+
11+
const modules = import.meta.glob(['./*.vue', '!./CodeBlockFile.vue'], { as: 'raw' })
12+
// console.log(`modules → `, modules)
13+
14+
function prepareContent(content: string) {
15+
return `\`\`\`${props.language || ''}${props.filename ? ` [${props.filename}]` : ''}\n${content}\n\`\`\``
16+
}
17+
18+
const { data: doc } = await useAsyncData(`playground-${props.path}`, async () => {
19+
try {
20+
const module = modules[props.path]
21+
if (!module)
22+
console.error('Component Not Found.')
23+
24+
const content = prepareContent(await module() as any)
25+
// console.log(`content → `, content)
26+
const parsed = await transformContent('content:index.md', content)
27+
return parsed
28+
}
29+
catch (e) {
30+
return doc.value
31+
}
32+
})
33+
</script>
34+
35+
<template>
36+
<ContentRenderer :key="doc.updatedAt" class="docus-content" :value="doc">
37+
<template #empty>
38+
<div class="p-8">
39+
<Alert type="warning">
40+
<p class="font-semibold">
41+
Content is empty!
42+
</p>
43+
<br><br>
44+
<p>
45+
Type any <span class="font-semibold">Markdown</span> or <span class="font-semibold">MDC code</span> in
46+
editor to see it replaced by rendered nodes in this panel.
47+
</p>
48+
</Alert>
49+
</div>
50+
</template>
51+
</ContentRenderer>
52+
</template>
53+
54+
<style scoped>
55+
.docus-content :deep(.filename) {
56+
display: block;
57+
}
58+
</style>

docs/content/2.get-started/1.guide/2.setup.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ Use plain CSS to define a `<PlainCssConfirmModal>`{lang=ts} component with `<Vue
115115
- Basic example
116116
::code-group
117117
::code-block{label="PlainCssConfirmModal.vue"}
118-
:code-block-file{path="./PlainCssConfirmModal.vue" language="vue"}
118+
<!-- :code-block-file{path="./PlainCssConfirmModal.vue" language="vue"} -->
119119
::
120120

121121
::code-block{label="Preview.vue"}

docs/content/4.use-cases/3.confirm-modal.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Create a `<ConfirmModal>` component with `<VueFinalModal>` and TailwindCSS.
1010

1111
::code-group
1212
::code-block{label="ConfirmModal.vue"}
13-
<!-- :code-block-file{path="./ConfirmModal.vue" language="vue"} -->
13+
:code-block-file{path="./ConfirmModal.vue" language="vue"}
1414
::
1515
::
1616

@@ -22,6 +22,6 @@ Create a `<ConfirmModal>` component with `<VueFinalModal>` and TailwindCSS.
2222
::
2323

2424
::code-block{label="Preview.vue"}
25-
<!-- :code-block-file{path="./ConfirmModalPreview.vue" language="vue"} -->
25+
:code-block-file{path="./ConfirmModalPreview.vue" language="vue"}
2626
::
2727
::

docs/content/4.use-cases/4.login-form-modal.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ This example use [Vorms](https://vorms.mini-ghost.dev/) to handle the form valid
1414

1515
::code-group
1616
::code-block{label="LoginFormModal.vue"}
17-
<!-- :code-block-file{path="./LoginFormModal.vue" language="vue"} -->
17+
:code-block-file{path="./LoginFormModal.vue" language="vue"}
1818
::
1919
::
2020

@@ -34,6 +34,6 @@ This example use [Vorms](https://vorms.mini-ghost.dev/) to handle the form valid
3434
::
3535

3636
::code-block{label="Preview.vue"}
37-
<!-- :code-block-file{path="./LoginFormModalPreview.vue" language="vue"} -->
37+
:code-block-file{path="./LoginFormModalPreview.vue" language="vue"}
3838
::
3939
::

docs/content/4.use-cases/5.nested-modal.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Use `<ConfirmModal>` to demo how to use nested modal.
1010

1111
::code-group
1212
::code-block{label="ConfirmModal.vue"}
13-
<!-- :code-block-file{path="./ConfirmModal.vue" language="vue"} -->
13+
:code-block-file{path="./ConfirmModal.vue" language="vue"}
1414
::
1515
::
1616

@@ -22,6 +22,6 @@ Use `<ConfirmModal>` to demo how to use nested modal.
2222
::
2323

2424
::code-block{label="NestedModalPreview.vue"}
25-
<!-- :code-block-file{path="./NestedModalPreview.vue" language="vue"} -->
25+
:code-block-file{path="./NestedModalPreview.vue" language="vue"}
2626
::
2727
::

docs/content/4.use-cases/6.fullscreen-modal.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Create a `<Fullscreen>` component with `<ModalFullscreen>` and TailwindCSS.
1010

1111
::code-group
1212
::code-block{label="Fullscreen.vue"}
13-
<!-- :code-block-file{path="./Fullscreen.vue" language="vue"} -->
13+
:code-block-file{path="./Fullscreen.vue" language="vue"}
1414
::
1515
::
1616

@@ -23,6 +23,6 @@ Create a `<Fullscreen>` component with `<ModalFullscreen>` and TailwindCSS.
2323
::
2424

2525
::code-block{label="FullscreenPreview.vue"}
26-
<!-- :code-block-file{path="./FullscreenPreview.vue" language="vue"} -->
26+
:code-block-file{path="./FullscreenPreview.vue" language="vue"}
2727
::
2828
::

docs/content/4.use-cases/7.bottom-sheet-modal.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Create a `<BottomSheet>` component with `<ModalBottom>` and TailwindCSS.
1010

1111
::code-group
1212
::code-block{label="BottomSheet.vue"}
13-
<!-- :code-block-file{path="./BottomSheet.vue" language="vue"} -->
13+
:code-block-file{path="./BottomSheet.vue" language="vue"}
1414
::
1515
::
1616

@@ -23,6 +23,6 @@ Create a `<BottomSheet>` component with `<ModalBottom>` and TailwindCSS.
2323
::
2424

2525
::code-block{label="BottomSheetPreview.vue"}
26-
<!-- :code-block-file{path="./BottomSheetPreview.vue" language="vue"} -->
26+
:code-block-file{path="./BottomSheetPreview.vue" language="vue"}
2727
::
2828
::

docs/content/4.use-cases/8.drag-resize-modal.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Here is a basic drag and resize modal example that using [vue3-drag-resize](http
1212

1313
::code-group
1414
::code-block{label="DragResizeModal.vue"}
15-
<!-- :code-block-file{path="./DragResizeModal.vue" language="vue"} -->
15+
:code-block-file{path="./DragResizeModal.vue" language="vue"}
1616
::
1717
::
1818

@@ -25,6 +25,6 @@ Here is a basic drag and resize modal example that using [vue3-drag-resize](http
2525
::
2626

2727
::code-block{label="DragResizeModalPreview.vue"}
28-
<!-- :code-block-file{path="./DragResizeModalPreview.vue" language="vue"} -->
28+
:code-block-file{path="./DragResizeModalPreview.vue" language="vue"}
2929
::
3030
::

docs/markdown-parser/compiler.ts

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import type { Node as UnistNode } from 'unist'
2+
import type { MarkdownNode, MarkdownOptions, MarkdownRoot } from '../types'
3+
4+
type Node = UnistNode & {
5+
tagName?: string
6+
value?: string
7+
children?: Node[]
8+
properties: Record<string, any>
9+
}
10+
11+
/**
12+
* JSON compiler
13+
*/
14+
export default function (this: any, _options: MarkdownOptions) {
15+
/**
16+
* Parses nodes for JSON structure. Attempts to drop
17+
* unwanted properties.
18+
*/
19+
function parseAsJSON(node: Node | Node[]) {
20+
if (Array.isArray(node))
21+
return node.map(parseAsJSON).filter(Boolean)
22+
23+
// Remove double dashes and trailing dash from heading ids
24+
if (node.tagName?.startsWith('h') && node.properties.id) {
25+
node.properties.id = node.properties.id
26+
.replace(/-+/g, '-')
27+
.replace(/-$/, '')
28+
.replace(/^-/, '')
29+
}
30+
31+
/**
32+
* Element node creates an isolated children array to
33+
* allow nested elements
34+
*/
35+
if (node.type === 'element') {
36+
if (node.tagName === 'li') {
37+
// unwrap unwanted paragraphs around `<li>` children
38+
let hasPreviousParagraph = false
39+
node.children = node.children.flatMap((child) => {
40+
if (child.tagName === 'p') {
41+
if (hasPreviousParagraph) {
42+
// Insert line break before new paragraph
43+
child.children.unshift({
44+
type: 'element',
45+
tagName: 'br',
46+
properties: {},
47+
})
48+
}
49+
50+
hasPreviousParagraph = true
51+
return child.children
52+
}
53+
return child
54+
}) as Node[]
55+
}
56+
57+
/**
58+
* Rename component slots tags name
59+
*/
60+
if (node.tagName === 'component-slot')
61+
node.tagName = 'template'
62+
63+
return <MarkdownNode> {
64+
type: 'element',
65+
tag: node.tagName as string,
66+
props: node.properties,
67+
children: parseAsJSON(node.children || []),
68+
}
69+
}
70+
71+
/**
72+
* Text node
73+
*/
74+
if (node.type === 'text') {
75+
// Remove new line nodes
76+
if (node.value === '\n')
77+
return null
78+
79+
return <MarkdownNode> {
80+
type: 'text',
81+
value: node.value as string,
82+
}
83+
}
84+
85+
// Remove comment nodes from AST tree
86+
if (node.type === 'comment')
87+
return null
88+
89+
node.children = parseAsJSON(node.children || [])
90+
91+
return node as MarkdownNode
92+
}
93+
94+
this.Compiler = function (root: Node): MarkdownRoot {
95+
/**
96+
* We do not use `map` operation, since each node can be expanded to multiple top level
97+
* nodes. Instead, we need a array to fill in as many elements inside a single
98+
* iteration
99+
*/
100+
return {
101+
type: 'root',
102+
children: parseAsJSON(root.children || []),
103+
}
104+
}
105+
}

docs/markdown-parser/content.ts

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import type { Processor } from 'unified'
2+
import { unified } from 'unified'
3+
import remarkParse from 'remark-parse'
4+
import remark2rehype from 'remark-rehype'
5+
import remarkMDC from 'remark-mdc'
6+
import type { MarkdownOptions, MarkdownPlugin, MarkdownRoot } from '../types'
7+
import handlers from './handler'
8+
import compiler from './compiler'
9+
import { flattenNodeText } from './utils/ast'
10+
import { nodeTextContent } from './utils/node'
11+
12+
const usePlugins = (plugins: Record<string, false | MarkdownPlugin>, stream: Processor) => {
13+
for (const plugin of Object.values(plugins)) {
14+
if (plugin) {
15+
const { instance, ...options } = plugin
16+
stream.use(instance, options)
17+
}
18+
}
19+
}
20+
21+
/**
22+
* Generate text excerpt summary
23+
* @param {string} excerptContent - JSON AST generated from excerpt markdown.
24+
* @returns {string} concatinated excerpt
25+
*/
26+
export function generateDescription(excerptContent: MarkdownRoot) {
27+
return flattenNodeText(excerptContent)
28+
}
29+
30+
/**
31+
* Generate json body
32+
* @param {string} content - file content
33+
* @param {object} data - document data
34+
* @returns {object} JSON AST body
35+
*/
36+
export function generateBody(content: string, options: MarkdownOptions & { data: any }): Promise<MarkdownRoot> {
37+
const rehypeOptions: any = {
38+
handlers,
39+
allowDangerousHtml: true,
40+
}
41+
42+
return new Promise((resolve, reject) => {
43+
const stream = unified().use(remarkParse)
44+
45+
if (options.mdc)
46+
stream.use(remarkMDC)
47+
48+
usePlugins(options.remarkPlugins, stream)
49+
stream.use(remark2rehype, rehypeOptions)
50+
usePlugins(options.rehypePlugins, stream)
51+
52+
stream.use(compiler, options as any)
53+
stream.process(
54+
{
55+
value: content,
56+
data: options.data,
57+
},
58+
(error, file) => {
59+
if (error)
60+
return reject(error)
61+
62+
Object.assign(options.data, file?.data || {})
63+
64+
resolve(file?.result as MarkdownRoot)
65+
},
66+
)
67+
})
68+
}
69+
70+
export function contentHeading(body: MarkdownRoot) {
71+
let title = ''
72+
let description = ''
73+
const children = body.children
74+
// top level `text` and `hr` can be ignored
75+
.filter(node => node.type !== 'text' && node.tag !== 'hr')
76+
77+
if (children.length && children[0].tag === 'h1') {
78+
/**
79+
* Remove node
80+
*/
81+
const node = children.shift()!
82+
83+
/**
84+
* Generate title
85+
*/
86+
title = nodeTextContent(node)
87+
}
88+
89+
if (children.length && children[0].tag === 'p') {
90+
/**
91+
* Remove node
92+
*/
93+
const node = children.shift()!
94+
95+
/**
96+
* Generate description
97+
*/
98+
description = nodeTextContent(node)
99+
}
100+
101+
return {
102+
title,
103+
description,
104+
}
105+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import type { H } from 'mdast-util-to-hast'
2+
import { all } from 'mdast-util-to-hast'
3+
import { wrap } from './utils'
4+
5+
export default function blockquote(h: H, node: any) {
6+
return h(node, 'blockquote', wrap(all(h, node), true))
7+
}

0 commit comments

Comments
 (0)