@wordup-md/nuxt-layer-shadcn-unocss 0.2.2 → 0.2.3

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.
@@ -5,4 +5,10 @@ icon: lucide:info
5
5
  toc: false
6
6
  ---
7
7
 
8
- :card-group{data="/getting-started/writing"}
8
+ ::list
9
+ ---
10
+ class: group grid gap-4 md:grid-cols-2 [&:not(:first-child)]:mt-4
11
+ component: card
12
+ path: /getting-started/writing
13
+ ---
14
+ ::
@@ -22,4 +22,20 @@ icon: lucide:table
22
22
  | 2 | Wonderful | Data |
23
23
  | 3 | Wonderful | Website |
24
24
  ```
25
- ::
25
+ ::
26
+
27
+ ## Alignment
28
+
29
+ ::stack
30
+ :::div{.p-4}
31
+ | Default (left) | Left | Center | Right |
32
+ | -------------- | :---------------- | :-----------------: | -----------------: |
33
+ | default text | left aligned text | center aligned text | right aligned text |
34
+ :::
35
+
36
+ ```md
37
+ | Default (left) | Left | Center | Right |
38
+ | -------------- | :---------------- | :-----------------: | -----------------: |
39
+ | default text | left aligned text | center aligned text | right aligned text |
40
+ ```
41
+ ::
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: Accordion
3
- icon: lucide:layout-list
3
+ icon: i-mingcute:list-expansion-line
4
4
  badges:
5
5
  - value: Source
6
6
  icon: lucide:code
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: Hero
3
- icon: lucide:align-center
3
+ icon: i-lucide:layout-panel-top
4
4
  badges:
5
5
  - value: Source
6
6
  icon: lucide:code
@@ -0,0 +1,42 @@
1
+ ---
2
+ title: Dynamic List
3
+ icon: i-lucide:layout-list
4
+ badges:
5
+ - value: Source
6
+ icon: lucide:code
7
+ to: https://github.com/wordup-md/nuxt-layer-shadcn-unocss/blob/main/components/content/List.vue
8
+ target: _blank
9
+ ---
10
+
11
+ ## Usage
12
+
13
+ ::stack
14
+ ::div{class="p-4"}
15
+ ::list
16
+ ---
17
+ path: /components/
18
+ query:
19
+ limit: 3
20
+ component: card
21
+ ---
22
+ ::
23
+ ::
24
+ ```mdc
25
+ ::list
26
+ ---
27
+ path: /components/
28
+ query:
29
+ limit: 3
30
+ component: card
31
+ ---
32
+ ::
33
+ ```
34
+ ::
35
+
36
+ ## Props
37
+
38
+ ::field-group
39
+ :field{name="path" type="string"}[Path to the list]
40
+ :field{name="query" type="object"}[Query parameters]
41
+ :field{name="component" type="string"}[Component to use for each item]
42
+ ::
@@ -1,14 +1,14 @@
1
1
  <template>
2
- <section :class="cn('flex flex-col gap-8 mt-8', String($attrs.class || ''))">
2
+ <section :class="cn('flex flex-col gap-4 mt-4', String($attrs.class || ''))">
3
3
  <ContentList
4
- v-if="path.length || Object.keys(query).length"
4
+ v-if="path.length || Object.keys(normalizedQuery).length"
5
5
  :path
6
- :query
6
+ :query="normalizedQuery"
7
7
  >
8
8
  <template #default="{ list }">
9
9
  <component
10
10
  :is="component || 'Card'"
11
- v-for="data in sortedList(filterList(list))"
11
+ v-for="data in sortedList(list)"
12
12
  :key="data._path"
13
13
  v-bind="itemProps ? { ...data, to: data._path, ...itemProps } : { ...data, to: data._path }"
14
14
  :class="cn('mt-0!', String(itemClass))"
@@ -42,9 +42,28 @@ const {
42
42
  itemClass?: string
43
43
  }>()
44
44
 
45
- const filterList = (list: ParsedContent[]) => {
46
- return list.filter(item => !item?._file?.includes('index.md'))
47
- }
45
+ // const { data } = await useAsyncData('homeiiii', () =>
46
+ // queryContent(path)
47
+ // // regex should exclude .../index.md file
48
+ // .where({ _type: { $not: 'yaml' }, _id: { $not: { $regex: /index\.md$/ } } })
49
+ // .find(),
50
+ // )
51
+ // console.log(data.value)
52
+
53
+ const normalizedQuery = computed(() => {
54
+ const _query = { ...query }
55
+ // Extends query.where
56
+ _query.where = {
57
+ ..._query.where,
58
+ _type: { $not: 'yaml' },
59
+ _id: { $not: { $regex: /index\.md$/ } },
60
+ }
61
+
62
+ return {
63
+ ..._query,
64
+ limit: _query.limit ? Number(_query.limit) : undefined,
65
+ }
66
+ })
48
67
 
49
68
  const sortedList = (list: ParsedContent[]) => {
50
69
  if (query?.sort && 'date' in query.sort) {
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div class="[&:not(:first-child)]:mt-5">
2
+ <div class="[&:not(:first-child)]:mt-4">
3
3
  <UiEditorHorizontalControls class="mb--1">
4
4
  <UiEditorInput
5
5
  v-model="mdcAttrs.data"
@@ -15,6 +15,7 @@ const { model, mdcAttrs } = getComponentProps(props, {
15
15
  type: String,
16
16
  },
17
17
  query: {
18
+ default: () => ({}),
18
19
  type: Object,
19
20
  },
20
21
  component: {
@@ -31,6 +32,15 @@ const { model, mdcAttrs } = getComponentProps(props, {
31
32
  flex-1
32
33
  placeholder="Path to folder"
33
34
  label="Chemin"
35
+ input-classes="INPUT_GHOST"
36
+ />
37
+
38
+ <UiEditorInput
39
+ v-model="mdcAttrs.query.limit"
40
+ flex-1
41
+ placeholder="Sans limite"
42
+ label="Limit"
43
+ input-classes="INPUT_GHOST"
34
44
  />
35
45
  </UiEditorHorizontalControls>
36
46
 
@@ -40,6 +50,7 @@ const { model, mdcAttrs } = getComponentProps(props, {
40
50
  :query="model.query"
41
51
  :component="model.component"
42
52
  contenteditable="false"
53
+ :class="model.class"
43
54
  />
44
55
  </div>
45
56
  </template>
@@ -0,0 +1,12 @@
1
+ export default defineNuxtRouteMiddleware((to, from) => {
2
+ const { client } = useUnpress()
3
+
4
+ if (to.path.startsWith('/admin') && to.path !== '/admin/login') {
5
+ if (!client.value) {
6
+ return navigateTo({
7
+ path: '/admin/login',
8
+ query: { redirectFrom: from.fullPath },
9
+ })
10
+ }
11
+ }
12
+ })
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.2",
4
+ "version": "0.2.3",
5
5
  "author": "Emmanuel Salomon <emmanuel.salomon@gmail.com>",
6
6
  "main": "./nuxt.config.ts",
7
7
  "repository": {
@@ -1,32 +1,27 @@
1
1
  <script setup lang="ts">
2
2
  import type { NavItem } from '@nuxt/content'
3
- import { useUnpress } from '#imports'
4
3
 
5
- const { client, mountCms, login } = useUnpress()
6
4
  const config = useConfig()
7
5
 
8
- const isDev = import.meta.dev
9
- const isLoggedIn = computed(() => !!client.value)
10
-
11
- const path = 'content-doc.json'
12
-
6
+ const contentDocFile = 'content-doc.json'
7
+ const adminPath = '/admin'
13
8
  // const { data: tree, status, error, refresh, clear } = await useAsyncData<NavItem[]>(
14
9
  const { data: tree } = await useAsyncData<NavItem[]>(
15
10
  'admin-docs',
16
- () => $fetch(`/${path}`), {
11
+ () => $fetch(`/${contentDocFile}`), {
17
12
  transform: (data) => {
18
13
  return data.map((item: NavItem) => ({
19
14
  ...item,
20
- '_path': `/admin/${item._path}`,
21
- 'navigation.redirect': item['navigation.redirect'] ? '/admin' + item['navigation.redirect'] : undefined,
15
+ '_path': `${adminPath}/${item._path}`,
16
+ 'navigation.redirect': item['navigation.redirect'] ? adminPath + item['navigation.redirect'] : undefined,
22
17
  'children': item.children?.map((child: NavItem) => ({
23
18
  ...child,
24
- '_path': `/admin/${child._path}`,
25
- 'navigation.redirect': child['navigation.redirect'] ? '/admin' + child['navigation.redirect'] : undefined,
19
+ '_path': `${adminPath}/${child._path}`,
20
+ 'navigation.redirect': child['navigation.redirect'] ? adminPath + child['navigation.redirect'] : undefined,
26
21
  'children': child.children?.map((child2: NavItem) => ({
27
22
  ...child2,
28
- '_path': `/admin/${child2._path}`,
29
- 'navigation.redirect': child2['navigation.redirect'] ? '/admin' + child2['navigation.redirect'] : undefined,
23
+ '_path': `${adminPath}/${child2._path}`,
24
+ 'navigation.redirect': child2['navigation.redirect'] ? adminPath + child2['navigation.redirect'] : undefined,
30
25
  })),
31
26
  })),
32
27
  }))
@@ -36,7 +31,7 @@ const { data: tree } = await useAsyncData<NavItem[]>(
36
31
 
37
32
  const { slug } = useRoute().params
38
33
 
39
- if (isLoggedIn.value && slug?.length === 0 && tree.value) {
34
+ if (slug?.length === 0 && tree.value) {
40
35
  if (tree.value[0]['navigation.redirect']) {
41
36
  await navigateTo(tree.value[0]['navigation.redirect'])
42
37
  }
@@ -47,19 +42,19 @@ if (isLoggedIn.value && slug?.length === 0 && tree.value) {
47
42
 
48
43
  const page = computed(() => {
49
44
  if (slug.length > 2) {
50
- const level0 = tree.value?.find(item => item._path === `/admin/${slug[0]}`)
51
- const level1 = level0?.children?.find(item => item._path === `/admin/${slug[0]}/${slug[1]}`)
52
- return level1?.children?.find(item => item._path === `/admin/${slug[0]}/${slug[1]}/${slug[2]}`)
45
+ const level0 = tree.value?.find(item => item._path === `${adminPath}/${slug[0]}`)
46
+ const level1 = level0?.children?.find(item => item._path === `${adminPath}/${slug[0]}/${slug[1]}`)
47
+ return level1?.children?.find(item => item._path === `${adminPath}/${slug[0]}/${slug[1]}/${slug[2]}`)
53
48
  }
54
49
  else if (slug.length > 1) {
55
- const level0 = tree.value?.find(item => item._path === `/admin/${slug[0]}`)
56
- return level0?.children?.find(item => item._path === `/admin/${slug[0]}/${slug[1]}`)
50
+ const level0 = tree.value?.find(item => item._path === `${adminPath}/${slug[0]}`)
51
+ return level0?.children?.find(item => item._path === `${adminPath}/${slug[0]}/${slug[1]}`)
57
52
  }
58
53
  else {
59
- const page = tree.value?.find(item => item._path === `/admin/${slug[0]}`)
54
+ const page = tree.value?.find(item => item._path === `${adminPath}/${slug[0]}`)
60
55
 
61
56
  if (!page?.['navigation.redirect'] && !page?.content && page?.children?.length) {
62
- return page.children.find(item => item._path === `/admin/${slug[0]}/index`)
57
+ return page.children.find(item => item._path === `${adminPath}/${slug[0]}/index`)
63
58
  }
64
59
 
65
60
  return page
@@ -77,7 +72,6 @@ watch(page, async (newVal) => {
77
72
  <NuxtLayout>
78
73
  <div class="h-full">
79
74
  <div
80
- v-if="isLoggedIn"
81
75
  class="flex-1 items-start px-4 md:grid md:gap-6 md:px-8 lg:gap-10"
82
76
  :class="[
83
77
  config.main.padded && 'container',
@@ -125,21 +119,6 @@ watch(page, async (newVal) => {
125
119
  </div>
126
120
  </main>
127
121
  </div>
128
-
129
- <div
130
- v-else
131
- class="col-span-3 mt-[20vh] flex items-center justify-center"
132
- >
133
- <div class="flex items-center justify-center gap-4">
134
- <h3 class="scroll-m-20 py-3 text-2xl font-semibold">
135
- Open administration
136
- </h3>
137
- <Icon name="lucide:arrow-right" />
138
- <UiButton @click="isDev ? mountCms() : login()">
139
- Connect & Open
140
- </Uibutton>
141
- </div>
142
- </div>
143
122
  </div>
144
123
  </NuxtLayout>
145
124
  </template>
@@ -0,0 +1,51 @@
1
+ <script lang="ts" setup>
2
+ import { useUnpress } from '#imports'
3
+
4
+ const { client, mountCms, login } = useUnpress()
5
+ const isDev = import.meta.dev
6
+
7
+ function onLogin() {
8
+ if (isDev) {
9
+ mountCms()
10
+ }
11
+ else {
12
+ login()
13
+ }
14
+ }
15
+
16
+ function navigateToAdmin() {
17
+ if (client.value) {
18
+ const route = useRoute()
19
+ const originUrl = route.query.redirectFrom
20
+
21
+ if (originUrl) {
22
+ return navigateTo(originUrl as string)
23
+ }
24
+ else {
25
+ return navigateTo('/admin/')
26
+ }
27
+ }
28
+ }
29
+
30
+ watch(client, navigateToAdmin, { immediate: true })
31
+ </script>
32
+
33
+ <template>
34
+ <NuxtLayout>
35
+ <div class="h-full">
36
+ <div
37
+ class="col-span-3 mt-[20vh] flex items-center justify-center"
38
+ >
39
+ <div class="flex items-center justify-center gap-4">
40
+ <h3 class="scroll-m-20 py-3 text-2xl font-semibold">
41
+ Open administration
42
+ </h3>
43
+ <Icon name="lucide:arrow-right" />
44
+ <UiButton @click="onLogin">
45
+ Connect & Open
46
+ </Uibutton>
47
+ </div>
48
+ </div>
49
+ </div>
50
+ </NuxtLayout>
51
+ </template>
@@ -6,7 +6,7 @@
6
6
  "title": "Introduction",
7
7
  "_id": "content:1.getting-started:1.introduction.md",
8
8
  "_path": "getting-started/introduction",
9
- "content": "\n\n:card-group{data=\"/getting-started/writing\"}\n",
9
+ "content": "\n\n::list\n---\nclass: group grid gap-4 md:grid-cols-2 [&:not(:first-child)]:mt-4\ncomponent: card\npath: /getting-started/writing\n---\n::\n",
10
10
  "description": "Documentation about how to write and configure the website.",
11
11
  "icon": "lucide:info",
12
12
  "toc": false
@@ -72,7 +72,7 @@
72
72
  "title": "Tables",
73
73
  "_id": "content:2.content-elements:11.tables.md",
74
74
  "_path": "content-elements/tables",
75
- "content": "\n\n## Usage\n\n::stack\n :::div{.p-4}\n | Key | Type | Description |\n | --- | --------- | ------------------------------------------- |\n | 1 | Wonderful | Table with `some long code snippet example` |\n | 2 | Wonderful | Data |\n | 3 | Wonderful | Website |\n :::\n\n```md\n| Key | Type | Description |\n| --- | --------- | ------------------------------------------- |\n| 1 | Wonderful | Table with `some long code snippet example` |\n| 2 | Wonderful | Data |\n| 3 | Wonderful | Website |\n```\n:: \n",
75
+ "content": "\n\n## Usage\n\n::stack\n :::div{.p-4}\n | Key | Type | Description |\n | --- | --------- | ------------------------------------------- |\n | 1 | Wonderful | Table with `some long code snippet example` |\n | 2 | Wonderful | Data |\n | 3 | Wonderful | Website |\n :::\n\n```md\n| Key | Type | Description |\n| --- | --------- | ------------------------------------------- |\n| 1 | Wonderful | Table with `some long code snippet example` |\n| 2 | Wonderful | Data |\n| 3 | Wonderful | Website |\n```\n::\n\n## Alignment\n\n::stack\n :::div{.p-4}\n | Default (left) | Left | Center | Right |\n | -------------- | :---------------- | :-----------------: | -----------------: |\n | default text | left aligned text | center aligned text | right aligned text |\n :::\n\n```md\n| Default (left) | Left | Center | Right |\n| -------------- | :---------------- | :-----------------: | -----------------: |\n| default text | left aligned text | center aligned text | right aligned text |\n```\n::\n",
76
76
  "description": "HTML table elements with headers and data cells.",
77
77
  "icon": "lucide:table"
78
78
  },
@@ -88,7 +88,7 @@
88
88
  "title": "Text Components",
89
89
  "_id": "content:2.content-elements:13.text-components.md",
90
90
  "_path": "content-elements/text-components",
91
- "content": "\n\nAll this content components can be written in text component format.\\\nIt's provide possibility to pass custom properties or customize the content with Tailwind CSS classes.\n\n::alert{type=\"warning\" icon=\"i-lucide:triangle-alert\" title=\"Don't overuse it\"}\nUse it when necessary, it's not ideal to add style markup in markdown. Adding a lot of styles in your markdown will be hard to maintain the content.\n\n**Repeating the same style or adding a lot of styles is a sign that you should use a markdown component instead.**\n::\n\n\n## Usage\n\n::stack\n :::div{.p-4}\n :h3[Heading 3]\n :p[Paragraph]{.text-center.text-primary}\n :br\n A colored :a[Link]{.bg-yellow-200.text-primary}\n :hr\n ![](https://picsum.photos/id/152/200/133){width=100}\n :::\n\n```md\n:h3[Heading 3]\n:p[Paragraph]{.text-center.text-primary}\n:br\nA colored :a[Link]{.bg-yellow-200.text-primary}\n:hr\n![](https://picsum.photos/id/152/200/133){width=100}\n```\n::\n",
91
+ "content": "\n\nAll this content components can be written in text component format.\\\nIt's provide possibility to pass custom properties or customize the content with Tailwind CSS classes.\n\n::alert{type=\"warning\" icon=\"i-lucide:triangle-alert\" title=\"Don't overuse it\"}\nUse it when necessary, it's not ideal to add style markup in markdown. Adding a lot of styles in your markdown will be hard to maintain the content.\\\n**Repeating the same style or adding a lot of styles is a sign that you should use a markdown component instead.**\n::\n\n\n## Usage\n\n::stack\n :::div{.p-4}\n :h3[Heading 3]\n :p[Paragraph]{.text-center.text-primary}\n :br\n A colored :a[Link]{.bg-yellow-200.text-primary}\n :hr\n ![](https://picsum.photos/id/152/200/133){width=100}\n :::\n\n```md\n:h3[Heading 3]\n:p[Paragraph]{.text-center.text-primary}\n:br\nA colored :a[Link]{.bg-yellow-200.text-primary}\n:hr\n![](https://picsum.photos/id/152/200/133){width=100}\n```\n::\n",
92
92
  "description": "Text components are used to display text in a variety of ways.",
93
93
  "icon": "i-lucide:brackets"
94
94
  },
