@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
package/package.json ADDED
@@ -0,0 +1,161 @@
1
+ {
2
+ "$schema": "https://www.schemastore.org/package.json",
3
+ "name": "@kirchdev/duxt",
4
+ "version": "0.1.0",
5
+ "description": "Nuxt documentation layer on Content v3 — multi-repo, versioned docs from one compact source list.",
6
+ "keywords": [
7
+ "content-v3",
8
+ "docs",
9
+ "documentation",
10
+ "duxt",
11
+ "kirchdev",
12
+ "nuxt",
13
+ "nuxt-content",
14
+ "nuxt-layer",
15
+ "nuxt-module",
16
+ "versioned-docs"
17
+ ],
18
+ "homepage": "https://github.com/kirchDev/duxt#readme",
19
+ "bugs": {
20
+ "url": "https://github.com/kirchDev/duxt/issues"
21
+ },
22
+ "license": "MIT",
23
+ "author": "Titus Kirch <titus.kirch@kirch.dev>",
24
+ "repository": {
25
+ "type": "git",
26
+ "url": "git+https://github.com/kirchDev/duxt.git"
27
+ },
28
+ "bin": {
29
+ "duxt-report": "./bin/duxt-report.mjs"
30
+ },
31
+ "files": [
32
+ "bin",
33
+ "app",
34
+ "components.json",
35
+ "content-cache.ts",
36
+ "content.config.ts",
37
+ "duxt-app-config.ts",
38
+ "highlight-langs.ts",
39
+ "i18n",
40
+ "mdc.config.ts",
41
+ "modules",
42
+ "nuxt.config.ts",
43
+ "openapi-model.ts",
44
+ "openapi-parse.ts",
45
+ "public",
46
+ "report.ts",
47
+ "repository-root.ts",
48
+ "sections-changelog.ts",
49
+ "sections-openapi.ts",
50
+ "sections-resolve.ts",
51
+ "section-reports.ts",
52
+ "sections.ts",
53
+ "server",
54
+ "sources-git.ts",
55
+ "sources-resolve.ts",
56
+ "sources.ts",
57
+ "validate-report.ts"
58
+ ],
59
+ "type": "module",
60
+ "main": "./nuxt.config.ts",
61
+ "exports": {
62
+ ".": "./nuxt.config.ts",
63
+ "./openapi-model": "./openapi-model.ts",
64
+ "./openapi-parse": "./openapi-parse.ts",
65
+ "./sections": "./sections.ts",
66
+ "./sections-openapi": "./sections-openapi.ts",
67
+ "./sections-resolve": "./sections-resolve.ts",
68
+ "./sources": "./sources.ts",
69
+ "./sources-resolve": "./sources-resolve.ts",
70
+ "./sources-git": "./sources-git.ts"
71
+ },
72
+ "publishConfig": {
73
+ "access": "public"
74
+ },
75
+ "dependencies": {
76
+ "@codemirror/autocomplete": "^6.20.3",
77
+ "@codemirror/commands": "^6.11.0",
78
+ "@codemirror/lang-json": "^6.0.2",
79
+ "@codemirror/language": "^6.12.4",
80
+ "@codemirror/lint": "^6.9.7",
81
+ "@codemirror/state": "^6.7.4",
82
+ "@codemirror/view": "^6.43.11",
83
+ "@iconify-json/flag": "^1.2.12",
84
+ "@iconify-json/lucide": "^1.2.127",
85
+ "@iconify-json/simple-icons": "^1.2.94",
86
+ "@lezer/highlight": "^1.2.3",
87
+ "@lucide/vue": "^1.37.0",
88
+ "@nuxt/content": "^3.16.0",
89
+ "@nuxt/icon": "^2.5.1",
90
+ "@nuxt/image": "^2.1.0",
91
+ "@nuxtjs/color-mode": "^4.0.1",
92
+ "@nuxtjs/i18n": "^10.6.0",
93
+ "@nuxtjs/mcp-toolkit": "^0.19.0",
94
+ "@nuxtjs/seo": "^5.3.14",
95
+ "@resvg/resvg-js": "^2.6.2",
96
+ "@shikijs/transformers": "^4.4.3",
97
+ "@tailwindcss/vite": "^4.3.3",
98
+ "@vueuse/core": "^14.4.0",
99
+ "class-variance-authority": "^0.7.1",
100
+ "clsx": "^2.1.1",
101
+ "fuse.js": "^7.5.0",
102
+ "jiti": "^2.7.0",
103
+ "mermaid": "^11.17.2",
104
+ "reka-ui": "^2.10.4",
105
+ "satori": "^0.33.4",
106
+ "shadcn-nuxt": "^2.8.2",
107
+ "shiki": "^4.4.3",
108
+ "tailwind-merge": "^3.6.0",
109
+ "tailwindcss": "^4.3.3",
110
+ "tw-animate-css": "^1.4.0",
111
+ "vue-sonner": "^2.0.9",
112
+ "yaml": "^2.9.0",
113
+ "zod": "^4.5.4"
114
+ },
115
+ "devDependencies": {
116
+ "@commitlint/cli": "^21.2.2",
117
+ "@commitlint/config-conventional": "^21.2.2",
118
+ "@commitlint/types": "^21.2.0",
119
+ "@types/jsdom": "^30.0.0",
120
+ "@types/node": "^26.4.0",
121
+ "axe-core": "^4.13.0",
122
+ "husky": "^9.1.7",
123
+ "jsdom": "^30.0.1",
124
+ "lint-staged": "^17.4.1",
125
+ "nuxt": "^4.5.2",
126
+ "oxfmt": "0.65.0",
127
+ "oxlint": "1.80.0",
128
+ "taze": "^21.1.0",
129
+ "typescript": "^6.0.3",
130
+ "vitest": "^4.1.11"
131
+ },
132
+ "peerDependencies": {
133
+ "nuxt": "^4.0.0"
134
+ },
135
+ "engines": {
136
+ "node": ">=24"
137
+ },
138
+ "scripts": {
139
+ "lint": "oxlint . --deny-warnings",
140
+ "lint:fix": "oxlint . --fix --deny-warnings",
141
+ "format": "oxfmt --check .",
142
+ "format:fix": "oxfmt .",
143
+ "typecheck": "tsc --noEmit",
144
+ "check": "pnpm lint && pnpm format && pnpm typecheck && pnpm typecheck:app && pnpm test && pnpm check:policy && pnpm check:previews && pnpm build:app && pnpm check:a11y && pnpm check:seo",
145
+ "check:fix": "pnpm lint:fix && pnpm format:fix",
146
+ "previews": "node scripts/build-devtools-previews.ts",
147
+ "check:previews": "node scripts/check-previews.ts",
148
+ "check:policy": "node scripts/check-policy-parity.ts",
149
+ "skills:update": "pnpm dlx skills@latest update -p -y",
150
+ "taze": "taze",
151
+ "taze:w": "taze -w",
152
+ "typecheck:app": "pnpm --filter www typecheck",
153
+ "test": "vitest run",
154
+ "test:watch": "vitest",
155
+ "report": "pnpm --filter www exec duxt-report",
156
+ "build:app": "pnpm --filter www build",
157
+ "deploy:www": "pnpm --filter www run deploy",
158
+ "check:a11y": "node scripts/check-a11y.ts",
159
+ "check:seo": "node scripts/check-seo.ts"
160
+ }
161
+ }
@@ -0,0 +1,318 @@
1
+ <!doctype html>
2
+ <html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
3
+ <title>duxt — Cache</title><style>
4
+ :root {
5
+ color-scheme: light dark;
6
+ --bg: #fff;
7
+ --fg: #12141a;
8
+ --muted: #6b7280;
9
+ --faint: #9ca3af;
10
+ --line: #e8e8ea;
11
+ --raised: #f6f6f7;
12
+ --accent: #00a86b;
13
+ --accent-soft: #e6f7f0;
14
+ --warn: #b45309;
15
+ --error: #b91c1c;
16
+ --ok: #15803d;
17
+ --radius: 7px;
18
+ }
19
+ @media (prefers-color-scheme: dark) {
20
+ :root:not([data-theme='light']) {
21
+ --bg: #0f1115;
22
+ --fg: #e8e8ea;
23
+ --muted: #9099a8;
24
+ --faint: #5b6472;
25
+ --line: #23262d;
26
+ --raised: #171a20;
27
+ --accent: #00dc82;
28
+ --accent-soft: #10291f;
29
+ --warn: #f59e0b;
30
+ --error: #f87171;
31
+ --ok: #4ade80;
32
+ }
33
+ }
34
+ :root[data-theme='dark'] {
35
+ --bg: #0f1115;
36
+ --fg: #e8e8ea;
37
+ --muted: #9099a8;
38
+ --faint: #5b6472;
39
+ --line: #23262d;
40
+ --raised: #171a20;
41
+ --accent: #00dc82;
42
+ --accent-soft: #10291f;
43
+ --warn: #f59e0b;
44
+ --error: #f87171;
45
+ --ok: #4ade80;
46
+ }
47
+
48
+ * { box-sizing: border-box; }
49
+ body {
50
+ margin: 0;
51
+ padding: 0 0 40px;
52
+ font: 13px/1.55 ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
53
+ color: var(--fg);
54
+ background: var(--bg);
55
+ -webkit-font-smoothing: antialiased;
56
+ }
57
+ a { color: inherit; }
58
+ :focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
59
+
60
+ header.bar {
61
+ position: sticky; top: 0; z-index: 2;
62
+ background: color-mix(in srgb, var(--bg) 88%, transparent);
63
+ backdrop-filter: blur(8px);
64
+ border-bottom: 1px solid var(--line);
65
+ padding: 10px 16px 0;
66
+ }
67
+ nav { display: flex; gap: 1px; flex-wrap: wrap; }
68
+ nav a {
69
+ padding: 5px 10px; border-radius: var(--radius) var(--radius) 0 0;
70
+ text-decoration: none; color: var(--muted); font-weight: 500;
71
+ border-bottom: 2px solid transparent; line-height: 1.4;
72
+ }
73
+ nav a:hover { color: var(--fg); background: var(--raised); }
74
+ nav a[aria-current] { color: var(--fg); border-bottom-color: var(--accent); font-weight: 600; }
75
+
76
+ main { padding: 18px 16px 0; max-width: 1400px; }
77
+ h1 { margin: 0 0 3px; font-size: 15px; font-weight: 650; letter-spacing: -0.01em; }
78
+ h2 {
79
+ margin: 26px 0 8px; font-size: 12px; font-weight: 600;
80
+ text-transform: uppercase; letter-spacing: .05em; color: var(--muted);
81
+ }
82
+ p.hint { margin: 0 0 16px; color: var(--muted); max-width: 78ch; }
83
+
84
+ .stats { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }
85
+ .stat {
86
+ display: flex; flex-direction: column; gap: 1px;
87
+ padding: 7px 12px; min-width: 78px;
88
+ border: 1px solid var(--line); border-radius: var(--radius); background: var(--raised);
89
+ }
90
+ .stat b { font-size: 16px; font-weight: 650; font-variant-numeric: tabular-nums; line-height: 1.2; }
91
+ .stat span { font-size: 10.5px; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); }
92
+ .stat.ok b { color: var(--ok); }
93
+ .stat.warn b { color: var(--warn); }
94
+ .stat.error b { color: var(--error); }
95
+
96
+ .scroll { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius); margin-bottom: 10px; }
97
+ table { width: 100%; border-collapse: collapse; }
98
+ th, td { padding: 7px 11px; text-align: left; vertical-align: top; }
99
+ /* Offset zero, not the height of the tab bar. .scroll sets overflow-x, which
100
+ computes overflow-y to auto as well, so the box — not the page — is what a
101
+ sticky heading offsets against. At 41px the heading sat 41px down from the
102
+ box's top edge, leaving a blank band above it AND covering the first row:
103
+ the Redirects panel counted eight rules and showed seven. */
104
+ thead th {
105
+ position: sticky; top: 0; z-index: 1;
106
+ background: var(--raised);
107
+ font-weight: 600; color: var(--muted);
108
+ font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em;
109
+ white-space: nowrap; border-bottom: 1px solid var(--line);
110
+ }
111
+ tbody tr { border-top: 1px solid var(--line); }
112
+ tbody tr:first-child { border-top: 0; }
113
+ tbody tr:hover { background: var(--raised); }
114
+ td.empty { color: var(--muted); padding: 16px 11px; text-align: center; }
115
+
116
+ code {
117
+ font: 11.5px/1.5 ui-monospace, 'SF Mono', Menlo, monospace;
118
+ background: var(--raised); border: 1px solid var(--line);
119
+ padding: 0 4px; border-radius: 4px; white-space: nowrap;
120
+ }
121
+ a.file { text-decoration: none; border-bottom: 1px dashed var(--faint); }
122
+ a.file:hover { border-bottom-style: solid; color: var(--accent); }
123
+ .dim { color: var(--faint); }
124
+ .trunc {
125
+ display: inline-block; max-width: 34ch; overflow: hidden;
126
+ text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom;
127
+ }
128
+ td.wide { min-width: 32ch; }
129
+
130
+ .tag {
131
+ display: inline-block; border-radius: 999px; padding: 1px 7px;
132
+ font-size: 10px; font-weight: 600; white-space: nowrap;
133
+ background: var(--accent-soft); color: var(--accent);
134
+ border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
135
+ }
136
+ .tag.warn { background: transparent; color: var(--warn); border-color: color-mix(in srgb, var(--warn) 40%, transparent); }
137
+ .tag.error { background: transparent; color: var(--error); border-color: color-mix(in srgb, var(--error) 40%, transparent); }
138
+ .tag.ok { background: transparent; color: var(--ok); border-color: color-mix(in srgb, var(--ok) 40%, transparent); }
139
+ .tag.muted { background: var(--raised); color: var(--muted); border-color: var(--line); }
140
+
141
+ form { display: flex; gap: 8px; margin-bottom: 14px; flex-wrap: wrap; align-items: center; }
142
+ input[type=text], input[type=search] {
143
+ flex: 1; min-width: 240px; padding: 6px 11px;
144
+ border: 1px solid var(--line); border-radius: var(--radius);
145
+ font: inherit; background: var(--bg); color: inherit;
146
+ }
147
+ .filterbar { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
148
+ .filterbar .count {
149
+ color: var(--muted); font-size: 11.5px;
150
+ font-variant-numeric: tabular-nums; white-space: nowrap;
151
+ }
152
+ input.filter {
153
+ flex: 0 1 340px; min-width: 0; margin: 0; padding-left: 31px;
154
+ background: var(--bg) no-repeat 10px 50% / 14px url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239099a8' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.6-3.6'/%3E%3C/svg%3E");
155
+ }
156
+ input.filter:focus { border-color: var(--accent); }
157
+ input.filter::-webkit-search-cancel-button { cursor: pointer; }
158
+ input::placeholder { color: var(--faint); }
159
+ button {
160
+ padding: 6px 14px; border: 1px solid var(--line); border-radius: var(--radius);
161
+ background: var(--raised); font: inherit; font-weight: 500; cursor: pointer; color: inherit;
162
+ }
163
+ button:hover { border-color: var(--accent); color: var(--accent); }
164
+
165
+ ol.steps { margin: 0 0 18px; padding: 0; list-style: none; counter-reset: step; }
166
+ ol.steps li {
167
+ position: relative; counter-increment: step;
168
+ padding: 8px 0 8px 30px; border-left: 2px solid var(--line); margin-left: 9px;
169
+ }
170
+ ol.steps li::before {
171
+ content: counter(step);
172
+ position: absolute; left: -10px; top: 8px;
173
+ width: 18px; height: 18px; border-radius: 999px;
174
+ background: var(--raised); border: 1px solid var(--line);
175
+ font-size: 10px; font-weight: 600; color: var(--muted);
176
+ display: flex; align-items: center; justify-content: center;
177
+ }
178
+ ol.steps li:last-child { border-left-color: transparent; }
179
+
180
+ .note {
181
+ padding: 10px 13px; border-radius: var(--radius);
182
+ background: var(--raised); border: 1px solid var(--line);
183
+ color: var(--muted); margin-bottom: 16px; max-width: 90ch;
184
+ }
185
+ .note code { background: var(--bg); }
186
+
187
+ details { margin-bottom: 10px; }
188
+ details > summary {
189
+ cursor: pointer; padding: 7px 11px; border-radius: var(--radius);
190
+ background: var(--raised); border: 1px solid var(--line);
191
+ font-weight: 600; list-style-position: inside;
192
+ }
193
+ details > summary:hover { border-color: var(--accent); }
194
+ details[open] > summary { border-radius: var(--radius) var(--radius) 0 0; margin-bottom: -1px; }
195
+ details[open] > summary + .scroll { border-radius: 0 0 var(--radius) var(--radius); }
196
+ details[open] > summary + .filterbar {
197
+ margin: 0; padding: 8px 11px;
198
+ background: var(--raised); border: 1px solid var(--line); border-top: 0;
199
+ }
200
+ details[open] > .filterbar + .scroll {
201
+ border-radius: 0 0 var(--radius) var(--radius); margin-top: -1px;
202
+ }
203
+
204
+ /* A disclosure inside a table cell is not the panel-sized one above: no bar,
205
+ no border, no weight — just a triangle in front of the preview. */
206
+ details.json { margin: 0; }
207
+ details.json > summary {
208
+ padding: 0; background: none; border: 0; border-radius: 0; font-weight: inherit;
209
+ list-style-position: outside; margin-left: 12px;
210
+ }
211
+ details.json > summary::marker { color: var(--faint); }
212
+ details.json > summary:hover { border: 0; }
213
+ details.json[open] > summary { margin-bottom: 6px; border-radius: 0; }
214
+ details.json[open] > summary .peek { display: none; }
215
+ pre.json {
216
+ margin: 0 0 2px; padding: 9px 11px; max-height: 320px; overflow: auto;
217
+ background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius);
218
+ font: 11.5px/1.6 ui-monospace, 'SF Mono', Menlo, monospace;
219
+ white-space: pre; tab-size: 2;
220
+ }
221
+ .j-key { color: var(--accent); }
222
+ .j-num { color: var(--warn); }
223
+ .j-word { color: var(--muted); font-style: italic; }
224
+
225
+ .matrix th:first-child, .matrix td:first-child {
226
+ position: sticky; left: 0; background: var(--bg);
227
+ border-right: 1px solid var(--line);
228
+ }
229
+ .matrix thead th:first-child { background: var(--raised); }
230
+ .matrix tbody tr:hover td:first-child { background: var(--raised); }
231
+ .matrix td.mark { text-align: center; }
232
+ .matrix td.yes { color: var(--ok); font-weight: 700; }
233
+ .matrix td.no { color: var(--faint); }
234
+ </style></head><body>
235
+
236
+ <main>
237
+ <h1>Cache</h1>
238
+ <p class="hint">Content's download cache under <code>.data/content</code>, and a way to drop an entry.</p>
239
+ <div class="stats"><div class="stat "><b>3</b><span>cached sources</span></div><div class="stat "><b>9.3 MB</b><span>on disk</span></div></div><p class="hint">/srv/acme-docs/.data/content</p><div class="scroll"><table>
240
+ <thead><tr><th scope="col">Entry</th><th scope="col">Size</th><th scope="col">Modified</th><th scope="col"></th></tr></thead>
241
+ <tbody><tr><td><code>github.com-acme-sdk-main</code></td><td>4.6 MB</td><td>2026-02-12 08:41</td><td><form method="post" style="margin:0">
242
+ <input type="hidden" name="drop" value="github.com-acme-sdk-main">
243
+ <button type="submit">Drop</button>
244
+ </form></td></tr><tr><td><code>github.com-acme-sdk-v1.9.4</code></td><td>3.9 MB</td><td>2026-01-30 17:03</td><td><form method="post" style="margin:0">
245
+ <input type="hidden" name="drop" value="github.com-acme-sdk-v1.9.4">
246
+ <button type="submit">Drop</button>
247
+ </form></td></tr><tr><td><code>github.com-acme-cli-main</code></td><td>820 kB</td><td>2026-02-11 12:20</td><td><form method="post" style="margin:0">
248
+ <input type="hidden" name="drop" value="github.com-acme-cli-main">
249
+ <button type="submit">Drop</button>
250
+ </form></td></tr></tbody>
251
+ </table></div><div class="note">Dropping an entry makes the next build download it again. Content keys a directory by repository <em>and</em> ref, so an entry for a ref you have renamed is never reused and never cleaned up either.</div>
252
+ </main>
253
+ <script>
254
+ document.addEventListener('input', (event) => {
255
+ const input = event.target;
256
+ if (!input.matches('[data-filter]')) return;
257
+
258
+ const term = input.value.trim().toLowerCase();
259
+ const scope = input.closest('details') ?? document;
260
+ const rows = scope.querySelectorAll('tbody tr');
261
+ let shown = 0;
262
+
263
+ for (const row of rows) {
264
+ row.hidden = Boolean(term) && !row.textContent.toLowerCase().includes(term);
265
+ if (!row.hidden) shown += 1;
266
+ }
267
+
268
+ const count = input.parentElement.querySelector('[data-filter-count]');
269
+ if (count) {
270
+ count.textContent = term
271
+ ? shown ? shown + ' of ' + rows.length : 'no matches'
272
+ : '';
273
+ }
274
+ });
275
+
276
+ // EVERY link and button, with no exception for the tab row — a preview has
277
+ // no tab row. Embedded in a documentation page, a reader who clicked one
278
+ // would land on another panel inside the frame while the prose around it went
279
+ // on explaining this one.
280
+ document.addEventListener('click', (event) => {
281
+ if (event.target.closest('a, button')) event.preventDefault();
282
+ });
283
+ document.addEventListener('submit', (event) => event.preventDefault());
284
+
285
+ // The page that framed this one owns the theme and the height: it knows
286
+ // which mode the reader picked, and only this document knows how tall it
287
+ // turned out. Two messages, one each way.
288
+ const theme = new URLSearchParams(location.search).get('theme');
289
+ if (theme) document.documentElement.dataset.theme = theme;
290
+
291
+ // Only from the frame that embedded this one, and only from its own origin.
292
+ // Both halves are needed: the origin alone would still accept a message from
293
+ // a sibling frame on the same site, and `event.source` alone would accept one
294
+ // from a parent on another origin. This document is served from `public/`, so
295
+ // the page framing it is always same-origin — a message from anywhere else is
296
+ // not a theme change, it is somebody else talking.
297
+ addEventListener('message', (event) => {
298
+ if (event.origin !== location.origin || event.source !== parent) return;
299
+
300
+ if (event.data && typeof event.data.duxtTheme === 'string') {
301
+ document.documentElement.dataset.theme = event.data.duxtTheme;
302
+ }
303
+ });
304
+
305
+ // Addressed rather than broadcast, for the same reason. `'*'` hands the
306
+ // height to whatever ends up framing this page, which on a consumer's site is
307
+ // not necessarily the page that asked for it.
308
+ const measure = () => parent.postMessage(
309
+ { duxtHeight: document.documentElement.scrollHeight },
310
+ location.origin
311
+ );
312
+
313
+ addEventListener('load', measure);
314
+ addEventListener('resize', measure);
315
+ document.addEventListener('toggle', measure, true);
316
+ document.addEventListener('input', () => setTimeout(measure, 0));
317
+ </script>
318
+ </body></html>