docs-please 0.2.0-beta.0

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.
Files changed (120) hide show
  1. package/README.md +63 -0
  2. package/app/app.config.ts +13 -0
  3. package/app/app.vue +17 -0
  4. package/app/assets/css/main.css +367 -0
  5. package/app/components/Icons.ts +163 -0
  6. package/app/components/app/AppFooter.vue +24 -0
  7. package/app/components/app/AppHeader.vue +58 -0
  8. package/app/components/content/BrowserFrame.vue +21 -0
  9. package/app/components/content/Callout.vue +80 -0
  10. package/app/components/content/Caution.vue +25 -0
  11. package/app/components/content/CodeBlockCommand.vue +92 -0
  12. package/app/components/content/CodeCollapsibleWrapper.vue +50 -0
  13. package/app/components/content/CodeTabs.vue +14 -0
  14. package/app/components/content/ComponentPreview.vue +71 -0
  15. package/app/components/content/ComponentsList.vue +24 -0
  16. package/app/components/content/CopyButton.vue +39 -0
  17. package/app/components/content/FeatureCard.vue +25 -0
  18. package/app/components/content/LinkedCard.vue +19 -0
  19. package/app/components/content/Note.vue +25 -0
  20. package/app/components/content/ProseA.vue +18 -0
  21. package/app/components/content/ProseBlockQuote.vue +8 -0
  22. package/app/components/content/ProseCode.vue +8 -0
  23. package/app/components/content/ProseH1.vue +7 -0
  24. package/app/components/content/ProseH2.vue +8 -0
  25. package/app/components/content/ProseH3.vue +9 -0
  26. package/app/components/content/ProseH4.vue +9 -0
  27. package/app/components/content/ProseH5.vue +7 -0
  28. package/app/components/content/ProseH6.vue +7 -0
  29. package/app/components/content/ProseHr.vue +6 -0
  30. package/app/components/content/ProseIcon.vue +32 -0
  31. package/app/components/content/ProseImg.vue +6 -0
  32. package/app/components/content/ProseLi.vue +8 -0
  33. package/app/components/content/ProseOl.vue +8 -0
  34. package/app/components/content/ProseP.vue +14 -0
  35. package/app/components/content/ProsePre.vue +80 -0
  36. package/app/components/content/ProseStrong.vue +8 -0
  37. package/app/components/content/ProseTable.vue +26 -0
  38. package/app/components/content/ProseTd.vue +8 -0
  39. package/app/components/content/ProseTh.vue +8 -0
  40. package/app/components/content/ProseTr.vue +8 -0
  41. package/app/components/content/ProseUl.vue +8 -0
  42. package/app/components/content/Step.vue +18 -0
  43. package/app/components/content/Steps.vue +18 -0
  44. package/app/components/content/Tabs.vue +129 -0
  45. package/app/components/content/TabsItem.vue +26 -0
  46. package/app/components/content/Tip.vue +25 -0
  47. package/app/components/content/UButton.vue +34 -0
  48. package/app/components/content/UColorModeImage.vue +48 -0
  49. package/app/components/content/UPageCard.vue +83 -0
  50. package/app/components/content/UPageGrid.vue +18 -0
  51. package/app/components/content/UPageHero.vue +92 -0
  52. package/app/components/content/UPageSection.vue +90 -0
  53. package/app/components/content/Warning.vue +25 -0
  54. package/app/components/docs/DocsPageHeader.vue +20 -0
  55. package/app/components/docs/DocsPageNav.vue +31 -0
  56. package/app/components/docs/DocsSidebar.vue +97 -0
  57. package/app/components/docs/DocsTableOfContents.vue +64 -0
  58. package/app/components/ui/accordion/Accordion.vue +22 -0
  59. package/app/components/ui/accordion/AccordionContent.vue +23 -0
  60. package/app/components/ui/accordion/AccordionItem.vue +24 -0
  61. package/app/components/ui/accordion/AccordionTrigger.vue +37 -0
  62. package/app/components/ui/accordion/index.ts +4 -0
  63. package/app/components/ui/alert/Alert.vue +21 -0
  64. package/app/components/ui/alert/AlertDescription.vue +17 -0
  65. package/app/components/ui/alert/AlertTitle.vue +17 -0
  66. package/app/components/ui/alert/index.ts +28 -0
  67. package/app/components/ui/button/Button.vue +29 -0
  68. package/app/components/ui/button/index.ts +38 -0
  69. package/app/components/ui/card/Card.vue +22 -0
  70. package/app/components/ui/card/CardAction.vue +17 -0
  71. package/app/components/ui/card/CardContent.vue +17 -0
  72. package/app/components/ui/card/CardDescription.vue +17 -0
  73. package/app/components/ui/card/CardFooter.vue +17 -0
  74. package/app/components/ui/card/CardHeader.vue +17 -0
  75. package/app/components/ui/card/CardTitle.vue +17 -0
  76. package/app/components/ui/card/index.ts +7 -0
  77. package/app/components/ui/collapsible/Collapsible.vue +19 -0
  78. package/app/components/ui/collapsible/CollapsibleContent.vue +15 -0
  79. package/app/components/ui/collapsible/CollapsibleTrigger.vue +15 -0
  80. package/app/components/ui/collapsible/index.ts +3 -0
  81. package/app/components/ui/separator/Separator.vue +29 -0
  82. package/app/components/ui/separator/index.ts +1 -0
  83. package/app/components/ui/switch/Switch.vue +35 -0
  84. package/app/components/ui/switch/index.ts +1 -0
  85. package/app/components/ui/table/Table.vue +16 -0
  86. package/app/components/ui/table/TableBody.vue +14 -0
  87. package/app/components/ui/table/TableCaption.vue +14 -0
  88. package/app/components/ui/table/TableCell.vue +21 -0
  89. package/app/components/ui/table/TableEmpty.vue +34 -0
  90. package/app/components/ui/table/TableFooter.vue +14 -0
  91. package/app/components/ui/table/TableHead.vue +14 -0
  92. package/app/components/ui/table/TableHeader.vue +14 -0
  93. package/app/components/ui/table/TableRow.vue +14 -0
  94. package/app/components/ui/table/index.ts +9 -0
  95. package/app/components/ui/tabs/Tabs.vue +15 -0
  96. package/app/components/ui/tabs/TabsContent.vue +20 -0
  97. package/app/components/ui/tabs/TabsList.vue +23 -0
  98. package/app/components/ui/tabs/TabsTrigger.vue +27 -0
  99. package/app/components/ui/tabs/index.ts +4 -0
  100. package/app/components/ui/tooltip/Tooltip.vue +19 -0
  101. package/app/components/ui/tooltip/TooltipContent.vue +34 -0
  102. package/app/components/ui/tooltip/TooltipProvider.vue +14 -0
  103. package/app/components/ui/tooltip/TooltipTrigger.vue +15 -0
  104. package/app/components/ui/tooltip/index.ts +4 -0
  105. package/app/composables/useConfig.ts +24 -0
  106. package/app/composables/useNavigation.ts +43 -0
  107. package/app/layouts/default.vue +12 -0
  108. package/app/layouts/docs.vue +27 -0
  109. package/app/lib/utils.ts +7 -0
  110. package/app/pages/[...slug].vue +97 -0
  111. package/app/pages/index.vue +29 -0
  112. package/app/plugins/ssr-width.ts +5 -0
  113. package/content.config.ts +36 -0
  114. package/i18n/locales/en.json +14 -0
  115. package/modules/config.ts +38 -0
  116. package/modules/css.ts +38 -0
  117. package/modules/shadcn.ts +116 -0
  118. package/nuxt.config.ts +125 -0
  119. package/nuxt.schema.ts +68 -0
  120. package/package.json +81 -0
