@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.
- package/LICENSE +21 -0
- package/README.md +151 -0
- package/app/app.config.ts +13 -0
- package/app/app.vue +122 -0
- package/app/assets/css/duxt.css +555 -0
- package/app/assets/css/typeset.css +498 -0
- package/app/components/DuxtBrand.vue +53 -0
- package/app/components/DuxtBreadcrumb.vue +37 -0
- package/app/components/DuxtCodeBlock.vue +143 -0
- package/app/components/DuxtCopyPage.vue +117 -0
- package/app/components/DuxtFooter.vue +86 -0
- package/app/components/DuxtHeader.vue +496 -0
- package/app/components/DuxtJsonEditor.vue +359 -0
- package/app/components/DuxtLandingProse.vue +90 -0
- package/app/components/DuxtLandingShowcase.vue +295 -0
- package/app/components/DuxtLiveWindow.vue +343 -0
- package/app/components/DuxtLocale.vue +86 -0
- package/app/components/DuxtMetaList.vue +76 -0
- package/app/components/DuxtNavigation.vue +94 -0
- package/app/components/DuxtNavigationLink.vue +41 -0
- package/app/components/DuxtOpenApiCallbacks.vue +92 -0
- package/app/components/DuxtOpenApiClient.vue +1339 -0
- package/app/components/DuxtOpenApiMedia.vue +108 -0
- package/app/components/DuxtOpenApiMethod.vue +59 -0
- package/app/components/DuxtOpenApiParameters.vue +114 -0
- package/app/components/DuxtOpenApiResponses.vue +109 -0
- package/app/components/DuxtOpenApiSchema.vue +365 -0
- package/app/components/DuxtOpenApiSecurity.vue +115 -0
- package/app/components/DuxtPageFeedback.vue +56 -0
- package/app/components/DuxtPageInfo.vue +194 -0
- package/app/components/DuxtPageNav.vue +93 -0
- package/app/components/DuxtPreviewSkeleton.vue +262 -0
- package/app/components/DuxtProgress.vue +45 -0
- package/app/components/DuxtSearch.vue +271 -0
- package/app/components/DuxtSections.vue +65 -0
- package/app/components/DuxtShortcuts.vue +46 -0
- package/app/components/DuxtSkipLink.vue +34 -0
- package/app/components/DuxtToc.vue +86 -0
- package/app/components/DuxtTranslationBanner.vue +64 -0
- package/app/components/DuxtVersion.vue +168 -0
- package/app/components/DuxtVersionBanner.vue +109 -0
- package/app/components/OgImage/Duxt.satori.vue +82 -0
- package/app/components/content/Accordion.vue +37 -0
- package/app/components/content/AccordionItem.vue +46 -0
- package/app/components/content/Callout.vue +58 -0
- package/app/components/content/ChangelogGroup.vue +91 -0
- package/app/components/content/ChangelogReleases.vue +520 -0
- package/app/components/content/CodeGroup.vue +183 -0
- package/app/components/content/DevtoolsPanel.vue +107 -0
- package/app/components/content/Field.vue +50 -0
- package/app/components/content/FieldGroup.vue +8 -0
- package/app/components/content/FileTree.vue +92 -0
- package/app/components/content/Mermaid.vue +70 -0
- package/app/components/content/OpenApiOperation.vue +185 -0
- package/app/components/content/OpenApiOperations.vue +72 -0
- package/app/components/content/OpenApiOverview.vue +302 -0
- package/app/components/content/PackageManagers.vue +187 -0
- package/app/components/content/PageCards.vue +48 -0
- package/app/components/content/Partial.vue +65 -0
- package/app/components/content/Preview.vue +173 -0
- package/app/components/content/ProseA.vue +55 -0
- package/app/components/content/ProseH2.vue +53 -0
- package/app/components/content/ProseH3.vue +53 -0
- package/app/components/content/ProseH4.vue +53 -0
- package/app/components/content/ProseImg.vue +87 -0
- package/app/components/content/ProsePre.vue +58 -0
- package/app/components/content/ProseTable.vue +11 -0
- package/app/components/content/Since.vue +21 -0
- package/app/components/content/Steps.vue +20 -0
- package/app/components/content/Tab.vue +23 -0
- package/app/components/content/TabGroup.vue +58 -0
- package/app/components/ui/alert/Alert.vue +21 -0
- package/app/components/ui/alert/AlertDescription.vue +22 -0
- package/app/components/ui/alert/AlertTitle.vue +22 -0
- package/app/components/ui/alert/index.ts +24 -0
- package/app/components/ui/badge/Badge.vue +28 -0
- package/app/components/ui/badge/index.ts +52 -0
- package/app/components/ui/breadcrumb/Breadcrumb.vue +13 -0
- package/app/components/ui/breadcrumb/BreadcrumbEllipsis.vue +22 -0
- package/app/components/ui/breadcrumb/BreadcrumbItem.vue +17 -0
- package/app/components/ui/breadcrumb/BreadcrumbLink.vue +24 -0
- package/app/components/ui/breadcrumb/BreadcrumbList.vue +22 -0
- package/app/components/ui/breadcrumb/BreadcrumbPage.vue +20 -0
- package/app/components/ui/breadcrumb/BreadcrumbSeparator.vue +21 -0
- package/app/components/ui/breadcrumb/index.ts +7 -0
- package/app/components/ui/button/Button.vue +31 -0
- package/app/components/ui/button/index.ts +39 -0
- package/app/components/ui/card/Card.vue +22 -0
- package/app/components/ui/card/CardAction.vue +22 -0
- package/app/components/ui/card/CardContent.vue +14 -0
- package/app/components/ui/card/CardDescription.vue +17 -0
- package/app/components/ui/card/CardFooter.vue +17 -0
- package/app/components/ui/card/CardHeader.vue +22 -0
- package/app/components/ui/card/CardTitle.vue +17 -0
- package/app/components/ui/card/index.ts +7 -0
- package/app/components/ui/collapsible/Collapsible.vue +19 -0
- package/app/components/ui/collapsible/CollapsibleContent.vue +12 -0
- package/app/components/ui/collapsible/CollapsibleTrigger.vue +12 -0
- package/app/components/ui/collapsible/index.ts +3 -0
- package/app/components/ui/command/Command.vue +98 -0
- package/app/components/ui/command/CommandDialog.vue +42 -0
- package/app/components/ui/command/CommandEmpty.vue +31 -0
- package/app/components/ui/command/CommandGroup.vue +52 -0
- package/app/components/ui/command/CommandInput.vue +45 -0
- package/app/components/ui/command/CommandItem.vue +85 -0
- package/app/components/ui/command/CommandList.vue +32 -0
- package/app/components/ui/command/CommandSeparator.vue +23 -0
- package/app/components/ui/command/CommandShortcut.vue +19 -0
- package/app/components/ui/command/index.ts +29 -0
- package/app/components/ui/dialog/Dialog.vue +15 -0
- package/app/components/ui/dialog/DialogClose.vue +12 -0
- package/app/components/ui/dialog/DialogContent.vue +61 -0
- package/app/components/ui/dialog/DialogDescription.vue +25 -0
- package/app/components/ui/dialog/DialogFooter.vue +30 -0
- package/app/components/ui/dialog/DialogHeader.vue +17 -0
- package/app/components/ui/dialog/DialogOverlay.vue +28 -0
- package/app/components/ui/dialog/DialogScrollContent.vue +65 -0
- package/app/components/ui/dialog/DialogTitle.vue +25 -0
- package/app/components/ui/dialog/DialogTrigger.vue +12 -0
- package/app/components/ui/dialog/index.ts +10 -0
- package/app/components/ui/dropdown-menu/DropdownMenu.vue +19 -0
- package/app/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +47 -0
- package/app/components/ui/dropdown-menu/DropdownMenuContent.vue +47 -0
- package/app/components/ui/dropdown-menu/DropdownMenuGroup.vue +12 -0
- package/app/components/ui/dropdown-menu/DropdownMenuItem.vue +41 -0
- package/app/components/ui/dropdown-menu/DropdownMenuLabel.vue +27 -0
- package/app/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +21 -0
- package/app/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +48 -0
- package/app/components/ui/dropdown-menu/DropdownMenuSeparator.vue +23 -0
- package/app/components/ui/dropdown-menu/DropdownMenuShortcut.vue +19 -0
- package/app/components/ui/dropdown-menu/DropdownMenuSub.vue +19 -0
- package/app/components/ui/dropdown-menu/DropdownMenuSubContent.vue +34 -0
- package/app/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +34 -0
- package/app/components/ui/dropdown-menu/DropdownMenuTrigger.vue +17 -0
- package/app/components/ui/dropdown-menu/index.ts +16 -0
- package/app/components/ui/input/Input.vue +35 -0
- package/app/components/ui/input/index.ts +1 -0
- package/app/components/ui/navigation-menu/NavigationMenu.vue +42 -0
- package/app/components/ui/navigation-menu/NavigationMenuContent.vue +35 -0
- package/app/components/ui/navigation-menu/NavigationMenuIndicator.vue +32 -0
- package/app/components/ui/navigation-menu/NavigationMenuItem.vue +23 -0
- package/app/components/ui/navigation-menu/NavigationMenuLink.vue +30 -0
- package/app/components/ui/navigation-menu/NavigationMenuList.vue +30 -0
- package/app/components/ui/navigation-menu/NavigationMenuTrigger.vue +31 -0
- package/app/components/ui/navigation-menu/NavigationMenuViewport.vue +30 -0
- package/app/components/ui/navigation-menu/index.ts +14 -0
- package/app/components/ui/scroll-area/ScrollArea.vue +31 -0
- package/app/components/ui/scroll-area/ScrollBar.vue +38 -0
- package/app/components/ui/scroll-area/index.ts +2 -0
- package/app/components/ui/select/Select.vue +15 -0
- package/app/components/ui/select/SelectContent.vue +59 -0
- package/app/components/ui/select/SelectGroup.vue +19 -0
- package/app/components/ui/select/SelectItem.vue +42 -0
- package/app/components/ui/select/SelectItemText.vue +12 -0
- package/app/components/ui/select/SelectLabel.vue +16 -0
- package/app/components/ui/select/SelectScrollDownButton.vue +28 -0
- package/app/components/ui/select/SelectScrollUpButton.vue +28 -0
- package/app/components/ui/select/SelectSeparator.vue +20 -0
- package/app/components/ui/select/SelectTrigger.vue +32 -0
- package/app/components/ui/select/SelectValue.vue +12 -0
- package/app/components/ui/select/index.ts +11 -0
- package/app/components/ui/separator/Separator.vue +30 -0
- package/app/components/ui/separator/index.ts +1 -0
- package/app/components/ui/sheet/Sheet.vue +15 -0
- package/app/components/ui/sheet/SheetClose.vue +12 -0
- package/app/components/ui/sheet/SheetContent.vue +68 -0
- package/app/components/ui/sheet/SheetDescription.vue +23 -0
- package/app/components/ui/sheet/SheetFooter.vue +15 -0
- package/app/components/ui/sheet/SheetHeader.vue +15 -0
- package/app/components/ui/sheet/SheetOverlay.vue +28 -0
- package/app/components/ui/sheet/SheetTitle.vue +23 -0
- package/app/components/ui/sheet/SheetTrigger.vue +12 -0
- package/app/components/ui/sheet/index.ts +8 -0
- package/app/components/ui/sidebar/Sidebar.vue +110 -0
- package/app/components/ui/sidebar/SidebarContent.vue +23 -0
- package/app/components/ui/sidebar/SidebarFooter.vue +18 -0
- package/app/components/ui/sidebar/SidebarGroup.vue +18 -0
- package/app/components/ui/sidebar/SidebarGroupAction.vue +31 -0
- package/app/components/ui/sidebar/SidebarGroupContent.vue +18 -0
- package/app/components/ui/sidebar/SidebarGroupLabel.vue +30 -0
- package/app/components/ui/sidebar/SidebarHeader.vue +18 -0
- package/app/components/ui/sidebar/SidebarInput.vue +19 -0
- package/app/components/ui/sidebar/SidebarInset.vue +23 -0
- package/app/components/ui/sidebar/SidebarMenu.vue +18 -0
- package/app/components/ui/sidebar/SidebarMenuAction.vue +42 -0
- package/app/components/ui/sidebar/SidebarMenuBadge.vue +28 -0
- package/app/components/ui/sidebar/SidebarMenuButton.vue +60 -0
- package/app/components/ui/sidebar/SidebarMenuButtonChild.vue +36 -0
- package/app/components/ui/sidebar/SidebarMenuItem.vue +18 -0
- package/app/components/ui/sidebar/SidebarMenuSkeleton.vue +35 -0
- package/app/components/ui/sidebar/SidebarMenuSub.vue +24 -0
- package/app/components/ui/sidebar/SidebarMenuSubButton.vue +43 -0
- package/app/components/ui/sidebar/SidebarMenuSubItem.vue +18 -0
- package/app/components/ui/sidebar/SidebarProvider.vue +109 -0
- package/app/components/ui/sidebar/SidebarRail.vue +35 -0
- package/app/components/ui/sidebar/SidebarSeparator.vue +19 -0
- package/app/components/ui/sidebar/SidebarTrigger.vue +26 -0
- package/app/components/ui/sidebar/index.ts +62 -0
- package/app/components/ui/sidebar/utils.ts +19 -0
- package/app/components/ui/skeleton/Skeleton.vue +17 -0
- package/app/components/ui/skeleton/index.ts +1 -0
- package/app/components/ui/sonner/Sonner.vue +67 -0
- package/app/components/ui/sonner/index.ts +1 -0
- package/app/components/ui/tabs/Tabs.vue +26 -0
- package/app/components/ui/tabs/TabsContent.vue +23 -0
- package/app/components/ui/tabs/TabsList.vue +28 -0
- package/app/components/ui/tabs/TabsTrigger.vue +30 -0
- package/app/components/ui/tabs/index.ts +4 -0
- package/app/components/ui/textarea/Textarea.vue +32 -0
- package/app/components/ui/textarea/index.ts +1 -0
- package/app/components/ui/tooltip/Tooltip.vue +15 -0
- package/app/components/ui/tooltip/TooltipContent.vue +49 -0
- package/app/components/ui/tooltip/TooltipProvider.vue +14 -0
- package/app/components/ui/tooltip/TooltipTrigger.vue +12 -0
- package/app/components/ui/tooltip/index.ts +4 -0
- package/app/composables/useActiveHeading.ts +90 -0
- package/app/composables/useDuxtAnimatedHeight.ts +155 -0
- package/app/composables/useDuxtBreadcrumb.ts +60 -0
- package/app/composables/useDuxtChoice.ts +28 -0
- package/app/composables/useDuxtCollection.ts +89 -0
- package/app/composables/useDuxtConfig.ts +47 -0
- package/app/composables/useDuxtNavigation.ts +87 -0
- package/app/composables/useDuxtPageFocus.ts +30 -0
- package/app/composables/useDuxtPath.ts +42 -0
- package/app/composables/useDuxtSearch.ts +208 -0
- package/app/composables/useDuxtSection.ts +44 -0
- package/app/composables/useDuxtSectionRow.ts +49 -0
- package/app/composables/useDuxtShortcuts.ts +58 -0
- package/app/composables/useDuxtSiteUrl.ts +27 -0
- package/app/composables/useDuxtToast.ts +25 -0
- package/app/composables/useDuxtVersion.ts +138 -0
- package/app/composables/useFuzzySearch.ts +83 -0
- package/app/composables/usePackageManager.ts +4 -0
- package/app/composables/useRecentPages.ts +52 -0
- package/app/error.vue +133 -0
- package/app/layouts/changelog.vue +85 -0
- package/app/layouts/default.vue +23 -0
- package/app/layouts/docs.vue +62 -0
- package/app/layouts/reference.vue +85 -0
- package/app/lib/utils.ts +7 -0
- package/app/middleware/duxt-section-layout.global.ts +57 -0
- package/app/pages/[...slug].vue +441 -0
- package/app/pages/index.vue +479 -0
- package/app/types/duxt.d.ts +955 -0
- package/app/utils/aside.ts +16 -0
- package/app/utils/changelog.ts +182 -0
- package/app/utils/code-highlight.ts +116 -0
- package/app/utils/duxt-config.ts +185 -0
- package/app/utils/duxt-text.ts +135 -0
- package/app/utils/file-icons.ts +62 -0
- package/app/utils/generated-sections.ts +190 -0
- package/app/utils/generated-toc.ts +216 -0
- package/app/utils/heading-link.ts +32 -0
- package/app/utils/locale-path.ts +45 -0
- package/app/utils/navigation-tree.ts +206 -0
- package/app/utils/nearest-page.ts +72 -0
- package/app/utils/openapi.ts +1028 -0
- package/app/utils/package-command.ts +162 -0
- package/app/utils/request-samples.ts +635 -0
- package/app/utils/section-scope.ts +97 -0
- package/app/utils/sheet-navigation.ts +100 -0
- package/app/utils/source-file.ts +84 -0
- package/app/utils/version-choices.ts +68 -0
- package/app/utils/version-paths.ts +65 -0
- package/bin/duxt-report.mjs +45 -0
- package/components.json +19 -0
- package/content-cache.ts +193 -0
- package/content.config.ts +38 -0
- package/duxt-app-config.ts +124 -0
- package/highlight-langs.ts +68 -0
- package/i18n/i18n.config.ts +16 -0
- package/i18n/locales/de/duxt/changelog.json +17 -0
- package/i18n/locales/de/duxt/code.json +13 -0
- package/i18n/locales/de/duxt/defaults.json +22 -0
- package/i18n/locales/de/duxt/devtools.json +7 -0
- package/i18n/locales/de/duxt/error.json +10 -0
- package/i18n/locales/de/duxt/footer.json +7 -0
- package/i18n/locales/de/duxt/locale.json +7 -0
- package/i18n/locales/de/duxt/nav.json +17 -0
- package/i18n/locales/de/duxt/openapi.json +89 -0
- package/i18n/locales/de/duxt/page.json +34 -0
- package/i18n/locales/de/duxt/search.json +12 -0
- package/i18n/locales/de/duxt/shortcuts.json +11 -0
- package/i18n/locales/de/duxt/theme.json +7 -0
- package/i18n/locales/de/duxt/toc.json +7 -0
- package/i18n/locales/de/duxt/version.json +25 -0
- package/i18n/locales/en/duxt/changelog.json +17 -0
- package/i18n/locales/en/duxt/code.json +13 -0
- package/i18n/locales/en/duxt/defaults.json +22 -0
- package/i18n/locales/en/duxt/devtools.json +7 -0
- package/i18n/locales/en/duxt/error.json +10 -0
- package/i18n/locales/en/duxt/footer.json +7 -0
- package/i18n/locales/en/duxt/locale.json +7 -0
- package/i18n/locales/en/duxt/nav.json +17 -0
- package/i18n/locales/en/duxt/openapi.json +89 -0
- package/i18n/locales/en/duxt/page.json +34 -0
- package/i18n/locales/en/duxt/search.json +12 -0
- package/i18n/locales/en/duxt/shortcuts.json +11 -0
- package/i18n/locales/en/duxt/theme.json +7 -0
- package/i18n/locales/en/duxt/toc.json +7 -0
- package/i18n/locales/en/duxt/version.json +25 -0
- package/i18n/locales/es/duxt/changelog.json +17 -0
- package/i18n/locales/es/duxt/code.json +13 -0
- package/i18n/locales/es/duxt/defaults.json +22 -0
- package/i18n/locales/es/duxt/devtools.json +7 -0
- package/i18n/locales/es/duxt/error.json +10 -0
- package/i18n/locales/es/duxt/footer.json +7 -0
- package/i18n/locales/es/duxt/locale.json +7 -0
- package/i18n/locales/es/duxt/nav.json +17 -0
- package/i18n/locales/es/duxt/openapi.json +89 -0
- package/i18n/locales/es/duxt/page.json +34 -0
- package/i18n/locales/es/duxt/search.json +12 -0
- package/i18n/locales/es/duxt/shortcuts.json +11 -0
- package/i18n/locales/es/duxt/theme.json +7 -0
- package/i18n/locales/es/duxt/toc.json +7 -0
- package/i18n/locales/es/duxt/version.json +25 -0
- package/i18n/locales/fr/duxt/changelog.json +17 -0
- package/i18n/locales/fr/duxt/code.json +13 -0
- package/i18n/locales/fr/duxt/defaults.json +22 -0
- package/i18n/locales/fr/duxt/devtools.json +7 -0
- package/i18n/locales/fr/duxt/error.json +10 -0
- package/i18n/locales/fr/duxt/footer.json +7 -0
- package/i18n/locales/fr/duxt/locale.json +7 -0
- package/i18n/locales/fr/duxt/nav.json +17 -0
- package/i18n/locales/fr/duxt/openapi.json +89 -0
- package/i18n/locales/fr/duxt/page.json +34 -0
- package/i18n/locales/fr/duxt/search.json +12 -0
- package/i18n/locales/fr/duxt/shortcuts.json +11 -0
- package/i18n/locales/fr/duxt/theme.json +7 -0
- package/i18n/locales/fr/duxt/toc.json +7 -0
- package/i18n/locales/fr/duxt/version.json +25 -0
- package/i18n/locales/pt/duxt/changelog.json +17 -0
- package/i18n/locales/pt/duxt/code.json +13 -0
- package/i18n/locales/pt/duxt/defaults.json +22 -0
- package/i18n/locales/pt/duxt/devtools.json +7 -0
- package/i18n/locales/pt/duxt/error.json +10 -0
- package/i18n/locales/pt/duxt/footer.json +7 -0
- package/i18n/locales/pt/duxt/locale.json +7 -0
- package/i18n/locales/pt/duxt/nav.json +17 -0
- package/i18n/locales/pt/duxt/openapi.json +89 -0
- package/i18n/locales/pt/duxt/page.json +34 -0
- package/i18n/locales/pt/duxt/search.json +12 -0
- package/i18n/locales/pt/duxt/shortcuts.json +11 -0
- package/i18n/locales/pt/duxt/theme.json +7 -0
- package/i18n/locales/pt/duxt/toc.json +7 -0
- package/i18n/locales/pt/duxt/version.json +25 -0
- package/i18n/locales/pt-BR/duxt/error.json +8 -0
- package/i18n/locales/pt-BR/duxt/nav.json +10 -0
- package/i18n/locales/pt-BR/duxt/page.json +10 -0
- package/i18n/locales/pt-BR/duxt/search.json +11 -0
- package/i18n/locales/pt-BR/duxt/version.json +13 -0
- package/mdc.config.ts +28 -0
- package/modules/config.ts +440 -0
- package/modules/devtools.ts +126 -0
- package/modules/git-meta.ts +349 -0
- package/modules/redirects.ts +152 -0
- package/modules/validate.ts +137 -0
- package/nuxt.config.ts +530 -0
- package/openapi-model.ts +358 -0
- package/openapi-parse.ts +1052 -0
- package/package.json +161 -0
- package/public/devtools/cache.html +318 -0
- package/public/devtools/checks.html +309 -0
- package/public/devtools/config.html +461 -0
- package/public/devtools/i18n.html +309 -0
- package/public/devtools/pages.html +348 -0
- package/public/devtools/paths.html +315 -0
- package/public/devtools/redirects.html +309 -0
- package/public/devtools/search.html +324 -0
- package/public/devtools/sources.html +309 -0
- package/public/devtools/versions.html +318 -0
- package/report.ts +303 -0
- package/repository-root.ts +26 -0
- package/section-reports.ts +55 -0
- package/sections-changelog.ts +644 -0
- package/sections-openapi.ts +450 -0
- package/sections-resolve.ts +711 -0
- package/sections.ts +157 -0
- package/server/devtools/content.ts +120 -0
- package/server/devtools/context.ts +38 -0
- package/server/devtools/entry-path.ts +30 -0
- package/server/devtools/handler.ts +104 -0
- package/server/devtools/preview.ts +461 -0
- package/server/devtools/render/content.ts +233 -0
- package/server/devtools/render/sources.ts +414 -0
- package/server/devtools/render/system.ts +352 -0
- package/server/devtools/shell.ts +611 -0
- package/server/devtools/sources.ts +122 -0
- package/server/devtools/system.ts +178 -0
- package/server/mcp/tools/list-pages.ts +52 -0
- package/server/mcp/tools/read-page.ts +57 -0
- package/server/mcp/tools/search-docs.ts +74 -0
- package/server/middleware/raw-markdown.ts +86 -0
- package/server/routes/llms-full.txt.get.ts +75 -0
- package/server/routes/llms.txt.get.ts +63 -0
- package/server/routes/rss.xml.get.ts +125 -0
- package/server/utils/duxt-server-text.ts +46 -0
- package/sources-git.ts +113 -0
- package/sources-resolve.ts +908 -0
- package/sources.ts +287 -0
- package/validate-report.ts +494 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type {
|
|
3
|
+
DuxtOpenApiOperation,
|
|
4
|
+
DuxtOpenApiSecurity,
|
|
5
|
+
DuxtOpenApiSecurityScheme,
|
|
6
|
+
DuxtOpenApiServer
|
|
7
|
+
} from '../../../openapi-model';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* One operation, as the two right-hand columns of the reference.
|
|
11
|
+
*
|
|
12
|
+
* MDC: the `openapi` section type writes `::open-api-operation` into every
|
|
13
|
+
* operation page, with the structure as props and the operation's own
|
|
14
|
+
* description in the slot. The description is Markdown because the
|
|
15
|
+
* specification says it is CommonMark — rendering it as plain text is the
|
|
16
|
+
* commonest thing a reference gets wrong, and it costs the author every link
|
|
17
|
+
* and every code span they wrote.
|
|
18
|
+
*
|
|
19
|
+
* THE COLUMNS. The `reference` layout gives the operation list on the left and
|
|
20
|
+
* the full width; this splits what is left into the description in the middle
|
|
21
|
+
* and the client on the right, which is the arrangement the issue settled on.
|
|
22
|
+
* It is one grid rather than two page regions on purpose: the right column is a
|
|
23
|
+
* property of the OPERATION — its servers, its parameters, its security — so it
|
|
24
|
+
* has to be rendered by whatever renders the operation, and a layout cannot
|
|
25
|
+
* reach it.
|
|
26
|
+
*
|
|
27
|
+
* The structural blocks carry `not-typeset`; the slot does not. A page's prose
|
|
28
|
+
* wants the typeset preset and a parameter table does not, and they are
|
|
29
|
+
* siblings here so each gets what it needs.
|
|
30
|
+
*/
|
|
31
|
+
const props = defineProps<{
|
|
32
|
+
operation: DuxtOpenApiOperation;
|
|
33
|
+
servers?: DuxtOpenApiServer[];
|
|
34
|
+
security?: DuxtOpenApiSecurity;
|
|
35
|
+
securitySchemes?: DuxtOpenApiSecurityScheme[];
|
|
36
|
+
}>();
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* A fragment that lands on the client rather than at the top of the page.
|
|
40
|
+
*
|
|
41
|
+
* The panel sits beside the endpoint at `xl` and BELOW the whole description
|
|
42
|
+
* everywhere narrower — so on a phone, and in any frame narrower than 80rem, a
|
|
43
|
+
* link to the operation shows the prose and hides the one control the page is
|
|
44
|
+
* about. `#…-try-it` is how a reader, a release note or the landing page's own
|
|
45
|
+
* window points at it.
|
|
46
|
+
*
|
|
47
|
+
* Keyed by the operation rather than a bare `try-it`, because
|
|
48
|
+
* `OpenApiOperations` renders a run of these on one page and a duplicated id is
|
|
49
|
+
* an anchor that resolves to whichever came first.
|
|
50
|
+
*/
|
|
51
|
+
const clientAnchor = computed(() =>
|
|
52
|
+
`${props.operation.operationId ?? `${props.operation.method}-${props.operation.path}`}-try-it`
|
|
53
|
+
.toLowerCase()
|
|
54
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
55
|
+
.replace(/^-|-$/g, '')
|
|
56
|
+
);
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
<template>
|
|
60
|
+
<!-- Wider on a wide screen: a `curl` line with a couple of headers wraps at
|
|
61
|
+
23rem however much room the window has, and the column that shows it is
|
|
62
|
+
why `reference` hands its page the whole column rather than capping it at
|
|
63
|
+
a reading measure the way `docs` and `changelog` do.
|
|
64
|
+
|
|
65
|
+
30rem AT `2xl`, not the 34 it was. That number was chosen while the shell
|
|
66
|
+
ran to 100rem, where it left the description the larger half; inside
|
|
67
|
+
90rem the same 34 split the row down the middle, and the description —
|
|
68
|
+
which is what the page is FOR — became the narrower side of a client. -->
|
|
69
|
+
<div
|
|
70
|
+
class="grid gap-8 xl:grid-cols-[minmax(0,1fr)_23rem] 2xl:grid-cols-[minmax(0,1fr)_30rem]"
|
|
71
|
+
>
|
|
72
|
+
<div class="min-w-0">
|
|
73
|
+
<div class="not-typeset flex flex-wrap items-center gap-2">
|
|
74
|
+
<DuxtOpenApiMethod :method="operation.method" class="h-6 px-2" />
|
|
75
|
+
|
|
76
|
+
<code class="font-mono text-sm break-all">{{ operation.path }}</code>
|
|
77
|
+
|
|
78
|
+
<!-- A webhook is the same object pointing the other way, and a reader
|
|
79
|
+
who does not know that will try to call it. -->
|
|
80
|
+
<UiBadge v-if="operation.kind === 'webhook'" variant="secondary">
|
|
81
|
+
{{ $t('duxt.openapi.webhook') }}
|
|
82
|
+
</UiBadge>
|
|
83
|
+
|
|
84
|
+
<UiBadge v-if="operation.deprecated" variant="destructive">
|
|
85
|
+
{{ $t('duxt.openapi.deprecated') }}
|
|
86
|
+
</UiBadge>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<p
|
|
90
|
+
v-if="operation.operationId"
|
|
91
|
+
class="not-typeset mt-2 font-mono text-xs text-muted-foreground"
|
|
92
|
+
>
|
|
93
|
+
{{ operation.operationId }}
|
|
94
|
+
</p>
|
|
95
|
+
|
|
96
|
+
<div class="mt-4">
|
|
97
|
+
<slot />
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
<div class="not-typeset">
|
|
101
|
+
<DuxtOpenApiSecurity :security="security" />
|
|
102
|
+
|
|
103
|
+
<DuxtOpenApiParameters :parameters="operation.parameters" />
|
|
104
|
+
|
|
105
|
+
<section v-if="operation.requestBody?.content?.length" class="mt-8">
|
|
106
|
+
<h2 class="duxt-label">
|
|
107
|
+
{{ $t('duxt.openapi.requestBody') }}
|
|
108
|
+
<span
|
|
109
|
+
v-if="operation.requestBody.required"
|
|
110
|
+
class="ml-1 text-xs font-medium text-destructive"
|
|
111
|
+
>
|
|
112
|
+
{{ $t('duxt.openapi.required') }}
|
|
113
|
+
</span>
|
|
114
|
+
</h2>
|
|
115
|
+
|
|
116
|
+
<p
|
|
117
|
+
v-if="operation.requestBody.description"
|
|
118
|
+
class="mt-2 text-sm text-muted-foreground"
|
|
119
|
+
>
|
|
120
|
+
{{ operation.requestBody.description }}
|
|
121
|
+
</p>
|
|
122
|
+
|
|
123
|
+
<div class="mt-3 border-t border-border/60 pt-3">
|
|
124
|
+
<DuxtOpenApiMedia
|
|
125
|
+
:content="operation.requestBody.content"
|
|
126
|
+
direction="request"
|
|
127
|
+
/>
|
|
128
|
+
</div>
|
|
129
|
+
</section>
|
|
130
|
+
|
|
131
|
+
<DuxtOpenApiResponses :responses="operation.responses" />
|
|
132
|
+
|
|
133
|
+
<DuxtOpenApiCallbacks :callbacks="operation.callbacks" />
|
|
134
|
+
|
|
135
|
+
<p v-if="operation.externalDocs" class="mt-8 text-sm">
|
|
136
|
+
<a
|
|
137
|
+
:href="operation.externalDocs.url"
|
|
138
|
+
rel="noopener noreferrer"
|
|
139
|
+
target="_blank"
|
|
140
|
+
class="text-primary underline underline-offset-4"
|
|
141
|
+
>
|
|
142
|
+
{{
|
|
143
|
+
operation.externalDocs.description ?? $t('duxt.openapi.moreInfo')
|
|
144
|
+
}}
|
|
145
|
+
</a>
|
|
146
|
+
</p>
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
|
|
150
|
+
<!-- Sticky only where there is a column to be sticky in: below `xl` the
|
|
151
|
+
client sits after the description, which is the order a phone reads.
|
|
152
|
+
|
|
153
|
+
AND IT SCROLLS ITSELF, the way the sidebar and the table of contents
|
|
154
|
+
already do — same expression, `100vh` less the chrome above it. Sticky
|
|
155
|
+
alone pinned a panel taller than the viewport, so the request samples
|
|
156
|
+
under the send button were cut off and only came into view once the
|
|
157
|
+
reader had scrolled the whole page to its end: the panel is beside the
|
|
158
|
+
endpoint precisely so it does not have to be chased there.
|
|
159
|
+
|
|
160
|
+
Bounded and scrollable only at `xl`, because below it the client is in
|
|
161
|
+
normal flow and a second scrollbar inside the page would be one nobody
|
|
162
|
+
asked for.
|
|
163
|
+
|
|
164
|
+
AND IT KEEPS A REM OFF THE CHROME. Pinned at exactly `--duxt-header-offset`
|
|
165
|
+
the card's top border sat against the navbar's bottom border, so the
|
|
166
|
+
two read as one thick line and the panel looked attached to the header
|
|
167
|
+
rather than floating under it. The `max-h` gives the same rem back at
|
|
168
|
+
the bottom, so the panel still ends clear of the viewport edge. -->
|
|
169
|
+
<div
|
|
170
|
+
:id="clientAnchor"
|
|
171
|
+
class="not-typeset min-w-0 scroll-mt-[var(--duxt-header-offset)]"
|
|
172
|
+
>
|
|
173
|
+
<div
|
|
174
|
+
class="xl:sticky xl:top-[calc(var(--duxt-header-offset)+1rem)] xl:max-h-[calc(100vh-var(--duxt-header-offset)-2.5rem)] xl:overflow-y-auto xl:pr-1"
|
|
175
|
+
>
|
|
176
|
+
<DuxtOpenApiClient
|
|
177
|
+
:operation="operation"
|
|
178
|
+
:servers="servers"
|
|
179
|
+
:security="security"
|
|
180
|
+
:security-schemes="securitySchemes"
|
|
181
|
+
/>
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
</template>
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { DuxtOpenApiExternalDocs } from '../../../openapi-model';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The endpoints under one tag, as the list a reader scans.
|
|
6
|
+
*
|
|
7
|
+
* MDC: `::open-api-operations` on a tag's index page. The method is a coloured
|
|
8
|
+
* chip and the path is the link text, because "find this endpoint" is the
|
|
9
|
+
* search a reader actually performs — a list of summaries alone makes them read
|
|
10
|
+
* every line to find `DELETE /pets/{id}`.
|
|
11
|
+
*/
|
|
12
|
+
defineProps<{
|
|
13
|
+
operations?: {
|
|
14
|
+
method: string;
|
|
15
|
+
path: string;
|
|
16
|
+
kind?: string;
|
|
17
|
+
summary?: string;
|
|
18
|
+
deprecated?: boolean;
|
|
19
|
+
to: string;
|
|
20
|
+
}[];
|
|
21
|
+
externalDocs?: DuxtOpenApiExternalDocs;
|
|
22
|
+
}>();
|
|
23
|
+
|
|
24
|
+
const localeLink = useDuxtLink();
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<template>
|
|
28
|
+
<div>
|
|
29
|
+
<!-- Outside `not-typeset`: the tag's own description is Markdown and wants
|
|
30
|
+
the typeset preset; the list below emphatically does not. -->
|
|
31
|
+
<slot />
|
|
32
|
+
|
|
33
|
+
<ul v-if="operations?.length" class="not-typeset mt-6 -mx-3">
|
|
34
|
+
<li
|
|
35
|
+
v-for="entry in operations"
|
|
36
|
+
:key="`${entry.method}-${entry.to}`"
|
|
37
|
+
class="border-t border-border/60 first:border-t-0"
|
|
38
|
+
>
|
|
39
|
+
<NuxtLink
|
|
40
|
+
:to="localeLink(entry.to) ?? entry.to"
|
|
41
|
+
class="flex flex-wrap items-center gap-3 rounded-lg px-3 py-3 transition-colors hover:bg-muted/40"
|
|
42
|
+
>
|
|
43
|
+
<DuxtOpenApiMethod :method="entry.method" class="w-16" />
|
|
44
|
+
|
|
45
|
+
<code class="font-mono text-sm break-all">{{ entry.path }}</code>
|
|
46
|
+
|
|
47
|
+
<span
|
|
48
|
+
v-if="entry.summary"
|
|
49
|
+
class="w-full text-sm text-muted-foreground sm:ml-auto sm:w-auto sm:text-right"
|
|
50
|
+
>
|
|
51
|
+
{{ entry.summary }}
|
|
52
|
+
</span>
|
|
53
|
+
|
|
54
|
+
<UiBadge v-if="entry.deprecated" variant="destructive">
|
|
55
|
+
{{ $t('duxt.openapi.deprecated') }}
|
|
56
|
+
</UiBadge>
|
|
57
|
+
</NuxtLink>
|
|
58
|
+
</li>
|
|
59
|
+
</ul>
|
|
60
|
+
|
|
61
|
+
<p v-if="externalDocs" class="not-typeset mt-6 text-sm">
|
|
62
|
+
<a
|
|
63
|
+
:href="externalDocs.url"
|
|
64
|
+
rel="noopener noreferrer"
|
|
65
|
+
target="_blank"
|
|
66
|
+
class="text-primary underline underline-offset-4"
|
|
67
|
+
>
|
|
68
|
+
{{ externalDocs.description ?? $t('duxt.openapi.moreInfo') }}
|
|
69
|
+
</a>
|
|
70
|
+
</p>
|
|
71
|
+
</div>
|
|
72
|
+
</template>
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type {
|
|
3
|
+
DuxtOpenApiExternalDocs,
|
|
4
|
+
DuxtOpenApiSecurity,
|
|
5
|
+
DuxtOpenApiSecurityScheme,
|
|
6
|
+
DuxtOpenApiServer
|
|
7
|
+
} from '../../../openapi-model';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The reference's front page: what the API is, where it lives, how to get in.
|
|
11
|
+
*
|
|
12
|
+
* MDC: `::open-api-overview` on the section's index page, with the document's
|
|
13
|
+
* own `info.description` in the slot. It is the page a reader lands on from the
|
|
14
|
+
* navbar entry, and the three questions it answers — base URL, authentication,
|
|
15
|
+
* which groups of endpoints exist — are the three a reference is opened for
|
|
16
|
+
* before any single endpoint is.
|
|
17
|
+
*/
|
|
18
|
+
const props = defineProps<{
|
|
19
|
+
version?: string;
|
|
20
|
+
servers?: DuxtOpenApiServer[];
|
|
21
|
+
securitySchemes?: DuxtOpenApiSecurityScheme[];
|
|
22
|
+
security?: DuxtOpenApiSecurity;
|
|
23
|
+
contact?: { name?: string; url?: string; email?: string };
|
|
24
|
+
license?: { name?: string; identifier?: string; url?: string };
|
|
25
|
+
termsOfService?: string;
|
|
26
|
+
externalDocs?: DuxtOpenApiExternalDocs;
|
|
27
|
+
groups?: {
|
|
28
|
+
name: string;
|
|
29
|
+
description?: string;
|
|
30
|
+
webhooks?: boolean;
|
|
31
|
+
operations?: number;
|
|
32
|
+
to: string;
|
|
33
|
+
}[];
|
|
34
|
+
}>();
|
|
35
|
+
|
|
36
|
+
const localeLink = useDuxtLink();
|
|
37
|
+
|
|
38
|
+
/** Every operation the document describes, counted over its groups. */
|
|
39
|
+
const operations = computed(() =>
|
|
40
|
+
(props.groups ?? []).reduce((all, group) => all + (group.operations ?? 0), 0)
|
|
41
|
+
);
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
<template>
|
|
45
|
+
<div>
|
|
46
|
+
<!-- NO SUMMARY LINE. `info.summary` is this page's description, and the
|
|
47
|
+
shell draws a description under the title like it does on every written
|
|
48
|
+
page — printing it here as well put the lead below the rule, where the
|
|
49
|
+
body starts, and said the same sentence twice. -->
|
|
50
|
+
<!-- The document's own description, as the Markdown it is written in. -->
|
|
51
|
+
<slot />
|
|
52
|
+
|
|
53
|
+
<!-- WHAT THE DOCUMENT IS, in figures — the same row the release history
|
|
54
|
+
opens with, and the reason the version is no longer a badge floating
|
|
55
|
+
over the page: a version is a fact about the document, and a fact
|
|
56
|
+
belongs where the other facts are. On its own above the title it read
|
|
57
|
+
as a label for the page, which it never was. -->
|
|
58
|
+
<dl
|
|
59
|
+
v-if="version || groups?.length"
|
|
60
|
+
class="not-typeset mt-8 grid grid-cols-2 gap-x-6 gap-y-7 border-b pb-5 sm:grid-cols-4"
|
|
61
|
+
>
|
|
62
|
+
<div v-if="version" class="flex flex-col gap-1">
|
|
63
|
+
<dd
|
|
64
|
+
class="font-mono text-2xl font-semibold tracking-tight tabular-nums sm:text-3xl"
|
|
65
|
+
>
|
|
66
|
+
{{ version }}
|
|
67
|
+
</dd>
|
|
68
|
+
<dt class="flex items-center gap-1.5 text-xs font-medium text-primary">
|
|
69
|
+
<Icon name="lucide:tag" class="size-3.5" />
|
|
70
|
+
{{ $t('duxt.openapi.version') }}
|
|
71
|
+
</dt>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<div v-if="groups?.length" class="flex flex-col gap-1">
|
|
75
|
+
<dd
|
|
76
|
+
class="text-2xl font-semibold tracking-tight tabular-nums sm:text-3xl"
|
|
77
|
+
>
|
|
78
|
+
{{ operations }}
|
|
79
|
+
</dd>
|
|
80
|
+
<dt class="flex items-center gap-1.5 text-xs font-medium text-primary">
|
|
81
|
+
<Icon name="lucide:arrow-left-right" class="size-3.5" />
|
|
82
|
+
{{ $t('duxt.openapi.operations') }}
|
|
83
|
+
</dt>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<div v-if="groups?.length" class="flex flex-col gap-1">
|
|
87
|
+
<dd
|
|
88
|
+
class="text-2xl font-semibold tracking-tight tabular-nums sm:text-3xl"
|
|
89
|
+
>
|
|
90
|
+
{{ groups.length }}
|
|
91
|
+
</dd>
|
|
92
|
+
<dt class="flex items-center gap-1.5 text-xs font-medium text-primary">
|
|
93
|
+
<Icon name="lucide:folder-tree" class="size-3.5" />
|
|
94
|
+
{{ $t('duxt.openapi.groups') }}
|
|
95
|
+
</dt>
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
<div v-if="servers?.length" class="flex flex-col gap-1">
|
|
99
|
+
<dd
|
|
100
|
+
class="text-2xl font-semibold tracking-tight tabular-nums sm:text-3xl"
|
|
101
|
+
>
|
|
102
|
+
{{ servers.length }}
|
|
103
|
+
</dd>
|
|
104
|
+
<dt class="flex items-center gap-1.5 text-xs font-medium text-primary">
|
|
105
|
+
<Icon name="lucide:server" class="size-3.5" />
|
|
106
|
+
{{ $t('duxt.openapi.serverCount') }}
|
|
107
|
+
</dt>
|
|
108
|
+
</div>
|
|
109
|
+
</dl>
|
|
110
|
+
|
|
111
|
+
<div class="not-typeset">
|
|
112
|
+
<!-- THE GROUPS FIRST, and that is the whole of this reordering: they
|
|
113
|
+
are what a reader opened the reference for, and they stood third —
|
|
114
|
+
under the base URL and the authentication, which are details you
|
|
115
|
+
come back to once you know which endpoint you want. -->
|
|
116
|
+
<section v-if="groups?.length" class="mt-8">
|
|
117
|
+
<h2 class="duxt-label">
|
|
118
|
+
{{ $t('duxt.openapi.endpoints') }}
|
|
119
|
+
</h2>
|
|
120
|
+
|
|
121
|
+
<!-- The groups as rows, with the arrow every other list of links on
|
|
122
|
+
this site steps forward under the pointer. A grid of cards claimed
|
|
123
|
+
they are alternatives to choose between; they are a table of
|
|
124
|
+
contents. -->
|
|
125
|
+
<ul class="mt-3 -mx-3">
|
|
126
|
+
<li
|
|
127
|
+
v-for="group in groups"
|
|
128
|
+
:key="group.to"
|
|
129
|
+
class="border-t border-border/60 first:border-t-0"
|
|
130
|
+
>
|
|
131
|
+
<NuxtLink
|
|
132
|
+
:to="localeLink(group.to) ?? group.to"
|
|
133
|
+
class="group flex items-start gap-3 rounded-lg px-3 py-3 transition-colors hover:bg-muted/40"
|
|
134
|
+
>
|
|
135
|
+
<span class="min-w-0 flex-1">
|
|
136
|
+
<span class="flex flex-wrap items-baseline gap-x-3">
|
|
137
|
+
<span class="font-medium">{{ group.name }}</span>
|
|
138
|
+
<span class="text-xs text-muted-foreground tabular-nums">
|
|
139
|
+
{{ group.operations }}
|
|
140
|
+
</span>
|
|
141
|
+
</span>
|
|
142
|
+
|
|
143
|
+
<span
|
|
144
|
+
v-if="group.description"
|
|
145
|
+
class="mt-1 line-clamp-2 block text-sm text-muted-foreground"
|
|
146
|
+
>
|
|
147
|
+
{{ group.description }}
|
|
148
|
+
</span>
|
|
149
|
+
</span>
|
|
150
|
+
|
|
151
|
+
<Icon
|
|
152
|
+
name="lucide:arrow-right"
|
|
153
|
+
aria-hidden="true"
|
|
154
|
+
class="mt-1 size-3.5 shrink-0 text-muted-foreground transition-transform group-hover:translate-x-0.5"
|
|
155
|
+
/>
|
|
156
|
+
</NuxtLink>
|
|
157
|
+
</li>
|
|
158
|
+
</ul>
|
|
159
|
+
</section>
|
|
160
|
+
|
|
161
|
+
<section v-if="servers?.length" class="mt-8">
|
|
162
|
+
<h2 class="duxt-label">
|
|
163
|
+
{{ $t('duxt.openapi.servers') }}
|
|
164
|
+
</h2>
|
|
165
|
+
|
|
166
|
+
<!-- Rows a hairline apart rather than a bordered card: the card said
|
|
167
|
+
"one object" about a list of several, and three of them down a page
|
|
168
|
+
put a frame around every fact the page states. -->
|
|
169
|
+
<ul class="mt-3 divide-y divide-border/60 border-t border-border/60">
|
|
170
|
+
<li v-for="server in servers" :key="server.url" class="py-3">
|
|
171
|
+
<code class="font-mono text-sm break-all">{{ server.url }}</code>
|
|
172
|
+
|
|
173
|
+
<p
|
|
174
|
+
v-if="server.description"
|
|
175
|
+
class="mt-1 text-sm text-muted-foreground"
|
|
176
|
+
>
|
|
177
|
+
{{ server.description }}
|
|
178
|
+
</p>
|
|
179
|
+
|
|
180
|
+
<!-- A `{variable}` in the URL is not decoration: without its
|
|
181
|
+
default and its allowed values the base URL is unusable. -->
|
|
182
|
+
<dl
|
|
183
|
+
v-if="server.variables?.length"
|
|
184
|
+
class="mt-2 space-y-1 text-xs text-muted-foreground"
|
|
185
|
+
>
|
|
186
|
+
<div
|
|
187
|
+
v-for="variable in server.variables"
|
|
188
|
+
:key="variable.name"
|
|
189
|
+
class="flex flex-wrap gap-x-2"
|
|
190
|
+
>
|
|
191
|
+
<dt class="font-mono">{{ variable.name }}</dt>
|
|
192
|
+
<dd class="font-mono">{{ variable.default }}</dd>
|
|
193
|
+
<dd v-if="variable.enum?.length" class="font-mono">
|
|
194
|
+
{{ variable.enum.join(' · ') }}
|
|
195
|
+
</dd>
|
|
196
|
+
</div>
|
|
197
|
+
</dl>
|
|
198
|
+
</li>
|
|
199
|
+
</ul>
|
|
200
|
+
</section>
|
|
201
|
+
|
|
202
|
+
<section v-if="securitySchemes?.length" class="mt-8">
|
|
203
|
+
<h2 class="duxt-label">
|
|
204
|
+
{{ $t('duxt.openapi.authentication') }}
|
|
205
|
+
</h2>
|
|
206
|
+
|
|
207
|
+
<ul class="mt-3 divide-y divide-border/60 border-t border-border/60">
|
|
208
|
+
<li v-for="scheme in securitySchemes" :key="scheme.key" class="py-3">
|
|
209
|
+
<div class="flex flex-wrap items-baseline gap-2">
|
|
210
|
+
<code class="font-mono text-sm font-medium">{{
|
|
211
|
+
scheme.key
|
|
212
|
+
}}</code>
|
|
213
|
+
<span class="text-xs text-muted-foreground">
|
|
214
|
+
{{ scheme.type }}
|
|
215
|
+
<template v-if="scheme.scheme">· {{ scheme.scheme }}</template>
|
|
216
|
+
<template v-if="scheme.name">· {{ scheme.name }}</template>
|
|
217
|
+
<template v-if="scheme.in">
|
|
218
|
+
· {{ $t(`duxt.openapi.in.${scheme.in}`) }}
|
|
219
|
+
</template>
|
|
220
|
+
</span>
|
|
221
|
+
</div>
|
|
222
|
+
|
|
223
|
+
<p
|
|
224
|
+
v-if="scheme.description"
|
|
225
|
+
class="mt-1 text-sm text-muted-foreground"
|
|
226
|
+
>
|
|
227
|
+
{{ scheme.description }}
|
|
228
|
+
</p>
|
|
229
|
+
</li>
|
|
230
|
+
</ul>
|
|
231
|
+
</section>
|
|
232
|
+
|
|
233
|
+
<!-- ONE ROW, not four labelled lines. Contact, licence and terms are
|
|
234
|
+
what a reader looks up once and never reads: as a definition list
|
|
235
|
+
they took four lines and the visual weight of a section, under an
|
|
236
|
+
actual section that answers what the API does. -->
|
|
237
|
+
<p
|
|
238
|
+
v-if="contact ?? license ?? termsOfService ?? externalDocs"
|
|
239
|
+
class="mt-10 flex flex-wrap items-center gap-x-5 gap-y-2 border-t pt-5 text-xs text-muted-foreground"
|
|
240
|
+
>
|
|
241
|
+
<a
|
|
242
|
+
v-if="contact"
|
|
243
|
+
:href="contact.url ?? `mailto:${contact.email}`"
|
|
244
|
+
rel="noopener noreferrer"
|
|
245
|
+
class="inline-flex items-center gap-1.5 transition-colors hover:text-foreground"
|
|
246
|
+
>
|
|
247
|
+
<Icon name="lucide:mail" class="size-3.5" />
|
|
248
|
+
<!-- The words the label used to print, kept for whoever cannot see
|
|
249
|
+
the icon that replaced them: an envelope beside "Support" says
|
|
250
|
+
"contact" only to a reader who can see the envelope. -->
|
|
251
|
+
<span class="sr-only">{{ $t('duxt.openapi.contact') }}:</span>
|
|
252
|
+
{{ contact.name ?? contact.url ?? contact.email }}
|
|
253
|
+
</a>
|
|
254
|
+
|
|
255
|
+
<a
|
|
256
|
+
v-if="license"
|
|
257
|
+
:href="license.url"
|
|
258
|
+
rel="noopener noreferrer"
|
|
259
|
+
class="inline-flex items-center gap-1.5 transition-colors hover:text-foreground"
|
|
260
|
+
>
|
|
261
|
+
<Icon name="lucide:scale" class="size-3.5" />
|
|
262
|
+
<span class="sr-only">{{ $t('duxt.openapi.license') }}:</span>
|
|
263
|
+
{{ license.name ?? license.identifier }}
|
|
264
|
+
</a>
|
|
265
|
+
|
|
266
|
+
<a
|
|
267
|
+
v-if="termsOfService"
|
|
268
|
+
:href="termsOfService"
|
|
269
|
+
rel="noopener noreferrer"
|
|
270
|
+
class="inline-flex items-center gap-1.5 transition-colors hover:text-foreground"
|
|
271
|
+
>
|
|
272
|
+
<Icon name="lucide:file-text" class="size-3.5" />
|
|
273
|
+
{{ $t('duxt.openapi.terms') }}
|
|
274
|
+
</a>
|
|
275
|
+
|
|
276
|
+
<!-- The one item here whose text the DOCUMENT wrote. `description` is
|
|
277
|
+
prose in OpenAPI's own words, so it may be a label ("Guide") or a
|
|
278
|
+
whole sentence — and a sentence in a row of two-word chips reads as
|
|
279
|
+
a paragraph that lost its paragraph. It is clamped rather than
|
|
280
|
+
shortened: the full text stays in the link, which is what a screen
|
|
281
|
+
reader announces and what the title shows on hover. -->
|
|
282
|
+
<a
|
|
283
|
+
v-if="externalDocs"
|
|
284
|
+
:href="externalDocs.url"
|
|
285
|
+
:title="externalDocs.description"
|
|
286
|
+
rel="noopener noreferrer"
|
|
287
|
+
target="_blank"
|
|
288
|
+
class="inline-flex min-w-0 items-center gap-1.5 transition-colors hover:text-foreground"
|
|
289
|
+
>
|
|
290
|
+
<Icon name="lucide:book-open" class="size-3.5 shrink-0" />
|
|
291
|
+
<span class="max-w-64 truncate">
|
|
292
|
+
{{ externalDocs.description ?? $t('duxt.openapi.moreInfo') }}
|
|
293
|
+
</span>
|
|
294
|
+
<Icon
|
|
295
|
+
name="lucide:arrow-up-right"
|
|
296
|
+
class="size-3 shrink-0 opacity-60"
|
|
297
|
+
/>
|
|
298
|
+
</a>
|
|
299
|
+
</p>
|
|
300
|
+
</div>
|
|
301
|
+
</div>
|
|
302
|
+
</template>
|