@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,168 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* The one place a version is shown.
|
|
4
|
+
*
|
|
5
|
+
* Before, the project's version sat as a badge beside the title while the
|
|
6
|
+
* documentation's versions lived in a separate dropdown on the far right —
|
|
7
|
+
* two controls saying different things, and the right-hand one appeared only
|
|
8
|
+
* on sources that have versions, so the icons beside it shifted as you moved
|
|
9
|
+
* between repositories.
|
|
10
|
+
*
|
|
11
|
+
* Now it is one element next to the title: a badge when there is nothing to
|
|
12
|
+
* choose, the same badge as a trigger when there is.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* `badge` is the header's inline pill. `block` is the mobile sheet's: a
|
|
17
|
+
* full-width control with its own caption, because in a column of navigation
|
|
18
|
+
* rows a bare pill reads as a label rather than as something to press.
|
|
19
|
+
*/
|
|
20
|
+
const props = withDefaults(defineProps<{ variant?: 'badge' | 'block' }>(), {
|
|
21
|
+
variant: 'badge'
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const duxt = useDuxtConfig();
|
|
25
|
+
const path = useDuxtPath();
|
|
26
|
+
const localeLink = useDuxtLink();
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Versions come from the resolved source manifest, so the control can only
|
|
30
|
+
* offer what has a collection behind it, and only for the repository being
|
|
31
|
+
* read — one project's versions say nothing about another's. The list itself
|
|
32
|
+
* is `useDuxtVersion`'s, because the sheet asks for it too — see
|
|
33
|
+
* `versionChoices`.
|
|
34
|
+
*/
|
|
35
|
+
const { choices: versions } = useDuxtVersion();
|
|
36
|
+
|
|
37
|
+
const current = computed(() =>
|
|
38
|
+
sourceForPath(
|
|
39
|
+
path.value,
|
|
40
|
+
versions.value.map((version) => ({ ...version, prefix: version.to ?? '' }))
|
|
41
|
+
)
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const { t, te } = useI18n();
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The caption beside an entry.
|
|
48
|
+
*
|
|
49
|
+
* The list carries a translation KEY where the layer wrote one
|
|
50
|
+
* (`duxt.version.status.deprecated`) and a plain word where a consumer did, so
|
|
51
|
+
* a key that resolves is translated and anything else is shown as written.
|
|
52
|
+
* `asText` because the config type keeps `DuxtText` even though
|
|
53
|
+
* `useDuxtConfig` has already collapsed it to a string.
|
|
54
|
+
*/
|
|
55
|
+
function caption(version: DuxtLink) {
|
|
56
|
+
const value = asText(version.description);
|
|
57
|
+
if (!value) return undefined;
|
|
58
|
+
|
|
59
|
+
return te(value) ? t(value) : value;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** Same page, other version: swap the prefix rather than jumping to its root. */
|
|
63
|
+
function pathIn(version: { to?: string }) {
|
|
64
|
+
return localeLink(
|
|
65
|
+
versionPath(path.value, current.value?.to, version.to ?? '/')
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<template>
|
|
71
|
+
<UiDropdownMenu v-if="versions.length > 1">
|
|
72
|
+
<!-- The trigger is a real <button>, with the Badge inside it. reka-ui puts
|
|
73
|
+
`aria-haspopup` and `aria-expanded` on whatever element it is handed,
|
|
74
|
+
and a <span> is allowed neither — which axe reports and a screen
|
|
75
|
+
reader acts on. -->
|
|
76
|
+
<UiDropdownMenuTrigger as-child>
|
|
77
|
+
<!-- Built like shadcn's own large sidebar button: a square mark, then
|
|
78
|
+
two lines, then the chevrons. The VERSION LEADS and the caption sits
|
|
79
|
+
under it — the reverse of what this was, where the reader met the
|
|
80
|
+
word "Version" before the number they came to read. The caption is
|
|
81
|
+
the version's own lifecycle where it has one ("default",
|
|
82
|
+
"maintenance"), because on a switcher that is the fact worth the
|
|
83
|
+
second line; the label is what is left when it has none. -->
|
|
84
|
+
<button
|
|
85
|
+
v-if="props.variant === 'block'"
|
|
86
|
+
type="button"
|
|
87
|
+
class="flex w-full cursor-pointer items-center gap-2 rounded-md border p-2 text-left transition-colors hover:bg-accent"
|
|
88
|
+
>
|
|
89
|
+
<span
|
|
90
|
+
class="flex aspect-square size-8 shrink-0 items-center justify-center rounded-lg bg-primary text-primary-foreground"
|
|
91
|
+
>
|
|
92
|
+
<Icon name="lucide:git-branch" class="size-4" />
|
|
93
|
+
</span>
|
|
94
|
+
|
|
95
|
+
<span class="grid min-w-0 flex-1 leading-tight">
|
|
96
|
+
<span class="truncate font-mono text-sm font-medium">
|
|
97
|
+
{{ current?.label ?? duxt.version }}
|
|
98
|
+
</span>
|
|
99
|
+
<span class="truncate text-xs text-muted-foreground">
|
|
100
|
+
{{ (current && caption(current)) ?? $t('duxt.version.label') }}
|
|
101
|
+
</span>
|
|
102
|
+
</span>
|
|
103
|
+
|
|
104
|
+
<Icon
|
|
105
|
+
name="lucide:chevrons-up-down"
|
|
106
|
+
class="size-4 shrink-0 text-muted-foreground"
|
|
107
|
+
/>
|
|
108
|
+
</button>
|
|
109
|
+
|
|
110
|
+
<button v-else type="button" class="cursor-pointer">
|
|
111
|
+
<UiBadge
|
|
112
|
+
variant="secondary"
|
|
113
|
+
class="gap-1 font-mono text-[10px] hover:bg-accent"
|
|
114
|
+
>
|
|
115
|
+
{{ current?.label ?? duxt.version }}
|
|
116
|
+
<Icon name="lucide:chevron-down" class="size-3 opacity-60" />
|
|
117
|
+
</UiBadge>
|
|
118
|
+
</button>
|
|
119
|
+
</UiDropdownMenuTrigger>
|
|
120
|
+
|
|
121
|
+
<!-- A project with thirty versions would otherwise open a menu the height
|
|
122
|
+
of the window: reka's available-height only stops it at the viewport
|
|
123
|
+
edge. `min()` keeps that cap and adds a shorter one, so the list
|
|
124
|
+
scrolls at about ten entries instead of filling the screen. -->
|
|
125
|
+
<UiDropdownMenuContent
|
|
126
|
+
align="start"
|
|
127
|
+
class="max-h-[min(20rem,var(--reka-dropdown-menu-content-available-height))]"
|
|
128
|
+
:class="
|
|
129
|
+
props.variant === 'block'
|
|
130
|
+
? 'w-[var(--reka-dropdown-menu-trigger-width)]'
|
|
131
|
+
: 'w-44'
|
|
132
|
+
"
|
|
133
|
+
>
|
|
134
|
+
<UiDropdownMenuItem
|
|
135
|
+
v-for="version in versions"
|
|
136
|
+
:key="version.to"
|
|
137
|
+
as-child
|
|
138
|
+
>
|
|
139
|
+
<NuxtLink :to="pathIn(version)" class="flex items-center gap-2">
|
|
140
|
+
<Icon
|
|
141
|
+
name="lucide:check"
|
|
142
|
+
class="size-3.5"
|
|
143
|
+
:class="version.label === current?.label ? '' : 'opacity-0'"
|
|
144
|
+
/>
|
|
145
|
+
<span class="font-mono text-xs">{{ version.label }}</span>
|
|
146
|
+
<span
|
|
147
|
+
v-if="caption(version)"
|
|
148
|
+
class="ml-auto text-xs text-muted-foreground"
|
|
149
|
+
>
|
|
150
|
+
{{ caption(version) }}
|
|
151
|
+
</span>
|
|
152
|
+
</NuxtLink>
|
|
153
|
+
</UiDropdownMenuItem>
|
|
154
|
+
</UiDropdownMenuContent>
|
|
155
|
+
</UiDropdownMenu>
|
|
156
|
+
|
|
157
|
+
<!-- Nothing to choose: the project's own version, stated rather than offered.
|
|
158
|
+
Always the badge, `block` included — a bordered box with a caption and no
|
|
159
|
+
control in it looks like a select that has stopped working, and the sheet
|
|
160
|
+
puts this one beside the brand rather than in the switcher's strip. -->
|
|
161
|
+
<UiBadge
|
|
162
|
+
v-else-if="duxt.version"
|
|
163
|
+
variant="secondary"
|
|
164
|
+
class="font-mono text-[10px]"
|
|
165
|
+
>
|
|
166
|
+
{{ duxt.version }}
|
|
167
|
+
</UiBadge>
|
|
168
|
+
</template>
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* The visible half of the version problem.
|
|
4
|
+
*
|
|
5
|
+
* `canonical` and `noindex` tell a crawler which version to serve; they tell
|
|
6
|
+
* the reader nothing. Someone who arrived on v0.7.0 from a search result, or
|
|
7
|
+
* from a link in an old issue, sees documentation that looks exactly like the
|
|
8
|
+
* current one. Either half alone leaves one audience wrong, so the head tags in
|
|
9
|
+
* `[...slug].vue` and this banner ship together.
|
|
10
|
+
*/
|
|
11
|
+
const { current, kind, preferred, preferredPath, shouldWarn } =
|
|
12
|
+
useDuxtVersion();
|
|
13
|
+
const localeLink = useDuxtLink();
|
|
14
|
+
|
|
15
|
+
const message = computed(() => `duxt.version.${kind.value}`);
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* An upcoming version is not a mistake to correct.
|
|
19
|
+
*
|
|
20
|
+
* Its reader is told what changes under them, not to upgrade — so the link out
|
|
21
|
+
* is offered only where going to the current version is actually the answer.
|
|
22
|
+
*/
|
|
23
|
+
const offersUpgrade = computed(() =>
|
|
24
|
+
['old', 'deprecated', 'eol'].includes(kind.value)
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Drawn as a Callout, because the theme already has a notice and this is one.
|
|
29
|
+
*
|
|
30
|
+
* The first version of this invented a second: a full coloured border over a
|
|
31
|
+
* tinted surface, beside a Callout three paragraphs below it in the same quiet
|
|
32
|
+
* style. Two notice styles on one page is one too many — a reader learns what a
|
|
33
|
+
* bordered panel means once. So the colour sits on the icon and a thin left
|
|
34
|
+
* rule, the surface stays close to the page, and the state reads as a title
|
|
35
|
+
* with the sentence beneath it.
|
|
36
|
+
*
|
|
37
|
+
* Same palette as `Callout`'s variants, on purpose: sky for information, amber
|
|
38
|
+
* for old, red for over. Whole class names rather than composed ones, because
|
|
39
|
+
* Tailwind scans source text and a class assembled at runtime is not in the
|
|
40
|
+
* stylesheet.
|
|
41
|
+
*/
|
|
42
|
+
const TONES = {
|
|
43
|
+
upcoming: {
|
|
44
|
+
rule: 'border-l-sky-500',
|
|
45
|
+
text: 'text-sky-500',
|
|
46
|
+
icon: 'lucide:flask-conical'
|
|
47
|
+
},
|
|
48
|
+
old: {
|
|
49
|
+
rule: 'border-l-amber-500',
|
|
50
|
+
text: 'text-amber-500',
|
|
51
|
+
icon: 'lucide:triangle-alert'
|
|
52
|
+
},
|
|
53
|
+
deprecated: {
|
|
54
|
+
rule: 'border-l-red-500',
|
|
55
|
+
text: 'text-red-500',
|
|
56
|
+
icon: 'lucide:triangle-alert'
|
|
57
|
+
},
|
|
58
|
+
eol: {
|
|
59
|
+
rule: 'border-l-red-500',
|
|
60
|
+
text: 'text-red-500',
|
|
61
|
+
icon: 'lucide:circle-off'
|
|
62
|
+
}
|
|
63
|
+
} as const;
|
|
64
|
+
|
|
65
|
+
const tone = computed(
|
|
66
|
+
() => TONES[kind.value as keyof typeof TONES] ?? TONES.old
|
|
67
|
+
);
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<template>
|
|
71
|
+
<!-- The icon belongs to the FIRST LINE of the text, not to a line of its own.
|
|
72
|
+
As siblings of one flex row the sentence became its own item and wrapped
|
|
73
|
+
below, leaving the icon stranded above it. -->
|
|
74
|
+
<UiAlert
|
|
75
|
+
v-if="shouldWarn"
|
|
76
|
+
role="status"
|
|
77
|
+
class="mb-6 flex items-start gap-2.5 rounded-md border border-l-2 bg-muted/30 px-3 py-2.5"
|
|
78
|
+
:class="tone.rule"
|
|
79
|
+
>
|
|
80
|
+
<Icon
|
|
81
|
+
:name="tone.icon"
|
|
82
|
+
class="mt-[3px] size-4 shrink-0"
|
|
83
|
+
:class="tone.text"
|
|
84
|
+
/>
|
|
85
|
+
|
|
86
|
+
<div class="min-w-0 flex-1">
|
|
87
|
+
<UiAlertTitle class="mb-0.5 font-medium text-foreground">
|
|
88
|
+
{{ $t(`duxt.version.titles.${kind}`) }}
|
|
89
|
+
</UiAlertTitle>
|
|
90
|
+
|
|
91
|
+
<UiAlertDescription class="text-muted-foreground">
|
|
92
|
+
{{
|
|
93
|
+
$t(message, {
|
|
94
|
+
version: current?.version ?? '',
|
|
95
|
+
preferred: preferred?.version ?? ''
|
|
96
|
+
})
|
|
97
|
+
}}
|
|
98
|
+
|
|
99
|
+
<NuxtLink
|
|
100
|
+
v-if="offersUpgrade && preferred"
|
|
101
|
+
:to="localeLink(preferredPath)"
|
|
102
|
+
class="font-medium text-foreground underline underline-offset-4"
|
|
103
|
+
>
|
|
104
|
+
{{ $t('duxt.version.goToCurrent', { preferred: preferred.version }) }}
|
|
105
|
+
</NuxtLink>
|
|
106
|
+
</UiAlertDescription>
|
|
107
|
+
</div>
|
|
108
|
+
</UiAlert>
|
|
109
|
+
</template>
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* The layer's Open Graph image.
|
|
4
|
+
*
|
|
5
|
+
* Rendered by satori, not a browser, so this is a deliberately small subset of
|
|
6
|
+
* CSS: flexbox, colours, borders, and nothing that needs layout beyond that. No
|
|
7
|
+
* icon font and no external image, because satori resolves neither.
|
|
8
|
+
*
|
|
9
|
+
* The `.satori` in the file name is not decoration: nuxt-og-image reads the
|
|
10
|
+
* renderer out of it and ignores a template that does not name one.
|
|
11
|
+
*
|
|
12
|
+
* A consumer overrides it the ordinary way — its own
|
|
13
|
+
* `app/components/OgImage/Duxt.satori.vue` wins over the layer's, and pages go
|
|
14
|
+
* on asking for `'Duxt'`.
|
|
15
|
+
*/
|
|
16
|
+
withDefaults(
|
|
17
|
+
defineProps<{
|
|
18
|
+
title?: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
site?: string;
|
|
21
|
+
version?: string;
|
|
22
|
+
}>(),
|
|
23
|
+
{
|
|
24
|
+
title: 'Documentation',
|
|
25
|
+
description: '',
|
|
26
|
+
site: '',
|
|
27
|
+
version: ''
|
|
28
|
+
}
|
|
29
|
+
);
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<template>
|
|
33
|
+
<div
|
|
34
|
+
style="
|
|
35
|
+
display: flex;
|
|
36
|
+
flex-direction: column;
|
|
37
|
+
justify-content: space-between;
|
|
38
|
+
width: 100%;
|
|
39
|
+
height: 100%;
|
|
40
|
+
padding: 80px;
|
|
41
|
+
background: #0a0a0a;
|
|
42
|
+
color: #fafafa;
|
|
43
|
+
font-family: sans-serif;
|
|
44
|
+
"
|
|
45
|
+
>
|
|
46
|
+
<div style="display: flex; align-items: center; font-size: 30px">
|
|
47
|
+
<span style="font-weight: 700">{{ site }}</span>
|
|
48
|
+
<span
|
|
49
|
+
v-if="version"
|
|
50
|
+
style="
|
|
51
|
+
margin-left: 20px;
|
|
52
|
+
padding: 6px 16px;
|
|
53
|
+
border: 2px solid #404040;
|
|
54
|
+
border-radius: 999px;
|
|
55
|
+
font-size: 22px;
|
|
56
|
+
color: #a3a3a3;
|
|
57
|
+
"
|
|
58
|
+
>
|
|
59
|
+
{{ version }}
|
|
60
|
+
</span>
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<div style="display: flex; flex-direction: column">
|
|
64
|
+
<div style="font-size: 68px; font-weight: 700; line-height: 1.1">
|
|
65
|
+
{{ title }}
|
|
66
|
+
</div>
|
|
67
|
+
<div
|
|
68
|
+
v-if="description"
|
|
69
|
+
style="
|
|
70
|
+
margin-top: 24px;
|
|
71
|
+
font-size: 30px;
|
|
72
|
+
line-height: 1.4;
|
|
73
|
+
color: #a3a3a3;
|
|
74
|
+
"
|
|
75
|
+
>
|
|
76
|
+
{{ description.slice(0, 140) }}
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|
|
79
|
+
|
|
80
|
+
<div style="display: flex; height: 10px; background: #fafafa" />
|
|
81
|
+
</div>
|
|
82
|
+
</template>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { AccordionRoot } from 'reka-ui';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* `::accordion` around `:::accordion-item{label="…"}` blocks.
|
|
6
|
+
*
|
|
7
|
+
* On reka-ui's primitives, like the tree and the tabs, for the same reason:
|
|
8
|
+
* a hand-rolled disclosure has no keyboard handling, no `aria-expanded` and no
|
|
9
|
+
* relationship between the trigger and the region it opens.
|
|
10
|
+
*
|
|
11
|
+
* `type="multiple"` on purpose. A FAQ where opening one answer closes the one
|
|
12
|
+
* you were half-way through is a worse FAQ.
|
|
13
|
+
*/
|
|
14
|
+
export interface DuxtAccordionContext {
|
|
15
|
+
register: (label: string) => string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const items = ref<{ value: string; label: string }[]>([]);
|
|
19
|
+
|
|
20
|
+
provide<DuxtAccordionContext>('duxt-accordion', {
|
|
21
|
+
register(label: string) {
|
|
22
|
+
const value = `item-${items.value.length}`;
|
|
23
|
+
items.value.push({ value, label });
|
|
24
|
+
return value;
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// The item component imports its own primitives from reka-ui. Re-exporting them
|
|
29
|
+
// here would be an ES module export inside <script setup>, which the SFC
|
|
30
|
+
// compiler rejects outright — a type export is fine, a value export is not.
|
|
31
|
+
</script>
|
|
32
|
+
|
|
33
|
+
<template>
|
|
34
|
+
<AccordionRoot type="multiple" class="my-6 rounded-lg border">
|
|
35
|
+
<slot />
|
|
36
|
+
</AccordionRoot>
|
|
37
|
+
</template>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
AccordionContent,
|
|
4
|
+
AccordionHeader,
|
|
5
|
+
AccordionItem as Item,
|
|
6
|
+
AccordionTrigger
|
|
7
|
+
} from 'reka-ui';
|
|
8
|
+
import type { DuxtAccordionContext } from './Accordion.vue';
|
|
9
|
+
|
|
10
|
+
const props = defineProps<{ label?: string; icon?: string }>();
|
|
11
|
+
|
|
12
|
+
const parent = inject<DuxtAccordionContext | undefined>(
|
|
13
|
+
'duxt-accordion',
|
|
14
|
+
undefined
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
const value = parent?.register(props.label ?? '') ?? 'item-0';
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<Item :value="value" class="border-b last:border-b-0">
|
|
22
|
+
<AccordionHeader>
|
|
23
|
+
<AccordionTrigger
|
|
24
|
+
class="group flex w-full cursor-pointer items-center gap-2 px-4 py-3 text-left text-sm font-medium hover:bg-accent/50"
|
|
25
|
+
>
|
|
26
|
+
<Icon v-if="icon" :name="icon" class="size-4 text-muted-foreground" />
|
|
27
|
+
<span class="min-w-0">{{ label }}</span>
|
|
28
|
+
<Icon
|
|
29
|
+
name="lucide:chevron-down"
|
|
30
|
+
class="ml-auto size-4 shrink-0 text-muted-foreground transition-transform group-data-[state=open]:rotate-180"
|
|
31
|
+
/>
|
|
32
|
+
</AccordionTrigger>
|
|
33
|
+
</AccordionHeader>
|
|
34
|
+
|
|
35
|
+
<!-- No enter/leave animation: the keyframes shadcn's own Accordion ships
|
|
36
|
+
come with that component, which this theme does not install. An
|
|
37
|
+
unstyled `animate-accordion-down` class is a silent no-op, and a
|
|
38
|
+
disclosure that opens instantly is not worse than one that appears
|
|
39
|
+
to. -->
|
|
40
|
+
<AccordionContent class="overflow-hidden">
|
|
41
|
+
<div class="px-4 pb-3 text-sm [&>*:last-child]:mb-0">
|
|
42
|
+
<slot />
|
|
43
|
+
</div>
|
|
44
|
+
</AccordionContent>
|
|
45
|
+
</Item>
|
|
46
|
+
</template>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// MDC: `::callout{type="warning"}`. Quieter than a coloured panel — the colour
|
|
3
|
+
// sits on the icon and a thin left rule, the surface stays close to the page,
|
|
4
|
+
// and the title reads as text rather than as a warning label.
|
|
5
|
+
const props = withDefaults(
|
|
6
|
+
defineProps<{
|
|
7
|
+
type?: 'info' | 'tip' | 'warning' | 'danger';
|
|
8
|
+
title?: string;
|
|
9
|
+
icon?: string;
|
|
10
|
+
}>(),
|
|
11
|
+
{ type: 'info' }
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
const variants = {
|
|
15
|
+
info: { icon: 'lucide:info', rule: 'border-l-sky-500', text: 'text-sky-500' },
|
|
16
|
+
tip: {
|
|
17
|
+
icon: 'lucide:lightbulb',
|
|
18
|
+
rule: 'border-l-emerald-500',
|
|
19
|
+
text: 'text-emerald-500'
|
|
20
|
+
},
|
|
21
|
+
warning: {
|
|
22
|
+
icon: 'lucide:triangle-alert',
|
|
23
|
+
rule: 'border-l-amber-500',
|
|
24
|
+
text: 'text-amber-500'
|
|
25
|
+
},
|
|
26
|
+
danger: {
|
|
27
|
+
icon: 'lucide:octagon-alert',
|
|
28
|
+
rule: 'border-l-red-500',
|
|
29
|
+
text: 'text-red-500'
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const variant = computed(() => variants[props.type]);
|
|
34
|
+
</script>
|
|
35
|
+
|
|
36
|
+
<template>
|
|
37
|
+
<UiAlert
|
|
38
|
+
class="my-5 flex items-start gap-2.5 rounded-md border border-l-2 bg-muted/30 px-3 py-2.5"
|
|
39
|
+
:class="variant.rule"
|
|
40
|
+
>
|
|
41
|
+
<Icon
|
|
42
|
+
:name="icon ?? variant.icon"
|
|
43
|
+
class="mt-[3px] size-4 shrink-0"
|
|
44
|
+
:class="variant.text"
|
|
45
|
+
/>
|
|
46
|
+
|
|
47
|
+
<div class="min-w-0 flex-1">
|
|
48
|
+
<UiAlertTitle v-if="title" class="mb-0.5 font-medium text-foreground">
|
|
49
|
+
{{ title }}
|
|
50
|
+
</UiAlertTitle>
|
|
51
|
+
<UiAlertDescription
|
|
52
|
+
class="text-muted-foreground [&>*:first-child]:mt-0 [&>*:last-child]:mb-0 [&_a]:text-foreground [&_code]:text-foreground [&_p]:my-1.5"
|
|
53
|
+
>
|
|
54
|
+
<slot />
|
|
55
|
+
</UiAlertDescription>
|
|
56
|
+
</div>
|
|
57
|
+
</UiAlert>
|
|
58
|
+
</template>
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* One group of a release — "Features", "Bug Fixes", whatever the file said.
|
|
4
|
+
*
|
|
5
|
+
* MDC: `::changelog-group{name}`, written by `sections-changelog.ts` around the
|
|
6
|
+
* entries it found under one heading. The NAME IS THE FILE'S OWN, verbatim and
|
|
7
|
+
* untranslated: release-please, changesets and Keep a Changelog each write
|
|
8
|
+
* their own set, in the language the project is kept in, and a layer that
|
|
9
|
+
* mapped them onto a fixed taxonomy would drop the first heading it did not
|
|
10
|
+
* recognise. The count beside it is the entries this group lists.
|
|
11
|
+
*
|
|
12
|
+
* The entries themselves arrive in the SLOT, as the Markdown they were written
|
|
13
|
+
* as — so the search indexes them, `llms-full.txt` carries them and the copy
|
|
14
|
+
* button hands a model prose rather than a component call.
|
|
15
|
+
*
|
|
16
|
+
* A LABEL, NOT A HEADLINE. The name is set small, upper-case and in the
|
|
17
|
+
* group's own tone, above a list that closes up under it — the shape a release
|
|
18
|
+
* note actually has. Set as a 20-pixel headline it claimed the weight of a
|
|
19
|
+
* chapter for a word that names four bullet points, and six of them down a page
|
|
20
|
+
* read as six sections rather than as one release. It is still an `<h2>`: the
|
|
21
|
+
* outline, the contents column and the anchor are unchanged, and only its
|
|
22
|
+
* setting says what it is worth.
|
|
23
|
+
*
|
|
24
|
+
* The COLOUR is the one thing added to the name, and it is the same colour the
|
|
25
|
+
* group has on the overview — see `changelogTone`. Here it is the tone's TEXT
|
|
26
|
+
* pair rather than the dot's fill: a run of words and a six-pixel dot do not
|
|
27
|
+
* clear contrast at the same lightness. It stays a hint and never a meaning: a
|
|
28
|
+
* name the hint list does not know still gets a stable colour of its own, which
|
|
29
|
+
* is what makes the same kind of change scannable down a page of forty releases
|
|
30
|
+
* in any language.
|
|
31
|
+
*
|
|
32
|
+
* The `⚠` release-please prefixes its breaking block with is DRAWN AWAY rather
|
|
33
|
+
* than parsed away — see `changelogLabel`. The name it matches, anchors and
|
|
34
|
+
* filters on is still the file's own, whole.
|
|
35
|
+
*
|
|
36
|
+
* The entries' own markers are GREY, and deliberately not the tone. The colour
|
|
37
|
+
* is already stated once, in the label directly above them; stated again on
|
|
38
|
+
* every line it stopped being a signal and became a page of confetti — which is
|
|
39
|
+
* the failure a hint makes when it is repeated rather than placed. They are
|
|
40
|
+
* styled from `duxt.css`, because they arrive as Markdown from the slot.
|
|
41
|
+
*/
|
|
42
|
+
const props = defineProps<{ name: string; count?: number }>();
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The heading's anchor, so one group of one release can be linked to.
|
|
46
|
+
*
|
|
47
|
+
* Shared with the contents column, which is built from the page's AST and
|
|
48
|
+
* never sees this component render — a slug computed in both places is a
|
|
49
|
+
* contents column whose links go nowhere. See `app/utils/changelog.ts`.
|
|
50
|
+
*/
|
|
51
|
+
const anchor = computed(() => changelogAnchor(props.name));
|
|
52
|
+
|
|
53
|
+
const tone = computed(() => changelogTone(props.name));
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<template>
|
|
57
|
+
<section class="mt-9 first:mt-5">
|
|
58
|
+
<!-- Flex rather than inline runs, which is what put the count a few pixels
|
|
59
|
+
off the word beside it: a badge set with `align-middle` sits on the
|
|
60
|
+
font's own middle, and neither an upper-case label nor a 0.75rem number
|
|
61
|
+
is centred there. A flex line centres the boxes, and `leading-none`
|
|
62
|
+
is what makes the number's box its digits — with the inherited line
|
|
63
|
+
height it sits low by the difference. -->
|
|
64
|
+
<h2
|
|
65
|
+
:id="anchor"
|
|
66
|
+
class="duxt-label group mb-3 flex scroll-mt-28 items-center gap-2"
|
|
67
|
+
:class="tone.text"
|
|
68
|
+
>
|
|
69
|
+
<a v-if="anchor" :href="`#${anchor}`" class="duxt-heading-link">
|
|
70
|
+
<span class="duxt-anchor" aria-hidden="true">#</span>
|
|
71
|
+
{{ changelogLabel(name) }}
|
|
72
|
+
</a>
|
|
73
|
+
<template v-else>{{ changelogLabel(name) }}</template>
|
|
74
|
+
|
|
75
|
+
<!-- Outside the link: a count is a fact about the group, not part of the
|
|
76
|
+
words it is called. A `span`, because a heading holds phrasing
|
|
77
|
+
content. Its own tracking, because the label's letter-spacing is for
|
|
78
|
+
upper-case words and pushes a number away from nothing. -->
|
|
79
|
+
<span
|
|
80
|
+
v-if="count"
|
|
81
|
+
class="text-xs leading-none font-medium tracking-normal text-muted-foreground tabular-nums"
|
|
82
|
+
>
|
|
83
|
+
{{ count }}
|
|
84
|
+
</span>
|
|
85
|
+
</h2>
|
|
86
|
+
|
|
87
|
+
<div class="duxt-release">
|
|
88
|
+
<slot />
|
|
89
|
+
</div>
|
|
90
|
+
</section>
|
|
91
|
+
</template>
|