@@ -163,7 +163,8 @@
163
163
  "content": "\n\n:card-group{data=\"/content-elements/\"}\n",
164
164
  "description": "The basic markdown elements for writing content.",
165
165
  "icon": "lucide:letter-text",
166
- "navigation": false
166
+ "navigation": false,
167
+ "toc": false
167
168
  }
168
169
  ],
169
170
  "description": "A set of basic markdown elements for writing content.",
@@ -314,7 +315,7 @@
314
315
  "title": "Field",
315
316
  "_id": "content:3.components:2.docs:field.md",
316
317
  "_path": "components/docs/field",
317
- "content": "\n\n## Usage\n\n::stack\n ::div{class=\"p-4\"}\n ::field{name=\"Field\" type=\"string\" defaultValue=\"'default'\" required}\n The _description_ can be set as prop or in the default slot with full **markdown** support.\n ::\n ::\n ```mdc\n ::field{name=\"Field\" type=\"string\" defaultValue=\"'default'\" required}\n The _description_ can be set as prop or in the default slot with full **markdown** support.\n ::\n ```\n::\n\nThe text `required` is configurable in [`main.fieldRequiredText`](/development/configuration/shadcn-docs#main).\n\n## Props\n\n::field-group\n :field{name=\"name\" type=\"string\"}[Field name]\n :field{name=\"type\" type=\"string\"}[Field type]\n :field{name=\"description\" type=\"string\"}[Field description]\n :field{name=\"defaultValue\" type=\"string\"}[Field default value]\n :field{name=\"required\" type=\"boolean\"}[Whether the field is required]\n::\n",
318
+ "content": "\n\n## Usage\n\n::stack\n ::div{class=\"p-4\"}\n ::field{name=\"Field\" type=\"string\" defaultValue=\"'default'\" required}\n The _description_ can be set as prop or in the default slot with full **markdown** support.\n ::\n ::\n ```mdc\n ::field{name=\"Field\" type=\"string\" defaultValue=\"'default'\" required}\n The _description_ can be set as prop or in the default slot with full **markdown** support.\n ::\n ```\n::\n\nThe text `required` is configurable in [`main.fieldRequiredText`](/development/configuration/overview#main).\n\n## Props\n\n::field-group\n :field{name=\"name\" type=\"string\"}[Field name]\n :field{name=\"type\" type=\"string\"}[Field type]\n :field{name=\"description\" type=\"string\"}[Field description]\n :field{name=\"defaultValue\" type=\"string\"}[Field default value]\n :field{name=\"required\" type=\"boolean\"}[Whether the field is required]\n::\n",
318
319
  "icon": "lucide:settings-2",
