@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,62 @@
1
+ import type { VariantProps } from 'class-variance-authority';
2
+ import type { HTMLAttributes } from 'vue';
3
+ import { cva } from 'class-variance-authority';
4
+
5
+ export interface SidebarProps {
6
+ side?: 'left' | 'right';
7
+ variant?: 'sidebar' | 'floating' | 'inset';
8
+ collapsible?: 'offcanvas' | 'icon' | 'none';
9
+ class?: HTMLAttributes['class'];
10
+ }
11
+
12
+ export { default as Sidebar } from './Sidebar.vue';
13
+ export { default as SidebarContent } from './SidebarContent.vue';
14
+ export { default as SidebarFooter } from './SidebarFooter.vue';
15
+ export { default as SidebarGroup } from './SidebarGroup.vue';
16
+ export { default as SidebarGroupAction } from './SidebarGroupAction.vue';
17
+ export { default as SidebarGroupContent } from './SidebarGroupContent.vue';
18
+ export { default as SidebarGroupLabel } from './SidebarGroupLabel.vue';
19
+ export { default as SidebarHeader } from './SidebarHeader.vue';
20
+ export { default as SidebarInput } from './SidebarInput.vue';
21
+ export { default as SidebarInset } from './SidebarInset.vue';
22
+ export { default as SidebarMenu } from './SidebarMenu.vue';
23
+ export { default as SidebarMenuAction } from './SidebarMenuAction.vue';
24
+ export { default as SidebarMenuBadge } from './SidebarMenuBadge.vue';
25
+ export { default as SidebarMenuButton } from './SidebarMenuButton.vue';
26
+ export { default as SidebarMenuItem } from './SidebarMenuItem.vue';
27
+ export { default as SidebarMenuSkeleton } from './SidebarMenuSkeleton.vue';
28
+ export { default as SidebarMenuSub } from './SidebarMenuSub.vue';
29
+ export { default as SidebarMenuSubButton } from './SidebarMenuSubButton.vue';
30
+ export { default as SidebarMenuSubItem } from './SidebarMenuSubItem.vue';
31
+ export { default as SidebarProvider } from './SidebarProvider.vue';
32
+ export { default as SidebarRail } from './SidebarRail.vue';
33
+ export { default as SidebarSeparator } from './SidebarSeparator.vue';
34
+ export { default as SidebarTrigger } from './SidebarTrigger.vue';
35
+
36
+ export { useSidebar } from './utils';
37
+
38
+ export const sidebarMenuButtonVariants = cva(
39
+ 'peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-hidden ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-data-[sidebar=menu-action]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0',
40
+ {
41
+ variants: {
42
+ variant: {
43
+ default: 'hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',
44
+ outline:
45
+ 'bg-background shadow-[0_0_0_1px_var(--sidebar-border)] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_var(--sidebar-accent)]'
46
+ },
47
+ size: {
48
+ default: 'h-8 text-sm',
49
+ sm: 'h-7 text-xs',
50
+ lg: 'h-12 text-sm group-data-[collapsible=icon]:p-0!'
51
+ }
52
+ },
53
+ defaultVariants: {
54
+ variant: 'default',
55
+ size: 'default'
56
+ }
57
+ }
58
+ );
59
+
60
+ export type SidebarMenuButtonVariants = VariantProps<
61
+ typeof sidebarMenuButtonVariants
62
+ >;
@@ -0,0 +1,19 @@
1
+ import type { ComputedRef, Ref } from 'vue';
2
+ import { createContext } from 'reka-ui';
3
+
4
+ export const SIDEBAR_COOKIE_NAME = 'sidebar_state';
5
+ export const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
6
+ export const SIDEBAR_WIDTH = '16rem';
7
+ export const SIDEBAR_WIDTH_MOBILE = '18rem';
8
+ export const SIDEBAR_WIDTH_ICON = '3rem';
9
+ export const SIDEBAR_KEYBOARD_SHORTCUT = 'b';
10
+
11
+ export const [useSidebar, provideSidebarContext] = createContext<{
12
+ state: ComputedRef<'expanded' | 'collapsed'>;
13
+ open: Ref<boolean>;
14
+ setOpen: (value: boolean) => void;
15
+ isMobile: Ref<boolean>;
16
+ openMobile: Ref<boolean>;
17
+ setOpenMobile: (value: boolean) => void;
18
+ toggleSidebar: () => void;
19
+ }>('Sidebar');
@@ -0,0 +1,17 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from 'vue';
3
+ import { cn } from '@duxt/lib/utils';
4
+
5
+ interface SkeletonProps {
6
+ class?: HTMLAttributes['class'];
7
+ }
8
+
9
+ const props = defineProps<SkeletonProps>();
10
+ </script>
11
+
12
+ <template>
13
+ <div
14
+ data-slot="skeleton"
15
+ :class="cn('animate-pulse rounded-md bg-primary/10', props.class)"
16
+ />
17
+ </template>
@@ -0,0 +1 @@
1
+ export { default as Skeleton } from './Skeleton.vue';
@@ -0,0 +1,67 @@
1
+ <script lang="ts" setup>
2
+ import type { ToasterProps } from 'vue-sonner';
3
+ import { Toaster as Sonner } from 'vue-sonner';
4
+
5
+ // Sonner needs to be told which theme it is in — it does not read the class
6
+ // itself. @nuxtjs/color-mode already tracks that, so the two stay in step.
7
+ const colorMode = useColorMode();
8
+
9
+ const {
10
+ theme: _theme,
11
+ closeButton = true,
12
+ duration = 4000,
13
+ position = 'bottom-right',
14
+ ...forwarded
15
+ } = defineProps<ToasterProps>();
16
+
17
+ const theme = computed(() => (colorMode.value === 'dark' ? 'dark' : 'light'));
18
+ </script>
19
+
20
+ <template>
21
+ <Sonner
22
+ class="toaster group"
23
+ :theme="theme"
24
+ :close-button="closeButton"
25
+ :duration="duration"
26
+ :position="position"
27
+ v-bind="forwarded"
28
+ :toast-options="{
29
+ classes: {
30
+ toast:
31
+ 'group toast group-[.toaster]:bg-popover group-[.toaster]:text-popover-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg group-[.toaster]:rounded-lg group-[.toaster]:px-4 group-[.toaster]:py-3 group-[.toaster]:gap-3',
32
+ icon: 'self-start mt-0.5',
33
+ content: 'grid gap-0.5',
34
+ title: 'font-medium leading-tight text-foreground',
35
+ description:
36
+ 'text-sm leading-relaxed group-[.toast]:text-muted-foreground',
37
+ closeButton:
38
+ 'group-[.toast]:border-border group-[.toast]:bg-popover group-[.toast]:text-muted-foreground hover:group-[.toast]:text-foreground',
39
+ actionButton:
40
+ 'group-[.toast]:bg-primary group-[.toast]:text-primary-foreground',
41
+ cancelButton:
42
+ 'group-[.toast]:bg-muted group-[.toast]:text-muted-foreground'
43
+ }
44
+ }"
45
+ >
46
+ <!-- Icons come from the layer's own icon component and take the semantic
47
+ status tokens, so they follow the theme instead of a fixed palette. -->
48
+ <template #success-icon>
49
+ <Icon name="lucide:circle-check" class="size-4 text-success" />
50
+ </template>
51
+ <template #info-icon>
52
+ <Icon name="lucide:info" class="size-4 text-info" />
53
+ </template>
54
+ <template #warning-icon>
55
+ <Icon name="lucide:triangle-alert" class="size-4 text-warning" />
56
+ </template>
57
+ <template #error-icon>
58
+ <Icon name="lucide:circle-x" class="size-4 text-destructive" />
59
+ </template>
60
+ <template #loading-icon>
61
+ <Icon
62
+ name="lucide:loader-circle"
63
+ class="size-4 animate-spin text-muted-foreground"
64
+ />
65
+ </template>
66
+ </Sonner>
67
+ </template>
@@ -0,0 +1 @@
1
+ export { default as Toaster } from './Sonner.vue';
@@ -0,0 +1,26 @@
1
+ <script setup lang="ts">
2
+ import type { TabsRootEmits, TabsRootProps } from 'reka-ui';
3
+ import type { HTMLAttributes } from 'vue';
4
+ import { reactiveOmit } from '@vueuse/core';
5
+ import { TabsRoot, useForwardPropsEmits } from 'reka-ui';
6
+ import { cn } from '@duxt/lib/utils';
7
+
8
+ const props = defineProps<
9
+ TabsRootProps & { class?: HTMLAttributes['class'] }
10
+ >();
11
+ const emits = defineEmits<TabsRootEmits>();
12
+
13
+ const delegatedProps = reactiveOmit(props, 'class');
14
+ const forwarded = useForwardPropsEmits(delegatedProps, emits);
15
+ </script>
16
+
17
+ <template>
18
+ <TabsRoot
19
+ v-slot="slotProps"
20
+ data-slot="tabs"
21
+ v-bind="forwarded"
22
+ :class="cn('flex flex-col gap-2', props.class)"
23
+ >
24
+ <slot v-bind="slotProps" />
25
+ </TabsRoot>
26
+ </template>
@@ -0,0 +1,23 @@
1
+ <script setup lang="ts">
2
+ import type { TabsContentProps } from 'reka-ui';
3
+ import type { HTMLAttributes } from 'vue';
4
+ import { reactiveOmit } from '@vueuse/core';
5
+ import { TabsContent } from 'reka-ui';
6
+ import { cn } from '@duxt/lib/utils';
7
+
8
+ const props = defineProps<
9
+ TabsContentProps & { class?: HTMLAttributes['class'] }
10
+ >();
11
+
12
+ const delegatedProps = reactiveOmit(props, 'class');
13
+ </script>
14
+
15
+ <template>
16
+ <TabsContent
17
+ data-slot="tabs-content"
18
+ :class="cn('flex-1 outline-none', props.class)"
19
+ v-bind="delegatedProps"
20
+ >
21
+ <slot />
22
+ </TabsContent>
23
+ </template>
@@ -0,0 +1,28 @@
1
+ <script setup lang="ts">
2
+ import type { TabsListProps } from 'reka-ui';
3
+ import type { HTMLAttributes } from 'vue';
4
+ import { reactiveOmit } from '@vueuse/core';
5
+ import { TabsList } from 'reka-ui';
6
+ import { cn } from '@duxt/lib/utils';
7
+
8
+ const props = defineProps<
9
+ TabsListProps & { class?: HTMLAttributes['class'] }
10
+ >();
11
+
12
+ const delegatedProps = reactiveOmit(props, 'class');
13
+ </script>
14
+
15
+ <template>
16
+ <TabsList
17
+ data-slot="tabs-list"
18
+ v-bind="delegatedProps"
19
+ :class="
20
+ cn(
21
+ 'bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-0.75',
22
+ props.class
23
+ )
24
+ "
25
+ >
26
+ <slot />
27
+ </TabsList>
28
+ </template>
@@ -0,0 +1,30 @@
1
+ <script setup lang="ts">
2
+ import type { TabsTriggerProps } from 'reka-ui';
3
+ import type { HTMLAttributes } from 'vue';
4
+ import { reactiveOmit } from '@vueuse/core';
5
+ import { TabsTrigger, useForwardProps } from 'reka-ui';
6
+ import { cn } from '@duxt/lib/utils';
7
+
8
+ const props = defineProps<
9
+ TabsTriggerProps & { class?: HTMLAttributes['class'] }
10
+ >();
11
+
12
+ const delegatedProps = reactiveOmit(props, 'class');
13
+
14
+ const forwardedProps = useForwardProps(delegatedProps);
15
+ </script>
16
+
17
+ <template>
18
+ <TabsTrigger
19
+ data-slot="tabs-trigger"
20
+ :class="
21
+ cn(
22
+ `data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-3 focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4`,
23
+ props.class
24
+ )
25
+ "
26
+ v-bind="forwardedProps"
27
+ >
28
+ <slot />
29
+ </TabsTrigger>
30
+ </template>
@@ -0,0 +1,4 @@
1
+ export { default as Tabs } from './Tabs.vue';
2
+ export { default as TabsContent } from './TabsContent.vue';
3
+ export { default as TabsList } from './TabsList.vue';
4
+ export { default as TabsTrigger } from './TabsTrigger.vue';
@@ -0,0 +1,32 @@
1
+ <script setup lang="ts">
2
+ import type { HTMLAttributes } from 'vue';
3
+ import { useVModel } from '@vueuse/core';
4
+ import { cn } from '@duxt/lib/utils';
5
+
6
+ const props = defineProps<{
7
+ class?: HTMLAttributes['class'];
8
+ defaultValue?: string | number;
9
+ modelValue?: string | number;
10
+ }>();
11
+
12
+ const emits = defineEmits<{
13
+ (e: 'update:modelValue', payload: string | number): void;
14
+ }>();
15
+
16
+ const modelValue = useVModel(props, 'modelValue', emits, {
17
+ passive: true,
18
+ defaultValue: props.defaultValue
19
+ });
20
+ </script>
21
+
22
+ <template>
23
+ <textarea
24
+ v-model="modelValue"
25
+ :class="
26
+ cn(
27
+ 'flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50',
28
+ props.class
29
+ )
30
+ "
31
+ />
32
+ </template>
@@ -0,0 +1 @@
1
+ export { default as Textarea } from './Textarea.vue';
@@ -0,0 +1,15 @@
1
+ <script setup lang="ts">
2
+ import type { TooltipRootEmits, TooltipRootProps } from 'reka-ui';
3
+ import { TooltipRoot, useForwardPropsEmits } from 'reka-ui';
4
+
5
+ const props = defineProps<TooltipRootProps>();
6
+ const emits = defineEmits<TooltipRootEmits>();
7
+
8
+ const forwarded = useForwardPropsEmits(props, emits);
9
+ </script>
10
+
11
+ <template>
12
+ <TooltipRoot v-slot="slotProps" data-slot="tooltip" v-bind="forwarded">
13
+ <slot v-bind="slotProps" />
14
+ </TooltipRoot>
15
+ </template>
@@ -0,0 +1,49 @@
1
+ <script setup lang="ts">
2
+ import type { TooltipContentEmits, TooltipContentProps } from 'reka-ui';
3
+ import type { HTMLAttributes } from 'vue';
4
+ import { reactiveOmit } from '@vueuse/core';
5
+ import {
6
+ TooltipArrow,
7
+ TooltipContent,
8
+ TooltipPortal,
9
+ useForwardPropsEmits
10
+ } from 'reka-ui';
11
+ import { cn } from '@duxt/lib/utils';
12
+
13
+ defineOptions({
14
+ inheritAttrs: false
15
+ });
16
+
17
+ const props = withDefaults(
18
+ defineProps<TooltipContentProps & { class?: HTMLAttributes['class'] }>(),
19
+ {
20
+ sideOffset: 4
21
+ }
22
+ );
23
+
24
+ const emits = defineEmits<TooltipContentEmits>();
25
+
26
+ const delegatedProps = reactiveOmit(props, 'class');
27
+ const forwarded = useForwardPropsEmits(delegatedProps, emits);
28
+ </script>
29
+
30
+ <template>
31
+ <TooltipPortal>
32
+ <TooltipContent
33
+ data-slot="tooltip-content"
34
+ v-bind="{ ...forwarded, ...$attrs }"
35
+ :class="
36
+ cn(
37
+ 'bg-foreground text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit rounded-md px-3 py-1.5 text-xs text-balance',
38
+ props.class
39
+ )
40
+ "
41
+ >
42
+ <slot />
43
+
44
+ <TooltipArrow
45
+ class="bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-xs"
46
+ />
47
+ </TooltipContent>
48
+ </TooltipPortal>
49
+ </template>
@@ -0,0 +1,14 @@
1
+ <script setup lang="ts">
2
+ import type { TooltipProviderProps } from 'reka-ui';
3
+ import { TooltipProvider } from 'reka-ui';
4
+
5
+ const props = withDefaults(defineProps<TooltipProviderProps>(), {
6
+ delayDuration: 0
7
+ });
8
+ </script>
9
+
10
+ <template>
11
+ <TooltipProvider v-bind="props">
12
+ <slot />
13
+ </TooltipProvider>
14
+ </template>
@@ -0,0 +1,12 @@
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 data-slot="tooltip-trigger" v-bind="props">
10
+ <slot />
11
+ </TooltipTrigger>
12
+ </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,90 @@
1
+ /**
2
+ * The heading currently in view, for marking the table of contents.
3
+ *
4
+ * WHY NOT AN INTERSECTIONOBSERVER, which is the obvious tool and was the first
5
+ * implementation here: it reports crossings, not state, so it can only answer
6
+ * "which heading last entered the band". Three cases have no crossing to
7
+ * report, and in all three the marker stuck to the wrong entry:
8
+ *
9
+ * - the last section on the page, whose heading can never reach a trigger
10
+ * line 30% down the viewport because the document runs out of scroll first;
11
+ * - a section longer than the viewport, where the heading has left the band
12
+ * above and the next has not arrived, so nothing fires for a whole screen
13
+ * of reading;
14
+ * - a jump — a hash on load, a click in this very list — which can skip a
15
+ * heading past the band entirely without ever intersecting it.
16
+ *
17
+ * Reading positions instead answers the question directly: the active heading
18
+ * is the LAST one whose top has passed the trigger line. That is true at every
19
+ * scroll offset rather than only at the moments something crossed, so all three
20
+ * cases fall out of it. The bottom of the document is the one place the rule
21
+ * still needs help — see below.
22
+ *
23
+ * The cost is running on scroll rather than on crossings. It is one
24
+ * `getBoundingClientRect` per heading, coalesced into an animation frame, so at
25
+ * most one pass per painted frame however fast the wheel turns.
26
+ */
27
+ export function useActiveHeading(ids: Ref<string[]>) {
28
+ const active = ref<string>();
29
+
30
+ /** Where a heading counts as reached: reading position, not the top edge. */
31
+ const TRIGGER = 96;
32
+
33
+ let frame = 0;
34
+
35
+ function measure() {
36
+ frame = 0;
37
+
38
+ const headings = ids.value
39
+ .map((id) => document.getElementById(id))
40
+ .filter((element): element is HTMLElement => Boolean(element));
41
+
42
+ if (!headings.length) {
43
+ active.value = undefined;
44
+ return;
45
+ }
46
+
47
+ // At the end of the document no further scrolling is possible, so the
48
+ // trigger line can no longer reach what is left. Everything still below it
49
+ // would stay unreachable forever; the last heading is the honest answer.
50
+ const atBottom =
51
+ window.innerHeight + window.scrollY >=
52
+ document.documentElement.scrollHeight - 2;
53
+
54
+ if (atBottom) {
55
+ active.value = headings.at(-1)!.id;
56
+ return;
57
+ }
58
+
59
+ let current = headings[0]!;
60
+ for (const heading of headings) {
61
+ if (heading.getBoundingClientRect().top > TRIGGER) break;
62
+ current = heading;
63
+ }
64
+
65
+ active.value = current.id;
66
+ }
67
+
68
+ function schedule() {
69
+ if (frame) return;
70
+ frame = requestAnimationFrame(measure);
71
+ }
72
+
73
+ onMounted(() => {
74
+ measure();
75
+ window.addEventListener('scroll', schedule, { passive: true });
76
+ window.addEventListener('resize', schedule, { passive: true });
77
+ });
78
+
79
+ // A new page's headings exist only after it renders, and the ids change
80
+ // before the DOM does.
81
+ watch(ids, () => nextTick(measure));
82
+
83
+ onBeforeUnmount(() => {
84
+ if (frame) cancelAnimationFrame(frame);
85
+ window.removeEventListener('scroll', schedule);
86
+ window.removeEventListener('resize', schedule);
87
+ });
88
+
89
+ return active;
90
+ }