@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.
Files changed (401) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +151 -0
  3. package/app/app.config.ts +13 -0
  4. package/app/app.vue +122 -0
  5. package/app/assets/css/duxt.css +555 -0
  6. package/app/assets/css/typeset.css +498 -0
  7. package/app/components/DuxtBrand.vue +53 -0
  8. package/app/components/DuxtBreadcrumb.vue +37 -0
  9. package/app/components/DuxtCodeBlock.vue +143 -0
  10. package/app/components/DuxtCopyPage.vue +117 -0
  11. package/app/components/DuxtFooter.vue +86 -0
  12. package/app/components/DuxtHeader.vue +496 -0
  13. package/app/components/DuxtJsonEditor.vue +359 -0
  14. package/app/components/DuxtLandingProse.vue +90 -0
  15. package/app/components/DuxtLandingShowcase.vue +295 -0
  16. package/app/components/DuxtLiveWindow.vue +343 -0
  17. package/app/components/DuxtLocale.vue +86 -0
  18. package/app/components/DuxtMetaList.vue +76 -0
  19. package/app/components/DuxtNavigation.vue +94 -0
  20. package/app/components/DuxtNavigationLink.vue +41 -0
  21. package/app/components/DuxtOpenApiCallbacks.vue +92 -0
  22. package/app/components/DuxtOpenApiClient.vue +1339 -0
  23. package/app/components/DuxtOpenApiMedia.vue +108 -0
  24. package/app/components/DuxtOpenApiMethod.vue +59 -0
  25. package/app/components/DuxtOpenApiParameters.vue +114 -0
  26. package/app/components/DuxtOpenApiResponses.vue +109 -0
  27. package/app/components/DuxtOpenApiSchema.vue +365 -0
  28. package/app/components/DuxtOpenApiSecurity.vue +115 -0
  29. package/app/components/DuxtPageFeedback.vue +56 -0
  30. package/app/components/DuxtPageInfo.vue +194 -0
  31. package/app/components/DuxtPageNav.vue +93 -0
  32. package/app/components/DuxtPreviewSkeleton.vue +262 -0
  33. package/app/components/DuxtProgress.vue +45 -0
  34. package/app/components/DuxtSearch.vue +271 -0
  35. package/app/components/DuxtSections.vue +65 -0
  36. package/app/components/DuxtShortcuts.vue +46 -0
  37. package/app/components/DuxtSkipLink.vue +34 -0
  38. package/app/components/DuxtToc.vue +86 -0
  39. package/app/components/DuxtTranslationBanner.vue +64 -0
  40. package/app/components/DuxtVersion.vue +168 -0
  41. package/app/components/DuxtVersionBanner.vue +109 -0
  42. package/app/components/OgImage/Duxt.satori.vue +82 -0
  43. package/app/components/content/Accordion.vue +37 -0
  44. package/app/components/content/AccordionItem.vue +46 -0
  45. package/app/components/content/Callout.vue +58 -0
  46. package/app/components/content/ChangelogGroup.vue +91 -0
  47. package/app/components/content/ChangelogReleases.vue +520 -0
  48. package/app/components/content/CodeGroup.vue +183 -0
  49. package/app/components/content/DevtoolsPanel.vue +107 -0
  50. package/app/components/content/Field.vue +50 -0
  51. package/app/components/content/FieldGroup.vue +8 -0
  52. package/app/components/content/FileTree.vue +92 -0
  53. package/app/components/content/Mermaid.vue +70 -0
  54. package/app/components/content/OpenApiOperation.vue +185 -0
  55. package/app/components/content/OpenApiOperations.vue +72 -0
  56. package/app/components/content/OpenApiOverview.vue +302 -0
  57. package/app/components/content/PackageManagers.vue +187 -0
  58. package/app/components/content/PageCards.vue +48 -0
  59. package/app/components/content/Partial.vue +65 -0
  60. package/app/components/content/Preview.vue +173 -0
  61. package/app/components/content/ProseA.vue +55 -0
  62. package/app/components/content/ProseH2.vue +53 -0
  63. package/app/components/content/ProseH3.vue +53 -0
  64. package/app/components/content/ProseH4.vue +53 -0
  65. package/app/components/content/ProseImg.vue +87 -0
  66. package/app/components/content/ProsePre.vue +58 -0
  67. package/app/components/content/ProseTable.vue +11 -0
  68. package/app/components/content/Since.vue +21 -0
  69. package/app/components/content/Steps.vue +20 -0
  70. package/app/components/content/Tab.vue +23 -0
  71. package/app/components/content/TabGroup.vue +58 -0
  72. package/app/components/ui/alert/Alert.vue +21 -0
  73. package/app/components/ui/alert/AlertDescription.vue +22 -0
  74. package/app/components/ui/alert/AlertTitle.vue +22 -0
  75. package/app/components/ui/alert/index.ts +24 -0
  76. package/app/components/ui/badge/Badge.vue +28 -0
  77. package/app/components/ui/badge/index.ts +52 -0
  78. package/app/components/ui/breadcrumb/Breadcrumb.vue +13 -0
  79. package/app/components/ui/breadcrumb/BreadcrumbEllipsis.vue +22 -0
  80. package/app/components/ui/breadcrumb/BreadcrumbItem.vue +17 -0
  81. package/app/components/ui/breadcrumb/BreadcrumbLink.vue +24 -0
  82. package/app/components/ui/breadcrumb/BreadcrumbList.vue +22 -0
  83. package/app/components/ui/breadcrumb/BreadcrumbPage.vue +20 -0
  84. package/app/components/ui/breadcrumb/BreadcrumbSeparator.vue +21 -0
  85. package/app/components/ui/breadcrumb/index.ts +7 -0
  86. package/app/components/ui/button/Button.vue +31 -0
  87. package/app/components/ui/button/index.ts +39 -0
  88. package/app/components/ui/card/Card.vue +22 -0
  89. package/app/components/ui/card/CardAction.vue +22 -0
  90. package/app/components/ui/card/CardContent.vue +14 -0
  91. package/app/components/ui/card/CardDescription.vue +17 -0
  92. package/app/components/ui/card/CardFooter.vue +17 -0
  93. package/app/components/ui/card/CardHeader.vue +22 -0
  94. package/app/components/ui/card/CardTitle.vue +17 -0
  95. package/app/components/ui/card/index.ts +7 -0
  96. package/app/components/ui/collapsible/Collapsible.vue +19 -0
  97. package/app/components/ui/collapsible/CollapsibleContent.vue +12 -0
  98. package/app/components/ui/collapsible/CollapsibleTrigger.vue +12 -0
  99. package/app/components/ui/collapsible/index.ts +3 -0
  100. package/app/components/ui/command/Command.vue +98 -0
  101. package/app/components/ui/command/CommandDialog.vue +42 -0
  102. package/app/components/ui/command/CommandEmpty.vue +31 -0
  103. package/app/components/ui/command/CommandGroup.vue +52 -0
  104. package/app/components/ui/command/CommandInput.vue +45 -0
  105. package/app/components/ui/command/CommandItem.vue +85 -0
  106. package/app/components/ui/command/CommandList.vue +32 -0
  107. package/app/components/ui/command/CommandSeparator.vue +23 -0
  108. package/app/components/ui/command/CommandShortcut.vue +19 -0
  109. package/app/components/ui/command/index.ts +29 -0
  110. package/app/components/ui/dialog/Dialog.vue +15 -0
  111. package/app/components/ui/dialog/DialogClose.vue +12 -0
  112. package/app/components/ui/dialog/DialogContent.vue +61 -0
  113. package/app/components/ui/dialog/DialogDescription.vue +25 -0
  114. package/app/components/ui/dialog/DialogFooter.vue +30 -0
  115. package/app/components/ui/dialog/DialogHeader.vue +17 -0
  116. package/app/components/ui/dialog/DialogOverlay.vue +28 -0
  117. package/app/components/ui/dialog/DialogScrollContent.vue +65 -0
  118. package/app/components/ui/dialog/DialogTitle.vue +25 -0
  119. package/app/components/ui/dialog/DialogTrigger.vue +12 -0
  120. package/app/components/ui/dialog/index.ts +10 -0
  121. package/app/components/ui/dropdown-menu/DropdownMenu.vue +19 -0
  122. package/app/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +47 -0
  123. package/app/components/ui/dropdown-menu/DropdownMenuContent.vue +47 -0
  124. package/app/components/ui/dropdown-menu/DropdownMenuGroup.vue +12 -0
  125. package/app/components/ui/dropdown-menu/DropdownMenuItem.vue +41 -0
  126. package/app/components/ui/dropdown-menu/DropdownMenuLabel.vue +27 -0
  127. package/app/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +21 -0
  128. package/app/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +48 -0
  129. package/app/components/ui/dropdown-menu/DropdownMenuSeparator.vue +23 -0
  130. package/app/components/ui/dropdown-menu/DropdownMenuShortcut.vue +19 -0
  131. package/app/components/ui/dropdown-menu/DropdownMenuSub.vue +19 -0
  132. package/app/components/ui/dropdown-menu/DropdownMenuSubContent.vue +34 -0
  133. package/app/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +34 -0
  134. package/app/components/ui/dropdown-menu/DropdownMenuTrigger.vue +17 -0
  135. package/app/components/ui/dropdown-menu/index.ts +16 -0
  136. package/app/components/ui/input/Input.vue +35 -0
  137. package/app/components/ui/input/index.ts +1 -0
  138. package/app/components/ui/navigation-menu/NavigationMenu.vue +42 -0
  139. package/app/components/ui/navigation-menu/NavigationMenuContent.vue +35 -0
  140. package/app/components/ui/navigation-menu/NavigationMenuIndicator.vue +32 -0
  141. package/app/components/ui/navigation-menu/NavigationMenuItem.vue +23 -0
  142. package/app/components/ui/navigation-menu/NavigationMenuLink.vue +30 -0
  143. package/app/components/ui/navigation-menu/NavigationMenuList.vue +30 -0
  144. package/app/components/ui/navigation-menu/NavigationMenuTrigger.vue +31 -0
  145. package/app/components/ui/navigation-menu/NavigationMenuViewport.vue +30 -0
  146. package/app/components/ui/navigation-menu/index.ts +14 -0
  147. package/app/components/ui/scroll-area/ScrollArea.vue +31 -0
  148. package/app/components/ui/scroll-area/ScrollBar.vue +38 -0
  149. package/app/components/ui/scroll-area/index.ts +2 -0
  150. package/app/components/ui/select/Select.vue +15 -0
  151. package/app/components/ui/select/SelectContent.vue +59 -0
  152. package/app/components/ui/select/SelectGroup.vue +19 -0
  153. package/app/components/ui/select/SelectItem.vue +42 -0
  154. package/app/components/ui/select/SelectItemText.vue +12 -0
  155. package/app/components/ui/select/SelectLabel.vue +16 -0
  156. package/app/components/ui/select/SelectScrollDownButton.vue +28 -0
  157. package/app/components/ui/select/SelectScrollUpButton.vue +28 -0
  158. package/app/components/ui/select/SelectSeparator.vue +20 -0
  159. package/app/components/ui/select/SelectTrigger.vue +32 -0
  160. package/app/components/ui/select/SelectValue.vue +12 -0
  161. package/app/components/ui/select/index.ts +11 -0
  162. package/app/components/ui/separator/Separator.vue +30 -0
  163. package/app/components/ui/separator/index.ts +1 -0
  164. package/app/components/ui/sheet/Sheet.vue +15 -0
  165. package/app/components/ui/sheet/SheetClose.vue +12 -0
  166. package/app/components/ui/sheet/SheetContent.vue +68 -0
  167. package/app/components/ui/sheet/SheetDescription.vue +23 -0
  168. package/app/components/ui/sheet/SheetFooter.vue +15 -0
  169. package/app/components/ui/sheet/SheetHeader.vue +15 -0
  170. package/app/components/ui/sheet/SheetOverlay.vue +28 -0
  171. package/app/components/ui/sheet/SheetTitle.vue +23 -0
  172. package/app/components/ui/sheet/SheetTrigger.vue +12 -0
  173. package/app/components/ui/sheet/index.ts +8 -0
  174. package/app/components/ui/sidebar/Sidebar.vue +110 -0
  175. package/app/components/ui/sidebar/SidebarContent.vue +23 -0
  176. package/app/components/ui/sidebar/SidebarFooter.vue +18 -0
  177. package/app/components/ui/sidebar/SidebarGroup.vue +18 -0
  178. package/app/components/ui/sidebar/SidebarGroupAction.vue +31 -0
  179. package/app/components/ui/sidebar/SidebarGroupContent.vue +18 -0
  180. package/app/components/ui/sidebar/SidebarGroupLabel.vue +30 -0
  181. package/app/components/ui/sidebar/SidebarHeader.vue +18 -0
  182. package/app/components/ui/sidebar/SidebarInput.vue +19 -0
  183. package/app/components/ui/sidebar/SidebarInset.vue +23 -0
  184. package/app/components/ui/sidebar/SidebarMenu.vue +18 -0
  185. package/app/components/ui/sidebar/SidebarMenuAction.vue +42 -0
  186. package/app/components/ui/sidebar/SidebarMenuBadge.vue +28 -0
  187. package/app/components/ui/sidebar/SidebarMenuButton.vue +60 -0
  188. package/app/components/ui/sidebar/SidebarMenuButtonChild.vue +36 -0
  189. package/app/components/ui/sidebar/SidebarMenuItem.vue +18 -0
  190. package/app/components/ui/sidebar/SidebarMenuSkeleton.vue +35 -0
  191. package/app/components/ui/sidebar/SidebarMenuSub.vue +24 -0
  192. package/app/components/ui/sidebar/SidebarMenuSubButton.vue +43 -0
  193. package/app/components/ui/sidebar/SidebarMenuSubItem.vue +18 -0
  194. package/app/components/ui/sidebar/SidebarProvider.vue +109 -0
  195. package/app/components/ui/sidebar/SidebarRail.vue +35 -0
  196. package/app/components/ui/sidebar/SidebarSeparator.vue +19 -0
  197. package/app/components/ui/sidebar/SidebarTrigger.vue +26 -0
  198. package/app/components/ui/sidebar/index.ts +62 -0
  199. package/app/components/ui/sidebar/utils.ts +19 -0
  200. package/app/components/ui/skeleton/Skeleton.vue +17 -0
  201. package/app/components/ui/skeleton/index.ts +1 -0
  202. package/app/components/ui/sonner/Sonner.vue +67 -0
  203. package/app/components/ui/sonner/index.ts +1 -0
  204. package/app/components/ui/tabs/Tabs.vue +26 -0
  205. package/app/components/ui/tabs/TabsContent.vue +23 -0
  206. package/app/components/ui/tabs/TabsList.vue +28 -0
  207. package/app/components/ui/tabs/TabsTrigger.vue +30 -0
  208. package/app/components/ui/tabs/index.ts +4 -0
  209. package/app/components/ui/textarea/Textarea.vue +32 -0
  210. package/app/components/ui/textarea/index.ts +1 -0
  211. package/app/components/ui/tooltip/Tooltip.vue +15 -0
  212. package/app/components/ui/tooltip/TooltipContent.vue +49 -0
  213. package/app/components/ui/tooltip/TooltipProvider.vue +14 -0
  214. package/app/components/ui/tooltip/TooltipTrigger.vue +12 -0
  215. package/app/components/ui/tooltip/index.ts +4 -0
  216. package/app/composables/useActiveHeading.ts +90 -0
  217. package/app/composables/useDuxtAnimatedHeight.ts +155 -0
  218. package/app/composables/useDuxtBreadcrumb.ts +60 -0
  219. package/app/composables/useDuxtChoice.ts +28 -0
  220. package/app/composables/useDuxtCollection.ts +89 -0
  221. package/app/composables/useDuxtConfig.ts +47 -0
  222. package/app/composables/useDuxtNavigation.ts +87 -0
  223. package/app/composables/useDuxtPageFocus.ts +30 -0
  224. package/app/composables/useDuxtPath.ts +42 -0
  225. package/app/composables/useDuxtSearch.ts +208 -0
  226. package/app/composables/useDuxtSection.ts +44 -0
  227. package/app/composables/useDuxtSectionRow.ts +49 -0
  228. package/app/composables/useDuxtShortcuts.ts +58 -0
  229. package/app/composables/useDuxtSiteUrl.ts +27 -0
  230. package/app/composables/useDuxtToast.ts +25 -0
  231. package/app/composables/useDuxtVersion.ts +138 -0
  232. package/app/composables/useFuzzySearch.ts +83 -0
  233. package/app/composables/usePackageManager.ts +4 -0
  234. package/app/composables/useRecentPages.ts +52 -0
  235. package/app/error.vue +133 -0
  236. package/app/layouts/changelog.vue +85 -0
  237. package/app/layouts/default.vue +23 -0
  238. package/app/layouts/docs.vue +62 -0
  239. package/app/layouts/reference.vue +85 -0
  240. package/app/lib/utils.ts +7 -0
  241. package/app/middleware/duxt-section-layout.global.ts +57 -0
  242. package/app/pages/[...slug].vue +441 -0
  243. package/app/pages/index.vue +479 -0
  244. package/app/types/duxt.d.ts +955 -0
  245. package/app/utils/aside.ts +16 -0
  246. package/app/utils/changelog.ts +182 -0
  247. package/app/utils/code-highlight.ts +116 -0
  248. package/app/utils/duxt-config.ts +185 -0
  249. package/app/utils/duxt-text.ts +135 -0
  250. package/app/utils/file-icons.ts +62 -0
  251. package/app/utils/generated-sections.ts +190 -0
  252. package/app/utils/generated-toc.ts +216 -0
  253. package/app/utils/heading-link.ts +32 -0
  254. package/app/utils/locale-path.ts +45 -0
  255. package/app/utils/navigation-tree.ts +206 -0
  256. package/app/utils/nearest-page.ts +72 -0
  257. package/app/utils/openapi.ts +1028 -0
  258. package/app/utils/package-command.ts +162 -0
  259. package/app/utils/request-samples.ts +635 -0
  260. package/app/utils/section-scope.ts +97 -0
  261. package/app/utils/sheet-navigation.ts +100 -0
  262. package/app/utils/source-file.ts +84 -0
  263. package/app/utils/version-choices.ts +68 -0
  264. package/app/utils/version-paths.ts +65 -0
  265. package/bin/duxt-report.mjs +45 -0
  266. package/components.json +19 -0
  267. package/content-cache.ts +193 -0
  268. package/content.config.ts +38 -0
  269. package/duxt-app-config.ts +124 -0
  270. package/highlight-langs.ts +68 -0
  271. package/i18n/i18n.config.ts +16 -0
  272. package/i18n/locales/de/duxt/changelog.json +17 -0
  273. package/i18n/locales/de/duxt/code.json +13 -0
  274. package/i18n/locales/de/duxt/defaults.json +22 -0
  275. package/i18n/locales/de/duxt/devtools.json +7 -0
  276. package/i18n/locales/de/duxt/error.json +10 -0
  277. package/i18n/locales/de/duxt/footer.json +7 -0
  278. package/i18n/locales/de/duxt/locale.json +7 -0
  279. package/i18n/locales/de/duxt/nav.json +17 -0
  280. package/i18n/locales/de/duxt/openapi.json +89 -0
  281. package/i18n/locales/de/duxt/page.json +34 -0
  282. package/i18n/locales/de/duxt/search.json +12 -0
  283. package/i18n/locales/de/duxt/shortcuts.json +11 -0
  284. package/i18n/locales/de/duxt/theme.json +7 -0
  285. package/i18n/locales/de/duxt/toc.json +7 -0
  286. package/i18n/locales/de/duxt/version.json +25 -0
  287. package/i18n/locales/en/duxt/changelog.json +17 -0
  288. package/i18n/locales/en/duxt/code.json +13 -0
  289. package/i18n/locales/en/duxt/defaults.json +22 -0
  290. package/i18n/locales/en/duxt/devtools.json +7 -0
  291. package/i18n/locales/en/duxt/error.json +10 -0
  292. package/i18n/locales/en/duxt/footer.json +7 -0
  293. package/i18n/locales/en/duxt/locale.json +7 -0
  294. package/i18n/locales/en/duxt/nav.json +17 -0
  295. package/i18n/locales/en/duxt/openapi.json +89 -0
  296. package/i18n/locales/en/duxt/page.json +34 -0
  297. package/i18n/locales/en/duxt/search.json +12 -0
  298. package/i18n/locales/en/duxt/shortcuts.json +11 -0
  299. package/i18n/locales/en/duxt/theme.json +7 -0
  300. package/i18n/locales/en/duxt/toc.json +7 -0
  301. package/i18n/locales/en/duxt/version.json +25 -0
  302. package/i18n/locales/es/duxt/changelog.json +17 -0
  303. package/i18n/locales/es/duxt/code.json +13 -0
  304. package/i18n/locales/es/duxt/defaults.json +22 -0
  305. package/i18n/locales/es/duxt/devtools.json +7 -0
  306. package/i18n/locales/es/duxt/error.json +10 -0
  307. package/i18n/locales/es/duxt/footer.json +7 -0
  308. package/i18n/locales/es/duxt/locale.json +7 -0
  309. package/i18n/locales/es/duxt/nav.json +17 -0
  310. package/i18n/locales/es/duxt/openapi.json +89 -0
  311. package/i18n/locales/es/duxt/page.json +34 -0
  312. package/i18n/locales/es/duxt/search.json +12 -0
  313. package/i18n/locales/es/duxt/shortcuts.json +11 -0
  314. package/i18n/locales/es/duxt/theme.json +7 -0
  315. package/i18n/locales/es/duxt/toc.json +7 -0
  316. package/i18n/locales/es/duxt/version.json +25 -0
  317. package/i18n/locales/fr/duxt/changelog.json +17 -0
  318. package/i18n/locales/fr/duxt/code.json +13 -0
  319. package/i18n/locales/fr/duxt/defaults.json +22 -0
  320. package/i18n/locales/fr/duxt/devtools.json +7 -0
  321. package/i18n/locales/fr/duxt/error.json +10 -0
  322. package/i18n/locales/fr/duxt/footer.json +7 -0
  323. package/i18n/locales/fr/duxt/locale.json +7 -0
  324. package/i18n/locales/fr/duxt/nav.json +17 -0
  325. package/i18n/locales/fr/duxt/openapi.json +89 -0
  326. package/i18n/locales/fr/duxt/page.json +34 -0
  327. package/i18n/locales/fr/duxt/search.json +12 -0
  328. package/i18n/locales/fr/duxt/shortcuts.json +11 -0
  329. package/i18n/locales/fr/duxt/theme.json +7 -0
  330. package/i18n/locales/fr/duxt/toc.json +7 -0
  331. package/i18n/locales/fr/duxt/version.json +25 -0
  332. package/i18n/locales/pt/duxt/changelog.json +17 -0
  333. package/i18n/locales/pt/duxt/code.json +13 -0
  334. package/i18n/locales/pt/duxt/defaults.json +22 -0
  335. package/i18n/locales/pt/duxt/devtools.json +7 -0
  336. package/i18n/locales/pt/duxt/error.json +10 -0
  337. package/i18n/locales/pt/duxt/footer.json +7 -0
  338. package/i18n/locales/pt/duxt/locale.json +7 -0
  339. package/i18n/locales/pt/duxt/nav.json +17 -0
  340. package/i18n/locales/pt/duxt/openapi.json +89 -0
  341. package/i18n/locales/pt/duxt/page.json +34 -0
  342. package/i18n/locales/pt/duxt/search.json +12 -0
  343. package/i18n/locales/pt/duxt/shortcuts.json +11 -0
  344. package/i18n/locales/pt/duxt/theme.json +7 -0
  345. package/i18n/locales/pt/duxt/toc.json +7 -0
  346. package/i18n/locales/pt/duxt/version.json +25 -0
  347. package/i18n/locales/pt-BR/duxt/error.json +8 -0
  348. package/i18n/locales/pt-BR/duxt/nav.json +10 -0
  349. package/i18n/locales/pt-BR/duxt/page.json +10 -0
  350. package/i18n/locales/pt-BR/duxt/search.json +11 -0
  351. package/i18n/locales/pt-BR/duxt/version.json +13 -0
  352. package/mdc.config.ts +28 -0
  353. package/modules/config.ts +440 -0
  354. package/modules/devtools.ts +126 -0
  355. package/modules/git-meta.ts +349 -0
  356. package/modules/redirects.ts +152 -0
  357. package/modules/validate.ts +137 -0
  358. package/nuxt.config.ts +530 -0
  359. package/openapi-model.ts +358 -0
  360. package/openapi-parse.ts +1052 -0
  361. package/package.json +161 -0
  362. package/public/devtools/cache.html +318 -0
  363. package/public/devtools/checks.html +309 -0
  364. package/public/devtools/config.html +461 -0
  365. package/public/devtools/i18n.html +309 -0
  366. package/public/devtools/pages.html +348 -0
  367. package/public/devtools/paths.html +315 -0
  368. package/public/devtools/redirects.html +309 -0
  369. package/public/devtools/search.html +324 -0
  370. package/public/devtools/sources.html +309 -0
  371. package/public/devtools/versions.html +318 -0
  372. package/report.ts +303 -0
  373. package/repository-root.ts +26 -0
  374. package/section-reports.ts +55 -0
  375. package/sections-changelog.ts +644 -0
  376. package/sections-openapi.ts +450 -0
  377. package/sections-resolve.ts +711 -0
  378. package/sections.ts +157 -0
  379. package/server/devtools/content.ts +120 -0
  380. package/server/devtools/context.ts +38 -0
  381. package/server/devtools/entry-path.ts +30 -0
  382. package/server/devtools/handler.ts +104 -0
  383. package/server/devtools/preview.ts +461 -0
  384. package/server/devtools/render/content.ts +233 -0
  385. package/server/devtools/render/sources.ts +414 -0
  386. package/server/devtools/render/system.ts +352 -0
  387. package/server/devtools/shell.ts +611 -0
  388. package/server/devtools/sources.ts +122 -0
  389. package/server/devtools/system.ts +178 -0
  390. package/server/mcp/tools/list-pages.ts +52 -0
  391. package/server/mcp/tools/read-page.ts +57 -0
  392. package/server/mcp/tools/search-docs.ts +74 -0
  393. package/server/middleware/raw-markdown.ts +86 -0
  394. package/server/routes/llms-full.txt.get.ts +75 -0
  395. package/server/routes/llms.txt.get.ts +63 -0
  396. package/server/routes/rss.xml.get.ts +125 -0
  397. package/server/utils/duxt-server-text.ts +46 -0
  398. package/sources-git.ts +113 -0
  399. package/sources-resolve.ts +908 -0
  400. package/sources.ts +287 -0
  401. package/validate-report.ts +494 -0
