@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,555 @@
1
+ @import 'tailwindcss';
2
+ @import 'tw-animate-css';
3
+ /* vue-sonner ships its own stylesheet; without it the toasts render as bare
4
+ text on the page background. */
5
+ @import 'vue-sonner/style.css';
6
+ @import './typeset.css';
7
+
8
+ /* Tailwind auto-detects sources from the build root, which is the CONSUMER's
9
+ directory — the layer sits outside it and would be scanned by nobody, so
10
+ every utility used in these components would be missing from the output.
11
+ Relative to this file, so it holds wherever the layer is installed. */
12
+ @source '../../../app';
13
+
14
+ /* shadcn switches themes on a class, not a media query — @nuxtjs/color-mode
15
+ sets it with classSuffix: '' so the two agree. */
16
+ @custom-variant dark (&:is(.dark *));
17
+
18
+ /*
19
+ * The neutral base palette, in oklch. A consumer overrides a token by
20
+ * redefining it in its own stylesheet — no fork of this file needed.
21
+ *
22
+ * IN A CASCADE LAYER, so that override cannot lose a race. Unlayered CSS beats
23
+ * layered CSS whatever the source order — and source order is not something
24
+ * this file controls. Vite resolves the stylesheet's absolute path along two
25
+ * routes at once, `/_nuxt/@fs/<abs>` and `/_nuxt/<abs>`, and deduplicates
26
+ * neither, so a second copy of this file lands AFTER the consumer's own `css`
27
+ * entry. At equal specificity the values below then won on order alone, and
28
+ * which one painted first came down to which 313 kB response arrived first: a
29
+ * consumer's buttons and badges flashed neutral before turning branded, and
30
+ * differently on every reload.
31
+ *
32
+ * The layer is ANONYMOUS on purpose. A named one can be reordered by a consumer
33
+ * writing `@layer` itself, which would hand the race straight back; an
34
+ * anonymous layer cannot be named again, so nothing downstream can move its own
35
+ * rules below these.
36
+ *
37
+ * Only the tokens go in here. Everything further down this file styles the
38
+ * layer's own components, where a consumer overriding by name is meant to need
39
+ * the specificity it already takes.
40
+ */
41
+ @layer {
42
+ :root {
43
+ --radius: 0.625rem;
44
+ --background: oklch(1 0 0);
45
+ --foreground: oklch(0.145 0 0);
46
+ --card: oklch(1 0 0);
47
+ --card-foreground: oklch(0.145 0 0);
48
+ --popover: oklch(1 0 0);
49
+ --popover-foreground: oklch(0.145 0 0);
50
+ --primary: oklch(0.205 0 0);
51
+ --primary-foreground: oklch(0.985 0 0);
52
+ --secondary: oklch(0.97 0 0);
53
+ --secondary-foreground: oklch(0.205 0 0);
54
+ --muted: oklch(0.97 0 0);
55
+ /* shadcn's own value is oklch(0.556 0 0). Measured, that is 4.73:1 on the
56
+ page background — and 4.34:1 on --muted / --accent, which is where this
57
+ token actually lands: a hovered sidebar link, a badge, the sheet. So the
58
+ default fails AA on exactly the surfaces it is used on. 0.52 gives 5.51:1
59
+ and 5.05:1, and this token carries the page descriptions, the table of
60
+ contents and the breadcrumb — too much text to leave borderline. */
61
+ --muted-foreground: oklch(0.52 0 0);
62
+ --accent: oklch(0.97 0 0);
63
+ --accent-foreground: oklch(0.205 0 0);
64
+ --destructive: oklch(0.577 0.245 27.325);
65
+ --destructive-foreground: oklch(0.985 0 0);
66
+ --border: oklch(0.922 0 0);
67
+ --input: oklch(0.922 0 0);
68
+ --ring: oklch(0.708 0 0);
69
+ /* THE FOREGROUND FOLLOWS THE BACKGROUND'S LIGHTNESS, not the mode's. A pale
70
+ green with white on it reads as a badge and measures 3.12:1, which is a
71
+ badge nobody with low vision can read. Above roughly L 0.6 the pair takes
72
+ dark text, below it white — `--warning` already did, and success, info and
73
+ dark-mode destructive were simply missed. Enforced in
74
+ `tests/contrast.test.ts`; see the note on `--muted-foreground` above for
75
+ why the browser check cannot answer this. */
76
+ --success: oklch(0.63 0.17 149);
77
+ --success-foreground: oklch(0.145 0 0);
78
+ --warning: oklch(0.75 0.16 70);
79
+ --warning-foreground: oklch(0.145 0 0);
80
+ --info: oklch(0.62 0.16 244);
81
+ --info-foreground: oklch(0.145 0 0);
82
+ }
83
+
84
+ .dark {
85
+ --background: oklch(0.145 0 0);
86
+ --foreground: oklch(0.985 0 0);
87
+ --card: oklch(0.205 0 0);
88
+ --card-foreground: oklch(0.985 0 0);
89
+ --popover: oklch(0.205 0 0);
90
+ --popover-foreground: oklch(0.985 0 0);
91
+ --primary: oklch(0.922 0 0);
92
+ --primary-foreground: oklch(0.205 0 0);
93
+ --secondary: oklch(0.269 0 0);
94
+ --secondary-foreground: oklch(0.985 0 0);
95
+ --muted: oklch(0.269 0 0);
96
+ /* Same measurement in the dark: 7.63:1 on the background but 5.83:1 on
97
+ --muted. Lifted for the same reason, by less, because it starts higher. */
98
+ --muted-foreground: oklch(0.72 0 0);
99
+ --accent: oklch(0.269 0 0);
100
+ --accent-foreground: oklch(0.985 0 0);
101
+ --destructive: oklch(0.704 0.191 22.216);
102
+ --destructive-foreground: oklch(0.145 0 0);
103
+ --border: oklch(1 0 0 / 10%);
104
+ --input: oklch(1 0 0 / 15%);
105
+ --ring: oklch(0.556 0 0);
106
+ --success: oklch(0.7 0.16 149);
107
+ --success-foreground: oklch(0.145 0 0);
108
+ --warning: oklch(0.8 0.15 70);
109
+ --warning-foreground: oklch(0.145 0 0);
110
+ --info: oklch(0.7 0.14 244);
111
+ --info-foreground: oklch(0.145 0 0);
112
+ }
113
+ }
114
+
115
+ @theme inline {
116
+ --radius-sm: calc(var(--radius) - 4px);
117
+ --radius-md: calc(var(--radius) - 2px);
118
+ --radius-lg: var(--radius);
119
+ --radius-xl: calc(var(--radius) + 4px);
120
+ --color-background: var(--background);
121
+ --color-foreground: var(--foreground);
122
+ --color-card: var(--card);
123
+ --color-card-foreground: var(--card-foreground);
124
+ --color-popover: var(--popover);
125
+ --color-popover-foreground: var(--popover-foreground);
126
+ --color-primary: var(--primary);
127
+ --color-primary-foreground: var(--primary-foreground);
128
+ --color-secondary: var(--secondary);
129
+ --color-secondary-foreground: var(--secondary-foreground);
130
+ --color-muted: var(--muted);
131
+ --color-muted-foreground: var(--muted-foreground);
132
+ --color-accent: var(--accent);
133
+ --color-accent-foreground: var(--accent-foreground);
134
+ --color-destructive: var(--destructive);
135
+ --color-destructive-foreground: var(--destructive-foreground);
136
+ --color-success: var(--success);
137
+ --color-success-foreground: var(--success-foreground);
138
+ --color-warning: var(--warning);
139
+ --color-warning-foreground: var(--warning-foreground);
140
+ --color-info: var(--info);
141
+ --color-info-foreground: var(--info-foreground);
142
+ --color-border: var(--border);
143
+ --color-input: var(--input);
144
+ --color-ring: var(--ring);
145
+ }
146
+
147
+ @layer base {
148
+ * {
149
+ @apply border-border outline-ring/50;
150
+ }
151
+
152
+ body {
153
+ @apply bg-background text-foreground;
154
+ }
155
+
156
+ /* The one line that tells the BROWSER which theme is on. Without it every
157
+ piece of native UI — scrollbars first, then form controls and the canvas
158
+ behind a short page — is drawn light on a dark site, which is why a
159
+ scrollbar inside an iframe looked nothing like the window's own.
160
+ `scrollbar-*` are inherited properties, so `:root` reaches every scroll
161
+ container in the page: the sidebar, the table of contents, a code block. */
162
+ :root {
163
+ color-scheme: light;
164
+ scrollbar-width: thin;
165
+ scrollbar-color: var(--border) transparent;
166
+ }
167
+
168
+ :root:is(.dark),
169
+ .dark {
170
+ color-scheme: dark;
171
+ }
172
+ }
173
+
174
+ /* The editor's own syntax colours, taken from the two Shiki themes the fences
175
+ use — `github-light` and `github-dark`, read off their token settings rather
176
+ than eyeballed: string `#032f62`/`#9ecbff`, every constant (number, boolean,
177
+ null) and every `support` scope (which is where a JSON property name lands)
178
+ `#005cc5`/`#79b8ff`, keyword `#d73a49`/`#f97583`.
179
+
180
+ Variables rather than two CodeMirror themes, for the reason the palette above
181
+ is variables: the editor is built once and would otherwise freeze whichever
182
+ mode was current when it mounted, and a consumer who wants other colours
183
+ redefines four names instead of forking a component. */
184
+ :root {
185
+ --duxt-cm-key: #005cc5;
186
+ --duxt-cm-string: #032f62;
187
+ --duxt-cm-value: #005cc5;
188
+ --duxt-cm-keyword: #d73a49;
189
+ --duxt-cm-comment: #6a737d;
190
+ }
191
+
192
+ :root:is(.dark),
193
+ .dark {
194
+ --duxt-cm-key: #79b8ff;
195
+ --duxt-cm-string: #9ecbff;
196
+ --duxt-cm-value: #79b8ff;
197
+ --duxt-cm-keyword: #f97583;
198
+ }
199
+
200
+ /* `defaultColor: false` emits BOTH themes as custom properties and sets no
201
+ colour at all, so a block highlighted that way renders flat until something
202
+ picks one. Content's own fences do not need this — they carry the light
203
+ colour inline and Content injects the dark rule — but every block this site
204
+ highlights itself does, which is why the two classes are named together:
205
+ forgetting the second is a box of grey text beside a coloured one. */
206
+ .duxt-shell span,
207
+ .duxt-code-body span {
208
+ color: var(--shiki-light);
209
+ }
210
+
211
+ .dark .duxt-shell span,
212
+ .dark .duxt-code-body span {
213
+ color: var(--shiki-dark);
214
+ }
215
+
216
+ .duxt-shell pre {
217
+ margin: 0;
218
+ background: transparent !important;
219
+ }
220
+
221
+ /* The layer's typeset preset. Three controls — size, leading, flow — and
222
+ everything else derives from them; see the typeset docs. A consumer
223
+ redefines these in its own stylesheet rather than restyling elements. */
224
+ .typeset-docs {
225
+ --typeset-size: 15px;
226
+ --typeset-leading: 1.7;
227
+ --typeset-flow: 1.25em;
228
+ }
229
+
230
+ /* Kept from the hand-written prose: a heading anchor in the margin, and code
231
+ blocks drawing their own surface rather than the highlighter's.
232
+
233
+ The surface matters: typeset gives every `pre` a muted background (its line
234
+ 293), which lands on top of the card DuxtCodeBlock already draws — two
235
+ surfaces, and in dark mode the inner one reads as a highlighted row. Not
236
+ scoped to .typeset, because the package-manager block renders the same
237
+ markup outside a rendered page. */
238
+ /* The heading link wraps the words, so it has to shed what `typeset` gives
239
+ every other link — the underline would draw a rule under every H2 on the
240
+ site. `relative` is what the marker below positions against: anchored to the
241
+ text rather than to the heading box, it lands the same distance out whatever
242
+ the heading's own margins are. */
243
+ .typeset :where(.duxt-heading-link) {
244
+ @apply relative no-underline;
245
+ text-decoration-line: none;
246
+ }
247
+
248
+ .typeset :where(.duxt-anchor) {
249
+ @apply absolute -left-5 font-normal text-muted-foreground opacity-0 transition-opacity;
250
+ }
251
+
252
+ /* THE MARKER AS THE LINK ITSELF, where the heading already contains one and
253
+ cannot be wrapped in a second — see `headingHasLink`. It sits in the flow
254
+ rather than out in the margin, and it is always visible: a control revealed
255
+ only on hover is a control no touch device can reach, which is tolerable
256
+ while the words beside it are the same link and not at all once they are
257
+ somebody else's. */
258
+ .typeset :where(.duxt-anchor-only) {
259
+ @apply relative left-auto mr-2 inline no-underline opacity-60 transition-opacity;
260
+ }
261
+
262
+ .typeset :where(.duxt-anchor-only:hover, .duxt-anchor-only:focus-visible) {
263
+ @apply opacity-100;
264
+ }
265
+
266
+ /* Revealed by hovering the heading, not the marker: the marker is 1.25rem
267
+ outside the text and nobody hunts for it. Focus does the same for the
268
+ keyboard, where the link is reached without a pointer at all. */
269
+ .typeset :where(h2:hover, h3:hover, h4:hover) .duxt-anchor,
270
+ .typeset :where(.duxt-heading-link:focus-visible) .duxt-anchor {
271
+ @apply opacity-100;
272
+ }
273
+
274
+ /* A SCHEMA ROW THAT OPENS. The whole row is the target and the tile is the
275
+ sign, because a 16-pixel box is under the size a fingertip can aim at — so
276
+ the click area is the summary and the tile only says that there is one.
277
+
278
+ The marker `details` draws itself is removed in both spellings browsers
279
+ still need. */
280
+ .duxt-schema-row {
281
+ @apply -mx-1.5 cursor-pointer rounded-lg px-1.5 py-0.5 transition-colors;
282
+ list-style: none;
283
+ }
284
+
285
+ .duxt-schema-row::-webkit-details-marker {
286
+ display: none;
287
+ }
288
+
289
+ .duxt-schema-row:hover {
290
+ background: color-mix(in oklch, var(--muted) 50%, transparent);
291
+ }
292
+
293
+ .duxt-schema-row:focus-visible {
294
+ outline: 2px solid var(--ring);
295
+ outline-offset: -2px;
296
+ }
297
+
298
+ /* A `+` that becomes a `−`, drawn by the icon set rather than by two
299
+ pseudo-elements: at this size the percentage insets that placed them rounded
300
+ to different thicknesses, so the cross had one heavy stroke and one thin.
301
+ Both icons ship in the markup and the state picks one — the alternative is a
302
+ `content` swap, which cannot draw an SVG. */
303
+ .duxt-schema-tile {
304
+ @apply relative inline-flex size-4 shrink-0 items-center justify-center rounded border bg-muted/40 text-muted-foreground transition-colors;
305
+ align-self: center;
306
+ }
307
+
308
+ .duxt-schema-tile .duxt-schema-minus,
309
+ details[open] > .duxt-schema-row .duxt-schema-tile .duxt-schema-plus {
310
+ display: none;
311
+ }
312
+
313
+ details[open] > .duxt-schema-row .duxt-schema-tile .duxt-schema-minus {
314
+ display: block;
315
+ }
316
+
317
+ /* The tile answers the hover of the ROW, not of itself: the row is what is
318
+ being aimed at, and a tile that lit only under the pointer would go dark
319
+ exactly when the reader is about to click the line beside it. */
320
+ .duxt-schema-row:hover .duxt-schema-tile {
321
+ @apply border-foreground/20 bg-muted text-foreground;
322
+ }
323
+
324
+ /* The label a section of generated furniture is headed with — the release
325
+ page's groups, the reference's "parameters" and "responses", the overview's
326
+ "servers".
327
+
328
+ ONE CLASS because there are six of them and they were six copies of five
329
+ utilities, which is exactly how the reference came to be set in
330
+ `text-sm font-semibold uppercase` at full strength while the changelog was
331
+ set at 0.6875rem in `muted-foreground`: the same idea, two sizes, two
332
+ weights, two colours, on pages a reader moves between.
333
+
334
+ The colour is the DEFAULT and not the rule: a caller that has a tone of its
335
+ own — a changelog group — sets it after this class and wins. */
336
+ .duxt-label {
337
+ @apply text-[0.6875rem] font-semibold tracking-[0.12em] text-muted-foreground uppercase;
338
+ }
339
+
340
+ /* A release group's ENTRIES, which arrive as ordinary Markdown in
341
+ `ChangelogGroup`'s slot and were therefore set as prose: 1.7 leading with a
342
+ paragraph's flow between them, so six one-line facts filled a screen and a
343
+ half and a release with twelve groups read as a document rather than as a
344
+ list. They are a list, and are set as one.
345
+
346
+ The MARKER IS MUTED, not the group's tone. The colour is already stated in
347
+ the label directly above these lines; stated again on every line it stops
348
+ being a signal — the same hint, repeated, is confetti. Drawn as a box rather
349
+ than through `::marker`, which takes a colour but not a size or a position.
350
+
351
+ Only the TOP level: a list nested inside an entry keeps the prose treatment,
352
+ because there the indent is what says it is nested. */
353
+ .typeset :where(.duxt-release > ul) {
354
+ margin: 0;
355
+ padding-left: 0;
356
+ list-style: none;
357
+ }
358
+
359
+ .typeset :where(.duxt-release > ul > li) {
360
+ position: relative;
361
+ margin: 0;
362
+ padding-left: 1.05rem;
363
+ line-height: 1.55;
364
+ }
365
+
366
+ .typeset :where(.duxt-release > ul > li + li) {
367
+ margin-top: 0.35rem;
368
+ }
369
+
370
+ .typeset :where(.duxt-release > ul > li)::before {
371
+ content: '';
372
+ position: absolute;
373
+ top: 0.6em;
374
+ left: 0;
375
+ height: 0.3125rem;
376
+ width: 0.3125rem;
377
+ border-radius: 999px;
378
+ background: var(--muted-foreground);
379
+ }
380
+
381
+ pre.shiki,
382
+ .typeset :where(pre) {
383
+ background-color: transparent;
384
+ }
385
+
386
+ /* Content injects `html.dark .shiki span { background: var(--shiki-dark-bg) }`
387
+ inline in the document head — specificity (0,2,2), which outranks anything
388
+ sensible we could write against it. The tokens inherit that variable from
389
+ the <pre>, where Shiki sets it to the theme's own page colour, so in dark
390
+ mode every token drew a #24292e rectangle over the card.
391
+
392
+ Redefining the variable is the way out: the rule still applies, it just has
393
+ nothing to paint. Set on the tokens rather than the <pre>, because there the
394
+ value is inline and would win. */
395
+ .shiki span {
396
+ --shiki-light-bg: transparent;
397
+ --shiki-dark-bg: transparent;
398
+ }
399
+
400
+ /* A code block draws its own card with a filename header, so the `<pre>` inside
401
+ is that card's body rather than a block in the flow. typeset's block spacing
402
+ on `pre` therefore lands *inside* the border and opens a gap between the
403
+ header and the first line. */
404
+ .typeset :where(.duxt-code pre) {
405
+ margin: 0;
406
+ }
407
+
408
+ /* Code this site highlighted itself rather than Content — a derived example, a
409
+ response, a `curl` sample — arrives as Shiki's own `<pre class="shiki">` with
410
+ no padding of its own. Content's fences get theirs from the MDC renderer, so
411
+ this is the same rule stated for the blocks that never went through it. Not
412
+ scoped to `.typeset`: the try-it client draws these outside a rendered
413
+ page. */
414
+ .duxt-code-body pre {
415
+ margin: 0;
416
+ overflow-x: auto;
417
+ padding: 1rem;
418
+ font-size: 0.875rem;
419
+ }
420
+
421
+ .duxt-code-body pre code {
422
+ font-family: inherit;
423
+ }
424
+
425
+ /* A long unbroken token — a URL, a package name, a path — is the other way a
426
+ page grows wider than the phone holding it. Inline code may break; the
427
+ scrollable blocks (code fences, tables) keep their own overflow. */
428
+ .typeset :where(:not(pre) > code) {
429
+ overflow-wrap: anywhere;
430
+ }
431
+
432
+ /* Honour a reader who has asked the system for less motion.
433
+
434
+ Blunt on purpose. The moving parts are the collapsible in the sidebar, the
435
+ mobile sheet and the toasts, but each of the three animates through a
436
+ different mechanism — tw-animate-css keyframes on a data-state, reka-ui's
437
+ presence, vue-sonner's own stylesheet — and naming them one by one leaves the
438
+ next component to be added moving again. A near-zero duration rather than
439
+ `none`: reka-ui waits for `animationend` before it unmounts a panel, and an
440
+ animation that never runs never ends. */
441
+ @media (prefers-reduced-motion: reduce) {
442
+ *,
443
+ *::before,
444
+ *::after {
445
+ animation-duration: 0.01ms !important;
446
+ animation-iteration-count: 1 !important;
447
+ transition-duration: 0.01ms !important;
448
+ scroll-behavior: auto !important;
449
+ }
450
+ }
451
+
452
+ /* Shiki's line annotations, which have classes and no styling of their own.
453
+ Four come from the transformers @nuxtjs/mdc enables by default, two more from
454
+ `mdc.config.ts`. Without these rules `// [!code highlight]` removes the
455
+ comment and changes nothing visible, which reads as the feature being off. */
456
+ .shiki .line.highlighted {
457
+ background-color: color-mix(in oklab, var(--color-primary) 12%, transparent);
458
+ display: inline-block;
459
+ width: 100%;
460
+ }
461
+
462
+ .shiki .line.diff.add {
463
+ background-color: color-mix(in oklab, var(--color-success) 14%, transparent);
464
+ display: inline-block;
465
+ width: 100%;
466
+ }
467
+
468
+ .shiki .line.diff.remove {
469
+ background-color: color-mix(
470
+ in oklab,
471
+ var(--color-destructive) 14%,
472
+ transparent
473
+ );
474
+ display: inline-block;
475
+ width: 100%;
476
+ opacity: 0.7;
477
+ }
478
+
479
+ .shiki .line.diff.add::before {
480
+ content: '+';
481
+ color: var(--color-success);
482
+ }
483
+
484
+ .shiki .line.diff.remove::before {
485
+ content: '-';
486
+ color: var(--color-destructive);
487
+ }
488
+
489
+ .shiki .highlighted-word {
490
+ background-color: color-mix(in oklab, var(--color-primary) 16%, transparent);
491
+ border-radius: 3px;
492
+ padding: 1px 2px;
493
+ }
494
+
495
+ /* `focus` dims everything that is not the point. Not a filter on the code
496
+ itself: blur on text is unreadable for anyone who needs the contrast, so the
497
+ unfocused rows lose opacity and come back on hover. */
498
+ .shiki:has(.line.focused) .line:not(.focused) {
499
+ opacity: 0.4;
500
+ transition: opacity 0.2s;
501
+ }
502
+
503
+ .shiki:hover .line:not(.focused) {
504
+ opacity: 1;
505
+ }
506
+
507
+ .shiki .line.error {
508
+ background-color: color-mix(
509
+ in oklab,
510
+ var(--color-destructive) 14%,
511
+ transparent
512
+ );
513
+ display: inline-block;
514
+ width: 100%;
515
+ }
516
+
517
+ .shiki .line.warning {
518
+ background-color: color-mix(in oklab, var(--color-warning) 16%, transparent);
519
+ display: inline-block;
520
+ width: 100%;
521
+ }
522
+
523
+ /* Line numbers, opt-in per fence with ```ts line-numbers.
524
+ A CSS counter rather than markup: the numbers are decoration, and a reader
525
+ copying the block must not get them in the clipboard. */
526
+ .duxt-line-numbers code {
527
+ counter-reset: duxt-line;
528
+ }
529
+
530
+ .duxt-line-numbers .line::before {
531
+ counter-increment: duxt-line;
532
+ content: counter(duxt-line);
533
+ display: inline-block;
534
+ width: 2ch;
535
+ margin-right: 1.5ch;
536
+ text-align: right;
537
+ color: var(--color-muted-foreground);
538
+ user-select: none;
539
+ }
540
+
541
+ /* A page whose LAST band carries a background of its own runs straight into the
542
+ footer.
543
+
544
+ `DuxtFooter` sets `mt-16`, which is right for a documentation page: the prose
545
+ ends and the footer needs air under it. It is wrong after a tinted, bordered
546
+ section — the tint stops, four rems of page colour follow, and then the
547
+ footer's own rule draws a second line under the first. Three edges where the
548
+ design has one.
549
+
550
+ Written as a rule rather than as a margin the page removes, because the two
551
+ elements are siblings of the layout and neither can reach the other: the
552
+ section is inside `main`, and `main` is what stands next to the footer. */
553
+ main:has(.duxt-flush-footer) + footer {
554
+ margin-top: 0;
555
+ }