@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,496 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const duxt = useDuxtConfig();
|
|
3
|
+
const colorMode = useColorMode();
|
|
4
|
+
const path = useDuxtPath();
|
|
5
|
+
const localeLink = useDuxtLink();
|
|
6
|
+
|
|
7
|
+
const { data: navigation } = await useDuxtNavigation();
|
|
8
|
+
|
|
9
|
+
// The mobile sheet shows the same branch the sidebar does.
|
|
10
|
+
const { items } = useDuxtSection(navigation);
|
|
11
|
+
|
|
12
|
+
function toggleTheme() {
|
|
13
|
+
colorMode.preference = colorMode.value === 'dark' ? 'light' : 'dark';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* An entry with neither `to` nor children means "the documentation".
|
|
18
|
+
*
|
|
19
|
+
* The layer's own "Docs" entry ships without a `to` on purpose: where the
|
|
20
|
+
* documentation lives depends on the consumer's prefixes, which the layer
|
|
21
|
+
* cannot know. Resolving it to the first section here is what makes the default
|
|
22
|
+
* navbar work on a versioned site and on a flat one alike — and every place
|
|
23
|
+
* that renders a navigation entry has to go through this, or the entry renders
|
|
24
|
+
* as an anchor with no href.
|
|
25
|
+
*/
|
|
26
|
+
function linkTarget(link: DuxtLink) {
|
|
27
|
+
return link.to ?? duxt.sections?.[0]?.to ?? '/';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function isActive(to?: string) {
|
|
31
|
+
return Boolean(to && to !== '/' && path.value.startsWith(to));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Whether a navbar entry owns the page — which for "the documentation" is not
|
|
36
|
+
* the same question as whether its href matches.
|
|
37
|
+
*
|
|
38
|
+
* A `to`-less entry resolves to the FIRST section so the link goes somewhere,
|
|
39
|
+
* and reusing that resolved href for the highlight was wrong: it lit "Docs"
|
|
40
|
+
* only inside section one and left the navbar showing nothing at all on every
|
|
41
|
+
* other section, which is exactly where a reader most needs to see where they
|
|
42
|
+
* are. Such an entry stands for the whole documentation, so it is active
|
|
43
|
+
* wherever ANY section is.
|
|
44
|
+
*/
|
|
45
|
+
function entryActive(link: DuxtLink) {
|
|
46
|
+
if (link.to) return isActive(link.to);
|
|
47
|
+
|
|
48
|
+
// THE ROOT AREA'S sections, not every entry the site declared: a to-less
|
|
49
|
+
// entry stands for the documentation, and on a site with a second source the
|
|
50
|
+
// list also holds that source's parts — which would light "Docs" on a page
|
|
51
|
+
// that is not documentation at all, beside the entry that really owns it.
|
|
52
|
+
return sectionsForPath(
|
|
53
|
+
duxt.sections ?? [],
|
|
54
|
+
duxt.resolvedSources ?? [],
|
|
55
|
+
'/'
|
|
56
|
+
).some((section) => isActive(section.to));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The sheet is controlled so that navigating closes it.
|
|
61
|
+
*
|
|
62
|
+
* Watching the route rather than binding a close to every link: the sheet holds
|
|
63
|
+
* four kinds of them — the navbar entries, their children, the sections, and
|
|
64
|
+
* `DuxtNavigation`'s whole tree — and that last one also renders in the desktop
|
|
65
|
+
* sidebar, where a `SheetClose` has no dialog to talk to. One watcher covers
|
|
66
|
+
* them all, and leaves an external link (which does not move the route) alone.
|
|
67
|
+
*/
|
|
68
|
+
// Whether the version is something to pick or something to state — it decides
|
|
69
|
+
// where the sheet puts it, so the sheet has to ask before it renders either.
|
|
70
|
+
const { switchable } = useDuxtVersion();
|
|
71
|
+
|
|
72
|
+
const sheetOpen = ref(false);
|
|
73
|
+
const route = useRoute();
|
|
74
|
+
|
|
75
|
+
watch(
|
|
76
|
+
() => route.fullPath,
|
|
77
|
+
() => {
|
|
78
|
+
sheetOpen.value = false;
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
// One tree instead of two lists: the sections become children of the entry
|
|
83
|
+
// that stands for the documentation. See `buildSheetNavigation`.
|
|
84
|
+
const sheet = computed(() =>
|
|
85
|
+
buildSheetNavigation(duxt.navigation, duxt.sections, duxt.resolvedSources)
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
/** A group owns the page when any of its children does. */
|
|
89
|
+
function groupActive(link: DuxtLink) {
|
|
90
|
+
return (link.children ?? []).some((child) => isActive(child.to));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Which navigation groups in the sheet are open.
|
|
95
|
+
*
|
|
96
|
+
* Controlled rather than `default-open`, for the reason `DuxtNavigation`
|
|
97
|
+
* spells out: the initial value is read once, so a group the reader lands
|
|
98
|
+
* inside would stay shut. A group they close by hand stays closed, because the
|
|
99
|
+
* route only ever forces one open.
|
|
100
|
+
*/
|
|
101
|
+
const openGroups = ref<Record<string, boolean>>({});
|
|
102
|
+
|
|
103
|
+
watchEffect(() => {
|
|
104
|
+
for (const entry of sheet.value.entries) {
|
|
105
|
+
const key = asText(entry.label);
|
|
106
|
+
if (key && entry.children?.length && groupActive(entry)) {
|
|
107
|
+
openGroups.value[key] = true;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
function groupOpen(link: DuxtLink) {
|
|
113
|
+
return openGroups.value[asText(link.label) ?? ''] ?? false;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function setGroupOpen(link: DuxtLink, value: boolean) {
|
|
117
|
+
openGroups.value[asText(link.label) ?? ''] = value;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** `page` for the page itself, `true` for the branch holding it. */
|
|
121
|
+
function current(to?: string) {
|
|
122
|
+
if (path.value === to) return 'page';
|
|
123
|
+
return isActive(to) ? 'true' : undefined;
|
|
124
|
+
}
|
|
125
|
+
</script>
|
|
126
|
+
|
|
127
|
+
<template>
|
|
128
|
+
<header
|
|
129
|
+
class="sticky top-0 z-50 w-full border-b bg-background/95 backdrop-blur-md"
|
|
130
|
+
>
|
|
131
|
+
<!-- Row one: identity and global links. Row two carries the sections, the
|
|
132
|
+
way nuxt.com splits them — the docs tree never reaches this far up. -->
|
|
133
|
+
<div
|
|
134
|
+
class="mx-auto grid h-14 max-w-[90rem] grid-cols-[auto_1fr_auto] items-center gap-4 px-4 lg:grid-cols-[1fr_auto_1fr] lg:px-8"
|
|
135
|
+
>
|
|
136
|
+
<div class="flex items-center gap-2">
|
|
137
|
+
<UiSheet v-model:open="sheetOpen">
|
|
138
|
+
<UiSheetTrigger as-child>
|
|
139
|
+
<UiButton
|
|
140
|
+
variant="ghost"
|
|
141
|
+
size="icon"
|
|
142
|
+
class="lg:hidden"
|
|
143
|
+
:aria-label="$t('duxt.nav.open')"
|
|
144
|
+
>
|
|
145
|
+
<Icon name="lucide:menu" class="size-5" />
|
|
146
|
+
</UiButton>
|
|
147
|
+
</UiSheetTrigger>
|
|
148
|
+
<UiSheetContent side="left" class="flex w-80 flex-col gap-0 p-0">
|
|
149
|
+
<UiSheetHeader class="border-b pr-14">
|
|
150
|
+
<UiSheetTitle class="flex items-center gap-2">
|
|
151
|
+
<DuxtBrand />
|
|
152
|
+
|
|
153
|
+
<!-- One version and no choice: a fact about the project, so it
|
|
154
|
+
sits with the identity as a badge rather than filling a
|
|
155
|
+
strip of its own with a control that cannot be used. Only
|
|
156
|
+
text, so a heading may hold it. -->
|
|
157
|
+
<span v-if="!switchable" class="sm:hidden">
|
|
158
|
+
<DuxtVersion />
|
|
159
|
+
</span>
|
|
160
|
+
</UiSheetTitle>
|
|
161
|
+
</UiSheetHeader>
|
|
162
|
+
|
|
163
|
+
<!-- Its own strip under the header rather than beside the brand:
|
|
164
|
+
the close button owns that corner, and the version is a control
|
|
165
|
+
the reader operates, not part of the identity. -->
|
|
166
|
+
<div v-if="switchable" class="border-b p-4 sm:hidden">
|
|
167
|
+
<DuxtVersion variant="block" />
|
|
168
|
+
</div>
|
|
169
|
+
|
|
170
|
+
<!-- Everything the desktop header holds, in one scrollable column,
|
|
171
|
+
widest first: the navbar links, then the sections, then the
|
|
172
|
+
tree of the section you are in. On a phone the second navbar
|
|
173
|
+
row is hidden, so without this the sections are unreachable. -->
|
|
174
|
+
<div class="flex-1 overflow-y-auto p-4">
|
|
175
|
+
<template v-if="sheet.entries.length || duxt.links?.length">
|
|
176
|
+
<p
|
|
177
|
+
class="mb-2 px-2 text-[11px] font-semibold tracking-wider text-muted-foreground uppercase"
|
|
178
|
+
>
|
|
179
|
+
{{ $t('duxt.nav.menu') }}
|
|
180
|
+
</p>
|
|
181
|
+
<ul class="space-y-0.5 text-sm">
|
|
182
|
+
<li v-for="link in sheet.entries" :key="asText(link.label)">
|
|
183
|
+
<!-- A group opens in place rather than flattening into its
|
|
184
|
+
parent's list: on the desktop it is a dropdown, and
|
|
185
|
+
spilling its five links between "Docs" and "Credits"
|
|
186
|
+
lost both the grouping and its name. -->
|
|
187
|
+
<UiCollapsible
|
|
188
|
+
v-if="link.children?.length"
|
|
189
|
+
:open="groupOpen(link)"
|
|
190
|
+
@update:open="(value) => setGroupOpen(link, value)"
|
|
191
|
+
>
|
|
192
|
+
<UiCollapsibleTrigger
|
|
193
|
+
class="group flex items-center gap-2 rounded-md px-2 py-1.5 transition-colors w-full cursor-pointer hover:bg-accent"
|
|
194
|
+
:class="
|
|
195
|
+
groupActive(link)
|
|
196
|
+
? 'font-medium text-foreground'
|
|
197
|
+
: 'text-muted-foreground hover:text-foreground'
|
|
198
|
+
"
|
|
199
|
+
>
|
|
200
|
+
<Icon
|
|
201
|
+
v-if="link.icon"
|
|
202
|
+
:name="link.icon"
|
|
203
|
+
class="size-4"
|
|
204
|
+
/>
|
|
205
|
+
<span class="truncate">{{ link.label }}</span>
|
|
206
|
+
<Icon
|
|
207
|
+
name="lucide:chevron-right"
|
|
208
|
+
class="ml-auto size-3.5 transition-transform group-data-[state=open]:rotate-90"
|
|
209
|
+
/>
|
|
210
|
+
</UiCollapsibleTrigger>
|
|
211
|
+
|
|
212
|
+
<UiCollapsibleContent>
|
|
213
|
+
<ul class="mt-0.5 ml-3.5 space-y-0.5 border-l pl-2.5">
|
|
214
|
+
<li
|
|
215
|
+
v-for="child in link.children"
|
|
216
|
+
:key="child.to ?? asText(child.label)"
|
|
217
|
+
>
|
|
218
|
+
<NuxtLink
|
|
219
|
+
:to="localeLink(child.to)"
|
|
220
|
+
:target="child.external ? '_blank' : undefined"
|
|
221
|
+
:aria-current="current(child.to)"
|
|
222
|
+
class="flex items-center gap-2 rounded-md px-2 py-1.5 transition-colors"
|
|
223
|
+
:class="
|
|
224
|
+
isActive(child.to)
|
|
225
|
+
? 'bg-accent font-medium text-foreground'
|
|
226
|
+
: 'text-muted-foreground hover:bg-accent hover:text-foreground'
|
|
227
|
+
"
|
|
228
|
+
>
|
|
229
|
+
<Icon
|
|
230
|
+
v-if="child.icon"
|
|
231
|
+
:name="child.icon"
|
|
232
|
+
class="size-4"
|
|
233
|
+
/>
|
|
234
|
+
{{ child.label }}
|
|
235
|
+
<Icon
|
|
236
|
+
v-if="child.external"
|
|
237
|
+
name="lucide:arrow-up-right"
|
|
238
|
+
class="size-3 opacity-50"
|
|
239
|
+
/>
|
|
240
|
+
</NuxtLink>
|
|
241
|
+
</li>
|
|
242
|
+
</ul>
|
|
243
|
+
</UiCollapsibleContent>
|
|
244
|
+
</UiCollapsible>
|
|
245
|
+
|
|
246
|
+
<NuxtLink
|
|
247
|
+
v-else
|
|
248
|
+
:to="localeLink(linkTarget(link))"
|
|
249
|
+
:target="link.external ? '_blank' : undefined"
|
|
250
|
+
:aria-current="current(link.to)"
|
|
251
|
+
class="flex items-center gap-2 rounded-md px-2 py-1.5 transition-colors"
|
|
252
|
+
:class="
|
|
253
|
+
entryActive(link)
|
|
254
|
+
? 'bg-accent font-medium text-foreground'
|
|
255
|
+
: 'text-muted-foreground hover:bg-accent hover:text-foreground'
|
|
256
|
+
"
|
|
257
|
+
>
|
|
258
|
+
<Icon v-if="link.icon" :name="link.icon" class="size-4" />
|
|
259
|
+
{{ link.label }}
|
|
260
|
+
<Icon
|
|
261
|
+
v-if="link.external"
|
|
262
|
+
name="lucide:arrow-up-right"
|
|
263
|
+
class="size-3 opacity-50"
|
|
264
|
+
/>
|
|
265
|
+
</NuxtLink>
|
|
266
|
+
</li>
|
|
267
|
+
|
|
268
|
+
<!-- Hidden from the row below lg, so this is the only place
|
|
269
|
+
they are left. -->
|
|
270
|
+
<li v-for="link in duxt.links ?? []" :key="link.to">
|
|
271
|
+
<a
|
|
272
|
+
:href="link.to"
|
|
273
|
+
target="_blank"
|
|
274
|
+
rel="noopener"
|
|
275
|
+
class="flex items-center gap-2 rounded-md px-2 py-1.5 transition-colors text-muted-foreground hover:bg-accent hover:text-foreground"
|
|
276
|
+
>
|
|
277
|
+
<Icon v-if="link.icon" :name="link.icon" class="size-4" />
|
|
278
|
+
{{ link.label }}
|
|
279
|
+
<Icon
|
|
280
|
+
name="lucide:arrow-up-right"
|
|
281
|
+
class="size-3 opacity-50"
|
|
282
|
+
/>
|
|
283
|
+
</a>
|
|
284
|
+
</li>
|
|
285
|
+
</ul>
|
|
286
|
+
</template>
|
|
287
|
+
|
|
288
|
+
<!-- Only what no entry took — see `buildSheetNavigation`. -->
|
|
289
|
+
<template v-if="sheet.sections.length">
|
|
290
|
+
<p
|
|
291
|
+
class="mt-6 mb-2 border-t px-2 pt-4 text-[11px] font-semibold tracking-wider text-muted-foreground uppercase first:mt-0 first:border-t-0 first:pt-0"
|
|
292
|
+
>
|
|
293
|
+
{{ $t('duxt.nav.sections') }}
|
|
294
|
+
</p>
|
|
295
|
+
<ul class="space-y-0.5 text-sm">
|
|
296
|
+
<!-- Keyed on the URL, as the desktop row is: two sources may
|
|
297
|
+
name a section the same, and a label is not unique. -->
|
|
298
|
+
<li
|
|
299
|
+
v-for="section in sheet.sections"
|
|
300
|
+
:key="section.to ?? asText(section.label)"
|
|
301
|
+
>
|
|
302
|
+
<NuxtLink
|
|
303
|
+
:to="localeLink(section.to)"
|
|
304
|
+
:aria-current="current(section.to)"
|
|
305
|
+
class="flex items-center gap-2 rounded-md px-2 py-1.5 transition-colors"
|
|
306
|
+
:class="
|
|
307
|
+
isActive(section.to)
|
|
308
|
+
? 'bg-accent font-medium text-foreground'
|
|
309
|
+
: 'text-muted-foreground hover:bg-accent hover:text-foreground'
|
|
310
|
+
"
|
|
311
|
+
>
|
|
312
|
+
<Icon
|
|
313
|
+
v-if="section.icon"
|
|
314
|
+
:name="section.icon"
|
|
315
|
+
class="size-4"
|
|
316
|
+
/>
|
|
317
|
+
{{ section.label }}
|
|
318
|
+
</NuxtLink>
|
|
319
|
+
</li>
|
|
320
|
+
</ul>
|
|
321
|
+
</template>
|
|
322
|
+
|
|
323
|
+
<template v-if="items.length">
|
|
324
|
+
<p
|
|
325
|
+
class="mt-6 mb-2 border-t px-2 pt-4 text-[11px] font-semibold tracking-wider text-muted-foreground uppercase first:mt-0 first:border-t-0 first:pt-0"
|
|
326
|
+
>
|
|
327
|
+
{{ $t('duxt.nav.pages') }}
|
|
328
|
+
</p>
|
|
329
|
+
<!-- No `label`, so no second "Documentation" landmark: the
|
|
330
|
+
sheet is a dialog with its own name, and the sidebar copy
|
|
331
|
+
of this tree already carries the one on the page. -->
|
|
332
|
+
<DuxtNavigation :items="items" />
|
|
333
|
+
</template>
|
|
334
|
+
</div>
|
|
335
|
+
|
|
336
|
+
<!-- Below sm the row keeps only the brand, the burger and the
|
|
337
|
+
search, so the two settings live here. `mt-auto` on SheetFooter
|
|
338
|
+
parks them at the bottom while the tree above scrolls. -->
|
|
339
|
+
<UiSheetFooter
|
|
340
|
+
class="flex-row items-center justify-center gap-2 border-t sm:hidden"
|
|
341
|
+
>
|
|
342
|
+
<DuxtLocale />
|
|
343
|
+
|
|
344
|
+
<UiButton
|
|
345
|
+
variant="ghost"
|
|
346
|
+
size="icon"
|
|
347
|
+
:aria-label="$t('duxt.theme.toggle')"
|
|
348
|
+
@click="toggleTheme"
|
|
349
|
+
>
|
|
350
|
+
<Icon
|
|
351
|
+
:name="
|
|
352
|
+
colorMode.value === 'dark' ? 'lucide:sun' : 'lucide:moon'
|
|
353
|
+
"
|
|
354
|
+
class="size-4"
|
|
355
|
+
/>
|
|
356
|
+
</UiButton>
|
|
357
|
+
</UiSheetFooter>
|
|
358
|
+
</UiSheetContent>
|
|
359
|
+
</UiSheet>
|
|
360
|
+
|
|
361
|
+
<NuxtLink
|
|
362
|
+
:to="localeLink('/')"
|
|
363
|
+
class="flex items-center gap-2 text-[15px] font-semibold tracking-tight"
|
|
364
|
+
>
|
|
365
|
+
<DuxtBrand />
|
|
366
|
+
</NuxtLink>
|
|
367
|
+
</div>
|
|
368
|
+
|
|
369
|
+
<!-- One middle column, two occupants. The links go at the same width the
|
|
370
|
+
burger arrives at, so the sheet is never a second copy of a row that
|
|
371
|
+
is still on screen; the search takes the space they leave, because on
|
|
372
|
+
a narrow screen it is the navigation. -->
|
|
373
|
+
<div class="flex min-w-0 items-center justify-center">
|
|
374
|
+
<nav
|
|
375
|
+
class="hidden items-center gap-0.5 text-sm lg:flex"
|
|
376
|
+
:aria-label="$t('duxt.nav.main')"
|
|
377
|
+
>
|
|
378
|
+
<template v-for="link in duxt.navigation" :key="link.label">
|
|
379
|
+
<UiDropdownMenu v-if="link.children?.length">
|
|
380
|
+
<UiDropdownMenuTrigger as-child>
|
|
381
|
+
<UiButton
|
|
382
|
+
variant="ghost"
|
|
383
|
+
size="sm"
|
|
384
|
+
class="gap-1.5 font-medium text-muted-foreground"
|
|
385
|
+
>
|
|
386
|
+
{{ link.label }}
|
|
387
|
+
<Icon
|
|
388
|
+
name="lucide:chevron-down"
|
|
389
|
+
class="size-3.5 opacity-60"
|
|
390
|
+
/>
|
|
391
|
+
</UiButton>
|
|
392
|
+
</UiDropdownMenuTrigger>
|
|
393
|
+
<UiDropdownMenuContent align="center" class="w-64">
|
|
394
|
+
<UiDropdownMenuItem
|
|
395
|
+
v-for="child in link.children"
|
|
396
|
+
:key="child.to"
|
|
397
|
+
as-child
|
|
398
|
+
>
|
|
399
|
+
<NuxtLink
|
|
400
|
+
:to="localeLink(child.to)"
|
|
401
|
+
:target="child.external ? '_blank' : undefined"
|
|
402
|
+
class="flex items-start gap-2.5"
|
|
403
|
+
>
|
|
404
|
+
<Icon
|
|
405
|
+
v-if="child.icon"
|
|
406
|
+
:name="child.icon"
|
|
407
|
+
class="mt-0.5 size-4 shrink-0"
|
|
408
|
+
/>
|
|
409
|
+
<span class="min-w-0">
|
|
410
|
+
<span class="block font-medium">{{ child.label }}</span>
|
|
411
|
+
<span
|
|
412
|
+
v-if="child.description"
|
|
413
|
+
class="block text-xs text-muted-foreground"
|
|
414
|
+
>
|
|
415
|
+
{{ child.description }}
|
|
416
|
+
</span>
|
|
417
|
+
</span>
|
|
418
|
+
</NuxtLink>
|
|
419
|
+
</UiDropdownMenuItem>
|
|
420
|
+
</UiDropdownMenuContent>
|
|
421
|
+
</UiDropdownMenu>
|
|
422
|
+
|
|
423
|
+
<UiButton
|
|
424
|
+
v-else
|
|
425
|
+
as-child
|
|
426
|
+
variant="ghost"
|
|
427
|
+
size="sm"
|
|
428
|
+
class="font-medium"
|
|
429
|
+
:class="
|
|
430
|
+
entryActive(link) ? 'text-foreground' : 'text-muted-foreground'
|
|
431
|
+
"
|
|
432
|
+
>
|
|
433
|
+
<NuxtLink
|
|
434
|
+
:to="localeLink(linkTarget(link))"
|
|
435
|
+
:target="link.external ? '_blank' : undefined"
|
|
436
|
+
>
|
|
437
|
+
{{ link.label }}
|
|
438
|
+
</NuxtLink>
|
|
439
|
+
</UiButton>
|
|
440
|
+
</template>
|
|
441
|
+
</nav>
|
|
442
|
+
|
|
443
|
+
<div class="w-full max-w-md lg:hidden">
|
|
444
|
+
<DuxtSearch />
|
|
445
|
+
</div>
|
|
446
|
+
</div>
|
|
447
|
+
|
|
448
|
+
<div class="flex items-center justify-end gap-2">
|
|
449
|
+
<!-- Beside the search rather than the title, and rendered even where
|
|
450
|
+
there is nothing to choose — as a badge — so the icons to its right
|
|
451
|
+
keep their place. Below sm the sheet's header carries it instead;
|
|
452
|
+
`v-if` here because an empty wrapper would still eat a gap. -->
|
|
453
|
+
<div v-if="duxt.version" class="hidden sm:block">
|
|
454
|
+
<DuxtVersion />
|
|
455
|
+
</div>
|
|
456
|
+
<div class="hidden w-56 lg:block">
|
|
457
|
+
<DuxtSearch />
|
|
458
|
+
</div>
|
|
459
|
+
|
|
460
|
+
<!-- The project links give way first: they are the only icons here the
|
|
461
|
+
sheet can carry as ordinary rows, where the locale and the theme
|
|
462
|
+
are controls that have to stay reachable in one tap. -->
|
|
463
|
+
<UiButton
|
|
464
|
+
v-for="link in duxt.links ?? []"
|
|
465
|
+
:key="link.to"
|
|
466
|
+
as-child
|
|
467
|
+
variant="ghost"
|
|
468
|
+
size="icon"
|
|
469
|
+
class="hidden lg:inline-flex"
|
|
470
|
+
:aria-label="link.label"
|
|
471
|
+
>
|
|
472
|
+
<a :href="link.to" target="_blank" rel="noopener">
|
|
473
|
+
<Icon v-if="link.icon" :name="link.icon" class="size-4" />
|
|
474
|
+
</a>
|
|
475
|
+
</UiButton>
|
|
476
|
+
|
|
477
|
+
<div class="hidden sm:block">
|
|
478
|
+
<DuxtLocale />
|
|
479
|
+
</div>
|
|
480
|
+
|
|
481
|
+
<UiButton
|
|
482
|
+
variant="ghost"
|
|
483
|
+
size="icon"
|
|
484
|
+
class="hidden sm:inline-flex"
|
|
485
|
+
:aria-label="$t('duxt.theme.toggle')"
|
|
486
|
+
@click="toggleTheme"
|
|
487
|
+
>
|
|
488
|
+
<Icon
|
|
489
|
+
:name="colorMode.value === 'dark' ? 'lucide:sun' : 'lucide:moon'"
|
|
490
|
+
class="size-4"
|
|
491
|
+
/>
|
|
492
|
+
</UiButton>
|
|
493
|
+
</div>
|
|
494
|
+
</div>
|
|
495
|
+
</header>
|
|
496
|
+
</template>
|