@kirchdev/duxt 0.1.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.
- package/LICENSE +21 -0
- package/README.md +151 -0
- package/app/app.config.ts +13 -0
- package/app/app.vue +122 -0
- package/app/assets/css/duxt.css +555 -0
- package/app/assets/css/typeset.css +498 -0
- package/app/components/DuxtBrand.vue +53 -0
- package/app/components/DuxtBreadcrumb.vue +37 -0
- package/app/components/DuxtCodeBlock.vue +143 -0
- package/app/components/DuxtCopyPage.vue +117 -0
- package/app/components/DuxtFooter.vue +86 -0
- package/app/components/DuxtHeader.vue +496 -0
- package/app/components/DuxtJsonEditor.vue +359 -0
- package/app/components/DuxtLandingProse.vue +90 -0
- package/app/components/DuxtLandingShowcase.vue +295 -0
- package/app/components/DuxtLiveWindow.vue +343 -0
- package/app/components/DuxtLocale.vue +86 -0
- package/app/components/DuxtMetaList.vue +76 -0
- package/app/components/DuxtNavigation.vue +94 -0
- package/app/components/DuxtNavigationLink.vue +41 -0
- package/app/components/DuxtOpenApiCallbacks.vue +92 -0
- package/app/components/DuxtOpenApiClient.vue +1339 -0
- package/app/components/DuxtOpenApiMedia.vue +108 -0
- package/app/components/DuxtOpenApiMethod.vue +59 -0
- package/app/components/DuxtOpenApiParameters.vue +114 -0
- package/app/components/DuxtOpenApiResponses.vue +109 -0
- package/app/components/DuxtOpenApiSchema.vue +365 -0
- package/app/components/DuxtOpenApiSecurity.vue +115 -0
- package/app/components/DuxtPageFeedback.vue +56 -0
- package/app/components/DuxtPageInfo.vue +194 -0
- package/app/components/DuxtPageNav.vue +93 -0
- package/app/components/DuxtPreviewSkeleton.vue +262 -0
- package/app/components/DuxtProgress.vue +45 -0
- package/app/components/DuxtSearch.vue +271 -0
- package/app/components/DuxtSections.vue +65 -0
- package/app/components/DuxtShortcuts.vue +46 -0
- package/app/components/DuxtSkipLink.vue +34 -0
- package/app/components/DuxtToc.vue +86 -0
- package/app/components/DuxtTranslationBanner.vue +64 -0
- package/app/components/DuxtVersion.vue +168 -0
- package/app/components/DuxtVersionBanner.vue +109 -0
- package/app/components/OgImage/Duxt.satori.vue +82 -0
- package/app/components/content/Accordion.vue +37 -0
- package/app/components/content/AccordionItem.vue +46 -0
- package/app/components/content/Callout.vue +58 -0
- package/app/components/content/ChangelogGroup.vue +91 -0
- package/app/components/content/ChangelogReleases.vue +520 -0
- package/app/components/content/CodeGroup.vue +183 -0
- package/app/components/content/DevtoolsPanel.vue +107 -0
- package/app/components/content/Field.vue +50 -0
- package/app/components/content/FieldGroup.vue +8 -0
- package/app/components/content/FileTree.vue +92 -0
- package/app/components/content/Mermaid.vue +70 -0
- package/app/components/content/OpenApiOperation.vue +185 -0
- package/app/components/content/OpenApiOperations.vue +72 -0
- package/app/components/content/OpenApiOverview.vue +302 -0
- package/app/components/content/PackageManagers.vue +187 -0
- package/app/components/content/PageCards.vue +48 -0
- package/app/components/content/Partial.vue +65 -0
- package/app/components/content/Preview.vue +173 -0
- package/app/components/content/ProseA.vue +55 -0
- package/app/components/content/ProseH2.vue +53 -0
- package/app/components/content/ProseH3.vue +53 -0
- package/app/components/content/ProseH4.vue +53 -0
- package/app/components/content/ProseImg.vue +87 -0
- package/app/components/content/ProsePre.vue +58 -0
- package/app/components/content/ProseTable.vue +11 -0
- package/app/components/content/Since.vue +21 -0
- package/app/components/content/Steps.vue +20 -0
- package/app/components/content/Tab.vue +23 -0
- package/app/components/content/TabGroup.vue +58 -0
- package/app/components/ui/alert/Alert.vue +21 -0
- package/app/components/ui/alert/AlertDescription.vue +22 -0
- package/app/components/ui/alert/AlertTitle.vue +22 -0
- package/app/components/ui/alert/index.ts +24 -0
- package/app/components/ui/badge/Badge.vue +28 -0
- package/app/components/ui/badge/index.ts +52 -0
- package/app/components/ui/breadcrumb/Breadcrumb.vue +13 -0
- package/app/components/ui/breadcrumb/BreadcrumbEllipsis.vue +22 -0
- package/app/components/ui/breadcrumb/BreadcrumbItem.vue +17 -0
- package/app/components/ui/breadcrumb/BreadcrumbLink.vue +24 -0
- package/app/components/ui/breadcrumb/BreadcrumbList.vue +22 -0
- package/app/components/ui/breadcrumb/BreadcrumbPage.vue +20 -0
- package/app/components/ui/breadcrumb/BreadcrumbSeparator.vue +21 -0
- package/app/components/ui/breadcrumb/index.ts +7 -0
- package/app/components/ui/button/Button.vue +31 -0
- package/app/components/ui/button/index.ts +39 -0
- package/app/components/ui/card/Card.vue +22 -0
- package/app/components/ui/card/CardAction.vue +22 -0
- package/app/components/ui/card/CardContent.vue +14 -0
- package/app/components/ui/card/CardDescription.vue +17 -0
- package/app/components/ui/card/CardFooter.vue +17 -0
- package/app/components/ui/card/CardHeader.vue +22 -0
- package/app/components/ui/card/CardTitle.vue +17 -0
- package/app/components/ui/card/index.ts +7 -0
- package/app/components/ui/collapsible/Collapsible.vue +19 -0
- package/app/components/ui/collapsible/CollapsibleContent.vue +12 -0
- package/app/components/ui/collapsible/CollapsibleTrigger.vue +12 -0
- package/app/components/ui/collapsible/index.ts +3 -0
- package/app/components/ui/command/Command.vue +98 -0
- package/app/components/ui/command/CommandDialog.vue +42 -0
- package/app/components/ui/command/CommandEmpty.vue +31 -0
- package/app/components/ui/command/CommandGroup.vue +52 -0
- package/app/components/ui/command/CommandInput.vue +45 -0
- package/app/components/ui/command/CommandItem.vue +85 -0
- package/app/components/ui/command/CommandList.vue +32 -0
- package/app/components/ui/command/CommandSeparator.vue +23 -0
- package/app/components/ui/command/CommandShortcut.vue +19 -0
- package/app/components/ui/command/index.ts +29 -0
- package/app/components/ui/dialog/Dialog.vue +15 -0
- package/app/components/ui/dialog/DialogClose.vue +12 -0
- package/app/components/ui/dialog/DialogContent.vue +61 -0
- package/app/components/ui/dialog/DialogDescription.vue +25 -0
- package/app/components/ui/dialog/DialogFooter.vue +30 -0
- package/app/components/ui/dialog/DialogHeader.vue +17 -0
- package/app/components/ui/dialog/DialogOverlay.vue +28 -0
- package/app/components/ui/dialog/DialogScrollContent.vue +65 -0
- package/app/components/ui/dialog/DialogTitle.vue +25 -0
- package/app/components/ui/dialog/DialogTrigger.vue +12 -0
- package/app/components/ui/dialog/index.ts +10 -0
- package/app/components/ui/dropdown-menu/DropdownMenu.vue +19 -0
- package/app/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +47 -0
- package/app/components/ui/dropdown-menu/DropdownMenuContent.vue +47 -0
- package/app/components/ui/dropdown-menu/DropdownMenuGroup.vue +12 -0
- package/app/components/ui/dropdown-menu/DropdownMenuItem.vue +41 -0
- package/app/components/ui/dropdown-menu/DropdownMenuLabel.vue +27 -0
- package/app/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +21 -0
- package/app/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +48 -0
- package/app/components/ui/dropdown-menu/DropdownMenuSeparator.vue +23 -0
- package/app/components/ui/dropdown-menu/DropdownMenuShortcut.vue +19 -0
- package/app/components/ui/dropdown-menu/DropdownMenuSub.vue +19 -0
- package/app/components/ui/dropdown-menu/DropdownMenuSubContent.vue +34 -0
- package/app/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +34 -0
- package/app/components/ui/dropdown-menu/DropdownMenuTrigger.vue +17 -0
- package/app/components/ui/dropdown-menu/index.ts +16 -0
- package/app/components/ui/input/Input.vue +35 -0
- package/app/components/ui/input/index.ts +1 -0
- package/app/components/ui/navigation-menu/NavigationMenu.vue +42 -0
- package/app/components/ui/navigation-menu/NavigationMenuContent.vue +35 -0
- package/app/components/ui/navigation-menu/NavigationMenuIndicator.vue +32 -0
- package/app/components/ui/navigation-menu/NavigationMenuItem.vue +23 -0
- package/app/components/ui/navigation-menu/NavigationMenuLink.vue +30 -0
- package/app/components/ui/navigation-menu/NavigationMenuList.vue +30 -0
- package/app/components/ui/navigation-menu/NavigationMenuTrigger.vue +31 -0
- package/app/components/ui/navigation-menu/NavigationMenuViewport.vue +30 -0
- package/app/components/ui/navigation-menu/index.ts +14 -0
- package/app/components/ui/scroll-area/ScrollArea.vue +31 -0
- package/app/components/ui/scroll-area/ScrollBar.vue +38 -0
- package/app/components/ui/scroll-area/index.ts +2 -0
- package/app/components/ui/select/Select.vue +15 -0
- package/app/components/ui/select/SelectContent.vue +59 -0
- package/app/components/ui/select/SelectGroup.vue +19 -0
- package/app/components/ui/select/SelectItem.vue +42 -0
- package/app/components/ui/select/SelectItemText.vue +12 -0
- package/app/components/ui/select/SelectLabel.vue +16 -0
- package/app/components/ui/select/SelectScrollDownButton.vue +28 -0
- package/app/components/ui/select/SelectScrollUpButton.vue +28 -0
- package/app/components/ui/select/SelectSeparator.vue +20 -0
- package/app/components/ui/select/SelectTrigger.vue +32 -0
- package/app/components/ui/select/SelectValue.vue +12 -0
- package/app/components/ui/select/index.ts +11 -0
- package/app/components/ui/separator/Separator.vue +30 -0
- package/app/components/ui/separator/index.ts +1 -0
- package/app/components/ui/sheet/Sheet.vue +15 -0
- package/app/components/ui/sheet/SheetClose.vue +12 -0
- package/app/components/ui/sheet/SheetContent.vue +68 -0
- package/app/components/ui/sheet/SheetDescription.vue +23 -0
- package/app/components/ui/sheet/SheetFooter.vue +15 -0
- package/app/components/ui/sheet/SheetHeader.vue +15 -0
- package/app/components/ui/sheet/SheetOverlay.vue +28 -0
- package/app/components/ui/sheet/SheetTitle.vue +23 -0
- package/app/components/ui/sheet/SheetTrigger.vue +12 -0
- package/app/components/ui/sheet/index.ts +8 -0
- package/app/components/ui/sidebar/Sidebar.vue +110 -0
- package/app/components/ui/sidebar/SidebarContent.vue +23 -0
- package/app/components/ui/sidebar/SidebarFooter.vue +18 -0
- package/app/components/ui/sidebar/SidebarGroup.vue +18 -0
- package/app/components/ui/sidebar/SidebarGroupAction.vue +31 -0
- package/app/components/ui/sidebar/SidebarGroupContent.vue +18 -0
- package/app/components/ui/sidebar/SidebarGroupLabel.vue +30 -0
- package/app/components/ui/sidebar/SidebarHeader.vue +18 -0
- package/app/components/ui/sidebar/SidebarInput.vue +19 -0
- package/app/components/ui/sidebar/SidebarInset.vue +23 -0
- package/app/components/ui/sidebar/SidebarMenu.vue +18 -0
- package/app/components/ui/sidebar/SidebarMenuAction.vue +42 -0
- package/app/components/ui/sidebar/SidebarMenuBadge.vue +28 -0
- package/app/components/ui/sidebar/SidebarMenuButton.vue +60 -0
- package/app/components/ui/sidebar/SidebarMenuButtonChild.vue +36 -0
- package/app/components/ui/sidebar/SidebarMenuItem.vue +18 -0
- package/app/components/ui/sidebar/SidebarMenuSkeleton.vue +35 -0
- package/app/components/ui/sidebar/SidebarMenuSub.vue +24 -0
- package/app/components/ui/sidebar/SidebarMenuSubButton.vue +43 -0
- package/app/components/ui/sidebar/SidebarMenuSubItem.vue +18 -0
- package/app/components/ui/sidebar/SidebarProvider.vue +109 -0
- package/app/components/ui/sidebar/SidebarRail.vue +35 -0
- package/app/components/ui/sidebar/SidebarSeparator.vue +19 -0
- package/app/components/ui/sidebar/SidebarTrigger.vue +26 -0
- package/app/components/ui/sidebar/index.ts +62 -0
- package/app/components/ui/sidebar/utils.ts +19 -0
- package/app/components/ui/skeleton/Skeleton.vue +17 -0
- package/app/components/ui/skeleton/index.ts +1 -0
- package/app/components/ui/sonner/Sonner.vue +67 -0
- package/app/components/ui/sonner/index.ts +1 -0
- package/app/components/ui/tabs/Tabs.vue +26 -0
- package/app/components/ui/tabs/TabsContent.vue +23 -0
- package/app/components/ui/tabs/TabsList.vue +28 -0
- package/app/components/ui/tabs/TabsTrigger.vue +30 -0
- package/app/components/ui/tabs/index.ts +4 -0
- package/app/components/ui/textarea/Textarea.vue +32 -0
- package/app/components/ui/textarea/index.ts +1 -0
- package/app/components/ui/tooltip/Tooltip.vue +15 -0
- package/app/components/ui/tooltip/TooltipContent.vue +49 -0
- package/app/components/ui/tooltip/TooltipProvider.vue +14 -0
- package/app/components/ui/tooltip/TooltipTrigger.vue +12 -0
- package/app/components/ui/tooltip/index.ts +4 -0
- package/app/composables/useActiveHeading.ts +90 -0
- package/app/composables/useDuxtAnimatedHeight.ts +155 -0
- package/app/composables/useDuxtBreadcrumb.ts +60 -0
- package/app/composables/useDuxtChoice.ts +28 -0
- package/app/composables/useDuxtCollection.ts +89 -0
- package/app/composables/useDuxtConfig.ts +47 -0
- package/app/composables/useDuxtNavigation.ts +87 -0
- package/app/composables/useDuxtPageFocus.ts +30 -0
- package/app/composables/useDuxtPath.ts +42 -0
- package/app/composables/useDuxtSearch.ts +208 -0
- package/app/composables/useDuxtSection.ts +44 -0
- package/app/composables/useDuxtSectionRow.ts +49 -0
- package/app/composables/useDuxtShortcuts.ts +58 -0
- package/app/composables/useDuxtSiteUrl.ts +27 -0
- package/app/composables/useDuxtToast.ts +25 -0
- package/app/composables/useDuxtVersion.ts +138 -0
- package/app/composables/useFuzzySearch.ts +83 -0
- package/app/composables/usePackageManager.ts +4 -0
- package/app/composables/useRecentPages.ts +52 -0
- package/app/error.vue +133 -0
- package/app/layouts/changelog.vue +85 -0
- package/app/layouts/default.vue +23 -0
- package/app/layouts/docs.vue +62 -0
- package/app/layouts/reference.vue +85 -0
- package/app/lib/utils.ts +7 -0
- package/app/middleware/duxt-section-layout.global.ts +57 -0
- package/app/pages/[...slug].vue +441 -0
- package/app/pages/index.vue +479 -0
- package/app/types/duxt.d.ts +955 -0
- package/app/utils/aside.ts +16 -0
- package/app/utils/changelog.ts +182 -0
- package/app/utils/code-highlight.ts +116 -0
- package/app/utils/duxt-config.ts +185 -0
- package/app/utils/duxt-text.ts +135 -0
- package/app/utils/file-icons.ts +62 -0
- package/app/utils/generated-sections.ts +190 -0
- package/app/utils/generated-toc.ts +216 -0
- package/app/utils/heading-link.ts +32 -0
- package/app/utils/locale-path.ts +45 -0
- package/app/utils/navigation-tree.ts +206 -0
- package/app/utils/nearest-page.ts +72 -0
- package/app/utils/openapi.ts +1028 -0
- package/app/utils/package-command.ts +162 -0
- package/app/utils/request-samples.ts +635 -0
- package/app/utils/section-scope.ts +97 -0
- package/app/utils/sheet-navigation.ts +100 -0
- package/app/utils/source-file.ts +84 -0
- package/app/utils/version-choices.ts +68 -0
- package/app/utils/version-paths.ts +65 -0
- package/bin/duxt-report.mjs +45 -0
- package/components.json +19 -0
- package/content-cache.ts +193 -0
- package/content.config.ts +38 -0
- package/duxt-app-config.ts +124 -0
- package/highlight-langs.ts +68 -0
- package/i18n/i18n.config.ts +16 -0
- package/i18n/locales/de/duxt/changelog.json +17 -0
- package/i18n/locales/de/duxt/code.json +13 -0
- package/i18n/locales/de/duxt/defaults.json +22 -0
- package/i18n/locales/de/duxt/devtools.json +7 -0
- package/i18n/locales/de/duxt/error.json +10 -0
- package/i18n/locales/de/duxt/footer.json +7 -0
- package/i18n/locales/de/duxt/locale.json +7 -0
- package/i18n/locales/de/duxt/nav.json +17 -0
- package/i18n/locales/de/duxt/openapi.json +89 -0
- package/i18n/locales/de/duxt/page.json +34 -0
- package/i18n/locales/de/duxt/search.json +12 -0
- package/i18n/locales/de/duxt/shortcuts.json +11 -0
- package/i18n/locales/de/duxt/theme.json +7 -0
- package/i18n/locales/de/duxt/toc.json +7 -0
- package/i18n/locales/de/duxt/version.json +25 -0
- package/i18n/locales/en/duxt/changelog.json +17 -0
- package/i18n/locales/en/duxt/code.json +13 -0
- package/i18n/locales/en/duxt/defaults.json +22 -0
- package/i18n/locales/en/duxt/devtools.json +7 -0
- package/i18n/locales/en/duxt/error.json +10 -0
- package/i18n/locales/en/duxt/footer.json +7 -0
- package/i18n/locales/en/duxt/locale.json +7 -0
- package/i18n/locales/en/duxt/nav.json +17 -0
- package/i18n/locales/en/duxt/openapi.json +89 -0
- package/i18n/locales/en/duxt/page.json +34 -0
- package/i18n/locales/en/duxt/search.json +12 -0
- package/i18n/locales/en/duxt/shortcuts.json +11 -0
- package/i18n/locales/en/duxt/theme.json +7 -0
- package/i18n/locales/en/duxt/toc.json +7 -0
- package/i18n/locales/en/duxt/version.json +25 -0
- package/i18n/locales/es/duxt/changelog.json +17 -0
- package/i18n/locales/es/duxt/code.json +13 -0
- package/i18n/locales/es/duxt/defaults.json +22 -0
- package/i18n/locales/es/duxt/devtools.json +7 -0
- package/i18n/locales/es/duxt/error.json +10 -0
- package/i18n/locales/es/duxt/footer.json +7 -0
- package/i18n/locales/es/duxt/locale.json +7 -0
- package/i18n/locales/es/duxt/nav.json +17 -0
- package/i18n/locales/es/duxt/openapi.json +89 -0
- package/i18n/locales/es/duxt/page.json +34 -0
- package/i18n/locales/es/duxt/search.json +12 -0
- package/i18n/locales/es/duxt/shortcuts.json +11 -0
- package/i18n/locales/es/duxt/theme.json +7 -0
- package/i18n/locales/es/duxt/toc.json +7 -0
- package/i18n/locales/es/duxt/version.json +25 -0
- package/i18n/locales/fr/duxt/changelog.json +17 -0
- package/i18n/locales/fr/duxt/code.json +13 -0
- package/i18n/locales/fr/duxt/defaults.json +22 -0
- package/i18n/locales/fr/duxt/devtools.json +7 -0
- package/i18n/locales/fr/duxt/error.json +10 -0
- package/i18n/locales/fr/duxt/footer.json +7 -0
- package/i18n/locales/fr/duxt/locale.json +7 -0
- package/i18n/locales/fr/duxt/nav.json +17 -0
- package/i18n/locales/fr/duxt/openapi.json +89 -0
- package/i18n/locales/fr/duxt/page.json +34 -0
- package/i18n/locales/fr/duxt/search.json +12 -0
- package/i18n/locales/fr/duxt/shortcuts.json +11 -0
- package/i18n/locales/fr/duxt/theme.json +7 -0
- package/i18n/locales/fr/duxt/toc.json +7 -0
- package/i18n/locales/fr/duxt/version.json +25 -0
- package/i18n/locales/pt/duxt/changelog.json +17 -0
- package/i18n/locales/pt/duxt/code.json +13 -0
- package/i18n/locales/pt/duxt/defaults.json +22 -0
- package/i18n/locales/pt/duxt/devtools.json +7 -0
- package/i18n/locales/pt/duxt/error.json +10 -0
- package/i18n/locales/pt/duxt/footer.json +7 -0
- package/i18n/locales/pt/duxt/locale.json +7 -0
- package/i18n/locales/pt/duxt/nav.json +17 -0
- package/i18n/locales/pt/duxt/openapi.json +89 -0
- package/i18n/locales/pt/duxt/page.json +34 -0
- package/i18n/locales/pt/duxt/search.json +12 -0
- package/i18n/locales/pt/duxt/shortcuts.json +11 -0
- package/i18n/locales/pt/duxt/theme.json +7 -0
- package/i18n/locales/pt/duxt/toc.json +7 -0
- package/i18n/locales/pt/duxt/version.json +25 -0
- package/i18n/locales/pt-BR/duxt/error.json +8 -0
- package/i18n/locales/pt-BR/duxt/nav.json +10 -0
- package/i18n/locales/pt-BR/duxt/page.json +10 -0
- package/i18n/locales/pt-BR/duxt/search.json +11 -0
- package/i18n/locales/pt-BR/duxt/version.json +13 -0
- package/mdc.config.ts +28 -0
- package/modules/config.ts +440 -0
- package/modules/devtools.ts +126 -0
- package/modules/git-meta.ts +349 -0
- package/modules/redirects.ts +152 -0
- package/modules/validate.ts +137 -0
- package/nuxt.config.ts +530 -0
- package/openapi-model.ts +358 -0
- package/openapi-parse.ts +1052 -0
- package/package.json +161 -0
- package/public/devtools/cache.html +318 -0
- package/public/devtools/checks.html +309 -0
- package/public/devtools/config.html +461 -0
- package/public/devtools/i18n.html +309 -0
- package/public/devtools/pages.html +348 -0
- package/public/devtools/paths.html +315 -0
- package/public/devtools/redirects.html +309 -0
- package/public/devtools/search.html +324 -0
- package/public/devtools/sources.html +309 -0
- package/public/devtools/versions.html +318 -0
- package/report.ts +303 -0
- package/repository-root.ts +26 -0
- package/section-reports.ts +55 -0
- package/sections-changelog.ts +644 -0
- package/sections-openapi.ts +450 -0
- package/sections-resolve.ts +711 -0
- package/sections.ts +157 -0
- package/server/devtools/content.ts +120 -0
- package/server/devtools/context.ts +38 -0
- package/server/devtools/entry-path.ts +30 -0
- package/server/devtools/handler.ts +104 -0
- package/server/devtools/preview.ts +461 -0
- package/server/devtools/render/content.ts +233 -0
- package/server/devtools/render/sources.ts +414 -0
- package/server/devtools/render/system.ts +352 -0
- package/server/devtools/shell.ts +611 -0
- package/server/devtools/sources.ts +122 -0
- package/server/devtools/system.ts +178 -0
- package/server/mcp/tools/list-pages.ts +52 -0
- package/server/mcp/tools/read-page.ts +57 -0
- package/server/mcp/tools/search-docs.ts +74 -0
- package/server/middleware/raw-markdown.ts +86 -0
- package/server/routes/llms-full.txt.get.ts +75 -0
- package/server/routes/llms.txt.get.ts +63 -0
- package/server/routes/rss.xml.get.ts +125 -0
- package/server/utils/duxt-server-text.ts +46 -0
- package/sources-git.ts +113 -0
- package/sources-resolve.ts +908 -0
- package/sources.ts +287 -0
- package/validate-report.ts +494 -0
package/nuxt.config.ts
ADDED
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { defineNuxtConfig } from 'nuxt/config';
|
|
5
|
+
import tailwindcss from '@tailwindcss/vite';
|
|
6
|
+
import { highlightLangs } from './highlight-langs';
|
|
7
|
+
|
|
8
|
+
/** Resolve against this layer, not the project extending it. */
|
|
9
|
+
const layer = (path: string) => fileURLToPath(new URL(path, import.meta.url));
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* The one file Nitro's tracer cannot see.
|
|
13
|
+
*
|
|
14
|
+
* satori shapes text with harfbuzz, which is a WebAssembly module read at
|
|
15
|
+
* runtime with `fs.readFile` — not imported. Nothing in the module graph
|
|
16
|
+
* mentions it, so the build copies `harfbuzzjs`'s JavaScript and leaves
|
|
17
|
+
* `hb.wasm` behind, and the first request for an OG image dies with ENOENT on a
|
|
18
|
+
* path inside `.output`. Naming the file explicitly is the whole fix.
|
|
19
|
+
*
|
|
20
|
+
* Resolved rather than hard-coded, and optional: a consumer who has replaced
|
|
21
|
+
* the renderer, or pruned satori, must not have the build fail over a file
|
|
22
|
+
* nothing reads.
|
|
23
|
+
*/
|
|
24
|
+
const require_ = createRequire(import.meta.url);
|
|
25
|
+
|
|
26
|
+
function harfbuzzWasm(): string | undefined {
|
|
27
|
+
try {
|
|
28
|
+
return join(
|
|
29
|
+
dirname(require_.resolve('harfbuzzjs/package.json')),
|
|
30
|
+
'hb.wasm'
|
|
31
|
+
);
|
|
32
|
+
} catch {
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const wasm = harfbuzzWasm();
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* The locales the layer ships strings for.
|
|
41
|
+
*
|
|
42
|
+
* Kept out of the config object so the icon client bundle below can derive the
|
|
43
|
+
* country flags from it, exactly as gildstone does. `code` needs `as const`:
|
|
44
|
+
* outside the literal TypeScript widens it to `string`, which no longer
|
|
45
|
+
* satisfies i18n's `LocaleObject<…>`.
|
|
46
|
+
*
|
|
47
|
+
* THE LANGUAGE CARRIES THE STRINGS, THE REGION ONLY ITS DEVIATIONS. i18n loads
|
|
48
|
+
* every file in `files` and deep-merges them in order, so `pt-BR` reads the
|
|
49
|
+
* European Portuguese set and then overwrites the handful of words Brazil
|
|
50
|
+
* spells differently. That is why there is no `en-GB/` or `en-US/` directory at
|
|
51
|
+
* all: nothing in this vocabulary differs between them, and a directory that
|
|
52
|
+
* would only duplicate `en/` is a directory that drifts from it.
|
|
53
|
+
*
|
|
54
|
+
* `name` is the endonym — each language written in itself, which is what a
|
|
55
|
+
* language switcher must show. It lives here rather than in the message files
|
|
56
|
+
* because it is the same string in every locale.
|
|
57
|
+
*/
|
|
58
|
+
const locales = [
|
|
59
|
+
{
|
|
60
|
+
code: 'en-GB' as const,
|
|
61
|
+
language: 'en-GB',
|
|
62
|
+
name: 'English (UK)',
|
|
63
|
+
files: [
|
|
64
|
+
'en/duxt/changelog.json',
|
|
65
|
+
'en/duxt/code.json',
|
|
66
|
+
'en/duxt/devtools.json',
|
|
67
|
+
'en/duxt/defaults.json',
|
|
68
|
+
'en/duxt/error.json',
|
|
69
|
+
'en/duxt/footer.json',
|
|
70
|
+
'en/duxt/locale.json',
|
|
71
|
+
'en/duxt/nav.json',
|
|
72
|
+
'en/duxt/openapi.json',
|
|
73
|
+
'en/duxt/page.json',
|
|
74
|
+
'en/duxt/search.json',
|
|
75
|
+
'en/duxt/shortcuts.json',
|
|
76
|
+
'en/duxt/theme.json',
|
|
77
|
+
'en/duxt/toc.json',
|
|
78
|
+
'en/duxt/version.json'
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
code: 'en-US' as const,
|
|
83
|
+
language: 'en-US',
|
|
84
|
+
name: 'English (US)',
|
|
85
|
+
files: [
|
|
86
|
+
'en/duxt/changelog.json',
|
|
87
|
+
'en/duxt/code.json',
|
|
88
|
+
'en/duxt/devtools.json',
|
|
89
|
+
'en/duxt/defaults.json',
|
|
90
|
+
'en/duxt/error.json',
|
|
91
|
+
'en/duxt/footer.json',
|
|
92
|
+
'en/duxt/locale.json',
|
|
93
|
+
'en/duxt/nav.json',
|
|
94
|
+
'en/duxt/openapi.json',
|
|
95
|
+
'en/duxt/page.json',
|
|
96
|
+
'en/duxt/search.json',
|
|
97
|
+
'en/duxt/shortcuts.json',
|
|
98
|
+
'en/duxt/theme.json',
|
|
99
|
+
'en/duxt/toc.json',
|
|
100
|
+
'en/duxt/version.json'
|
|
101
|
+
]
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
code: 'de-DE' as const,
|
|
105
|
+
language: 'de-DE',
|
|
106
|
+
name: 'Deutsch',
|
|
107
|
+
files: [
|
|
108
|
+
'de/duxt/changelog.json',
|
|
109
|
+
'de/duxt/code.json',
|
|
110
|
+
'de/duxt/devtools.json',
|
|
111
|
+
'de/duxt/defaults.json',
|
|
112
|
+
'de/duxt/error.json',
|
|
113
|
+
'de/duxt/footer.json',
|
|
114
|
+
'de/duxt/locale.json',
|
|
115
|
+
'de/duxt/nav.json',
|
|
116
|
+
'de/duxt/openapi.json',
|
|
117
|
+
'de/duxt/page.json',
|
|
118
|
+
'de/duxt/search.json',
|
|
119
|
+
'de/duxt/shortcuts.json',
|
|
120
|
+
'de/duxt/theme.json',
|
|
121
|
+
'de/duxt/toc.json',
|
|
122
|
+
'de/duxt/version.json'
|
|
123
|
+
]
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
code: 'es-ES' as const,
|
|
127
|
+
language: 'es-ES',
|
|
128
|
+
name: 'Español',
|
|
129
|
+
files: [
|
|
130
|
+
'es/duxt/changelog.json',
|
|
131
|
+
'es/duxt/code.json',
|
|
132
|
+
'es/duxt/devtools.json',
|
|
133
|
+
'es/duxt/defaults.json',
|
|
134
|
+
'es/duxt/error.json',
|
|
135
|
+
'es/duxt/footer.json',
|
|
136
|
+
'es/duxt/locale.json',
|
|
137
|
+
'es/duxt/nav.json',
|
|
138
|
+
'es/duxt/openapi.json',
|
|
139
|
+
'es/duxt/page.json',
|
|
140
|
+
'es/duxt/search.json',
|
|
141
|
+
'es/duxt/shortcuts.json',
|
|
142
|
+
'es/duxt/theme.json',
|
|
143
|
+
'es/duxt/toc.json',
|
|
144
|
+
'es/duxt/version.json'
|
|
145
|
+
]
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
code: 'fr-FR' as const,
|
|
149
|
+
language: 'fr-FR',
|
|
150
|
+
name: 'Français',
|
|
151
|
+
files: [
|
|
152
|
+
'fr/duxt/changelog.json',
|
|
153
|
+
'fr/duxt/code.json',
|
|
154
|
+
'fr/duxt/devtools.json',
|
|
155
|
+
'fr/duxt/defaults.json',
|
|
156
|
+
'fr/duxt/error.json',
|
|
157
|
+
'fr/duxt/footer.json',
|
|
158
|
+
'fr/duxt/locale.json',
|
|
159
|
+
'fr/duxt/nav.json',
|
|
160
|
+
'fr/duxt/openapi.json',
|
|
161
|
+
'fr/duxt/page.json',
|
|
162
|
+
'fr/duxt/search.json',
|
|
163
|
+
'fr/duxt/shortcuts.json',
|
|
164
|
+
'fr/duxt/theme.json',
|
|
165
|
+
'fr/duxt/toc.json',
|
|
166
|
+
'fr/duxt/version.json'
|
|
167
|
+
]
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
code: 'pt-PT' as const,
|
|
171
|
+
language: 'pt-PT',
|
|
172
|
+
name: 'Português',
|
|
173
|
+
files: [
|
|
174
|
+
'pt/duxt/changelog.json',
|
|
175
|
+
'pt/duxt/code.json',
|
|
176
|
+
'pt/duxt/devtools.json',
|
|
177
|
+
'pt/duxt/defaults.json',
|
|
178
|
+
'pt/duxt/error.json',
|
|
179
|
+
'pt/duxt/footer.json',
|
|
180
|
+
'pt/duxt/locale.json',
|
|
181
|
+
'pt/duxt/nav.json',
|
|
182
|
+
'pt/duxt/openapi.json',
|
|
183
|
+
'pt/duxt/page.json',
|
|
184
|
+
'pt/duxt/search.json',
|
|
185
|
+
'pt/duxt/shortcuts.json',
|
|
186
|
+
'pt/duxt/theme.json',
|
|
187
|
+
'pt/duxt/toc.json',
|
|
188
|
+
'pt/duxt/version.json'
|
|
189
|
+
]
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
code: 'pt-BR' as const,
|
|
193
|
+
language: 'pt-BR',
|
|
194
|
+
name: 'Português (Brasil)',
|
|
195
|
+
files: [
|
|
196
|
+
'pt/duxt/changelog.json',
|
|
197
|
+
'pt/duxt/code.json',
|
|
198
|
+
'pt/duxt/devtools.json',
|
|
199
|
+
'pt/duxt/defaults.json',
|
|
200
|
+
'pt/duxt/error.json',
|
|
201
|
+
'pt/duxt/footer.json',
|
|
202
|
+
'pt/duxt/locale.json',
|
|
203
|
+
'pt/duxt/nav.json',
|
|
204
|
+
'pt/duxt/openapi.json',
|
|
205
|
+
'pt/duxt/page.json',
|
|
206
|
+
'pt/duxt/search.json',
|
|
207
|
+
'pt/duxt/shortcuts.json',
|
|
208
|
+
'pt/duxt/theme.json',
|
|
209
|
+
'pt/duxt/toc.json',
|
|
210
|
+
'pt/duxt/version.json',
|
|
211
|
+
'pt-BR/duxt/error.json',
|
|
212
|
+
'pt-BR/duxt/nav.json',
|
|
213
|
+
'pt-BR/duxt/page.json',
|
|
214
|
+
'pt-BR/duxt/search.json',
|
|
215
|
+
'pt-BR/duxt/version.json'
|
|
216
|
+
]
|
|
217
|
+
}
|
|
218
|
+
];
|
|
219
|
+
|
|
220
|
+
// The layer itself. A consumer gets all of this by extending '@kirchdev/duxt',
|
|
221
|
+
// which resolves through package.json's `main` to this file.
|
|
222
|
+
export default defineNuxtConfig({
|
|
223
|
+
modules: [
|
|
224
|
+
// First: it narrows the locale list before @nuxtjs/i18n reads it, and
|
|
225
|
+
// resolves the source manifest before anything queries a collection.
|
|
226
|
+
layer('./modules/config.ts'),
|
|
227
|
+
|
|
228
|
+
// Reads what Content parses and reports what the build would otherwise
|
|
229
|
+
// swallow — an empty collection, a folder shadowed by a prefix, a link
|
|
230
|
+
// pointing nowhere, a page with no title.
|
|
231
|
+
layer('./modules/validate.ts'),
|
|
232
|
+
|
|
233
|
+
// A devtools tab showing the resolved sources — dev only, and a no-op
|
|
234
|
+
// outside it.
|
|
235
|
+
layer('./modules/devtools.ts'),
|
|
236
|
+
|
|
237
|
+
// "Last updated" and the contributor list, read off each page's own git
|
|
238
|
+
// history at parse time.
|
|
239
|
+
layer('./modules/git-meta.ts'),
|
|
240
|
+
|
|
241
|
+
// `redirectFrom:` in a page's frontmatter, under every prefix the site
|
|
242
|
+
// serves that page at.
|
|
243
|
+
layer('./modules/redirects.ts'),
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* The SEO half, BEFORE Content on purpose.
|
|
247
|
+
*
|
|
248
|
+
* @nuxtjs/sitemap wires itself into Content's collections, and it says so
|
|
249
|
+
* out loud when it is loaded second — "this may cause issues with the
|
|
250
|
+
* integration". It does: the sitemap then lists the site's routes and not
|
|
251
|
+
* one documentation page. The bundle loads its modules in its own order,
|
|
252
|
+
* so the whole bundle goes here rather than three named modules.
|
|
253
|
+
*
|
|
254
|
+
* `@nuxtjs/seo` is an ALIAS, not a wrapper — its own documentation says it
|
|
255
|
+
* "contains no logic of its own". What it buys is the four modules this
|
|
256
|
+
* layer used to do by hand: schema.org from `nuxt-schema-org`, the
|
|
257
|
+
* automatic canonical and og/twitter tags from `nuxt-seo-utils`, the link
|
|
258
|
+
* check, and `nuxt-site-config` as the one place `site.url` is read from.
|
|
259
|
+
* It also completes the shared devtools panel, which every one of these
|
|
260
|
+
* modules feeds and which lists the ones that are missing.
|
|
261
|
+
*
|
|
262
|
+
* They all read `site.url`, which the duxt module fills in from
|
|
263
|
+
* `i18n.baseUrl` so a consumer states its origin once rather than five
|
|
264
|
+
* times; without one they degrade to relative output rather than inventing
|
|
265
|
+
* a domain.
|
|
266
|
+
*/
|
|
267
|
+
'@nuxtjs/seo',
|
|
268
|
+
'@nuxt/image',
|
|
269
|
+
|
|
270
|
+
'@nuxt/content',
|
|
271
|
+
'@nuxt/icon',
|
|
272
|
+
'@nuxtjs/color-mode',
|
|
273
|
+
'shadcn-nuxt',
|
|
274
|
+
'@nuxtjs/mcp-toolkit',
|
|
275
|
+
'@nuxtjs/i18n'
|
|
276
|
+
],
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* NO `hooks` KEY, AND NO `serverDir`. The layer's own `server/` is found by
|
|
280
|
+
* Nitro without either.
|
|
281
|
+
*
|
|
282
|
+
* These routes used to be pushed by hand from a `nitro:config` hook, on the
|
|
283
|
+
* belief that only the consumer's server directory is scanned. The
|
|
284
|
+
* production bundle disproves it: its handler list carried every one of them
|
|
285
|
+
* TWICE — once lazily, in alphabetical order, from a filesystem scan of this
|
|
286
|
+
* layer's `server/routes/`, and once eagerly in the order the hook pushed
|
|
287
|
+
* them. The middleware too.
|
|
288
|
+
*
|
|
289
|
+
* So Nitro scans `server/routes/` and `server/middleware/` in EVERY layer,
|
|
290
|
+
* derives the route from the file name and the method from its `.get`
|
|
291
|
+
* suffix, and loads each handler on demand. A consumer's own `server/` is
|
|
292
|
+
* merged rather than replaced, which is what the hook was there to protect
|
|
293
|
+
* and never had to.
|
|
294
|
+
*
|
|
295
|
+
* Left as a comment rather than deleted: the next person to add a route here
|
|
296
|
+
* will look for the place it is registered, and the answer is that there
|
|
297
|
+
* isn't one.
|
|
298
|
+
*/
|
|
299
|
+
|
|
300
|
+
// A real MCP server at /mcp, through the official SDK, instead of a JSON
|
|
301
|
+
// endpoint someone else has to wrap. Tools live in server/mcp/tools.
|
|
302
|
+
// No `name`: the module's own default is the empty string, so
|
|
303
|
+
// `modules/config.ts` derives one from the site's own title instead. Left as
|
|
304
|
+
// a literal here it published duxt's name from every downstream site.
|
|
305
|
+
mcp: {
|
|
306
|
+
description: 'The documentation this site publishes, readable by an agent.',
|
|
307
|
+
instructions:
|
|
308
|
+
'Call list_pages for the table of contents, search_docs to find a page by ' +
|
|
309
|
+
'term, and read_page for the full text of one page.'
|
|
310
|
+
},
|
|
311
|
+
|
|
312
|
+
nitro: wasm ? { externals: { traceInclude: [wasm] } } : {},
|
|
313
|
+
|
|
314
|
+
css: [layer('./app/assets/css/duxt.css')],
|
|
315
|
+
|
|
316
|
+
// '@' belongs to whoever extends the layer. Imports inside the layer use
|
|
317
|
+
// '@duxt' so they resolve here regardless of the consumer's own aliases.
|
|
318
|
+
alias: {
|
|
319
|
+
'@duxt': layer('./app')
|
|
320
|
+
},
|
|
321
|
+
|
|
322
|
+
content: {
|
|
323
|
+
build: {
|
|
324
|
+
markdown: {
|
|
325
|
+
// Without an explicit theme Content ships no highlighter at all, and
|
|
326
|
+
// every fence renders as flat text. Two themes so the switch follows
|
|
327
|
+
// the site's own light/dark class rather than a media query.
|
|
328
|
+
highlight: {
|
|
329
|
+
theme: {
|
|
330
|
+
default: 'github-light',
|
|
331
|
+
dark: 'github-dark'
|
|
332
|
+
},
|
|
333
|
+
langs: highlightLangs
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
|
|
338
|
+
// Content's default driver, better-sqlite3, is a native addon compiled
|
|
339
|
+
// through node-gyp. Node 24 ships node:sqlite, so no driver package is
|
|
340
|
+
// needed — see CLAUDE.md for the fallback if this flag ever goes away.
|
|
341
|
+
experimental: {
|
|
342
|
+
nativeSqlite: true
|
|
343
|
+
}
|
|
344
|
+
},
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* The sitemap lists pages, not versions of pages.
|
|
348
|
+
*
|
|
349
|
+
* `exclude` is filled in by the duxt module from the resolved manifest — a
|
|
350
|
+
* version that is not the default carries `noindex` and a canonical pointing
|
|
351
|
+
* elsewhere, so listing it here would ask a crawler to fetch exactly what the
|
|
352
|
+
* page then tells it to drop. Same for an `eol` version, which is excluded
|
|
353
|
+
* whether or not it is the default.
|
|
354
|
+
*/
|
|
355
|
+
// The devtools previews in `public/` are fixtures for one reference page, not
|
|
356
|
+
// pages of anybody's site. Every consumer serves them, because Nuxt serves
|
|
357
|
+
// every layer's `public/` — and none of them wants ten documents titled
|
|
358
|
+
// "duxt — Sources" indexed against their own domain.
|
|
359
|
+
//
|
|
360
|
+
// defu concatenates the list across layers, so a consumer's own `disallow`
|
|
361
|
+
// is added to this rather than replacing it.
|
|
362
|
+
robots: {
|
|
363
|
+
disallow: ['/devtools/']
|
|
364
|
+
},
|
|
365
|
+
|
|
366
|
+
sitemap: {
|
|
367
|
+
// Content pages reach the sitemap through the module's own Content
|
|
368
|
+
// integration; the duxt module adds what the version rules exclude.
|
|
369
|
+
//
|
|
370
|
+
// Partials are the one entry written by hand: they share the pages' schema
|
|
371
|
+
// (see `definePartials`), so the sitemap module treats them as pages, and
|
|
372
|
+
// a block of prose meant to be included in three places is not a page a
|
|
373
|
+
// crawler should be offered.
|
|
374
|
+
exclude: ['/_partials/**', '/*/_partials/**']
|
|
375
|
+
},
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* nuxt-seo-utils, whose defaults are written for a site that sets no head
|
|
379
|
+
* tags of its own. Three of them are wrong HERE, and each for a reason this
|
|
380
|
+
* layer cannot design away.
|
|
381
|
+
*/
|
|
382
|
+
seo: {
|
|
383
|
+
/**
|
|
384
|
+
* A LOCALE PREFIX IS CASE-SENSITIVE. i18n routes this site's locales under
|
|
385
|
+
* their own codes — `/de-DE/guides`, `/pt-BR/guides` — and lowercasing a
|
|
386
|
+
* canonical would point every translated page at a URL that 404s. The
|
|
387
|
+
* option exists for sites whose paths differ only in case; ours do not.
|
|
388
|
+
*/
|
|
389
|
+
canonicalLowercase: false,
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* A title invented from the last slug segment is a title nobody wrote.
|
|
393
|
+
* Every page here carries one from its frontmatter, and `modules/validate`
|
|
394
|
+
* fails the build over a page that does not — so the fallback can only ever
|
|
395
|
+
* mask that check.
|
|
396
|
+
*/
|
|
397
|
+
fallbackTitle: false,
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* `app.vue` owns the title template — it appends the site's own name, which
|
|
401
|
+
* is what a tab and a search result need. Letting site config inject a
|
|
402
|
+
* second one leaves two templates competing over one title.
|
|
403
|
+
*/
|
|
404
|
+
mergeWithSiteConfig: false
|
|
405
|
+
},
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* The link check REPORTS, it does not fail the build: `modules/validate.ts`
|
|
409
|
+
* already fails it over a link pointing nowhere, and it is the one that knows
|
|
410
|
+
* about versions and locale fallbacks. Two gates over one rule means the
|
|
411
|
+
* looser one decides when a build breaks, which is the wrong way round.
|
|
412
|
+
*
|
|
413
|
+
* What the module adds over that is the devtools panel and the live check
|
|
414
|
+
* while writing, which is where a broken link is cheapest to fix.
|
|
415
|
+
*/
|
|
416
|
+
linkChecker: {
|
|
417
|
+
failOnError: false,
|
|
418
|
+
excludeLinks: ['/devtools/**']
|
|
419
|
+
},
|
|
420
|
+
|
|
421
|
+
colorMode: {
|
|
422
|
+
// shadcn switches on a `dark` class, not a data attribute or a media query.
|
|
423
|
+
classSuffix: '',
|
|
424
|
+
preference: 'system',
|
|
425
|
+
fallback: 'light'
|
|
426
|
+
},
|
|
427
|
+
|
|
428
|
+
shadcn: {
|
|
429
|
+
// PREFIXED, and deliberately. Without one the layer auto-imports `Button`,
|
|
430
|
+
// `Input`, `Card` and a hundred more into every site that extends it —
|
|
431
|
+
// ordinary words a consumer is likely to want for a component of their own,
|
|
432
|
+
// and a collision resolves silently in favour of whichever Nuxt registered
|
|
433
|
+
// last. `Ui` says where a component comes from at the call site and keeps
|
|
434
|
+
// the plain names free for the site being built.
|
|
435
|
+
prefix: 'Ui',
|
|
436
|
+
componentDir: layer('./app/components/ui')
|
|
437
|
+
},
|
|
438
|
+
|
|
439
|
+
icon: {
|
|
440
|
+
// SVG mode, not the default span: shadcn's Alert, Button and Sidebar all
|
|
441
|
+
// style their icon slot with `>svg` selectors, which never match a span.
|
|
442
|
+
mode: 'svg',
|
|
443
|
+
|
|
444
|
+
// Inline the icons actually used into the client bundle instead of fetching
|
|
445
|
+
// them per collection after hydration — no roundtrip, no icon flash.
|
|
446
|
+
clientBundle: {
|
|
447
|
+
// Vue and TS files, plus the MARKDOWN a docs site is made of. Without the
|
|
448
|
+
// second glob an icon named only in a page's frontmatter — which is where
|
|
449
|
+
// a documentation tree names most of its icons — is missing from the
|
|
450
|
+
// bundle, so it is absent from the server-rendered HTML and arrives, if
|
|
451
|
+
// at all, over the network after hydration. `**/*.md` reaches the pages
|
|
452
|
+
// of the consumer's own repository; a source downloaded from another one
|
|
453
|
+
// is cached outside the scan and still falls back to the API.
|
|
454
|
+
scan: {
|
|
455
|
+
globInclude: ['**/*.{vue,jsx,tsx,ts,js,mjs}', '**/*.md']
|
|
456
|
+
},
|
|
457
|
+
sizeLimitKb: 512,
|
|
458
|
+
|
|
459
|
+
// The locale switcher names its flags at runtime (`flag:${code}-4x3`), so
|
|
460
|
+
// the scanner above cannot see them and they would be fetched over the
|
|
461
|
+
// network after hydration instead. Derived from `locales` rather than
|
|
462
|
+
// listed by hand: a new locale brings its flag along by itself.
|
|
463
|
+
icons: locales.map(
|
|
464
|
+
(locale) => `flag:${locale.code.split('-')[1]!.toLowerCase()}-4x3`
|
|
465
|
+
)
|
|
466
|
+
}
|
|
467
|
+
},
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* The layer's own interface, translated. NOT the Markdown — that is a
|
|
471
|
+
* separate question and deliberately untouched here.
|
|
472
|
+
*
|
|
473
|
+
* `strategy: 'prefix_except_default'` is the load-bearing choice. duxt serves
|
|
474
|
+
* `/getting-started` today, and `prefix` would move that to
|
|
475
|
+
* `/en-GB/getting-started` for every consumer that has one — a breaking
|
|
476
|
+
* change to the URLs docs are reached by, paid by the many single-locale
|
|
477
|
+
* consumers to benefit the few multilingual ones. It is also what VitePress,
|
|
478
|
+
* Starlight and Docusaurus all do. A consumer whose site has no leading
|
|
479
|
+
* language writes `i18n: { strategy: 'prefix' }` and gets the symmetric
|
|
480
|
+
* scheme in one line.
|
|
481
|
+
*
|
|
482
|
+
* The price: `defaultLocale` becomes URL-relevant. Changing it later moves
|
|
483
|
+
* every page in both directions at once. Set it once, then leave it.
|
|
484
|
+
*
|
|
485
|
+
* `langDir` stays RELATIVE on purpose, against this layer's own i18n/
|
|
486
|
+
* directory. Everything else layer-relative in this file goes through
|
|
487
|
+
* `layer()`, but i18n resolves langDir per layer itself — that is what its
|
|
488
|
+
* layers support is — and handing it an absolute path opts out of the
|
|
489
|
+
* merging that lets a consumer override a single string.
|
|
490
|
+
*/
|
|
491
|
+
i18n: {
|
|
492
|
+
locales,
|
|
493
|
+
defaultLocale: 'en-GB',
|
|
494
|
+
langDir: 'locales',
|
|
495
|
+
strategy: 'prefix_except_default',
|
|
496
|
+
vueI18n: 'i18n.config.ts',
|
|
497
|
+
detectBrowserLanguage: {
|
|
498
|
+
fallbackLocale: 'en-GB',
|
|
499
|
+
useCookie: true,
|
|
500
|
+
cookieKey: 'duxt_locale',
|
|
501
|
+
cookieSecure: true,
|
|
502
|
+
// An explicit URL stays authoritative: /de-DE/guide shared into a chat
|
|
503
|
+
// must still be German for whoever opens it. Only '/' follows the
|
|
504
|
+
// browser's preference.
|
|
505
|
+
redirectOn: 'root',
|
|
506
|
+
alwaysRedirect: false
|
|
507
|
+
}
|
|
508
|
+
},
|
|
509
|
+
|
|
510
|
+
vite: {
|
|
511
|
+
plugins: [tailwindcss()],
|
|
512
|
+
|
|
513
|
+
ssr: {
|
|
514
|
+
// reka-ui is a dependency of the LAYER, so Nitro externalises it for SSR
|
|
515
|
+
// and the server imports a different copy than the client bundle uses.
|
|
516
|
+
// Its provide/inject then never matches and SSR dies with a null
|
|
517
|
+
// instance. Inlining it keeps one copy on both sides.
|
|
518
|
+
noExternal: ['reka-ui', 'vue-sonner']
|
|
519
|
+
},
|
|
520
|
+
|
|
521
|
+
resolve: {
|
|
522
|
+
// Force singleton resolution. The layer and the project extending it can
|
|
523
|
+
// each resolve their own copy of these, and reka-ui's provide/inject then
|
|
524
|
+
// stops matching across the two — which only fails in a production build,
|
|
525
|
+
// where dev's shared module graph is gone. gildstone carries the same
|
|
526
|
+
// dedupe for the same class of bug.
|
|
527
|
+
dedupe: ['vue', 'reka-ui', 'vue-sonner']
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
});
|