319
320
  "badges": [
320
321
  {
@@ -352,7 +353,7 @@
352
353
  "title": "Icon",
353
354
  "_id": "content:3.components:2.docs:icon.md",
354
355
  "_path": "components/docs/icon",
355
- "content": "\n\n## Usage\n\n::stack\n ::div{class=\"p-4 space-x-2\"}\n :icon{name=\"lucide:box\"}\n :icon{name=\"vscode-icons:file-type-js-official\"}\n :icon{name=\"vscode-icons:file-type-vue\"}\n :icon{name=\"vscode-icons:file-type-nuxt\" size=\"30\"}\n ::\n\n ```mdc\n :icon{name=\"lucide:box\"}\n :icon{name=\"vscode-icons:file-type-js-official\"}\n :icon{name=\"vscode-icons:file-type-vue\"}\n :icon{name=\"vscode-icons:file-type-nuxt\" size=\"30\"}\n ```\n::\n\nIf you want to use other icons, it is highly recommended to install them locally, which is faster and more reliable on both SSR and client-side.\n\n```bash [Terminal]\nnpm i -D @iconify-json/collection-name\n```\n\n`@iconify-json/lucide` and `@iconify-json/vscode-icons` are installed by default.\n\n### Smart Icon\n\n:badge[0.5.3]{variant=\"outline\"}\n\nYou can put iconify icons, emojis and urls in `icon`. Smart icon will render them automatically.\n\n::stack\n ::div{class=\"p-4\"}\n **Iconify**\n <div class=\"space-x-2\">\n\n :icon{name=\"lucide:box\"}\n :icon{name=\"vscode-icons:file-type-js-official\"}\n :icon{name=\"vscode-icons:file-type-vue\" size=30}\n\n </div>\n\n **Emojis**\n <div class=\"space-x-2\">\n\n :icon{name=\"😍\"}\n :icon{name=\"🚀\"}\n :icon{name=\"🎉\" size=30}\n\n </div>\n\n **URL**\n <div class=\"space-x-2\">\n\n :icon{name=\"/logo.svg\"}\n :icon{name=\"https://vueuse.org/favicon.svg\" size=40}\n\n </div>\n ::\n\n ```mdc\n **Iconify**\n :icon{name=\"lucide:box\"}\n :icon{name=\"vscode-icons:file-type-js-official\"}\n :icon{name=\"vscode-icons:file-type-vue\"}\n\n **Emojis**\n :icon{name=\"😍\"}\n :icon{name=\"🚀\"}\n :icon{name=\"🎉\" size=30}\n\n **URL**\n :icon{name=\"/logo.svg\"}\n :icon{name=\"https://vueuse.org/favicon.svg\" size=40}\n ```\n::\n\n::alert{to=\"https://github.com/nuxt-modules/icon\" target=\"_blank\"}\nThe icon component uses **Nuxt Icon** under the hood. Check out the usage guide from Nuxt Icon.\n::",
356
+ "content": "\n\n## Usage\n\n::stack\n ::div{class=\"p-4 space-x-2\"}\n :icon{name=\"lucide:box\"}\n :icon{name=\"vscode-icons:file-type-js-official\"}\n :icon{name=\"vscode-icons:file-type-vue\"}\n :icon{name=\"vscode-icons:file-type-nuxt\" size=\"30\"}\n ::\n\n ```mdc\n :icon{name=\"lucide:box\"}\n :icon{name=\"vscode-icons:file-type-js-official\"}\n :icon{name=\"vscode-icons:file-type-vue\"}\n :icon{name=\"vscode-icons:file-type-nuxt\" size=\"30\"}\n ```\n::\n\nIf you want to use other icons, it is highly recommended to install them locally, which is faster and more reliable on both SSR and client-side.\n\n```bash [Terminal]\nnpm i -D @iconify-json/collection-name\n```\n\n`@iconify-json/lucide` and `@iconify-json/vscode-icons` are installed by default.\n\n### Smart Icon\n\n:badge[0.5.3]{variant=\"outline\"}\n\nYou can put iconify icons, emojis and urls in `icon`. Smart icon will render them automatically.\n\n::stack\n ::div{class=\"p-4\"}\n **Iconify**\n <div class=\"space-x-2\">\n\n :icon{name=\"lucide:box\"}\n :icon{name=\"vscode-icons:file-type-js-official\"}\n :icon{name=\"vscode-icons:file-type-vue\" size=30}\n\n </div>\n\n **Emojis**\n <div class=\"space-x-2\">\n\n :icon{name=\"😍\"}\n :icon{name=\"🚀\"}\n :icon{name=\"🎉\" size=30}\n\n </div>\n\n **URL**\n <div class=\"space-x-2\">\n\n :icon{name=\"/logo.svg\"}\n :icon{name=\"https://vueuse.org/favicon.svg\" size=40}\n\n </div>\n ::\n\n ```mdc\n **Iconify**\n :icon{name=\"lucide:box\"}\n :icon{name=\"vscode-icons:file-type-js-official\"}\n :icon{name=\"vscode-icons:file-type-vue\"}\n\n **Emojis**\n :icon{name=\"😍\"}\n :icon{name=\"🚀\"}\n :icon{name=\"🎉\" size=30}\n\n **URL**\n :icon{name=\"/logo.svg\"}\n :icon{name=\"https://vueuse.org/favicon.svg\" size=40}\n ```\n::\n\n::alert{to=\"https://github.com/nuxt-modules/icon\" target=\"_blank\"}\nThe icon component uses **Nuxt Icon** under the hood. Check out the usage guide from Nuxt Icon.\n::\n",
356
357
  "icon": "/iconesjs.svg",
357
358
  "badges": [
358
359
  {
@@ -372,7 +373,7 @@
372
373
  "title": "Package Manager",
373
374
  "_id": "content:3.components:2.docs:pm.md",
374
375
  "_path": "components/docs/pm",
375
- "content": "\n\n## Usage\n\nThe package managers shown can be configured in [`main.pm`](/development/configuration/shadcn-docs#main).\n\n### Install\n\n::stack\n ::div{class=\"p-4\"}\n :pm-install{name=\"shadcn-docs-nuxt\"}\n :pm-install{name=\"shadcn-docs-nuxt\" save-dev}\n :pm-install\n :pm-install{name=\"-g nuxi@latest\"}\n ::\n ```mdc\n :pm-install{name=\"shadcn-docs-nuxt\"}\n :pm-install{name=\"shadcn-docs-nuxt\" save-dev}\n :pm-install\n :pm-install{name=\"-g nuxi@latest\"}\n ```\n::\n\n### Run\n\n::stack\n ::div{class=\"p-4\"}\n :pm-run{script=\"dev\"}\n :pm-run{script=\"build --watch -o\"}\n ::\n ```mdc\n :pm-run{script=\"dev\"}\n :pm-run{script=\"build --watch -o\"}\n ```\n::\n\n### X\n\n::stack\n ::div{class=\"p-4\"}\n :pm-x{command=\"nuxi@latest init <project-name>\"}\n ::\n ```mdc\n :pm-x{command=\"nuxi@latest init <project-name>\"}\n ```\n::\n\n### No Sync\n\n::stack\n ::div{class=\"p-4\"}\n :pm-x{command=\"nuxi@latest init <project-name>\" no-sync}\n ::\n ```mdc\n :pm-x{command=\"nuxi@latest init <project-name>\" no-sync}\n ```\n::\n",
376
+ "content": "\n\n## Usage\n\nThe package managers shown can be configured in [`main.pm`](/development/configuration/overview#main).\n\n### Install\n\n::stack\n ::div{class=\"p-4\"}\n :pm-install{name=\"shadcn-docs-nuxt\"}\n :pm-install{name=\"shadcn-docs-nuxt\" save-dev}\n :pm-install\n :pm-install{name=\"-g nuxi@latest\"}\n ::\n ```mdc\n :pm-install{name=\"shadcn-docs-nuxt\"}\n :pm-install{name=\"shadcn-docs-nuxt\" save-dev}\n :pm-install\n :pm-install{name=\"-g nuxi@latest\"}\n ```\n::\n\n### Run\n\n::stack\n ::div{class=\"p-4\"}\n :pm-run{script=\"dev\"}\n :pm-run{script=\"build --watch -o\"}\n ::\n ```mdc\n :pm-run{script=\"dev\"}\n :pm-run{script=\"build --watch -o\"}\n ```\n::\n\n### X\n\n::stack\n ::div{class=\"p-4\"}\n :pm-x{command=\"nuxi@latest init <project-name>\"}\n ::\n ```mdc\n :pm-x{command=\"nuxi@latest init <project-name>\"}\n ```\n::\n\n### No Sync\n\n::stack\n ::div{class=\"p-4\"}\n :pm-x{command=\"nuxi@latest init <project-name>\" no-sync}\n ::\n ```mdc\n :pm-x{command=\"nuxi@latest init <project-name>\" no-sync}\n ```\n::\n",
376
377
  "icon": "lucide:package",
377
378
  "description": "",
378
379
  "badges": [
@@ -496,7 +497,7 @@
496
497
  "_id": "content:3.components:3.page:accordion.md",
497
498
  "_path": "components/page/accordion",
498
499
  "content": "\n\n## Usage\n\n::stack\n ::div{class=\"p-4\"}\n ::accordion{default-value=\"first-item\" collapsible}\n ::accordion-item{value=\"first-item\"}\n #title\n Is it accessible?\n\n #content\n Yes. It adheres to the WAI-ARIA design pattern.\n ::\n ::accordion-item\n #title\n Is it unstyled?\n\n #content\n Yes. It's unstyled by default, giving you freedom over the look and feel.\n ::\n :accordion-item{title=\"Can it be animated?\" content=\"Yes! You can use the transition prop to configure the animation.\"}\n ::\n ::\n ```mdc\n ::accordion{default-value=\"first-item\" collapsible}\n ::accordion-item{value=\"first-item\"}\n #title\n Is it accessible?\n\n #content\n Yes. It adheres to the WAI-ARIA design pattern.\n ::\n\n ::accordion-item\n #title\n Is it unstyled?\n\n #content\n Yes. It's unstyled by default, giving you freedom over the look and feel.\n ::\n :accordion-item{title=\"Can it be animated?\" content=\"Yes! You can use the transition prop to configure the animation.\"}\n ::\n ```\n::\n\nThe `value` prop in `::accordion-item`{lang=\"mdc\"} is auto-generated by default. You can set them to other _unique_ values and put them in the `default-value` prop of `::accordion`{lang=\"mdc\"}.\n\n## Props\n\n#### `::accordion-item`{lang=\"mdc\"}\n\n::field-group\n :field{name=\"type\" type=\"'single' | 'multiple'\" default-value=\"'single'\"}\n :field{name=\"collapsible\" type=\"boolean\" default-value=\"undefined\"}[Whether the items can be collapsed]\n :field{name=\"defaultValue\" type=\"string | string[]\"}[Default open item]\n::\n\n#### `::accordion`{lang=\"mdc\"}\n\n::field-group\n :field{name=\"value\" type=\"string\"}[Item value]\n :field{name=\"title\" type=\"string\"}[Item title]\n :field{name=\"content\" type=\"string\"}[Item content]\n::\n",
499
- "icon": "lucide:layout-list",
500
+ "icon": "i-mingcute:list-expansion-line",
500
501
  "badges": [
501
502
  {
502
503
  "value": "Source",
@@ -601,7 +602,7 @@
601
602
  "_id": "content:3.components:3.page:hero.md",
602
603
  "_path": "components/page/hero",
603
604
  "content": "\n\n## Usage\n\n::stack\n ::div{class=\"p-4\"}\n ::hero\n ---\n announcement:\n title: 'Release v1.0.0'\n icon: 'lucide:party-popper'\n to: /getting-started\n actions:\n - name: Get Started\n to: /getting-started\n - name: GitHub\n variant: outline\n to: https://github.com/wordup-md/nuxt-layer-shadcn-unocss\n leftIcon: 'lucide:github'\n ---\n\n #title\n Effortless and Beautiful :br Docs Template.\n\n #description\n Beautifully designed Nuxt Content template with shadcn-vue. :br Customizable. Compatible. Open Source.\n ::\n ::\n ```mdc\n ::hero\n ---\n announcement:\n title: 'Release v1.0.0'\n icon: 'lucide:party-popper'\n to: /getting-started\n actions:\n - name: Get Started\n to: /getting-started\n - name: GitHub\n variant: outline\n to: https://github.com/wordup-md/nuxt-layer-shadcn-unocss\n leftIcon: 'lucide:github'\n ---\n\n #title\n Effortless and Beautiful :br Docs Template.\n\n #description\n Beautifully designed Nuxt Content template with shadcn-vue. :br Customizable. Compatible. Open Source.\n ::\n ```\n::\n",
604
- "icon": "lucide:align-center",
605
+ "icon": "i-lucide:layout-panel-top",
605
606
  "badges": [
606
607
  {
607
608
  "value": "Source",
@@ -611,6 +612,21 @@
611
612
  }
612
613
  ]
613
614
  },
615
+ {
616
+ "title": "Dynamic List",
617
+ "_id": "content:3.components:3.page:list.md",
618
+ "_path": "components/page/list",
619
+ "content": "\n\n## Usage\n\n::stack\n ::div{class=\"p-4\"}\n ::list\n ---\n path: /components/\n query:\n limit: 3\n component: card\n ---\n ::\n ::\n ```mdc\n ::list\n ---\n path: /components/\n query:\n limit: 3\n component: card\n ---\n ::\n ```\n::\n\n## Props\n\n::field-group\n :field{name=\"path\" type=\"string\"}[Path to the list]\n :field{name=\"query\" type=\"object\"}[Query parameters]\n :field{name=\"component\" type=\"string\"}[Component to use for each item]\n::\n",
620
+ "icon": "i-lucide:layout-list",
621
+ "badges": [
622
+ {
623
+ "value": "Source",
624
+ "icon": "lucide:code",
625
+ "to": "https://github.com/wordup-md/nuxt-layer-shadcn-unocss/blob/main/components/content/List.vue",
626
+ "target": "_blank"
627
+ }
628
+ ]
629
+ },
614
630
  {
615
631
  "title": "Team Card",
616
632
  "_id": "content:3.components:3.page:team-card.md",
@@ -664,7 +680,7 @@
664
680
  "title": "OG Image",
665
681
  "_id": "content:4.development:1.configuration:3.og-image.md",
666
682
  "_path": "development/configuration/og-image",
667
- "content": "\n\n**shadcn-docs-nuxt** utilizes the [nuxt-og-image](https://nuxtseo.com/og-image/getting-started/installation) module to generate dynamic OG Images.\n\nThe dynamic OG Image is used in all pages **except** the index page. The index page uses a static OG Image defined in the [`ogImage`](/development/configuration/shadcn-docs#site) field instead.\n\n## Using Built-in Templates\n\nTo use a template, set the name of the OG Image component in the [`ogImageComponent`](/development/configuration/shadcn-docs#site).\n\n```ts [app.config.ts]\nexport default defineAppConfig({\n shadcnDocs: {\n site: {\n ogImageComponent: 'ShadcnDocs',\n ogImageColor: 'light', // or 'dark'\n },\n },\n});\n```\n\nOut of the box, a shadcn-docs-nuxt template and multiple community templates are available.\n\n::tabs{variant=\"card\"}\n ::div{label=\"ShadcnDocs\"}\n ![Shadcn Docs OG Image Preview](/og-shadcn-docs.png){width=\"1000\"}\n ::\n ::div{label=\"ShadcnDocs (Dark)\"}\n ![Shadcn Docs OG Image Preview](/og-shadcn-docs-dark.png){width=\"1000\"}\n ::\n ::div{label=\"Nuxt\"}\n ![Nuxt OG Image Preview](/og-nuxt.png){width=\"1000\"}\n ::\n ::div{label=\"Nuxt SEO\"}\n ![NuxtSEO OG Image Preview](/og-nuxt-seo.png){width=\"1000\"}\n ::\n::\n\n::alert{to=\"https://github.com/nuxt-modules/og-image/tree/main/src/runtime/nuxt/components/Templates/Community\" icon=\"lucide:list\"}\nSee the full list of community templates.\n::\n\n## Using Custom Templates\n\nTo use a custom template, create a template by following the guide in the [Nuxt SEO Docs](https://nuxtseo.com/og-image/getting-started/getting-familar-with-nuxt-og-image#_1-create-your-template-component). Then set the component name of your template in `ogImageComponent`.\n\n::code-group\n```vue [components/OgImage/BlogPost.vue]\n<template>\n <div class=\"flex size-full items-start justify-start border-[12px] border-solid border-blue-500 bg-gray-50\">\n <div class=\"flex h-full items-start justify-start\">\n <div class=\"flex size-full flex-col justify-between\">\n <h1 class=\"p-20 text-left text-[80px] font-black\">\n {{ title }}\n </h1>\n <p class=\"mb-0 px-20 pb-10 text-2xl font-bold\">\n mycoolsite.com\n </p>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nwithDefaults(defineProps<{\n title?: string;\n}>(), {\n title: 'title',\n});\n</script>\n```\n\n```ts [app.config.ts]\nexport default defineAppConfig({\n shadcnDocs: {\n site: {\n ogImageComponent: 'BlogPost',\n },\n },\n});\n```\n::\n",
683
+ "content": "\n\n**shadcn-docs-nuxt** utilizes the [nuxt-og-image](https://nuxtseo.com/og-image/getting-started/installation) module to generate dynamic OG Images.\n\nThe dynamic OG Image is used in all pages **except** the index page. The index page uses a static OG Image defined in the [`ogImage`](/development/configuration/overview#site) field instead.\n\n## Using Built-in Templates\n\nTo use a template, set the name of the OG Image component in the [`ogImageComponent`](/development/configuration/overview#site).\n\n```ts [app.config.ts]\nexport default defineAppConfig({\n shadcnDocs: {\n site: {\n ogImageComponent: 'ShadcnDocs',\n ogImageColor: 'light', // or 'dark'\n },\n },\n});\n```\n\nOut of the box, a shadcn-docs-nuxt template and multiple community templates are available.\n\n::tabs{variant=\"card\"}\n ::div{label=\"ShadcnDocs\"}\n ![Shadcn Docs OG Image Preview](/og-shadcn-docs.png){width=\"1000\"}\n ::\n ::div{label=\"ShadcnDocs (Dark)\"}\n ![Shadcn Docs OG Image Preview](/og-shadcn-docs-dark.png){width=\"1000\"}\n ::\n ::div{label=\"Nuxt\"}\n ![Nuxt OG Image Preview](/og-nuxt.png){width=\"1000\"}\n ::\n ::div{label=\"Nuxt SEO\"}\n ![NuxtSEO OG Image Preview](/og-nuxt-seo.png){width=\"1000\"}\n ::\n::\n\n::alert{to=\"https://github.com/nuxt-modules/og-image/tree/main/src/runtime/nuxt/components/Templates/Community\" icon=\"lucide:list\"}\nSee the full list of community templates.\n::\n\n## Using Custom Templates\n\nTo use a custom template, create a template by following the guide in the [Nuxt SEO Docs](https://nuxtseo.com/og-image/getting-started/getting-familar-with-nuxt-og-image#_1-create-your-template-component). Then set the component name of your template in `ogImageComponent`.\n\n::code-group\n```vue [components/OgImage/BlogPost.vue]\n<template>\n <div class=\"flex size-full items-start justify-start border-[12px] border-solid border-blue-500 bg-gray-50\">\n <div class=\"flex h-full items-start justify-start\">\n <div class=\"flex size-full flex-col justify-between\">\n <h1 class=\"p-20 text-left text-[80px] font-black\">\n {{ title }}\n </h1>\n <p class=\"mb-0 px-20 pb-10 text-2xl font-bold\">\n mycoolsite.com\n </p>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nwithDefaults(defineProps<{\n title?: string;\n}>(), {\n title: 'title',\n});\n</script>\n```\n\n```ts [app.config.ts]\nexport default defineAppConfig({\n shadcnDocs: {\n site: {\n ogImageComponent: 'BlogPost',\n },\n },\n});\n```\n::\n",
668
684
  "description": "Customizing the dynamic OG Image.",
669
685
  "icon": "lucide:image"
670
686
  },
@@ -710,6 +726,14 @@
710
726
  "content": "\n\n**shadcn-docs-nuxt** has built-in support for [Umami Analytics](https://umami.is/). Add your Umami `data-website-id` to `app.config.ts`.\n\n```ts [app.config.ts]\nexport default defineAppConfig({\n shadcnDocs: {\n site: {\n umami: {\n enable: true,\n src: 'https://cloud.umami.is/script.js',\n dataWebsiteId: 'your-data-website-id',\n },\n },\n },\n});\n```\n\nThese values are used to add the Umami script to `<head>`{lang=\"html\"} as shown below.\n\n```html\n<script defer src=\"https://cloud.umami.is/script.js\" data-website-id=\"your-data-website-id\"></script>\n```\n\n## Parameters\n\n::field-group\n ::field{name=\"enable\" type=\"boolean\" default-value=\"false\"}\n Whether to turn on the umami integration.\n ::\n ::field{name=\"src\" type=\"string\" default-value=\"https://cloud.umami.is/script.js\"}\n The link src in the tracking code.\n ::\n ::field{name=\"dataWebsiteId\" type=\"string\"}\n The _Website ID_ from umami dashboard.\n ::\n::\n",
711
727
  "icon": "lucide:cloud",
712
728
  "description": "Integration for Umami analytics."
729
+ },
730
+ {
731
+ "title": "Layouts",
732
+ "_id": "content:4.development:1.configuration:8.layouts.md",
733
+ "_path": "development/configuration/layouts",
734
+ "content": "\n\nLayouts are used to structure the pages. They can be defined in the frontmatter.\n\n```md\n---\nlayout: default\n---\n```\n\n## Default Layout\n\nThis is the default layout for most pages, providing a consistent, centered content area with left and right sidebars.\n\nYou can configure the layout via frontmatter options:\n\n```mdc\n---\n# Layout structure\naside: true # Show sidebar\ntoc: false # Hide table of contents\n\n# Content display\nshowTitle: true # Show page title\nbreadcrumb: true # Show breadcrumb navigation\npageFooter: false # Hide page footer\n---\n```\n\n## Blank Layout\n\n- **Purpose:** Minimal, unstyled layout for custom structures (e.g., modals, full-bleed landing pages, error pages).\n- **Features:**\n - Renders only a `<div>` with the default slot.\n - No additional classes or structure.\n- **Accessibility:** Use semantic HTML and ARIA roles in your custom content.\n\n**Usage Example:**\n```vue\n<template>\n <NuxtLayout name=\"blank\">\n <!-- Custom content here -->\n </NuxtLayout>\n</template>\n```\n\n---\n\n## Editorial Layout\n\n- **Purpose:** For editorial or content-rich pages (articles, docs, marketing), supporting advanced grid-based layouts.\n- **Features:**\n - Wraps content in a responsive `<div>` with adjustable padding.\n - Provides a `.content-grid` CSS class for advanced grid layouts:\n - Full-width, wide, and standard content columns\n - Responsive padding and max-widths via CSS variables\n - Utility classes for alignment and constraint\n - Designed for use with atomic components and rich content blocks.\n - Ensures accessibility and responsive design out-of-the-box.\n- **Customization:**\n - Adjust grid behavior with CSS variables:\n - `--editorial-content-max-width` (default: 80ch)\n - `--editorial-wide-content-max-width` (default: 1280px)\n - `--padding-inline` (default: 1rem/2rem)\n\n**Usage Example:**\n```vue\n<template>\n <NuxtLayout name=\"editorial\">\n <div class=\"content-grid\">\n <!-- Editorial content here -->\n </div>\n </NuxtLayout>\n</template>\n```\n\n::card{title=\"Best Practices\"}\n- Use the `default` layout for most pages to ensure consistency.\n- Use `blank` only when you need full control over the page structure.\n- Use `editorial` for content-heavy or marketing pages that benefit from advanced grid layouts.\n- Always ensure your content is accessible and responsive.\n- Reference [projectbrief.md](mdc:memory-bank/projectbrief.md) and [productContext.md](mdc:memory-bank/productContext.md) for user experience and accessibility goals.\n::\n\n::prose-section{title=\"Related Components\"}\n- [ProseSection](mdc:components/content/ProseSection.vue): For rich content blocks within layouts.\n- [Hero](mdc:components/content/Hero.vue): For prominent page headers.\n- [Card](mdc:components/content/Card.vue): For modular content presentation.\n::\n",
735
+ "description": "Structuring your pages.",
736
+ "icon": "i-lucide:layout-template"
713
737
  }
714
738
  ],
715
739
  "icon": "lucide:settings",
@@ -760,7 +784,7 @@
760
784
  "title": "Installation",
761
785
  "_id": "content:4.development:5.installation.md",
762
786
  "_path": "development/installation",
763
- "content": "\n\n## Using the starter template\n\n::steps\n### Get Starter Template\n\n:pm-x{command=\"nuxi@latest init <project-name> -t github:ZTL-UwU/shadcn-docs-nuxt-starter\"}\n\n::alert\nAlternatively, you can clone or download the template from the [GitHub repo](https://github.com/wordup-md/nuxt-layer-shadcn-unocss-starter).\n::\n\n### Install Dependencies\n\n:pm-install\n\n### Development Server\n\n:pm-run{script=\"dev\"}\n\n::alert{type=\"success\" icon=\"lucide:circle-check\"}\nWell done! A browser window should automatically open for http://localhost:3000.\n::\n\n### Configure shadcn-docs\n\nPick the theme or adjust other settings to your liking.\n\n:read-more{to=\"/development/configuration/shadcn-docs\"}\n\n::\n",
787
+ "content": "\n\n## Using the starter template\n\n::steps\n### Get Starter Template\n\n:pm-x{command=\"nuxi@latest init <project-name> -t github:ZTL-UwU/shadcn-docs-nuxt-starter\"}\n\n::alert\nAlternatively, you can clone or download the template from the [GitHub repo](https://github.com/wordup-md/nuxt-layer-shadcn-unocss-starter).\n::\n\n### Install Dependencies\n\n:pm-install\n\n### Development Server\n\n:pm-run{script=\"dev\"}\n\n::alert{type=\"success\" icon=\"lucide:circle-check\"}\nWell done! A browser window should automatically open for http://localhost:3000.\n::\n\n### Configure shadcn-docs\n\nPick the theme or adjust other settings to your liking.\n\n:read-more{to=\"/development/configuration/overview\"}\n\n::\n",
764
788
  "description": "How to install shadcn-docs-nuxt in your app.",
765
789
  "icon": "lucide:play"
766
790
  }
@@ -768,5 +792,16 @@
768
792
  "icon": "lucide:code-xml",
769
793
  "navigation.redirect": "/development/configuration",
770
794
  "_path": "development"
795
+ },
796
+ {
797
+ "title": "Home",
798
+ "_id": "content:layout.md",
799
+ "_path": "layout",
800
+ "content": "\n\n::hero\n---\nactions:\n - name: Get Started\n to: /getting-started/introduction\n - name: GitHub\n variant: outline\n to: https://github.com/wordup-md/nuxt-layer-shadcn-unocss\n leftIcon: lucide:github\nannouncement:\n title: Release v0.8.13\n icon: 🎉\n to: https://github.com/wordup-md/nuxt-layer-shadcn-unocss/releases/latest\n target: _blank\nclass: bg-gradient-to-b from-primary/20 to-transparent full-width full-content\n---\n#title\nEffortless and Beautiful Template.\n\n#description\nBeautifully designed Nuxt Content template built with :br\n[shadcn-vue](https://www.shadcn-vue.com) and [unocss](https://unocss.dev).\n::\n\n::div{.bg-gray-100}\ntest div\n::\n\n::section{.bg-gray-100}\ntest section\n::\n\n::prose-section{.bg-gray-100}\n :::card\n lorem ipsum\n :::\n\n :::card\n auiea\n :::\n::\n\nlatuinerst nrst auiea Quisque rutrum. Praesent congue erat at massa. Vestibulum purus quam, scelerisque ut, mollis sed, nonummy id, metus. Duis vel nibh at velit scelerisque suscipit. Praesent nec nisl a purus blandit viverra.\n\n::prose-section{.wide-content.bg-gray-100}\nsection wide-content\n::\n\n::prose-section{.full-width.bg-gray-100}\nsection full-width\n::\n\n::prose-section{.bg-gray-100.full-width.wide-content}\nsection full-width wide-content\n::\n\n::prose-section{.bg-gray-100.full-width.full-content}\nsection full-width full-content\n::\n",
801
+ "navigation": false,
802
+ "layout": "editorial",
803
+ "header": {
804
+ "position": "floating"
805
+ }
771
806
  }
772
- ]
807
+ ]
@@ -14,6 +14,8 @@ interface TreeNode {
14
14
  icon?: string
15
15
  }