@@ -0,0 +1,155 @@
1
+ /**
2
+ * A box whose height FOLLOWS its content instead of switching to it.
3
+ *
4
+ * Two places need this and they need exactly the same thing: the request-sample
5
+ * card, whose `curl` of four lines becomes a Go client of twenty, and
6
+ * `CodeGroup`, whose tabs hold files of different lengths. Both used to change
7
+ * height in a single frame, which moves everything below them at once.
8
+ *
9
+ * MEASURED, because CSS cannot do it. `transition: height` needs two computed
10
+ * values to travel between, and a box that sizes to its content is `auto`
11
+ * before and `auto` after — no change a browser can see. `interpolate-size:
12
+ * allow-keywords` does not help either: it makes `auto` a value a transition
13
+ * can REACH, not one that transitions to itself.
14
+ *
15
+ * A `ResizeObserver` rather than a watcher on whatever changed, and that is the
16
+ * part that matters. Highlighted code arrives asynchronously — the string
17
+ * changes on the click, the markup a tick or two later — so anything measuring
18
+ * straight after the click measures the content on its way out. The observer
19
+ * measures what is actually there, whenever it is there, and catches the other
20
+ * reasons a box resizes too: the window narrowing, a line rewrapping, a font
21
+ * finishing loading.
22
+ */
23
+
24
+ /**
25
+ * The step the height moves in — a line of code plus its leading.
26
+ *
27
+ * A threshold on the CHANGE was the first attempt and it still jumped: below it
28
+ * the box snapped, above it the box slid, and a reader switching tabs got both.
29
+ * A grid removes the small changes instead of deciding what to do about them. A
30
+ * reflow of two pixels lands on the same step and is not a height change at
31
+ * all; a different file is at least one step away and always animates.
32
+ *
33
+ * The buffer it adds is never more than a line's worth of space under the last
34
+ * line.
35
+ */
36
+ const HEIGHT_STEP = 24;
37
+
38
+ /**
39
+ * How long a measurement has to hold still before it counts.
40
+ *
41
+ * Long enough to cover an unmount, a mount and the tick that swaps plain code
42
+ * for highlighted code; short enough that the box does not feel late. Every
43
+ * resize inside the window replaces the one before it, so only the last one is
44
+ * ever acted on.
45
+ */
46
+ const SETTLE_MS = 60;
47
+
48
+ /**
49
+ * How long the content takes to come back once the box is on its way.
50
+ *
51
+ * Shorter than the box's own 300ms on purpose: the point is to be readable
52
+ * again well before the box stops moving, not to make the reader wait out two
53
+ * animations in a row.
54
+ */
55
+ const FADE_MS = 200;
56
+
57
+ export function useDuxtAnimatedHeight(
58
+ shell: Readonly<import('vue').ShallowRef<HTMLElement | null>>,
59
+ body: Readonly<import('vue').ShallowRef<HTMLElement | null>>,
60
+ /** Whether to follow at all — a layout that should size at once passes false. */
61
+ enabled: () => boolean = () => true
62
+ ): void {
63
+ onMounted(() => {
64
+ if (!enabled() || !('ResizeObserver' in window)) return;
65
+
66
+ const box = shell.value;
67
+ const content = body.value;
68
+ if (!box || !content) return;
69
+
70
+ // The box carries the border and `box-sizing: border-box`, so its height
71
+ // has to include what that border takes; the content's height does not.
72
+ const chrome = box.offsetHeight - box.clientHeight;
73
+
74
+ const step = (height: number) =>
75
+ Math.ceil((height + chrome) / HEIGHT_STEP) * HEIGHT_STEP;
76
+
77
+ let last = step(content.offsetHeight);
78
+
79
+ // PIN THE STARTING HEIGHT, without animating to it.
80
+ //
81
+ // Until a height is set the box is `auto`, and `auto` is not a value a
82
+ // transition can travel FROM — so the very first change jumped instead of
83
+ // sliding, however carefully everything after it was handled. Set once, on
84
+ // mount, with the transition off for that one frame.
85
+ box.style.transition = 'none';
86
+ box.style.height = `${last}px`;
87
+ requestAnimationFrame(() => {
88
+ box.style.transition = '';
89
+ });
90
+
91
+ let settle: ReturnType<typeof setTimeout> | undefined;
92
+
93
+ const reduced = window.matchMedia('(prefers-reduced-motion: reduce)');
94
+
95
+ const observer = new ResizeObserver(() => {
96
+ const next = step(content.offsetHeight);
97
+ if (next === last) return;
98
+
99
+ // THE CONTENT FADES WHILE THE BOX TRAVELS.
100
+ //
101
+ // The new panel is there the instant the tab is clicked, and until the
102
+ // box has grown to fit it, `overflow-hidden` cuts it off — a taller
103
+ // sample appeared with its last lines sliced away for the length of the
104
+ // animation. Hidden for that moment and faded back in as the box arrives,
105
+ // there is nothing cut off to see: what a reader watches is one sample
106
+ // replacing another, not a box catching up with its contents.
107
+ //
108
+ // Set with the transition off, so it is instant going out and animated
109
+ // coming back — a fade in both directions would be twice as long a wait
110
+ // for the same effect.
111
+ if (!reduced.matches) {
112
+ content.style.transition = 'none';
113
+ content.style.opacity = '0';
114
+ }
115
+
116
+ // ONLY THE VALUE IT SETTLES ON, never the ones on the way.
117
+ //
118
+ // A tab change is not one resize, it is several: the old panel unmounts,
119
+ // leaving nothing for a frame; the new one mounts unhighlighted; the
120
+ // highlighted markup replaces it a tick later. Followed literally, the box
121
+ // collapsed to nothing, sprang open at one size and slid to another —
122
+ // which is the "the tab disappears first, then it expands" of it.
123
+ //
124
+ // Waiting for the measurement to hold still skips all of that: one
125
+ // animation, from the height before the click to the height after it.
126
+ clearTimeout(settle);
127
+ settle = setTimeout(() => {
128
+ const settled = step(content.offsetHeight);
129
+
130
+ if (settled !== last) {
131
+ last = settled;
132
+ box.style.height = `${settled}px`;
133
+ }
134
+
135
+ if (!reduced.matches) {
136
+ requestAnimationFrame(() => {
137
+ content.style.transition = `opacity ${FADE_MS}ms ease-out`;
138
+ content.style.opacity = '1';
139
+ });
140
+ }
141
+ }, SETTLE_MS);
142
+ });
143
+
144
+ observer.observe(content);
145
+
146
+ onBeforeUnmount(() => {
147
+ observer.disconnect();
148
+ clearTimeout(settle);
149
+ box.style.height = '';
150
+ box.style.transition = '';
151
+ content.style.opacity = '';
152
+ content.style.transition = '';
153
+ });
154
+ });
155
+ }
@@ -0,0 +1,60 @@
1
+ import type { ContentNavigationItem } from '@nuxt/content';
2
+ import type { MaybeRefOrGetter } from 'vue';
3
+
4
+ /**
5
+ * The trail from the section down to a page.
6
+ *
7
+ * Lives in a composable rather than in `DuxtBreadcrumb` because two things want
8
+ * it: the component draws it, and the page emits it as `BreadcrumbList`
9
+ * JSON-LD. Computing it twice is how the drawn trail and the structured one
10
+ * would come to disagree.
11
+ */
12
+ export async function useDuxtBreadcrumb(path: MaybeRefOrGetter<string>) {
13
+ // EVERY composable call happens before the await, deliberately. This is a
14
+ // plain async function, not a `<script setup>` block, so nothing restores the
15
+ // Nuxt instance after an await inside it — a call placed below one dies with
16
+ // E1001 and takes the whole page render with it. `useAsyncData`'s return is
17
+ // awaitable as well as reactive, which is what lets the fetch be started here
18
+ // and waited for at the end.
19
+ const navigation = useDuxtNavigation();
20
+ const { source } = useDuxtCollection();
21
+ const { section } = useDuxtSection(navigation.data);
22
+
23
+ const trail = computed<ContentNavigationItem[]>(() => {
24
+ const current = toValue(path);
25
+
26
+ // The trail starts at the section — the entry the reader clicked in the row
27
+ // above — and continues with what lies below the source's own prefix.
28
+ const below = trailBelowPrefix(
29
+ navigation.data.value ?? [],
30
+ current,
31
+ source.value?.prefix ?? ''
32
+ );
33
+
34
+ const head = section.value?.to
35
+ ? [
36
+ {
37
+ title: section.value.label,
38
+ path: section.value.to
39
+ } as ContentNavigationItem
40
+ ]
41
+ : [];
42
+
43
+ // A section's index page is the section: both carry `/duxt/getting-started`,
44
+ // so the trail listed the same destination twice under two names — the
45
+ // config's label and the page's own title. Keep the first of each path.
46
+ const seen = new Set<string>();
47
+
48
+ return [...head, ...below].filter((item) => {
49
+ const itemPath = item.path ?? '';
50
+ if (seen.has(itemPath)) return false;
51
+
52
+ seen.add(itemPath);
53
+ return true;
54
+ });
55
+ });
56
+
57
+ await navigation;
58
+
59
+ return trail;
60
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * A choice the reader made, remembered across pages.
3
+ *
4
+ * A cookie rather than localStorage, and the reason is the jump: storage is
5
+ * readable only in the browser, so the server always renders the default and
6
+ * the control visibly switches after hydration. Reading it earlier does not
7
+ * help — the server has already sent the wrong markup. A cookie travels with
8
+ * the request, so the first byte is already correct.
9
+ *
10
+ * Still privacy-clean: first-party, no identifier, no analytics, a value the
11
+ * reader set by clicking a tab. Under GDPR/ePrivacy that is a functional
12
+ * preference the reader asked for, not something needing consent — the same
13
+ * category as a language or theme choice. SameSite=Lax keeps it off cross-site
14
+ * requests, and it expires after a year.
15
+ *
16
+ * ONE PER KIND OF CONTROL, never one per instance: a reader who picked `pnpm`
17
+ * on the install page means it on every other page, and the same is true of
18
+ * `curl` over `fetch` and of the form over raw JSON. A component that stores
19
+ * its own answer per block asks the same question again three screens later.
20
+ */
21
+ export function useDuxtChoice(name: string) {
22
+ return useCookie<string | undefined>(`duxt-${name}`, {
23
+ sameSite: 'lax',
24
+ maxAge: 60 * 60 * 24 * 365,
25
+ // No `secure: true`: it would drop the cookie on a plain-HTTP preview.
26
+ default: () => undefined
27
+ });
28
+ }
@@ -0,0 +1,89 @@
1
+ import { sourcesForRoute } from '../../sources-resolve';
2
+
3
+ /**
4
+ * Which collection serves the current route.
5
+ *
6
+ * `duxtSources` generates one collection per source, version and language,
7
+ * named after what it serves. Every query in the theme has to ask the right
8
+ * one, or a site with two sources shows nothing at all — the collection a
9
+ * single source produces is called `docs`, and the ones a versioned or
10
+ * translated site produces are not.
11
+ *
12
+ * The choice itself is `sourcesForRoute`, pure and tested beside the resolver,
13
+ * so the devtools path debugger answers with the same chain rather than a
14
+ * second implementation of it. This composable is the reactive wrapper: the
15
+ * route, the locale, and vue-i18n's own fallback — used so the interface and
16
+ * the pages agree on where a missing translation resolves to.
17
+ *
18
+ * The manifest reaches the app through `app.config.ts`, because Content loads
19
+ * `content.config.ts` in its own pass and the app never sees the result. Both
20
+ * come from one call site; see the Sources reference.
21
+ */
22
+ export function useDuxtCollection() {
23
+ const duxt = useDuxtConfig();
24
+ const path = useDuxtPath();
25
+ const { locale, fallbackLocale } = useI18n();
26
+
27
+ const sources = computed(() => duxt.resolvedSources ?? []);
28
+
29
+ /**
30
+ * The collections to try, best first.
31
+ *
32
+ * One entry on a site without translations, which is every site that does
33
+ * not set `locales` — and then this composable behaves exactly as it did
34
+ * before the key existed.
35
+ */
36
+ const chain = computed(() =>
37
+ sourcesForRoute(
38
+ path.value,
39
+ locale.value,
40
+ sources.value,
41
+ fallbackLocale.value as string | string[] | undefined
42
+ )
43
+ );
44
+
45
+ const current = computed(() => chain.value[0]);
46
+
47
+ /**
48
+ * The default-language entry for this prefix.
49
+ *
50
+ * The one collection guaranteed to hold every page, which is what a
51
+ * navigation tree has to be built from — see `overlayTranslations`.
52
+ */
53
+ const base = computed(
54
+ () =>
55
+ sources.value.find(
56
+ (source) =>
57
+ source.prefix === current.value?.prefix && source.isDefaultLocale
58
+ ) ?? current.value
59
+ );
60
+
61
+ /** Cast because the name is data: Content types collections from the config. */
62
+ const name = computed(
63
+ () => (current.value?.collection ?? 'docs') as DuxtCollectionName
64
+ );
65
+
66
+ return {
67
+ collection: name,
68
+ /** The complete tree's collection — the default language for this prefix. */
69
+ baseCollection: computed(
70
+ () => (base.value?.collection ?? 'docs') as DuxtCollectionName
71
+ ),
72
+ source: current,
73
+ /** The collections a missing page falls back to, after the first. */
74
+ fallbacks: computed(() => chain.value.slice(1)),
75
+ /**
76
+ * Whether this site declares translations at all.
77
+ *
78
+ * Without it the fallback banner cannot be told apart from the normal
79
+ * state of a single-language site: there, every locale but the default one
80
+ * is served the same pages by design, and announcing that as a missing
81
+ * translation would put a notice on six of seven languages of every duxt
82
+ * site that never asked for any of this.
83
+ */
84
+ translates: computed(() =>
85
+ sources.value.some((source) => source.locale && !source.isDefaultLocale)
86
+ ),
87
+ sources: computed(() => sources.value)
88
+ };
89
+ }
@@ -0,0 +1,47 @@
1
+ import { toReactive } from '@vueuse/core';
2
+
3
+ /**
4
+ * The layer's config, with the consumer's app.config merged over it and every
5
+ * text field resolved for the current locale.
6
+ *
7
+ * Two things happen here that a component should never have to know about:
8
+ *
9
+ * - Nuxt's own app.config merge APPENDS arrays instead of replacing them, so
10
+ * a consumer overriding `navigation` would get the layer's entries after
11
+ * its own — see `duxt-config.ts`.
12
+ * - a label may be a literal, an i18n key or a per-locale record, and
13
+ * `resolveDuxtTexts` collapses all three to a string — see `duxt-text.ts`.
14
+ * - a generated section's navbar entry is not in the config a human wrote at
15
+ * all; it follows from the resolved manifest AND from where the reader
16
+ * currently is — see `withGeneratedSections`.
17
+ *
18
+ * Resolving here rather than at each call site is the point: `DuxtHeader`,
19
+ * `DuxtFooter` and the rest keep writing `{{ section.label }}` and none of them
20
+ * imports i18n. `toReactive` keeps the result live, so switching language
21
+ * updates the navbar without a full page load.
22
+ */
23
+ export function useDuxtConfig(): DuxtConfigResolved {
24
+ const appConfig = useAppConfig();
25
+ const { t, te, locale } = useI18n();
26
+ // The reader's position, because a section resolved per version has one
27
+ // entry and it is the one for the version being read.
28
+ const path = useDuxtPath();
29
+
30
+ return toReactive(
31
+ computed(() =>
32
+ resolveDuxtTexts(
33
+ // After the merge, because a generated section's entry is APPENDED to
34
+ // whatever list the consumer wrote — see `withGeneratedSections`.
35
+ withGeneratedSections(
36
+ mergeDuxtConfig(appConfig.duxt, duxtDefaults),
37
+ path.value
38
+ ),
39
+ locale.value,
40
+ // `te` first, so a literal never reaches `t` and never produces a
41
+ // "key not found" warning. duxt's OWN missing keys still warn, which a
42
+ // global `missingWarn: false` would have silenced along with them.
43
+ (key) => (te(key) ? t(key) : undefined)
44
+ )
45
+ )
46
+ ) as DuxtConfigResolved;
47
+ }
@@ -0,0 +1,87 @@
1
+ import type { ContentNavigationItem } from '@nuxt/content';
2
+
3
+ /**
4
+ * Which collections the navigation is being fetched from.
5
+ *
6
+ * `useState`, and neither a module-level ref nor a closure, because the two
7
+ * obvious options each break one half of this:
8
+ *
9
+ * - A MODULE-LEVEL ref is one variable shared by every request the server has
10
+ * in flight. With two of them and two awaits in the handler below, one
11
+ * request could read what another had just written — the server then
12
+ * rendered one collection's navigation and the browser another, and the
13
+ * hydration mismatch took the page down with it.
14
+ * - A CLOSURE is a new function on every call, and Nuxt compares handlers by
15
+ * reference: several components asking for the same key with a handler each
16
+ * is NUXT_E3004, after which the first handler wins and the rest are
17
+ * silently ignored.
18
+ *
19
+ * `useState` is per request and reachable from a handler that stays one stable
20
+ * function, which is what both halves need.
21
+ */
22
+ const useNavigationSource = () =>
23
+ useState('duxt-navigation-source', () => ({
24
+ base: 'docs' as DuxtCollectionName,
25
+ translation: 'docs' as DuxtCollectionName
26
+ }));
27
+
28
+ /**
29
+ * The tree of the default language, wearing the translated titles.
30
+ *
31
+ * Never the translation's own tree: a partly translated documentation would
32
+ * then lose every page it has not reached yet — pages the fallback serves
33
+ * perfectly well, so hiding them from the sidebar leaves the reader with no way
34
+ * to them at all. Structure from the original, wording from the translation;
35
+ * see `overlayTranslations`.
36
+ */
37
+ const handler = async (): Promise<ContentNavigationItem[]> => {
38
+ // Read BEFORE the first await: after it, the route may have moved on.
39
+ const { base, translation } = useNavigationSource().value;
40
+
41
+ const tree = await queryCollectionNavigation(base as DuxtCollectionArg, [
42
+ 'icon',
43
+ 'description'
44
+ ]);
45
+
46
+ // Before the overlay: a folder's title comes from its own index page, and a
47
+ // translated index has to be able to carry that up with it.
48
+ const named = titleFoldersFromIndex(tree);
49
+
50
+ if (translation === base) return named;
51
+
52
+ const translated = await queryCollection(translation as DuxtCollectionArg)
53
+ .select('path', 'title', 'description')
54
+ .all();
55
+
56
+ return titleFoldersFromIndex(
57
+ overlayTranslations(
58
+ named,
59
+ new Map(translated.map((page) => [page.path, page]))
60
+ )
61
+ );
62
+ };
63
+
64
+ /**
65
+ * The navigation tree for the collection serving this route.
66
+ *
67
+ * The key tracks both collections: two sources are two trees and must not share
68
+ * one cache entry, and neither may two languages of one.
69
+ */
70
+ export function useDuxtNavigation() {
71
+ const { collection, baseCollection } = useDuxtCollection();
72
+ const source = useNavigationSource();
73
+
74
+ // Kept in step before every fetch, including the ones `watch` triggers.
75
+ watchEffect(() => {
76
+ source.value = {
77
+ base: baseCollection.value,
78
+ translation: collection.value
79
+ };
80
+ });
81
+
82
+ return useAsyncData<ContentNavigationItem[]>(
83
+ () => `duxt-navigation-${baseCollection.value}-${collection.value}`,
84
+ handler,
85
+ { watch: [collection, baseCollection] }
86
+ );
87
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Move focus to the page's own heading after a client-side navigation.
3
+ *
4
+ * Vue Router replaces the view without touching focus, so after a sidebar click
5
+ * the focus is still on the link that was left behind: a keyboard reader's next
6
+ * Tab continues down the sidebar, and a screen reader is told nothing at all
7
+ * about the page that just arrived. Focusing the `<h1>` puts both back at the
8
+ * top of the new document.
9
+ *
10
+ * Not on the first paint. On a full load the focus is already at the start of
11
+ * the document, and taking it would scroll past the header before the reader
12
+ * has seen the page — so only a route CHANGE moves it.
13
+ *
14
+ * The announcement is a separate job, done by `<NuxtRouteAnnouncer>` in
15
+ * `app.vue`, which reads the new title into a live region.
16
+ */
17
+ export function useDuxtPageFocus() {
18
+ const heading = ref<HTMLElement | null>(null);
19
+ const route = useRoute();
20
+
21
+ watch(
22
+ () => route.fullPath,
23
+ async () => {
24
+ await nextTick();
25
+ heading.value?.focus();
26
+ }
27
+ );
28
+
29
+ return heading;
30
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * The path the DOCUMENTATION is at, as opposed to the one the browser shows.
3
+ *
4
+ * The two differ by the locale segment. Read `stripLocalePrefix` for why every
5
+ * content lookup wants this one rather than `route.path`.
6
+ */
7
+ export function useDuxtPath() {
8
+ const route = useRoute();
9
+ const { locales } = useI18n();
10
+
11
+ const codes = computed(() =>
12
+ locales.value.map((entry) =>
13
+ typeof entry === 'string' ? entry : entry.code
14
+ )
15
+ );
16
+
17
+ return computed(() => stripLocalePrefix(route.path, codes.value));
18
+ }
19
+
20
+ /**
21
+ * The counterpart: a documentation path, written back out as a link the
22
+ * current locale can be reached at.
23
+ *
24
+ * Only paths are localised. An absolute URL, a mail link or a bare hash passes
25
+ * through untouched, so the same helper serves the navbar's external entries
26
+ * and the sidebar's internal ones without either side special-casing the other.
27
+ */
28
+ export function useDuxtLink() {
29
+ const localePath = useLocalePath();
30
+
31
+ return (to?: string) => {
32
+ if (!to?.startsWith('/')) return to;
33
+
34
+ // localePath resolves a route, and a trailing anchor is not part of one.
35
+ // Split it off and put it back, so a sidebar entry pointing at a heading
36
+ // keeps pointing at that heading.
37
+ const [path, hash] = to.split('#');
38
+ const localised = localePath(path!);
39
+
40
+ return hash ? `${localised}#${hash}` : localised;
41
+ };
42
+ }