@@ -0,0 +1,15 @@
1
+ <script setup lang="ts">
2
+ import type { TooltipTriggerProps } from 'reka-ui'
3
+ import { TooltipTrigger } from 'reka-ui'
4
+
5
+ const props = defineProps<TooltipTriggerProps>()
6
+ </script>
7
+
8
+ <template>
9
+ <TooltipTrigger
10
+ data-slot="tooltip-trigger"
11
+ v-bind="props"
12
+ >
13
+ <slot />
14
+ </TooltipTrigger>
15
+ </template>
@@ -0,0 +1,4 @@
1
+ export { default as Tooltip } from './Tooltip.vue'
2
+ export { default as TooltipContent } from './TooltipContent.vue'
3
+ export { default as TooltipProvider } from './TooltipProvider.vue'
4
+ export { default as TooltipTrigger } from './TooltipTrigger.vue'
@@ -0,0 +1,24 @@
1
+ import { createSharedComposable } from '@vueuse/core'
2
+
3
+ const COOKIE_NAME = 'docs_config'
4
+ export type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun'
5
+ export type InstallationType = 'cli' | 'manual'
6
+
7
+ export const useConfig = createSharedComposable(() => {
8
+ const config = useCookie<{
9
+ packageManager: PackageManager
10
+ installationType: InstallationType
11
+ }>(
12
+ COOKIE_NAME,
13
+ {
14
+ default: () => ({ packageManager: 'bun', installationType: 'cli' }),
15
+ path: '/',
16
+ maxAge: 31536000,
17
+ sameSite: 'lax',
18
+ },
19
+ )
20
+
21
+ return {
22
+ config,
23
+ }
24
+ })
@@ -0,0 +1,43 @@
1
+ import type { ContentNavigationItem } from '@nuxt/content'
2
+
3
+ export type NavigationItemType = 'page' | 'group'
4
+
5
+ export interface NavigationItem {
6
+ title: string
7
+ path: string
8
+ stem?: string
9
+ children?: NavigationItem[]
10
+ page?: false
11
+ type?: NavigationItemType
12
+ [key: string]: unknown
13
+ }
14
+
15
+ function navigationItemType(item: ContentNavigationItem): NavigationItemType {
16
+ if (item.children && item.children.length > 0) {
17
+ return 'group'
18
+ }
19
+ return 'page'
20
+ }
21
+
22
+ function mapWithType(item: ContentNavigationItem): NavigationItem {
23
+ return {
24
+ ...item,
25
+ type: navigationItemType(item),
26
+ children: item.children?.map(child => mapWithType(child)),
27
+ }
28
+ }
29
+
30
+ export async function useNavigation(): Promise<{ data: Ref<NavigationItem[]> }> {
31
+ const { data } = useAsyncData('navigation', () => {
32
+ return queryCollectionNavigation('docs')
33
+ }, {
34
+ default: () => ([]),
35
+ transform: (data) => {
36
+ return data.map(item => mapWithType(item))
37
+ },
38
+ })
39
+
40
+ return {
41
+ data,
42
+ }
43
+ }
@@ -0,0 +1,12 @@
1
+ <script setup lang="ts">
2
+ </script>
3
+
4
+ <template>
5
+ <div class="relative flex min-h-svh flex-col bg-background">
6
+ <AppHeader />
7
+ <main class="flex-1">
8
+ <slot />
9
+ </main>
10
+ <AppFooter />
11
+ </div>
12
+ </template>
@@ -0,0 +1,27 @@
1
+ <script setup lang="ts">
2
+ </script>
3
+
4
+ <template>
5
+ <div class="relative flex min-h-svh flex-col bg-background">
6
+ <AppHeader />
7
+ <div class="container flex-1">
8
+ <div class="flex gap-8 py-8">
9
+ <!-- Sidebar -->
10
+ <aside class="hidden w-64 shrink-0 lg:block">
11
+ <DocsSidebar />
12
+ </aside>
13
+
14
+ <!-- Main content -->
15
+ <main class="min-w-0 flex-1">
16
+ <slot />
17
+ </main>
18
+
19
+ <!-- Table of contents -->
20
+ <aside class="hidden w-56 shrink-0 xl:block">
21
+ <DocsTableOfContents />
22
+ </aside>
23
+ </div>
24
+ </div>
25
+ <AppFooter />
26
+ </div>
27
+ </template>
@@ -0,0 +1,7 @@
1
+ import type { ClassValue } from 'clsx'
2
+ import { clsx } from 'clsx'
3
+ import { twMerge } from 'tailwind-merge'
4
+
5
+ export function cn(...inputs: ClassValue[]) {
6
+ return twMerge(clsx(inputs))
7
+ }
@@ -0,0 +1,97 @@
1
+ <script setup lang="ts">
2
+ definePageMeta({
3
+ layout: 'docs',
4
+ })
5
+
6
+ const route = useRoute()
7
+
8
+ const { data: page } = await useAsyncData(`docs-${route.path}`, () =>
9
+ queryCollection('docs').path(route.path).first())
10
+
11
+ const { data: surround } = await useAsyncData(`surround-${route.path}`, () =>
12
+ queryCollectionItemSurroundings('docs', route.path))
13
+
14
+ // Extract TOC from page body
15
+ const _toc = computed(() => {
16
+ if (!page.value?.body)
17
+ return []
18
+
19
+ const headings: { id: string, text: string, depth: number }[] = []
20
+
21
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
+ function extractHeadings(node: any) {
23
+ if (node.tag && node.tag.match(/^h[2-4]$/)) {
24
+ const id = node.props?.id
25
+ const text = extractText(node.children)
26
+ const depth = Number.parseInt(node.tag.charAt(1))
27
+ if (id && text) {
28
+ headings.push({ id, text, depth })
29
+ }
30
+ }
31
+ if (node.children) {
32
+ for (const child of node.children) {
33
+ extractHeadings(child)
34
+ }
35
+ }
36
+ }
37
+
38
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
39
+ function extractText(children: any[]): string {
40
+ if (!children)
41
+ return ''
42
+ return children
43
+ .map((child) => {
44
+ if (typeof child === 'string')
45
+ return child
46
+ if (child.children)
47
+ return extractText(child.children)
48
+ return ''
49
+ })
50
+ .join('')
51
+ }
52
+
53
+ if (page.value.body.children) {
54
+ for (const child of page.value.body.children) {
55
+ extractHeadings(child)
56
+ }
57
+ }
58
+
59
+ return headings
60
+ })
61
+
62
+ useSeoMeta({
63
+ title: page.value?.title,
64
+ description: page.value?.description,
65
+ })
66
+ </script>
67
+
68
+ <template>
69
+ <div v-if="page">
70
+ <DocsPageHeader
71
+ :title="page.title"
72
+ :description="page.description"
73
+ />
74
+
75
+ <UiSeparator class="my-6" />
76
+
77
+ <div class="prose dark:prose-invert max-w-none">
78
+ <ContentRenderer :value="page" />
79
+ </div>
80
+
81
+ <DocsPageNav
82
+ :prev="surround?.[0]"
83
+ :next="surround?.[1]"
84
+ />
85
+ </div>
86
+ <div
87
+ v-else
88
+ class="py-12 text-center"
89
+ >
90
+ <h1 class="text-2xl font-bold">
91
+ Page not found
92
+ </h1>
93
+ <p class="mt-2 text-muted-foreground">
94
+ The page you're looking for doesn't exist.
95
+ </p>
96
+ </div>
97
+ </template>
@@ -0,0 +1,29 @@
1
+ <script setup lang="ts">
2
+ definePageMeta({
3
+ layout: 'default',
4
+ })
5
+
6
+ const { data: page } = await useAsyncData('landing', () =>
7
+ queryCollection('landing').first())
8
+
9
+ if (!page.value) {
10
+ throw createError({ statusCode: 404, statusMessage: 'Page not found', fatal: true })
11
+ }
12
+
13
+ const title = page.value.seo?.title || page.value.title
14
+ const description = page.value.seo?.description || page.value.description
15
+
16
+ useSeoMeta({
17
+ title,
18
+ ogTitle: title,
19
+ description,
20
+ ogDescription: description,
21
+ })
22
+ </script>
23
+
24
+ <template>
25
+ <ContentRenderer
26
+ v-if="page"
27
+ :value="page"
28
+ />
29
+ </template>
@@ -0,0 +1,5 @@
1
+ import { provideSSRWidth } from '@vueuse/core'
2
+
3
+ export default defineNuxtPlugin((nuxtApp) => {
4
+ provideSSRWidth(1024, nuxtApp.vueApp)
5
+ })
@@ -0,0 +1,36 @@
1
+ import { defineCollection, defineContentConfig, z } from '@nuxt/content'
2
+ import { useNuxt } from '@nuxt/kit'
3
+ import { joinURL } from 'ufo'
4
+
5
+ const { options } = useNuxt()
6
+ const cwd = joinURL(options.rootDir, 'content')
7
+
8
+ const docsSchema = z.object({
9
+ links: z.array(z.object({
10
+ label: z.string(),
11
+ icon: z.string(),
12
+ to: z.string(),
13
+ target: z.string().optional(),
14
+ })).optional(),
15
+ })
16
+
17
+ export default defineContentConfig({
18
+ collections: {
19
+ landing: defineCollection({
20
+ type: 'page',
21
+ source: {
22
+ cwd,
23
+ include: 'index.md',
24
+ },
25
+ }),
26
+ docs: defineCollection({
27
+ type: 'page',
28
+ source: {
29
+ cwd,
30
+ include: '**',
31
+ exclude: ['index.md'],
32
+ },
33
+ schema: docsSchema,
34
+ }),
35
+ },
36
+ })
@@ -0,0 +1,14 @@
1
+ {
2
+ "common": {
3
+ "or": "or",
4
+ "error": {
5
+ "title": "Something went wrong",
6
+ "description": "An error occurred while loading this page."
7
+ }
8
+ },
9
+ "docs": {
10
+ "toc": "On this page",
11
+ "edit": "Edit this page",
12
+ "report": "Report an issue"
13
+ }
14
+ }
@@ -0,0 +1,38 @@
1
+ import { defineNuxtModule } from '@nuxt/kit'
2
+ import { defu } from 'defu'
3
+ import { getGitBranch, getGitEnv } from '../utils/git'
4
+ import { getPackageJsonMetadata, inferSiteURL } from '../utils/meta'
5
+
6
+ export default defineNuxtModule({
7
+ meta: {
8
+ name: 'docs-config',
9
+ },
10
+ async setup(_options, nuxt) {
11
+ const dir = nuxt.options.rootDir
12
+ const url = inferSiteURL()
13
+ const meta = await getPackageJsonMetadata(dir)
14
+ const gitInfo = getGitEnv()
15
+ const siteName = meta.name || gitInfo?.name || 'Docs'
16
+
17
+ nuxt.options.appConfig.docs = defu(nuxt.options.appConfig.docs, {
18
+ title: siteName,
19
+ description: meta.description || '',
20
+ url,
21
+ github: {
22
+ owner: gitInfo?.owner,
23
+ name: gitInfo?.name,
24
+ url: gitInfo?.url,
25
+ branch: getGitBranch(),
26
+ },
27
+ })
28
+
29
+ // SEO defaults
30
+ nuxt.options.app.head = defu(nuxt.options.app.head, {
31
+ title: siteName,
32
+ titleTemplate: `%s - ${siteName}`,
33
+ meta: [
34
+ { name: 'description', content: meta.description || '' },
35
+ ],
36
+ })
37
+ },
38
+ })
package/modules/css.ts ADDED
@@ -0,0 +1,38 @@
1
+ import { addTemplate, createResolver, defineNuxtModule } from '@nuxt/kit'
2
+ import { joinURL } from 'ufo'
3
+ import { resolveModulePath } from 'exsolve'
4
+
5
+ export default defineNuxtModule({
6
+ meta: {
7
+ name: 'docs-css',
8
+ },
9
+ async setup(_options, nuxt) {
10
+ const dir = nuxt.options.rootDir
11
+ const resolver = createResolver(import.meta.url)
12
+
13
+ const contentDir = joinURL(dir, 'content')
14
+ const layerDir = resolver.resolve('../app')
15
+ const mainCssPath = resolver.resolve('../app/assets/css/main.css')
16
+ const tailwindPath = resolveModulePath('tailwindcss', { from: import.meta.url, conditions: ['style'] })
17
+
18
+ // Create a CSS template that includes source directives for Tailwind
19
+ const cssTemplate = addTemplate({
20
+ filename: 'docs-layer.css',
21
+ getContents: () => {
22
+ return `@import ${JSON.stringify(tailwindPath)};
23
+
24
+ @source "${contentDir.replace(/\\/g, '/')}/**/*";
25
+ @source "${layerDir.replace(/\\/g, '/')}/**/*";
26
+ @source "../../app.config.ts";
27
+
28
+ @import ${JSON.stringify(mainCssPath)};`
29
+ },
30
+ })
31
+
32
+ // Remove main.css from nuxt.options.css if present (we import it in docs-layer.css)
33
+ nuxt.options.css = nuxt.options.css.filter(css => !css.includes('main.css'))
34
+
35
+ // Add the generated CSS file to Nuxt - unshift to load first
36
+ nuxt.options.css.unshift(cssTemplate.dst)
37
+ },
38
+ })
@@ -0,0 +1,116 @@
1
+ import { readdirSync, readFileSync } from 'node:fs'
2
+ import { join } from 'node:path'
3
+ import {
4
+ addComponent,
5
+ addComponentsDir,
6
+ createResolver,
7
+ defineNuxtModule,
8
+ findPath,
9
+ useLogger,
10
+ } from '@nuxt/kit'
11
+ import { parseSync } from 'oxc-parser'
12
+
13
+ // Module options TypeScript interface definition
14
+ export interface ModuleOptions {
15
+ /**
16
+ * Prefix for all the imported component.
17
+ * @default "Ui"
18
+ */
19
+ prefix?: string
20
+ /**
21
+ * Directory that the component lives in.
22
+ * Will respect the Nuxt aliases.
23
+ * @link https://nuxt.com/docs/api/nuxt-config#alias
24
+ * @default "@/components/ui"
25
+ */
26
+ componentDir?: string
27
+ }
28
+
29
+ export default defineNuxtModule<ModuleOptions>({
30
+ meta: {
31
+ name: 'shadcn',
32
+ configKey: 'shadcn',
33
+ },
34
+ defaults: {
35
+ prefix: 'Ui',
36
+ componentDir: '@/components/ui',
37
+ },
38
+ async setup({ prefix, componentDir }, nuxt) {
39
+ const COMPONENT_DIR_PATH = componentDir!
40
+ const ROOT_DIR_PATH = nuxt.options.rootDir
41
+
42
+ const logger = useLogger('shadcn-nuxt')
43
+ logger.start('Setting up shadcn-nuxt module', { COMPONENT_DIR_PATH, ROOT_DIR_PATH })
44
+
45
+ // Build list of potential component directory paths from all layers
46
+ // _layers[0] is the app, subsequent entries are extended layers
47
+ // We check all layers and find the first existing component directory
48
+ const potentialPaths: string[] = []
49
+
50
+ for (const layer of nuxt.options._layers) {
51
+ const layerRoot = layer.cwd
52
+ // Resolve component directory relative to layer root
53
+ const componentPath = COMPONENT_DIR_PATH.replace(/^@\//, '')
54
+
55
+ // Try app/ subdirectory first (Nuxt 4 layer structure)
56
+ potentialPaths.push(join(layerRoot, 'app', componentPath))
57
+ // Also try direct path (traditional structure)
58
+ potentialPaths.push(join(layerRoot, componentPath))
59
+ }
60
+
61
+ logger.info('Checking', { potentialPaths })
62
+ // Use findPath to find the first existing component directory
63
+ const componentsPath = (await findPath(potentialPaths, {}, 'dir')) || ROOT_DIR_PATH
64
+
65
+ logger.info('Decided on', { componentsPath })
66
+
67
+ // Create resolver relative to the found components path
68
+ const { resolve, resolvePath } = createResolver(componentsPath)
69
+
70
+ // Tell Nuxt to not scan `componentsDir` for auto imports as we will do it manually
71
+ // See https://github.com/unovue/shadcn-vue/pull/528#discussion_r1590206268
72
+ addComponentsDir({
73
+ path: componentsPath,
74
+ extensions: [],
75
+ ignore: ['**/*'],
76
+ }, {
77
+ prepend: true,
78
+ })
79
+
80
+ // Manually scan `componentsDir` for components and register them for auto imports
81
+ try {
82
+ await Promise.all(readdirSync(componentsPath).map(async (dir) => {
83
+ try {
84
+ const filePath = await resolvePath(join(componentsPath, dir, 'index'), { extensions: ['.ts', '.js'] })
85
+ const content = readFileSync(filePath, { encoding: 'utf8' })
86
+ const ast = parseSync(filePath, content, {
87
+ sourceType: 'module',
88
+ })
89
+
90
+ const exportedKeys: string[] = ast.program.body
91
+ .filter(node => node.type === 'ExportNamedDeclaration')
92
+ // @ts-expect-error parse return any
93
+ .flatMap(node => node.specifiers?.map(specifier => specifier.exported?.name) || [])
94
+ .filter((key: string) => /^[A-Z]/.test(key))
95
+
96
+ exportedKeys.forEach((key) => {
97
+ addComponent({
98
+ name: `${prefix}${key}`, // name of the component to be used in vue templates
99
+ export: key, // (optional) if the component is a named (rather than default) export
100
+ filePath: resolve(filePath),
101
+ priority: 1,
102
+ })
103
+ })
104
+ }
105
+ catch (err) {
106
+ if (err instanceof Error)
107
+ console.warn('Module error: ', err.message)
108
+ }
109
+ }))
110
+ }
111
+ catch (err) {
112
+ if (err instanceof Error)
113
+ console.warn(err.message)
114
+ }
115
+ },
116
+ })
package/nuxt.config.ts ADDED
@@ -0,0 +1,125 @@
1
+ import { createResolver, useNuxt } from '@nuxt/kit'
2
+ import tailwindcss from '@tailwindcss/vite'
3
+
4
+ const { resolve } = createResolver(import.meta.url)
5
+
6
+ export default defineNuxtConfig({
7
+ modules: [
8
+ resolve('./modules/config'),
9
+ resolve('./modules/css'),
10
+ resolve('./modules/shadcn'),
11
+ '@nuxtjs/color-mode',
12
+ '@nuxt/content',
13
+ '@nuxt/image',
14
+ '@nuxt/icon',
15
+ 'nuxt-og-image',
16
+ ],
17
+ devtools: { enabled: true },
18
+ css: [resolve('./app/assets/css/main.css')],
19
+ colorMode: {
20
+ classSuffix: '',
21
+ preference: 'system',
22
+ fallback: 'light',
23
+ },
24
+ content: {
25
+ build: {
26
+ markdown: {
27
+ highlight: {
28
+ theme: {
29
+ light: 'github-light-default',
30
+ dark: 'github-dark',
31
+ },
32
+ langs: [
33
+ 'ts',
34
+ 'tsx',
35
+ 'js',
36
+ 'vue',
37
+ 'vue-html',
38
+ 'html',
39
+ 'css',
40
+ 'json',
41
+ 'bash',
42
+ 'shell',
43
+ 'yaml',
44
+ 'md',
45
+ 'mdc',
46
+ ],
47
+ },
48
+ },
49
+ },
50
+ },
51
+ mdc: {
52
+ components: {
53
+ map: {
54
+ 'browser-frame': 'BrowserFrame',
55
+ 'callout': 'Callout',
56
+ 'caution': 'Caution',
57
+ 'icon': 'ProseIcon',
58
+ 'note': 'Note',
59
+ 'tip': 'Tip',
60
+ 'warning': 'Warning',
61
+ 'tabs': 'Tabs',
62
+ 'tabs-item': 'TabsItem',
63
+ 'u-color-mode-image': 'UColorModeImage',
64
+ },
65
+ },
66
+ },
67
+ compatibilityDate: '2025-01-01',
68
+ nitro: {
69
+ prerender: {
70
+ crawlLinks: true,
71
+ failOnError: false,
72
+ autoSubfolderIndex: false,
73
+ },
74
+ },
75
+ vite: {
76
+ plugins: [tailwindcss()],
77
+ },
78
+ hooks: {
79
+ 'components:dirs': (dirs) => {
80
+ // Register app components from the layer directory
81
+ dirs.push({
82
+ path: resolve('./app/components/app'),
83
+ pathPrefix: false,
84
+ global: true,
85
+ })
86
+ // Register docs components from the layer directory
87
+ dirs.push({
88
+ path: resolve('./app/components/docs'),
89
+ pathPrefix: false,
90
+ global: true,
91
+ })
92
+ // Register content components from the layer directory
93
+ dirs.push({
94
+ path: resolve('./app/components/content'),
95
+ pathPrefix: false,
96
+ global: true,
97
+ })
98
+ },
99
+ 'nitro:config': (nitroConfig) => {
100
+ const nuxt = useNuxt()
101
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
102
+ const i18nOptions = (nuxt.options as any).i18n
103
+
104
+ const routes: string[] = []
105
+ if (!i18nOptions) {
106
+ routes.push('/')
107
+ }
108
+ else {
109
+ routes.push(...(i18nOptions.locales?.map((locale: string | { code: string }) =>
110
+ typeof locale === 'string' ? `/${locale}` : `/${locale.code}`) || []))
111
+ }
112
+
113
+ nitroConfig.prerender = nitroConfig.prerender || {}
114
+ nitroConfig.prerender.routes = nitroConfig.prerender.routes || []
115
+ nitroConfig.prerender.routes.push(...routes)
116
+ },
117
+ },
118
+ ogImage: {
119
+ fonts: [
120
+ 'Geist:400',
121
+ 'Geist:500',
122
+ 'Geist:600',
123
+ ],
124
+ },
125
+ })