16
16
 
17
+ const dirFile = '_dir.yml'
18
+
17
19
  export async function buildContentTree(dirPath: string): Promise<TreeNode[]> {
18
20
  const tree: TreeNode[] = []
19
21
 
@@ -25,7 +27,7 @@ export async function buildContentTree(dirPath: string): Promise<TreeNode[]> {
25
27
  const stats = await stat(fullPath)
26
28
 
27
29
  // Skip hidden files and _dir.yml
28
- if (file.startsWith('.') || file === '_dir.yml') {
30
+ if (file.startsWith('.') || file === dirFile) {
29
31
  continue
30
32
  }
31
33
 
@@ -38,9 +40,9 @@ export async function buildContentTree(dirPath: string): Promise<TreeNode[]> {
38
40
  children,
39
41
  }
40
42
 
41
- const dirConfigPath = join(fullPath, '_dir.yml')
43
+ const dirConfigPath = join(fullPath, dirFile)
42
44
  if (await stat(dirConfigPath).catch(() => false)) {
43
- const _dir = await readFile(fullPath + '/_dir.yml', 'utf-8')
45
+ const _dir = await readFile(fullPath + '/' + dirFile, 'utf-8')
44
46
  const yaml = parse(_dir)
45
47
  dir = {
46
48
  ...dir,