@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,324 @@
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 — Search</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>Search</h1>
238
+ <p class="hint">Ask the search index what it actually holds.</p>
239
+ <form method="get">
240
+ <input type="search" name="q" value="install" placeholder="A word as a reader would type it" autofocus>
241
+ <button type="submit">Search</button>
242
+ </form><div class="stats"><div class="stat "><b>5</b><span>sections indexed</span></div><div class="stat "><b>2</b><span>matching</span></div></div><div class="note">One row per heading — which is what the dialog groups back into pages. The text column is exactly what FTS5 matches against.</div><div class="scroll"><table>
243
+ <thead><tr><th scope="col">Collection</th><th scope="col">Id</th><th scope="col">Heading</th><th scope="col">Under</th><th scope="col">Indexed text</th></tr></thead>
244
+ <tbody><tr>
245
+ <td><code>docs_sdk</code></td>
246
+ <td><code class="trunc" title="docs_sdk/1.getting-started/1.install.md#install">docs_sdk/1.getting-started/1.install.md#install</code></td>
247
+ <td>Install</td>
248
+ <td>Getting started</td>
249
+ <td class="wide">Add the package with your package manager of choice. The SDK ships types, so nothing else is needed to get autocompletion in an editor.</td>
250
+ </tr><tr>
251
+ <td><code>docs_de_sdk</code></td>
252
+ <td><code class="trunc" title="docs_de_sdk/de/1.getting-started/1.install.md#installation">docs_de_sdk/de/1.getting-started/1.install.md#installation</code></td>
253
+ <td>Installation</td>
254
+ <td>Erste Schritte</td>
255
+ <td class="wide">Das Paket wird mit dem Paketmanager der Wahl hinzugefügt. Typen liegen bei, mehr braucht ein Editor nicht.</td>
256
+ </tr></tbody>
257
+ </table></div>
258
+ </main>
259
+ <script>
260
+ document.addEventListener('input', (event) => {
261
+ const input = event.target;
262
+ if (!input.matches('[data-filter]')) return;
263
+
264
+ const term = input.value.trim().toLowerCase();
265
+ const scope = input.closest('details') ?? document;
266
+ const rows = scope.querySelectorAll('tbody tr');
267
+ let shown = 0;
268
+
269
+ for (const row of rows) {
270
+ row.hidden = Boolean(term) && !row.textContent.toLowerCase().includes(term);
271
+ if (!row.hidden) shown += 1;
272
+ }
273
+
274
+ const count = input.parentElement.querySelector('[data-filter-count]');
275
+ if (count) {
276
+ count.textContent = term
277
+ ? shown ? shown + ' of ' + rows.length : 'no matches'
278
+ : '';
279
+ }
280
+ });
281
+
282
+ // EVERY link and button, with no exception for the tab row — a preview has
283
+ // no tab row. Embedded in a documentation page, a reader who clicked one
284
+ // would land on another panel inside the frame while the prose around it went
285
+ // on explaining this one.
286
+ document.addEventListener('click', (event) => {
287
+ if (event.target.closest('a, button')) event.preventDefault();
288
+ });
289
+ document.addEventListener('submit', (event) => event.preventDefault());
290
+
291
+ // The page that framed this one owns the theme and the height: it knows
292
+ // which mode the reader picked, and only this document knows how tall it
293
+ // turned out. Two messages, one each way.
294
+ const theme = new URLSearchParams(location.search).get('theme');
295
+ if (theme) document.documentElement.dataset.theme = theme;
296
+
297
+ // Only from the frame that embedded this one, and only from its own origin.
298
+ // Both halves are needed: the origin alone would still accept a message from
299
+ // a sibling frame on the same site, and `event.source` alone would accept one
300
+ // from a parent on another origin. This document is served from `public/`, so
301
+ // the page framing it is always same-origin — a message from anywhere else is
302
+ // not a theme change, it is somebody else talking.
303
+ addEventListener('message', (event) => {
304
+ if (event.origin !== location.origin || event.source !== parent) return;
305
+
306
+ if (event.data && typeof event.data.duxtTheme === 'string') {
307
+ document.documentElement.dataset.theme = event.data.duxtTheme;
308
+ }
309
+ });
310
+
311
+ // Addressed rather than broadcast, for the same reason. `'*'` hands the
312
+ // height to whatever ends up framing this page, which on a consumer's site is
313
+ // not necessarily the page that asked for it.
314
+ const measure = () => parent.postMessage(
315
+ { duxtHeight: document.documentElement.scrollHeight },
316
+ location.origin
317
+ );
318
+
319
+ addEventListener('load', measure);
320
+ addEventListener('resize', measure);
321
+ document.addEventListener('toggle', measure, true);
322
+ document.addEventListener('input', () => setTimeout(measure, 0));
323
+ </script>
324
+ </body></html>
@@ -0,0 +1,309 @@
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 — Sources</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>Sources</h1>
238
+ <p class="hint">What <code>duxt.sources</code> became: one collection per source and version, and the URL prefix each serves.</p>
239
+ <div class="stats"><div class="stat "><b>6</b><span>collections</span></div><div class="stat "><b>2</b><span>repositories</span></div><div class="stat "><b>2</b><span>versions</span></div><div class="stat "><b>1</b><span>generated section</span></div><div class="stat warn"><b>2</b><span>not current</span></div></div><div class="scroll"><table>
240
+ <thead><tr><th scope="col">Prefix</th><th scope="col">Collection</th><th scope="col">Repository</th><th scope="col">Folder / artefact</th><th scope="col">Ref</th><th scope="col">Version</th><th scope="col">Status</th><th scope="col">Reserved segments</th></tr></thead>
241
+ <tbody><tr><td><code>/sdk</code></td><td><code>docs_sdk</code></td><td><a class="file" href="https://github.com/acme/sdk" target="_blank">acme/sdk</a></td><td><code>docs</code></td><td>main <span class="dim">(branch)</span></td><td>v2 <span class="tag">default</span></td><td><span class="tag ok">current</span></td><td><code>v1.9</code> <code>releases</code></td></tr><tr><td><code>/sdk</code></td><td><code>docs_de_sdk</code></td><td><a class="file" href="https://github.com/acme/sdk" target="_blank">acme/sdk</a></td><td><code>docs/de</code></td><td>main <span class="dim">(branch)</span></td><td>v2 <span class="tag">default</span></td><td><span class="tag ok">current</span></td><td><code>v1.9</code> <code>releases</code></td></tr><tr><td><code>/sdk/v1.9</code></td><td><code>docs_sdk_v1_9</code></td><td><a class="file" href="https://github.com/acme/sdk" target="_blank">acme/sdk</a></td><td><code>docs</code></td><td>v1.9.4 <span class="dim">(tag)</span></td><td>v1.9</td><td><span class="tag warn">deprecated</span></td><td><span class="dim">—</span></td></tr><tr><td><code>/sdk/v1.9</code></td><td><code>docs_de_sdk_v1_9</code></td><td><a class="file" href="https://github.com/acme/sdk" target="_blank">acme/sdk</a></td><td><code>docs/de</code></td><td>v1.9.4 <span class="dim">(tag)</span></td><td>v1.9</td><td><span class="tag warn">deprecated</span></td><td><span class="dim">—</span></td></tr><tr><td><code>/cli</code></td><td><code>docs_cli</code></td><td><a class="file" href="https://github.com/acme/cli" target="_blank">acme/cli</a></td><td><code>docs</code></td><td><span class="dim">checkout</span></td><td>— <span class="tag">default</span></td><td><span class="tag ok">current</span></td><td><span class="dim">—</span></td></tr><tr><td><code>/sdk/releases</code></td><td><code>docs_sdk_releases</code> <span class="tag">changelog</span></td><td><a class="file" href="https://github.com/acme/sdk" target="_blank">acme/sdk</a></td><td><code>CHANGELOG.md</code></td><td>main <span class="dim">(branch)</span></td><td>— <span class="tag">default</span></td><td><span class="tag ok">current</span></td><td><span class="dim">—</span></td></tr></tbody>
242
+ </table></div><p class="hint">Configured in /srv/acme-docs/app/app.config.ts.</p>
243
+ </main>
244
+ <script>
245
+ document.addEventListener('input', (event) => {
246
+ const input = event.target;
247
+ if (!input.matches('[data-filter]')) return;
248
+
249
+ const term = input.value.trim().toLowerCase();
250
+ const scope = input.closest('details') ?? document;
251
+ const rows = scope.querySelectorAll('tbody tr');
252
+ let shown = 0;
253
+
254
+ for (const row of rows) {
255
+ row.hidden = Boolean(term) && !row.textContent.toLowerCase().includes(term);
256
+ if (!row.hidden) shown += 1;
257
+ }
258
+
259
+ const count = input.parentElement.querySelector('[data-filter-count]');
260
+ if (count) {
261
+ count.textContent = term
262
+ ? shown ? shown + ' of ' + rows.length : 'no matches'
263
+ : '';
264
+ }
265
+ });
266
+
267
+ // EVERY link and button, with no exception for the tab row — a preview has
268
+ // no tab row. Embedded in a documentation page, a reader who clicked one
269
+ // would land on another panel inside the frame while the prose around it went
270
+ // on explaining this one.
271
+ document.addEventListener('click', (event) => {
272
+ if (event.target.closest('a, button')) event.preventDefault();
273
+ });
274
+ document.addEventListener('submit', (event) => event.preventDefault());
275
+
276
+ // The page that framed this one owns the theme and the height: it knows
277
+ // which mode the reader picked, and only this document knows how tall it
278
+ // turned out. Two messages, one each way.
279
+ const theme = new URLSearchParams(location.search).get('theme');
280
+ if (theme) document.documentElement.dataset.theme = theme;
281
+
282
+ // Only from the frame that embedded this one, and only from its own origin.
283
+ // Both halves are needed: the origin alone would still accept a message from
284
+ // a sibling frame on the same site, and `event.source` alone would accept one
285
+ // from a parent on another origin. This document is served from `public/`, so
286
+ // the page framing it is always same-origin — a message from anywhere else is
287
+ // not a theme change, it is somebody else talking.
288
+ addEventListener('message', (event) => {
289
+ if (event.origin !== location.origin || event.source !== parent) return;
290
+
291
+ if (event.data && typeof event.data.duxtTheme === 'string') {
292
+ document.documentElement.dataset.theme = event.data.duxtTheme;
293
+ }
294
+ });
295
+
296
+ // Addressed rather than broadcast, for the same reason. `'*'` hands the
297
+ // height to whatever ends up framing this page, which on a consumer's site is
298
+ // not necessarily the page that asked for it.
299
+ const measure = () => parent.postMessage(
300
+ { duxtHeight: document.documentElement.scrollHeight },
301
+ location.origin
302
+ );
303
+
304
+ addEventListener('load', measure);
305
+ addEventListener('resize', measure);
306
+ document.addEventListener('toggle', measure, true);
307
+ document.addEventListener('input', () => setTimeout(measure, 0));
308
+ </script>
309
+ </body></html>