@wordup-md/nuxt-layer-shadcn-unocss 0.2.26 → 0.2.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.playground/content/1.getting-started/2.writing/2.pages.md +100 -85
- package/.playground/nuxt.config.ts +2 -2
- package/assets/css/mdc-editor.css +2 -2
- package/components/content/global/AlertEditor.vue +39 -3
- package/components/content/global/SectionEditor.vue +10 -11
- package/components/layout/Header.vue +5 -3
- package/nuxt.config.ts +23 -23
- package/package.json +21 -14
- package/plugins/wordup.ts +143 -7
- package/public/content-doc.json +1 -1
|
@@ -25,41 +25,41 @@ Add `:` before the key to bind the frontmatter value to the component.\
|
|
|
25
25
|
Or use the `{{ $doc.key }}` syntax to bind the value of the frontmatter.
|
|
26
26
|
|
|
27
27
|
::stack
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
:::div{.p-4}
|
|
29
|
+
This is the title from the frontmatter: **Title of the page**.
|
|
30
|
+
|
|
31
|
+
::::alert
|
|
32
32
|
---
|
|
33
33
|
:type: key
|
|
34
34
|
---
|
|
35
35
|
With the property `:type: key`, it displays a **{{ $doc.key }} alert**.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
::::
|
|
37
|
+
|
|
38
|
+
Or inline:
|
|
39
|
+
|
|
40
|
+
:alert[Title of the page]{:icon="icon" :type="key"}
|
|
41
|
+
:::
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
```mdc
|
|
44
|
+
---
|
|
45
|
+
title: Title of the page
|
|
46
|
+
icon: lucide:file
|
|
47
|
+
key: example
|
|
48
|
+
---
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
This is the title from the frontmatter: **{{ $doc.title }}**.
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
::alert
|
|
53
|
+
---
|
|
54
|
+
:type: key
|
|
55
|
+
---
|
|
56
|
+
With the property `:type: key`, it displays a **{{ $doc.key }} alert**.
|
|
57
|
+
::
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
Or inline:
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
:alert[{{ $doc.title }}]{:type="key" :icon="icon"}
|
|
62
|
+
```
|
|
63
63
|
::
|
|
64
64
|
|
|
65
65
|
## Available Frontmatter Attributes
|
|
@@ -98,80 +98,95 @@ authors:
|
|
|
98
98
|
## Showcases
|
|
99
99
|
|
|
100
100
|
::tabs{variant="line"}
|
|
101
|
-
|
|
102
|
-
{
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
101
|
+
:::stack{label="badges"}
|
|
102
|
+
{.w-full}
|
|
103
|
+
|
|
104
|
+
```yml
|
|
105
|
+
badges:
|
|
106
|
+
- value: 0.8.10
|
|
107
|
+
- value: Source
|
|
108
|
+
icon: lucide:code
|
|
109
|
+
to: https://github.com/wordup-md/nuxt-layer-shadcn-unocss/blob/main/components/content/FileTree.vue
|
|
110
|
+
target: _blank
|
|
111
|
+
```
|
|
112
|
+
:::
|
|
113
|
+
|
|
114
|
+
:::stack{label="authors"}
|
|
115
|
+
{.w-full}
|
|
116
|
+
|
|
117
|
+
```yml
|
|
118
|
+
authors:
|
|
119
|
+
- name: Tony Zhang
|
|
120
|
+
username: ZTL-UwU
|
|
121
|
+
avatar: https://www.github.com/ZTL-UwU.png
|
|
122
|
+
to: https://github.com/ZTL-UwU
|
|
123
|
+
target: _blank
|
|
124
|
+
```
|
|
125
|
+
:::
|
|
126
|
+
|
|
127
|
+
:::stack{label="navBadges"}
|
|
128
|
+
{.w-full}
|
|
129
|
+
|
|
130
|
+
```yml
|
|
131
|
+
navBadges:
|
|
132
|
+
- value: New
|
|
133
|
+
type: lime
|
|
134
|
+
```
|
|
135
|
+
:::
|
|
133
136
|
::
|
|
134
137
|
|
|
135
138
|
## Parameters
|
|
136
139
|
|
|
137
140
|
::field-group
|
|
138
|
-
|
|
141
|
+
:::field{name="title" type="string"}
|
|
139
142
|
Title of the page. Defaults to the filename.
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
143
|
+
:::
|
|
144
|
+
|
|
145
|
+
:::field{name="description" type="string"}
|
|
146
|
+
Description of the page. Defaults to the first `<p>` of the page.
|
|
147
|
+
:::
|
|
148
|
+
|
|
149
|
+
:::field{default-value="true" name="navigation" type="boolean"}
|
|
145
150
|
Define if the page is included in the sidebar. Set it to `false` in `index.md`.
|
|
146
|
-
|
|
147
|
-
|
|
151
|
+
:::
|
|
152
|
+
|
|
153
|
+
:::field{name="icon" type="string"}
|
|
148
154
|
The icon shown in the sidebar for the page.
|
|
149
|
-
|
|
150
|
-
|
|
155
|
+
:::
|
|
156
|
+
|
|
157
|
+
:::field{name="navBadges" type="[]"}
|
|
151
158
|
A list of badges appended to the end of the sidebar link.
|
|
152
|
-
|
|
153
|
-
|
|
159
|
+
:::
|
|
160
|
+
|
|
161
|
+
:::field{default-value="true" name="navTruncate" type="boolean"}
|
|
154
162
|
Whether to truncate the sidebar title.
|
|
155
|
-
|
|
156
|
-
|
|
163
|
+
:::
|
|
164
|
+
|
|
165
|
+
:::field{name="badges" type="[]"}
|
|
157
166
|
A list of badges shown at the bottom of page title.
|
|
158
|
-
|
|
159
|
-
|
|
167
|
+
:::
|
|
168
|
+
|
|
169
|
+
:::field{name="authors" type="[]"}
|
|
160
170
|
A list of authors shown at the bottom of page title.
|
|
161
|
-
|
|
162
|
-
|
|
171
|
+
:::
|
|
172
|
+
|
|
173
|
+
:::field{default-value="true" name="toc" type="boolean"}
|
|
163
174
|
Whether to show the toc section for this page.
|
|
164
|
-
|
|
165
|
-
|
|
175
|
+
:::
|
|
176
|
+
|
|
177
|
+
:::field{default-value="true" name="aside" type="boolean"}
|
|
166
178
|
Whether to show the aside section for this page.
|
|
167
|
-
|
|
168
|
-
|
|
179
|
+
:::
|
|
180
|
+
|
|
181
|
+
:::field{default-value="true" name="editLink" type="boolean"}
|
|
169
182
|
Whether to show the edit link for this page.
|
|
170
|
-
|
|
171
|
-
|
|
183
|
+
:::
|
|
184
|
+
|
|
185
|
+
:::field{default-value="true" name="prevNext" type="boolean"}
|
|
172
186
|
Whether to show the previous & next page buttons.
|
|
173
|
-
|
|
174
|
-
|
|
187
|
+
:::
|
|
188
|
+
|
|
189
|
+
:::field{default-value="true" name="breadcrumb" type="boolean"}
|
|
175
190
|
Whether to show the breadcrumb.
|
|
176
|
-
|
|
191
|
+
:::
|
|
177
192
|
::
|
|
@@ -4,7 +4,7 @@ export default defineNuxtConfig({
|
|
|
4
4
|
extends: ['..'],
|
|
5
5
|
modules: [
|
|
6
6
|
'@nuxt/eslint',
|
|
7
|
-
'@unpress/nuxt-module',
|
|
7
|
+
// '@unpress/nuxt-module',
|
|
8
8
|
// '../../../unpress/packages/nuxt-module/src/module',
|
|
9
9
|
],
|
|
10
10
|
|
|
@@ -51,7 +51,7 @@ export default defineNuxtConfig({
|
|
|
51
51
|
},
|
|
52
52
|
|
|
53
53
|
unpress: {
|
|
54
|
-
repo: 'https://
|
|
54
|
+
// repo: 'https://gitlab.com/ManUtopiK/nuxt-layer/-/tree/gitlab',
|
|
55
55
|
autoMountIfDevMode: true,
|
|
56
56
|
allowMountWithoutLogin: true,
|
|
57
57
|
},
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
& pre {
|
|
41
|
-
--at-apply: "p-3 rounded-lg border bg-muted/30! text-card-foreground shadow-sm overflow-x-auto";
|
|
41
|
+
--at-apply: "my-5! p-3 rounded-lg border bg-muted/30! text-card-foreground shadow-sm overflow-x-auto";
|
|
42
42
|
|
|
43
43
|
& code {
|
|
44
44
|
--at-apply: "bg-transparent p-0 border-none";
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
--at-apply: "rounded-none border-b-none border-l-none border-r-none shadow-none";
|
|
50
50
|
}
|
|
51
51
|
.FRONTMATTER pre {
|
|
52
|
-
--at-apply: "rounded-none border-none shadow-none bg-transparent";
|
|
52
|
+
--at-apply: "my-0! rounded-none border-none shadow-none bg-transparent";
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
& > div {
|
|
@@ -1,14 +1,38 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="group relative">
|
|
3
3
|
<UiEditorDropdown
|
|
4
|
-
v-model="mdcAttrs.type"
|
|
5
4
|
chevron
|
|
6
5
|
tooltip="Type"
|
|
7
6
|
placement="bottom-start"
|
|
8
|
-
:items="types"
|
|
9
7
|
class="absolute left-3 top--2 z-10 opacity-0 border rounded pl-2 pr-1 transition-opacity group-hover:opacity-100 bg-background"
|
|
10
8
|
>
|
|
11
9
|
<span class="text-xs font-mono capitalize">{{ model.type }}</span>
|
|
10
|
+
<template #menu>
|
|
11
|
+
<UiEditorMenuItem
|
|
12
|
+
v-for="item of types"
|
|
13
|
+
:key="item"
|
|
14
|
+
:label="item"
|
|
15
|
+
:pressed="mdcAttrs.type === item"
|
|
16
|
+
class="mb-0.5 last:mb-0"
|
|
17
|
+
@click="mdcAttrs.type = item"
|
|
18
|
+
/>
|
|
19
|
+
<hr
|
|
20
|
+
v-if="filteredFrontmatter.length > 0"
|
|
21
|
+
class="my-1"
|
|
22
|
+
>
|
|
23
|
+
<UiEditorMenuItem
|
|
24
|
+
v-for="[key, value] of filteredFrontmatter"
|
|
25
|
+
:key="key"
|
|
26
|
+
:label="`${key}: ${value}`"
|
|
27
|
+
:pressed="mdcAttrs.type === `:${key}`"
|
|
28
|
+
class="mb-0.5 last:mb-0 fmkeys"
|
|
29
|
+
@click="mdcAttrs.type = `:${key}`"
|
|
30
|
+
>
|
|
31
|
+
<template #label>
|
|
32
|
+
{{ key }}: <strong>{{ value }}</strong>
|
|
33
|
+
</template>
|
|
34
|
+
</UiEditorMenuItem>
|
|
35
|
+
</template>
|
|
12
36
|
</UiEditorDropdown>
|
|
13
37
|
|
|
14
38
|
<Alert
|
|
@@ -27,10 +51,12 @@
|
|
|
27
51
|
import type { VueNodeViewProps } from 'prosekit/vue'
|
|
28
52
|
|
|
29
53
|
const props = defineProps<VueNodeViewProps>()
|
|
30
|
-
const { getComponentProps } = useMdcEditor()
|
|
54
|
+
const { getComponentProps, frontmatter } = useMdcEditor()
|
|
31
55
|
|
|
32
56
|
const types = ['default', 'info', 'success', 'warning', 'danger', 'example', 'secondary']
|
|
33
57
|
|
|
58
|
+
const filteredFrontmatter = computed(() => Object.entries(frontmatter.value).filter(([key, value]) => types.includes(value as string)))
|
|
59
|
+
|
|
34
60
|
const { model, mdcAttrs } = getComponentProps(props, {
|
|
35
61
|
id: {
|
|
36
62
|
type: String,
|
|
@@ -62,3 +88,13 @@ const { model, mdcAttrs } = getComponentProps(props, {
|
|
|
62
88
|
},
|
|
63
89
|
})
|
|
64
90
|
</script>
|
|
91
|
+
|
|
92
|
+
<style scoped>
|
|
93
|
+
.fmkeys :deep(div) {
|
|
94
|
+
@apply first-letter:lowercase! font-mono;
|
|
95
|
+
}
|
|
96
|
+
:deep(p) {
|
|
97
|
+
margin-top: 0;
|
|
98
|
+
margin-bottom: 0;
|
|
99
|
+
}
|
|
100
|
+
</style>
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<section
|
|
3
3
|
:ref="props.contentRef"
|
|
4
|
-
v-bind="model"
|
|
5
4
|
/>
|
|
6
5
|
</template>
|
|
7
6
|
|
|
@@ -9,14 +8,14 @@
|
|
|
9
8
|
import type { VueNodeViewProps } from 'prosekit/vue'
|
|
10
9
|
|
|
11
10
|
const props = defineProps<VueNodeViewProps>()
|
|
12
|
-
const { getComponentProps } = useMdcEditor()
|
|
13
|
-
const { model } = getComponentProps(props, {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
})
|
|
11
|
+
// const { getComponentProps } = useMdcEditor()
|
|
12
|
+
// const { model } = getComponentProps(props, {
|
|
13
|
+
// id: {
|
|
14
|
+
// type: String,
|
|
15
|
+
// },
|
|
16
|
+
// class: {
|
|
17
|
+
// type: String,
|
|
18
|
+
// default: '',
|
|
19
|
+
// },
|
|
20
|
+
// })
|
|
22
21
|
</script>
|
|
@@ -46,14 +46,15 @@
|
|
|
46
46
|
v-if="!config.search.inAside && config.search.style === 'button'"
|
|
47
47
|
/>
|
|
48
48
|
|
|
49
|
+
<LangSwitcher v-if="i18nEnabled" />
|
|
49
50
|
<ThemePopover v-if="config.theme.customizable" />
|
|
50
51
|
<DarkModeToggle v-if="config.header.darkModeToggle" />
|
|
51
52
|
<A11yModeToggle />
|
|
52
53
|
|
|
53
|
-
<
|
|
54
|
+
<NuxtLinkLocale
|
|
54
55
|
v-for="(link, i) in config.header.links"
|
|
55
56
|
:key="i"
|
|
56
|
-
:to="link?.to"
|
|
57
|
+
:to="localePath(link?.to)"
|
|
57
58
|
:target="link?.target"
|
|
58
59
|
>
|
|
59
60
|
<UiButton
|
|
@@ -67,7 +68,7 @@
|
|
|
67
68
|
:size="18"
|
|
68
69
|
/>
|
|
69
70
|
</UiButton>
|
|
70
|
-
</
|
|
71
|
+
</NuxtLinkLocale>
|
|
71
72
|
</div>
|
|
72
73
|
</div>
|
|
73
74
|
</div>
|
|
@@ -86,6 +87,7 @@ import { useWindowScroll } from '@vueuse/core'
|
|
|
86
87
|
import { cn } from '@/lib/utils'
|
|
87
88
|
|
|
88
89
|
const config = useConfig()
|
|
90
|
+
const { i18nEnabled, localePath } = useI18nDocs()
|
|
89
91
|
|
|
90
92
|
const { y } = useWindowScroll()
|
|
91
93
|
|
package/nuxt.config.ts
CHANGED
|
@@ -21,36 +21,36 @@ export default defineNuxtConfig({
|
|
|
21
21
|
$env: {
|
|
22
22
|
development: {
|
|
23
23
|
modules: [
|
|
24
|
-
'@unpress/nuxt-module',
|
|
24
|
+
!process.env.UNPRESS ? '@unpress/nuxt-module' : '../../../unpress/packages/nuxt-module/src/module',
|
|
25
25
|
],
|
|
26
|
+
|
|
27
|
+
alias: !process.env.UNPRESS
|
|
28
|
+
? undefined
|
|
29
|
+
: {
|
|
30
|
+
'@unpress/mdc-editor': r('../../unpress/packages/mdc-editor/src/module'),
|
|
31
|
+
'@unpress/nuxt-module': r('../../unpress/packages/nuxt-module/src/module'),
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
vite: !process.env.UNPRESS
|
|
35
|
+
? undefined
|
|
36
|
+
: {
|
|
37
|
+
server: {
|
|
38
|
+
fs: {
|
|
39
|
+
allow: [
|
|
40
|
+
// Allow serving files from the project root
|
|
41
|
+
currentDir,
|
|
42
|
+
// Allow serving files from the monorepo root (parent directories)
|
|
43
|
+
resolve(currentDir, '../../..'),
|
|
44
|
+
],
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
26
48
|
},
|
|
27
49
|
production: {
|
|
28
50
|
modules: [
|
|
29
51
|
'@unpress/nuxt-module',
|
|
30
52
|
],
|
|
31
53
|
},
|
|
32
|
-
|
|
33
|
-
unpress: {
|
|
34
|
-
modules: [
|
|
35
|
-
'../../../unpress/packages/nuxt-module/src/module',
|
|
36
|
-
],
|
|
37
|
-
alias: {
|
|
38
|
-
'@unpress/mdc-editor': r('../../unpress/packages/mdc-editor/src/module'),
|
|
39
|
-
'@unpress/nuxt-module': r('../../unpress/packages/nuxt-module/src/module'),
|
|
40
|
-
},
|
|
41
|
-
vite: {
|
|
42
|
-
server: {
|
|
43
|
-
fs: {
|
|
44
|
-
allow: [
|
|
45
|
-
// Allow serving files from the project root
|
|
46
|
-
currentDir,
|
|
47
|
-
// Allow serving files from the monorepo root (parent directories)
|
|
48
|
-
resolve(currentDir, '../../..'),
|
|
49
|
-
],
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
},
|
|
54
54
|
},
|
|
55
55
|
|
|
56
56
|
components: {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordup-md/nuxt-layer-shadcn-unocss",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.28",
|
|
5
5
|
"author": "Emmanuel Salomon <emmanuel.salomon@gmail.com>",
|
|
6
6
|
"main": "./nuxt.config.ts",
|
|
7
7
|
"repository": {
|
|
@@ -16,6 +16,20 @@
|
|
|
16
16
|
"wordup-md"
|
|
17
17
|
],
|
|
18
18
|
"license": "MIT",
|
|
19
|
+
"scripts": {
|
|
20
|
+
"dev": "nuxt dev .playground",
|
|
21
|
+
"dev:unpress": "UNPRESS=true nuxt dev .playground",
|
|
22
|
+
"dev:root": "nuxt dev",
|
|
23
|
+
"prepare": "npx nuxt prepare .playground",
|
|
24
|
+
"build": "npx nuxt build .playground",
|
|
25
|
+
"generate": "npx nuxt generate .playground",
|
|
26
|
+
"preview": "npx nuxt preview .playground",
|
|
27
|
+
"lint": "eslint .",
|
|
28
|
+
"build:json-doc": "tsx scripts/buildContentDoc-cli.ts",
|
|
29
|
+
"bump": "pnpm build:json-doc && git add public/content-doc.json && bumpp --skip-install --commit --push --tag",
|
|
30
|
+
"release": "pnpm bump && npm publish",
|
|
31
|
+
"clean": "find . -name 'node_modules' -type d -prune -exec rm -rf '{}' + && find . -name '.nuxt' -type d -prune -exec rm -rf '{}' + && find . -name '.output' -type d -prune -exec rm -rf '{}' + && find . -name 'dist' -prune -exec rm -rf '{}' +"
|
|
32
|
+
},
|
|
19
33
|
"devDependencies": {
|
|
20
34
|
"@nuxt/eslint": "latest",
|
|
21
35
|
"@nuxt/kit": "^3.17.2",
|
|
@@ -46,7 +60,7 @@
|
|
|
46
60
|
"@nuxtjs/i18n": "^9.5.4",
|
|
47
61
|
"@nuxtjs/robots": "^5.6.0",
|
|
48
62
|
"@tanstack/vue-table": "^8.21.3",
|
|
49
|
-
"@unpress/nuxt-module": "0.1.
|
|
63
|
+
"@unpress/nuxt-module": "0.1.14-beta.2",
|
|
50
64
|
"class-variance-authority": "^0.7.1",
|
|
51
65
|
"clsx": "^2.1.1",
|
|
52
66
|
"nuxt": "3.17.2",
|
|
@@ -55,16 +69,9 @@
|
|
|
55
69
|
"tailwind-merge": "^3.2.0"
|
|
56
70
|
},
|
|
57
71
|
"packageManager": "pnpm@10.4.1",
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
"generate": "npx nuxt generate .playground",
|
|
63
|
-
"preview": "npx nuxt preview .playground",
|
|
64
|
-
"lint": "eslint .",
|
|
65
|
-
"build:json-doc": "tsx scripts/buildContentDoc-cli.ts",
|
|
66
|
-
"bump": "pnpm build:json-doc && git add public/content-doc.json && bumpp --skip-install --commit --push --tag",
|
|
67
|
-
"release": "pnpm bump && npm publish",
|
|
68
|
-
"clean": "find . -name 'node_modules' -type d -prune -exec rm -rf '{}' + && find . -name '.nuxt' -type d -prune -exec rm -rf '{}' + && find . -name '.output' -type d -prune -exec rm -rf '{}' + && find . -name 'dist' -prune -exec rm -rf '{}' +"
|
|
72
|
+
"pnpm": {
|
|
73
|
+
"onlyBuiltDependencies": [
|
|
74
|
+
"sharp"
|
|
75
|
+
]
|
|
69
76
|
}
|
|
70
|
-
}
|
|
77
|
+
}
|
package/plugins/wordup.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { TextSelection } from 'prosemirror-state'
|
|
2
|
+
import type { Node } from 'prosemirror-model'
|
|
3
|
+
|
|
1
4
|
export default defineNuxtPlugin((nuxtApp) => {
|
|
2
5
|
nuxtApp.hook('mdc-editor:config', ({ config, editor }: { config: any, editor: any }) => {
|
|
3
6
|
config.components.push({
|
|
@@ -16,9 +19,127 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|
|
16
19
|
transform() {
|
|
17
20
|
return { type: 'containerComponent', attrs: { componentName: 'alert' } }
|
|
18
21
|
},
|
|
19
|
-
onSelect: () =>
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
onSelect: async () => {
|
|
23
|
+
const nodes = await config.convertMarkdownToNode(`::alert{type="info"}
|
|
24
|
+
{|}
|
|
25
|
+
::`)
|
|
26
|
+
// console.log('nodes', nodes, editor, editor.commands, editor.schema.nodeFromJSON(nodes))
|
|
27
|
+
|
|
28
|
+
const { schema, view, state } = editor
|
|
29
|
+
const insertPos = state.selection.anchor - 1
|
|
30
|
+
|
|
31
|
+
// Find and replace {|} cursor placeholder with a paragraph node containing empty text
|
|
32
|
+
const findAndReplaceCursor = (obj: Record<string, unknown>, path: number[] = []): number[] | null => {
|
|
33
|
+
if (typeof obj !== 'object' || obj === null) return null
|
|
34
|
+
|
|
35
|
+
// Check for cursor placeholder in content array
|
|
36
|
+
if (Array.isArray(obj.content)) {
|
|
37
|
+
for (let i = 0; i < obj.content.length; i++) {
|
|
38
|
+
const item = obj.content[i] as Record<string, unknown>
|
|
39
|
+
if (item.type === 'text' && item.text === '{|}') {
|
|
40
|
+
return [...path, i]
|
|
41
|
+
}
|
|
42
|
+
const found = findAndReplaceCursor(item, [...path, i])
|
|
43
|
+
if (found) return found
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Check text property directly
|
|
48
|
+
if (obj.text === '{|}') {
|
|
49
|
+
return path
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return null
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const cursorPath = findAndReplaceCursor(nodes as Record<string, unknown>)
|
|
56
|
+
console.log(cursorPath)
|
|
57
|
+
if (cursorPath) {
|
|
58
|
+
// Replace cursor placeholder with a paragraph node containing empty text
|
|
59
|
+
let current: Record<string, unknown> = nodes as Record<string, unknown>
|
|
60
|
+
for (let i = 0; i < cursorPath.length - 1; i++) {
|
|
61
|
+
const content = current.content as Record<string, unknown>[]
|
|
62
|
+
if (content) {
|
|
63
|
+
current = content[cursorPath[i]] as Record<string, unknown>
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (Array.isArray(current.content)) {
|
|
68
|
+
const cursorIndex = cursorPath[cursorPath.length - 1]
|
|
69
|
+
// Replace {|} with a paragraph node containing a text node with a space
|
|
70
|
+
current.content[cursorIndex] = {
|
|
71
|
+
// type: 'paragraph',
|
|
72
|
+
// content: [
|
|
73
|
+
// {
|
|
74
|
+
type: 'text',
|
|
75
|
+
text: '\u200b',
|
|
76
|
+
// },
|
|
77
|
+
// ],
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const parsedNodes = schema.nodeFromJSON(nodes)
|
|
83
|
+
console.log('parsedNodes', parsedNodes, cursorPath)
|
|
84
|
+
|
|
85
|
+
// Calculate cursor position offset within the parsed nodes structure
|
|
86
|
+
// The path is an array of indices: [0, 1, 2] means content[0].content[1].content[2]
|
|
87
|
+
const calculateCursorOffset = (node: Node, path: number[]): number | null => {
|
|
88
|
+
if (path.length === 0) {
|
|
89
|
+
return 1 // Base case: position 1 is inside the root node
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
let offset = 1 // Start inside the root node (after opening tag)
|
|
93
|
+
let currentNode = node
|
|
94
|
+
|
|
95
|
+
// Traverse the path, summing up node sizes as we go
|
|
96
|
+
for (let i = 0; i < path.length; i++) {
|
|
97
|
+
const pathIndex = path[i]
|
|
98
|
+
const isLastStep = i === path.length - 1
|
|
99
|
+
|
|
100
|
+
if (!currentNode.content || currentNode.content.childCount <= pathIndex) {
|
|
101
|
+
return null // Invalid path
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Sum sizes of all nodes before the target index
|
|
105
|
+
for (let j = 0; j < pathIndex; j++) {
|
|
106
|
+
offset += currentNode.content.child(j).nodeSize
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (isLastStep) {
|
|
110
|
+
// For the last step, we want the position at the start of the text node
|
|
111
|
+
// The position is after the opening tag of the parent, plus the sum of previous siblings
|
|
112
|
+
return offset + 1
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Move into the target child node (+1 to get inside it)
|
|
116
|
+
offset += 1
|
|
117
|
+
currentNode = currentNode.content.child(pathIndex)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return offset
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
let cursorOffset: number | null = null
|
|
124
|
+
if (cursorPath) {
|
|
125
|
+
// Calculate the offset from the root of parsedNodes
|
|
126
|
+
cursorOffset = calculateCursorOffset(parsedNodes, cursorPath)
|
|
127
|
+
// console.log('cursorOffset', cursorOffset, 'cursorPath', cursorPath)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const tr = state.tr
|
|
131
|
+
tr.insert(insertPos, parsedNodes)
|
|
132
|
+
|
|
133
|
+
// Set cursor position if we calculated the offset
|
|
134
|
+
if (cursorOffset !== null) {
|
|
135
|
+
const cursorPos = insertPos + cursorOffset
|
|
136
|
+
// console.log('Setting cursor at', cursorPos, 'insertPos', insertPos, 'offset', cursorOffset)
|
|
137
|
+
tr.setSelection(TextSelection.create(tr.doc, cursorPos))
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
view.focus()
|
|
141
|
+
return view.dispatch(tr)
|
|
142
|
+
},
|
|
22
143
|
})
|
|
23
144
|
|
|
24
145
|
config.components.push({
|
|
@@ -89,7 +210,7 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|
|
89
210
|
// get next html element with js
|
|
90
211
|
setTimeout(() => {
|
|
91
212
|
prevNode.node.nextElementSibling?.querySelector('input.INLINE_MENU_LINK_INPUT')?.focus()
|
|
92
|
-
},
|
|
213
|
+
}, 300)
|
|
93
214
|
// const node = editor.state.doc.nodeAt(nodePos)
|
|
94
215
|
// if (node && node.type.name === 'read-more') {
|
|
95
216
|
// const input = node.firstChild?.firstChild?.firstChild as HTMLInputElement
|
|
@@ -133,9 +254,24 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|
|
133
254
|
transform() {
|
|
134
255
|
return { type: 'containerComponent', attrs: { componentName: 'steps' } }
|
|
135
256
|
},
|
|
136
|
-
onSelect: () => editor.commands.insertContainerComponent({
|
|
137
|
-
|
|
138
|
-
}),
|
|
257
|
+
// onSelect: () => editor.commands.insertContainerComponent({
|
|
258
|
+
// name: 'steps',
|
|
259
|
+
// }),
|
|
260
|
+
onSelect: async () => {
|
|
261
|
+
const nodes = await config.convertMarkdownToNode(`::steps
|
|
262
|
+
###
|
|
263
|
+
::`)
|
|
264
|
+
|
|
265
|
+
const { schema, view, state } = editor
|
|
266
|
+
const parsedNodes = schema.nodeFromJSON(nodes)
|
|
267
|
+
// console.log('parsedNodes', parsedNodes)
|
|
268
|
+
|
|
269
|
+
const tr = state.tr
|
|
270
|
+
const insertPos = state.selection.anchor - 2
|
|
271
|
+
tr.insert(insertPos, parsedNodes)
|
|
272
|
+
|
|
273
|
+
return view.dispatch(tr)
|
|
274
|
+
},
|
|
139
275
|
})
|
|
140
276
|
|
|
141
277
|
config.components.push({
|
package/public/content-doc.json
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"title": "Pages",
|
|
27
27
|
"_id": "content:1.getting-started:2.writing:2.pages.md",
|
|
28
28
|
"_path": "getting-started/writing/pages",
|
|
29
|
-
"content": "\n\n## `^-` Frontmatter\n\nFront-matter is a convention of Markdown-based CMS to provide metadata to documents, like description or title. Remark MDC uses the YAML syntax with `key: value` pairs.\n\nTo define frontmatter, start your document with `---\\n---` section and put your desired data in YAML format within this section.\n\n```md\n---\ntitle: Title of the page\ndescription: meta description of the page\n---\n\n<!-- Content of the page -->\n```\n\nYou can reuse the same frontmatter attributes in the content or in the components props.\\\nAdd `:` before the key to bind the frontmatter value to the component.\\\nOr use the `{{ $doc.key }}` syntax to bind the value of the frontmatter.\n\n::stack\n
|
|
29
|
+
"content": "\n\n## `^-` Frontmatter\n\nFront-matter is a convention of Markdown-based CMS to provide metadata to documents, like description or title. Remark MDC uses the YAML syntax with `key: value` pairs.\n\nTo define frontmatter, start your document with `---\\n---` section and put your desired data in YAML format within this section.\n\n```md\n---\ntitle: Title of the page\ndescription: meta description of the page\n---\n\n<!-- Content of the page -->\n```\n\nYou can reuse the same frontmatter attributes in the content or in the components props.\\\nAdd `:` before the key to bind the frontmatter value to the component.\\\nOr use the `{{ $doc.key }}` syntax to bind the value of the frontmatter.\n\n::stack\n :::div{.p-4}\n This is the title from the frontmatter: **Title of the page**.\n \n ::::alert\n ---\n :type: key\n ---\n With the property `:type: key`, it displays a **{{ $doc.key }} alert**.\n ::::\n \n Or inline:\n \n :alert[Title of the page]{:icon=\"icon\" :type=\"key\"}\n :::\n\n```mdc\n---\ntitle: Title of the page\nicon: lucide:file\nkey: example\n---\n\nThis is the title from the frontmatter: **{{ $doc.title }}**.\n\n::alert\n---\n:type: key\n---\nWith the property `:type: key`, it displays a **{{ $doc.key }} alert**.\n::\n\nOr inline:\n\n:alert[{{ $doc.title }}]{:type=\"key\" :icon=\"icon\"}\n```\n::\n\n## Available Frontmatter Attributes\n\n```md\n---\ntitle: Front Matter\ndescription: Front matter attributes used in shadcn-docs-nuxt.\nicon: lucide:book-type\n\nnavTruncate: false\nnavBadges:\n - value: New\n type: lime\n\nbadges:\n - value: Docus\n to: https://docus.dev/api/components#alert\n target: _blank\n - value: Source\n icon: lucide:code\n to: https://github.com/wordup-md/nuxt-layer-shadcn-unocss/blob/main/components/content/Alert.vue\n target: _blank\n\nauthors:\n - name: Tony Zhang\n username: ZTL-UwU\n avatar: https://www.github.com/ZTL-UwU.png\n to: https://github.com/ZTL-UwU\n target: _blank\n---\n\n<!-- Content of the page -->\n```\n\n## Showcases\n\n::tabs{variant=\"line\"}\n :::stack{label=\"badges\"}\n {.w-full}\n \n ```yml\n badges:\n - value: 0.8.10\n - value: Source\n icon: lucide:code\n to: https://github.com/wordup-md/nuxt-layer-shadcn-unocss/blob/main/components/content/FileTree.vue\n target: _blank\n ```\n :::\n\n :::stack{label=\"authors\"}\n {.w-full}\n \n ```yml\n authors:\n - name: Tony Zhang\n username: ZTL-UwU\n avatar: https://www.github.com/ZTL-UwU.png\n to: https://github.com/ZTL-UwU\n target: _blank\n ```\n :::\n\n :::stack{label=\"navBadges\"}\n {.w-full}\n \n ```yml\n navBadges:\n - value: New\n type: lime\n ```\n :::\n::\n\n## Parameters\n\n::field-group\n :::field{name=\"title\" type=\"string\"}\n Title of the page. Defaults to the filename.\n :::\n\n :::field{name=\"description\" type=\"string\"}\n Description of the page. Defaults to the first `<p>` of the page.\n :::\n\n :::field{default-value=\"true\" name=\"navigation\" type=\"boolean\"}\n Define if the page is included in the sidebar. Set it to `false` in `index.md`.\n :::\n\n :::field{name=\"icon\" type=\"string\"}\n The icon shown in the sidebar for the page.\n :::\n\n :::field{name=\"navBadges\" type=\"[]\"}\n A list of badges appended to the end of the sidebar link.\n :::\n\n :::field{default-value=\"true\" name=\"navTruncate\" type=\"boolean\"}\n Whether to truncate the sidebar title.\n :::\n\n :::field{name=\"badges\" type=\"[]\"}\n A list of badges shown at the bottom of page title.\n :::\n\n :::field{name=\"authors\" type=\"[]\"}\n A list of authors shown at the bottom of page title.\n :::\n\n :::field{default-value=\"true\" name=\"toc\" type=\"boolean\"}\n Whether to show the toc section for this page.\n :::\n\n :::field{default-value=\"true\" name=\"aside\" type=\"boolean\"}\n Whether to show the aside section for this page.\n :::\n\n :::field{default-value=\"true\" name=\"editLink\" type=\"boolean\"}\n Whether to show the edit link for this page.\n :::\n\n :::field{default-value=\"true\" name=\"prevNext\" type=\"boolean\"}\n Whether to show the previous & next page buttons.\n :::\n\n :::field{default-value=\"true\" name=\"breadcrumb\" type=\"boolean\"}\n Whether to show the breadcrumb.\n :::\n::\n",
|
|
30
30
|
"description": "Front matter attributes.",
|
|
31
31
|
"icon": "lucide:file",
|
|
32
32
|
"key": "example"
|