@lupinum/ginko-docs 0.2.2 → 0.2.3
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/README.md +130 -73
- package/app/app.config.ts +14 -12
- package/app/app.vue +2 -2
- package/app/assets/css/prose.css +2203 -149
- package/app/assets/css/tailwind.css +60 -38
- package/app/assets/css/theme-palettes.css +309 -0
- package/app/components/content/DocumentPageShell.vue +1 -1
- package/app/components/content/Feedback.vue +12 -11
- package/app/components/content/ImageZoomDialog.vue +84 -0
- package/app/components/content/PageMarkdownCopy.vue +2 -0
- package/app/components/content/imageZoom.ts +25 -0
- package/app/components/mdc/MdcAccordion.vue +6 -3
- package/app/components/mdc/MdcAccordionItem.vue +7 -16
- package/app/components/mdc/MdcApi.vue +159 -0
- package/app/components/mdc/MdcAside.vue +6 -10
- package/app/components/mdc/MdcCallout.vue +9 -10
- package/app/components/mdc/MdcCard.vue +36 -47
- package/app/components/mdc/MdcCards.vue +30 -0
- package/app/components/mdc/MdcCodeGroup.vue +4 -0
- package/app/components/mdc/MdcCodeTree.vue +234 -0
- package/app/components/mdc/MdcCollapse.vue +61 -0
- package/app/components/mdc/MdcError.vue +8 -1
- package/app/components/mdc/MdcExcerpt.vue +26 -0
- package/app/components/mdc/MdcFigure.vue +54 -20
- package/app/components/mdc/MdcFiles.vue +120 -0
- package/app/components/mdc/MdcIdea.vue +2 -1
- package/app/components/mdc/MdcInfo.vue +2 -1
- package/app/components/mdc/MdcInlineToc.vue +51 -0
- package/app/components/{ui/dialog/DialogHeader.vue → mdc/MdcKbd.vue} +2 -4
- package/app/components/mdc/MdcNote.vue +2 -1
- package/app/components/mdc/MdcQuiz.vue +43 -83
- package/app/components/mdc/MdcQuizQuestion.vue +104 -109
- package/app/components/mdc/MdcReadMore.vue +57 -77
- package/app/components/mdc/MdcSteps.vue +45 -11
- package/app/components/mdc/MdcSuccess.vue +8 -1
- package/app/components/mdc/MdcTabs.vue +44 -26
- package/app/components/mdc/MdcTimeline.vue +4 -1
- package/app/components/mdc/MdcTimelineItem.vue +18 -27
- package/app/components/mdc/MdcWarning.vue +8 -1
- package/app/components/mdc/api.utils.ts +132 -0
- package/app/components/mdc/code-tree.utils.ts +22 -0
- package/app/components/mdc/quiz.utils.ts +38 -0
- package/app/components/prose/ProseBlockquote.vue +17 -1
- package/app/components/prose/ProseH1.vue +1 -1
- package/app/components/prose/ProseH2.vue +7 -2
- package/app/components/prose/ProseH3.vue +7 -2
- package/app/components/prose/ProseH4.vue +17 -2
- package/app/components/{ui/kbd/KbdGroup.vue → prose/ProseH5.vue} +4 -3
- package/app/components/{ui/card/CardTitle.vue → prose/ProseH6.vue} +4 -3
- package/app/components/prose/ProseImg.vue +19 -112
- package/app/components/prose/ProsePre.vue +63 -100
- package/app/components/prose/ProseTable.vue +5 -3
- package/app/components/site/ModeToggle.vue +12 -3
- package/app/components/site/SiteBanner.vue +43 -2
- package/app/components/site/SiteFooter.vue +3 -5
- package/app/components/site/SiteHeader.vue +255 -132
- package/app/components/site/SiteHeroCode.vue +164 -0
- package/app/components/site/SiteLocaleSwitcher.vue +22 -4
- package/app/components/ui/badge/Badge.vue +1 -1
- package/app/components/ui/button/Button.vue +1 -1
- package/app/components/ui/collapsible/CollapsibleContent.vue +1 -1
- package/app/components/ui/dropdown-menu/DropdownMenuContent.vue +14 -4
- package/app/components/ui/dropdown-menu/DropdownMenuItem.vue +1 -1
- package/app/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +1 -1
- package/app/components/ui/dropdown-menu/DropdownMenuSeparator.vue +1 -1
- package/app/components/ui/dropdown-menu/index.ts +0 -9
- package/app/components/ui/kbd/Kbd.vue +1 -1
- package/app/components/ui/kbd/index.ts +0 -1
- package/app/components/ui/scroll-area/ScrollArea.vue +1 -1
- package/app/components/ui/scroll-area/ScrollBar.vue +1 -1
- package/app/components/ui/separator/Separator.vue +1 -1
- package/app/components/ui/sheet/SheetContent.vue +1 -1
- package/app/components/ui/sheet/SheetDescription.vue +1 -1
- package/app/components/ui/sheet/SheetOverlay.vue +1 -1
- package/app/components/ui/sheet/SheetTitle.vue +1 -1
- package/app/components/ui/sheet/index.ts +0 -3
- package/app/components/ui/tabs/Tabs.vue +1 -1
- package/app/components/ui/tabs/TabsList.vue +1 -1
- package/app/components/ui/tabs/TabsTrigger.vue +1 -1
- package/app/components/ui/tabs/index.ts +0 -1
- package/app/composables/site-navigation.utils.ts +29 -11
- package/app/composables/useContentRouteAlternates.ts +13 -21
- package/app/composables/useLocalizedRouteSwitch.ts +1 -1
- package/app/composables/useMetaKey.ts +18 -0
- package/app/composables/useProseAppearance.ts +24 -0
- package/app/composables/useSiteNavigation.ts +3 -18
- package/app/config/site.utils.ts +1 -1
- package/app/error.vue +1 -5
- package/app/features/docs/components/DocsBreadcrumb.vue +37 -0
- package/app/features/docs/components/DocsContributeLinks.vue +28 -18
- package/app/features/docs/components/DocsMobileToc.vue +12 -8
- package/app/features/docs/components/DocsPageContent.vue +84 -47
- package/app/features/docs/components/DocsPageNav.vue +1 -1
- package/app/features/docs/components/DocsSidebar.vue +30 -20
- package/app/features/docs/components/DocsSidebarItem.vue +53 -100
- package/app/features/docs/components/DocsSidebarRow.vue +27 -0
- package/app/features/docs/components/DocsSidebarTabs.vue +46 -22
- package/app/features/docs/components/DocsToc.vue +80 -34
- package/app/features/docs/composables/useDocsNavigation.ts +2 -2
- package/app/features/docs/composables/useDocsNavigationData.ts +4 -1
- package/app/features/docs/composables/useRevealActive.ts +58 -0
- package/app/features/docs/composables/useScrollspy.ts +87 -19
- package/app/features/docs/docs-navigation.ts +17 -30
- package/app/features/docs/toc-context.ts +6 -0
- package/app/features/search/command-center.ts +11 -90
- package/app/features/search/components/SiteCommandCenter.vue +58 -38
- package/app/features/search/useCommandCenter.ts +46 -46
- package/app/layouts/docs.vue +1 -1
- package/app/lib/errors.ts +2 -49
- package/app/pages/blog/[slug].vue +16 -8
- package/app/pages/blog/index.vue +26 -13
- package/app/pages/docs/index.vue +10 -14
- package/app/pages/index.vue +174 -59
- package/app/plugins/ginko-docs-theme.ts +12 -0
- package/app/utils/content.ts +11 -0
- package/app/utils/file-icons.ts +90 -0
- package/app/utils/index.ts +7 -1
- package/app/utils/repository.ts +20 -0
- package/content.js +23 -26
- package/content.ts +30 -28
- package/i18n/messages/global/blog.ts +4 -0
- package/i18n/messages/global/command.ts +6 -2
- package/i18n/messages/global/docs.ts +3 -0
- package/i18n/messages/global/nav.ts +6 -2
- package/i18n/messages/index.ts +3 -3
- package/icon-bundle.ts +5 -0
- package/index.d.ts +7 -1
- package/nuxt.config.ts +2 -2
- package/package.json +9 -6
- package/runtime/server/agent-markdown.ts +0 -2
- package/shared/theme-palettes.ts +37 -0
- package/shared/types/app-config.ts +63 -6
- package/tags.ts +47 -59
- package/app/components/mdc/MdcAlert.vue +0 -34
- package/app/components/mdc/MdcCardGroup.vue +0 -47
- package/app/components/mdc/MdcDocImg.vue +0 -25
- package/app/components/mdc/MdcField.vue +0 -62
- package/app/components/mdc/MdcFieldGroup.vue +0 -18
- package/app/components/mdc/MdcPassage.vue +0 -32
- package/app/components/mdc/MdcQuizOption.vue +0 -91
- package/app/components/mdc/MdcReadMoreGroup.vue +0 -18
- package/app/components/mdc/MdcShortcut.vue +0 -46
- package/app/components/mdc/MdcStep.vue +0 -42
- package/app/components/ui/accordion/Accordion.vue +0 -15
- package/app/components/ui/accordion/AccordionContent.vue +0 -23
- package/app/components/ui/accordion/AccordionItem.vue +0 -24
- package/app/components/ui/accordion/AccordionTrigger.vue +0 -35
- package/app/components/ui/accordion/index.ts +0 -4
- package/app/components/ui/alert/Alert.vue +0 -21
- package/app/components/ui/alert/AlertDescription.vue +0 -22
- package/app/components/ui/alert/AlertTitle.vue +0 -22
- package/app/components/ui/alert/index.ts +0 -34
- package/app/components/ui/card/Card.vue +0 -16
- package/app/components/ui/card/CardAction.vue +0 -17
- package/app/components/ui/card/CardContent.vue +0 -14
- package/app/components/ui/card/CardDescription.vue +0 -14
- package/app/components/ui/card/CardFooter.vue +0 -14
- package/app/components/ui/card/CardHeader.vue +0 -22
- package/app/components/ui/card/card-variants.ts +0 -15
- package/app/components/ui/card/index.ts +0 -8
- package/app/components/ui/checkbox/Checkbox.vue +0 -35
- package/app/components/ui/checkbox/index.ts +0 -1
- package/app/components/ui/dialog/Dialog.vue +0 -15
- package/app/components/ui/dialog/DialogClose.vue +0 -12
- package/app/components/ui/dialog/DialogContent.vue +0 -69
- package/app/components/ui/dialog/DialogDescription.vue +0 -21
- package/app/components/ui/dialog/DialogFooter.vue +0 -15
- package/app/components/ui/dialog/DialogOverlay.vue +0 -26
- package/app/components/ui/dialog/DialogPortal.vue +0 -12
- package/app/components/ui/dialog/DialogTitle.vue +0 -21
- package/app/components/ui/dialog/DialogTrigger.vue +0 -12
- package/app/components/ui/dialog/index.ts +0 -10
- package/app/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +0 -36
- package/app/components/ui/dropdown-menu/DropdownMenuGroup.vue +0 -12
- package/app/components/ui/dropdown-menu/DropdownMenuLabel.vue +0 -25
- package/app/components/ui/dropdown-menu/DropdownMenuShortcut.vue +0 -17
- package/app/components/ui/dropdown-menu/DropdownMenuSub.vue +0 -15
- package/app/components/ui/dropdown-menu/DropdownMenuSubContent.vue +0 -29
- package/app/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +0 -31
- package/app/components/ui/input/Input.vue +0 -23
- package/app/components/ui/input/index.ts +0 -1
- package/app/components/ui/label/Label.vue +0 -14
- package/app/components/ui/label/index.ts +0 -1
- package/app/components/ui/sheet/SheetClose.vue +0 -12
- package/app/components/ui/sheet/SheetFooter.vue +0 -12
- package/app/components/ui/sheet/SheetHeader.vue +0 -12
- package/app/components/ui/switch/Switch.vue +0 -39
- package/app/components/ui/switch/index.ts +0 -1
- package/app/components/ui/tabs/TabsContent.vue +0 -21
- package/app/components/ui/textarea/Textarea.vue +0 -31
- package/app/components/ui/textarea/index.ts +0 -1
- package/app/features/docs/composables/useDocsEntryPath.ts +0 -13
- package/app/lib/utils.ts +0 -7
- package/i18n/messages/source.ts +0 -5
- package/runtime/markdown/inline-code-highlight.ts +0 -155
- package/runtime/utils.ts +0 -7
|
@@ -4,7 +4,7 @@ import type { HTMLAttributes } from "vue";
|
|
|
4
4
|
import type { BadgeVariants } from ".";
|
|
5
5
|
import { reactiveOmit } from "@vueuse/core";
|
|
6
6
|
import { Primitive } from "reka-ui";
|
|
7
|
-
import { cn } from "#ginko-docs/
|
|
7
|
+
import { cn } from "#ginko-docs/utils";
|
|
8
8
|
import { badgeVariants } from ".";
|
|
9
9
|
|
|
10
10
|
const props = defineProps<
|
|
@@ -3,7 +3,7 @@ import type { PrimitiveProps } from "reka-ui";
|
|
|
3
3
|
import type { HTMLAttributes } from "vue";
|
|
4
4
|
import type { ButtonVariants } from ".";
|
|
5
5
|
import { Primitive } from "reka-ui";
|
|
6
|
-
import { cn } from "#ginko-docs/
|
|
6
|
+
import { cn } from "#ginko-docs/utils";
|
|
7
7
|
import { buttonVariants } from ".";
|
|
8
8
|
|
|
9
9
|
interface Props extends PrimitiveProps {
|
|
@@ -3,7 +3,7 @@ import type { CollapsibleContentProps } from "reka-ui";
|
|
|
3
3
|
import type { HTMLAttributes } from "vue";
|
|
4
4
|
import { reactiveOmit } from "@vueuse/core";
|
|
5
5
|
import { CollapsibleContent } from "reka-ui";
|
|
6
|
-
import { cn } from "#ginko-docs/
|
|
6
|
+
import { cn } from "#ginko-docs/utils";
|
|
7
7
|
|
|
8
8
|
const props = defineProps<CollapsibleContentProps & { class?: HTMLAttributes["class"] }>();
|
|
9
9
|
|
|
@@ -3,27 +3,37 @@ import type { DropdownMenuContentEmits, DropdownMenuContentProps } from "reka-ui
|
|
|
3
3
|
import type { HTMLAttributes } from "vue";
|
|
4
4
|
import { reactiveOmit } from "@vueuse/core";
|
|
5
5
|
import { DropdownMenuContent, DropdownMenuPortal, useForwardPropsEmits } from "reka-ui";
|
|
6
|
-
import { cn } from "#ginko-docs/
|
|
6
|
+
import { cn } from "#ginko-docs/utils";
|
|
7
7
|
|
|
8
8
|
defineOptions({
|
|
9
9
|
inheritAttrs: false,
|
|
10
10
|
});
|
|
11
11
|
|
|
12
12
|
const props = withDefaults(
|
|
13
|
-
defineProps<
|
|
13
|
+
defineProps<
|
|
14
|
+
DropdownMenuContentProps & {
|
|
15
|
+
class?: HTMLAttributes["class"];
|
|
16
|
+
/**
|
|
17
|
+
* Render in place instead of teleporting to body. Required inside modal
|
|
18
|
+
* dialogs (e.g. the mobile menu sheet), where body-level portals are
|
|
19
|
+
* blocked by the dialog's pointer-events lock.
|
|
20
|
+
*/
|
|
21
|
+
portalDisabled?: boolean;
|
|
22
|
+
}
|
|
23
|
+
>(),
|
|
14
24
|
{
|
|
15
25
|
sideOffset: 4,
|
|
16
26
|
},
|
|
17
27
|
);
|
|
18
28
|
const emits = defineEmits<DropdownMenuContentEmits>();
|
|
19
29
|
|
|
20
|
-
const delegatedProps = reactiveOmit(props, "class");
|
|
30
|
+
const delegatedProps = reactiveOmit(props, "class", "portalDisabled");
|
|
21
31
|
|
|
22
32
|
const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
|
23
33
|
</script>
|
|
24
34
|
|
|
25
35
|
<template>
|
|
26
|
-
<DropdownMenuPortal>
|
|
36
|
+
<DropdownMenuPortal :disabled="props.portalDisabled">
|
|
27
37
|
<DropdownMenuContent
|
|
28
38
|
data-slot="dropdown-menu-content"
|
|
29
39
|
v-bind="{ ...$attrs, ...forwarded }"
|
|
@@ -3,7 +3,7 @@ import type { DropdownMenuItemProps } from "reka-ui";
|
|
|
3
3
|
import type { HTMLAttributes } from "vue";
|
|
4
4
|
import { reactiveOmit } from "@vueuse/core";
|
|
5
5
|
import { DropdownMenuItem, useForwardProps } from "reka-ui";
|
|
6
|
-
import { cn } from "#ginko-docs/
|
|
6
|
+
import { cn } from "#ginko-docs/utils";
|
|
7
7
|
|
|
8
8
|
const props = withDefaults(
|
|
9
9
|
defineProps<
|
|
@@ -3,7 +3,7 @@ import type { DropdownMenuRadioItemEmits, DropdownMenuRadioItemProps } from "rek
|
|
|
3
3
|
import type { HTMLAttributes } from "vue";
|
|
4
4
|
import { reactiveOmit } from "@vueuse/core";
|
|
5
5
|
import { DropdownMenuItemIndicator, DropdownMenuRadioItem, useForwardPropsEmits } from "reka-ui";
|
|
6
|
-
import { cn } from "#ginko-docs/
|
|
6
|
+
import { cn } from "#ginko-docs/utils";
|
|
7
7
|
|
|
8
8
|
const props = defineProps<DropdownMenuRadioItemProps & { class?: HTMLAttributes["class"] }>();
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ import type { DropdownMenuSeparatorProps } from "reka-ui";
|
|
|
3
3
|
import type { HTMLAttributes } from "vue";
|
|
4
4
|
import { reactiveOmit } from "@vueuse/core";
|
|
5
5
|
import { DropdownMenuSeparator } from "reka-ui";
|
|
6
|
-
import { cn } from "#ginko-docs/
|
|
6
|
+
import { cn } from "#ginko-docs/utils";
|
|
7
7
|
|
|
8
8
|
const props = defineProps<
|
|
9
9
|
DropdownMenuSeparatorProps & {
|
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
export { default as DropdownMenu } from "./DropdownMenu.vue";
|
|
2
|
-
|
|
3
|
-
export { default as DropdownMenuCheckboxItem } from "./DropdownMenuCheckboxItem.vue";
|
|
4
2
|
export { default as DropdownMenuContent } from "./DropdownMenuContent.vue";
|
|
5
|
-
export { default as DropdownMenuGroup } from "./DropdownMenuGroup.vue";
|
|
6
3
|
export { default as DropdownMenuItem } from "./DropdownMenuItem.vue";
|
|
7
|
-
export { default as DropdownMenuLabel } from "./DropdownMenuLabel.vue";
|
|
8
4
|
export { default as DropdownMenuRadioGroup } from "./DropdownMenuRadioGroup.vue";
|
|
9
5
|
export { default as DropdownMenuRadioItem } from "./DropdownMenuRadioItem.vue";
|
|
10
6
|
export { default as DropdownMenuSeparator } from "./DropdownMenuSeparator.vue";
|
|
11
|
-
export { default as DropdownMenuShortcut } from "./DropdownMenuShortcut.vue";
|
|
12
|
-
export { default as DropdownMenuSub } from "./DropdownMenuSub.vue";
|
|
13
|
-
export { default as DropdownMenuSubContent } from "./DropdownMenuSubContent.vue";
|
|
14
|
-
export { default as DropdownMenuSubTrigger } from "./DropdownMenuSubTrigger.vue";
|
|
15
7
|
export { default as DropdownMenuTrigger } from "./DropdownMenuTrigger.vue";
|
|
16
|
-
export { DropdownMenuPortal } from "reka-ui";
|
|
@@ -2,7 +2,6 @@ import type { VariantProps } from "class-variance-authority";
|
|
|
2
2
|
import { cva } from "class-variance-authority";
|
|
3
3
|
|
|
4
4
|
export { default as Kbd } from "./Kbd.vue";
|
|
5
|
-
export { default as KbdGroup } from "./KbdGroup.vue";
|
|
6
5
|
|
|
7
6
|
export const kbdVariants = cva(
|
|
8
7
|
"bg-muted text-muted-foreground ring-1 ring-border pointer-events-none inline-flex w-fit items-center justify-center gap-1 rounded-sm font-sans font-medium select-none [&_svg:not([class*='size-'])]:size-3 [[data-slot=tooltip-content]_&]:bg-background/20 [[data-slot=tooltip-content]_&]:text-background dark:[[data-slot=tooltip-content]_&]:bg-background/10",
|
|
@@ -3,7 +3,7 @@ import type { ScrollAreaRootProps } from "reka-ui";
|
|
|
3
3
|
import type { HTMLAttributes } from "vue";
|
|
4
4
|
import { reactiveOmit } from "@vueuse/core";
|
|
5
5
|
import { ScrollAreaCorner, ScrollAreaRoot, ScrollAreaViewport } from "reka-ui";
|
|
6
|
-
import { cn } from "#ginko-docs/
|
|
6
|
+
import { cn } from "#ginko-docs/utils";
|
|
7
7
|
import ScrollBar from "./ScrollBar.vue";
|
|
8
8
|
|
|
9
9
|
const props = defineProps<
|
|
@@ -3,7 +3,7 @@ import type { ScrollAreaScrollbarProps } from "reka-ui";
|
|
|
3
3
|
import type { HTMLAttributes } from "vue";
|
|
4
4
|
import { reactiveOmit } from "@vueuse/core";
|
|
5
5
|
import { ScrollAreaScrollbar, ScrollAreaThumb } from "reka-ui";
|
|
6
|
-
import { cn } from "#ginko-docs/
|
|
6
|
+
import { cn } from "#ginko-docs/utils";
|
|
7
7
|
|
|
8
8
|
const props = withDefaults(
|
|
9
9
|
defineProps<ScrollAreaScrollbarProps & { class?: HTMLAttributes["class"] }>(),
|
|
@@ -3,7 +3,7 @@ import type { SeparatorProps } from "reka-ui";
|
|
|
3
3
|
import type { HTMLAttributes } from "vue";
|
|
4
4
|
import { reactiveOmit } from "@vueuse/core";
|
|
5
5
|
import { Separator } from "reka-ui";
|
|
6
|
-
import { cn } from "#ginko-docs/
|
|
6
|
+
import { cn } from "#ginko-docs/utils";
|
|
7
7
|
|
|
8
8
|
const props = withDefaults(defineProps<SeparatorProps & { class?: HTMLAttributes["class"] }>(), {
|
|
9
9
|
orientation: "horizontal",
|
|
@@ -3,7 +3,7 @@ import type { DialogContentEmits, DialogContentProps } from "reka-ui";
|
|
|
3
3
|
import type { HTMLAttributes } from "vue";
|
|
4
4
|
import { reactiveOmit } from "@vueuse/core";
|
|
5
5
|
import { DialogClose, DialogContent, DialogPortal, useForwardPropsEmits } from "reka-ui";
|
|
6
|
-
import { cn } from "#ginko-docs/
|
|
6
|
+
import { cn } from "#ginko-docs/utils";
|
|
7
7
|
import SheetOverlay from "./SheetOverlay.vue";
|
|
8
8
|
|
|
9
9
|
interface SheetContentProps extends DialogContentProps {
|
|
@@ -3,7 +3,7 @@ import type { DialogDescriptionProps } from "reka-ui";
|
|
|
3
3
|
import type { HTMLAttributes } from "vue";
|
|
4
4
|
import { reactiveOmit } from "@vueuse/core";
|
|
5
5
|
import { DialogDescription } from "reka-ui";
|
|
6
|
-
import { cn } from "#ginko-docs/
|
|
6
|
+
import { cn } from "#ginko-docs/utils";
|
|
7
7
|
|
|
8
8
|
const props = defineProps<DialogDescriptionProps & { class?: HTMLAttributes["class"] }>();
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ import type { DialogOverlayProps } from "reka-ui";
|
|
|
3
3
|
import type { HTMLAttributes } from "vue";
|
|
4
4
|
import { reactiveOmit } from "@vueuse/core";
|
|
5
5
|
import { DialogOverlay } from "reka-ui";
|
|
6
|
-
import { cn } from "#ginko-docs/
|
|
6
|
+
import { cn } from "#ginko-docs/utils";
|
|
7
7
|
|
|
8
8
|
const props = defineProps<DialogOverlayProps & { class?: HTMLAttributes["class"] }>();
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ import type { DialogTitleProps } from "reka-ui";
|
|
|
3
3
|
import type { HTMLAttributes } from "vue";
|
|
4
4
|
import { reactiveOmit } from "@vueuse/core";
|
|
5
5
|
import { DialogTitle } from "reka-ui";
|
|
6
|
-
import { cn } from "#ginko-docs/
|
|
6
|
+
import { cn } from "#ginko-docs/utils";
|
|
7
7
|
|
|
8
8
|
const props = defineProps<DialogTitleProps & { class?: HTMLAttributes["class"] }>();
|
|
9
9
|
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
export { default as Sheet } from "./Sheet.vue";
|
|
2
|
-
export { default as SheetClose } from "./SheetClose.vue";
|
|
3
2
|
export { default as SheetContent } from "./SheetContent.vue";
|
|
4
3
|
export { default as SheetDescription } from "./SheetDescription.vue";
|
|
5
|
-
export { default as SheetFooter } from "./SheetFooter.vue";
|
|
6
|
-
export { default as SheetHeader } from "./SheetHeader.vue";
|
|
7
4
|
export { default as SheetTitle } from "./SheetTitle.vue";
|
|
8
5
|
export { default as SheetTrigger } from "./SheetTrigger.vue";
|
|
@@ -3,7 +3,7 @@ import type { TabsRootEmits, TabsRootProps } from "reka-ui";
|
|
|
3
3
|
import type { HTMLAttributes } from "vue";
|
|
4
4
|
import { reactiveOmit } from "@vueuse/core";
|
|
5
5
|
import { TabsRoot, useForwardPropsEmits } from "reka-ui";
|
|
6
|
-
import { cn } from "#ginko-docs/
|
|
6
|
+
import { cn } from "#ginko-docs/utils";
|
|
7
7
|
|
|
8
8
|
const props = defineProps<TabsRootProps & { class?: HTMLAttributes["class"] }>();
|
|
9
9
|
const emits = defineEmits<TabsRootEmits>();
|
|
@@ -3,7 +3,7 @@ import type { TabsListProps } from "reka-ui";
|
|
|
3
3
|
import type { HTMLAttributes } from "vue";
|
|
4
4
|
import { reactiveOmit } from "@vueuse/core";
|
|
5
5
|
import { TabsList } from "reka-ui";
|
|
6
|
-
import { cn } from "#ginko-docs/
|
|
6
|
+
import { cn } from "#ginko-docs/utils";
|
|
7
7
|
|
|
8
8
|
const props = defineProps<TabsListProps & { class?: HTMLAttributes["class"] }>();
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ import type { TabsTriggerProps } from "reka-ui";
|
|
|
3
3
|
import type { HTMLAttributes } from "vue";
|
|
4
4
|
import { reactiveOmit } from "@vueuse/core";
|
|
5
5
|
import { TabsTrigger, useForwardProps } from "reka-ui";
|
|
6
|
-
import { cn } from "#ginko-docs/
|
|
6
|
+
import { cn } from "#ginko-docs/utils";
|
|
7
7
|
|
|
8
8
|
const props = defineProps<TabsTriggerProps & { class?: HTMLAttributes["class"] }>();
|
|
9
9
|
|
|
@@ -6,6 +6,7 @@ export interface NavItem {
|
|
|
6
6
|
href: string;
|
|
7
7
|
external?: boolean;
|
|
8
8
|
icon?: string;
|
|
9
|
+
description?: string;
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export interface MainNavContext {
|
|
@@ -15,6 +16,8 @@ export interface MainNavContext {
|
|
|
15
16
|
blogExists: boolean;
|
|
16
17
|
docsLabel: string;
|
|
17
18
|
blogLabel: string;
|
|
19
|
+
docsDescription?: string;
|
|
20
|
+
blogDescription?: string;
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
const isExternalHref = (href: string) => /^https?:\/\//.test(href);
|
|
@@ -30,21 +33,35 @@ export function resolveMainNav(
|
|
|
30
33
|
label: getLocalizedSiteText(link.label, ctx.locale),
|
|
31
34
|
href,
|
|
32
35
|
external: isExternalHref(href),
|
|
36
|
+
icon: link.icon,
|
|
37
|
+
description: link.description
|
|
38
|
+
? getLocalizedSiteText(link.description, ctx.locale)
|
|
39
|
+
: undefined,
|
|
33
40
|
};
|
|
34
41
|
});
|
|
35
42
|
}
|
|
36
43
|
|
|
37
|
-
const items: NavItem[] = [
|
|
44
|
+
const items: NavItem[] = [
|
|
45
|
+
{
|
|
46
|
+
label: ctx.docsLabel,
|
|
47
|
+
href: ctx.docsPath,
|
|
48
|
+
icon: "lucide:book-open",
|
|
49
|
+
description: ctx.docsDescription,
|
|
50
|
+
},
|
|
51
|
+
];
|
|
38
52
|
if (ctx.blogExists) {
|
|
39
|
-
items.push({
|
|
53
|
+
items.push({
|
|
54
|
+
label: ctx.blogLabel,
|
|
55
|
+
href: ctx.blogPath,
|
|
56
|
+
icon: "lucide:file-text",
|
|
57
|
+
description: ctx.blogDescription,
|
|
58
|
+
});
|
|
40
59
|
}
|
|
41
60
|
return items;
|
|
42
61
|
}
|
|
43
62
|
|
|
44
63
|
export interface BannerContext {
|
|
45
64
|
locale: string;
|
|
46
|
-
blogPath: string;
|
|
47
|
-
blogExists: boolean;
|
|
48
65
|
defaultText: string;
|
|
49
66
|
defaultLinkLabel: string;
|
|
50
67
|
}
|
|
@@ -65,16 +82,17 @@ export function resolveBanner(
|
|
|
65
82
|
config: GinkoDocsAppConfig["banner"],
|
|
66
83
|
ctx: BannerContext,
|
|
67
84
|
): ResolvedBanner {
|
|
68
|
-
const show = config.enabled === "auto" ? ctx.blogExists : config.enabled;
|
|
69
85
|
const text = config.text ? getLocalizedSiteText(config.text, ctx.locale) : ctx.defaultText;
|
|
70
|
-
const linkHref = config.link?.to
|
|
71
|
-
? getLocalizedSiteText(config.link.to, ctx.locale)
|
|
72
|
-
: ctx.blogExists
|
|
73
|
-
? ctx.blogPath
|
|
74
|
-
: undefined;
|
|
86
|
+
const linkHref = config.link?.to ? getLocalizedSiteText(config.link.to, ctx.locale) : undefined;
|
|
75
87
|
const linkLabel = config.link?.label
|
|
76
88
|
? getLocalizedSiteText(config.link.label, ctx.locale)
|
|
77
89
|
: ctx.defaultLinkLabel;
|
|
78
90
|
|
|
79
|
-
return {
|
|
91
|
+
return {
|
|
92
|
+
show: config.enabled,
|
|
93
|
+
text,
|
|
94
|
+
linkLabel,
|
|
95
|
+
linkHref,
|
|
96
|
+
storageKey: bannerStorageKey(config.id),
|
|
97
|
+
};
|
|
80
98
|
}
|
|
@@ -18,26 +18,18 @@ export function useContentRouteAlternates() {
|
|
|
18
18
|
state.value.sourcePath === route.path ? state.value.alternates : [],
|
|
19
19
|
);
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
21
|
+
function sync(page: Ref<{ route?: { alternates?: ContentAlternate[] } } | null | undefined>) {
|
|
22
|
+
watch(
|
|
23
|
+
page,
|
|
24
|
+
(document) => {
|
|
25
|
+
state.value = {
|
|
26
|
+
sourcePath: route.path,
|
|
27
|
+
alternates: document?.route?.alternates ?? [],
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
{ immediate: true },
|
|
31
|
+
);
|
|
32
|
+
}
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
page,
|
|
35
|
-
(document) => {
|
|
36
|
-
state.value = {
|
|
37
|
-
sourcePath: route.path,
|
|
38
|
-
alternates: document?.route?.alternates ?? [],
|
|
39
|
-
};
|
|
40
|
-
},
|
|
41
|
-
{ immediate: true },
|
|
42
|
-
);
|
|
34
|
+
return { current, sync };
|
|
43
35
|
}
|
|
@@ -6,7 +6,7 @@ import { isLocaleCode } from "../../i18n/locales";
|
|
|
6
6
|
export function useLocalizedRouteSwitch() {
|
|
7
7
|
const route = useRoute();
|
|
8
8
|
const switchLocalePath = useSwitchLocalePath();
|
|
9
|
-
const alternates = useContentRouteAlternates();
|
|
9
|
+
const { current: alternates } = useContentRouteAlternates();
|
|
10
10
|
|
|
11
11
|
function switchPathname(targetLocale: string) {
|
|
12
12
|
if (!isLocaleCode(targetLocale)) {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { onMounted, ref, type Ref } from "vue";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Platform-aware modifier key label. Defaults to "Ctrl" during SSR and
|
|
5
|
+
* upgrades to "⌘" on Apple platforms after mount (onMounted is client-only,
|
|
6
|
+
* so hydration stays consistent).
|
|
7
|
+
*/
|
|
8
|
+
export function useMetaKey(): Ref<string> {
|
|
9
|
+
const metaSymbol = ref("Ctrl");
|
|
10
|
+
|
|
11
|
+
onMounted(() => {
|
|
12
|
+
if (typeof navigator !== "undefined" && navigator.userAgent.includes("Macintosh")) {
|
|
13
|
+
metaSymbol.value = "⌘";
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
return metaSymbol;
|
|
18
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { computed, type MaybeRefOrGetter, toValue } from "vue";
|
|
2
|
+
import type { GinkoDocsProseAppearance, GinkoDocsProseFamily } from "../../shared/types/app-config";
|
|
3
|
+
import { useGinkoDocsConfig } from "./useGinkoDocsConfig";
|
|
4
|
+
|
|
5
|
+
const DEFAULT_APPEARANCE: GinkoDocsProseAppearance = "quiet";
|
|
6
|
+
|
|
7
|
+
function normalizeAppearance(value: unknown): GinkoDocsProseAppearance | undefined {
|
|
8
|
+
return value === "quiet" || value === "tint" ? value : undefined;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function useProseAppearance(
|
|
12
|
+
family: GinkoDocsProseFamily,
|
|
13
|
+
appearance?: MaybeRefOrGetter<string | undefined>,
|
|
14
|
+
) {
|
|
15
|
+
const config = useGinkoDocsConfig();
|
|
16
|
+
|
|
17
|
+
return computed<GinkoDocsProseAppearance>(
|
|
18
|
+
() =>
|
|
19
|
+
normalizeAppearance(toValue(appearance)) ??
|
|
20
|
+
normalizeAppearance(config.prose?.components?.[family]) ??
|
|
21
|
+
normalizeAppearance(config.prose?.appearance) ??
|
|
22
|
+
DEFAULT_APPEARANCE,
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -5,11 +5,6 @@ import { computed } from "vue";
|
|
|
5
5
|
import { useGinkoDocsConfig } from "./useGinkoDocsConfig";
|
|
6
6
|
import { resolveBanner, resolveMainNav, type NavItem } from "./site-navigation.utils";
|
|
7
7
|
|
|
8
|
-
export interface SidebarSection {
|
|
9
|
-
title: string;
|
|
10
|
-
items: { label: string; href: string; badge?: string }[];
|
|
11
|
-
}
|
|
12
|
-
|
|
13
8
|
export const useSiteNavigation = () => {
|
|
14
9
|
const config = useGinkoDocsConfig();
|
|
15
10
|
const { locale, t } = useI18n();
|
|
@@ -32,8 +27,6 @@ export const useSiteNavigation = () => {
|
|
|
32
27
|
const banner = computed(() =>
|
|
33
28
|
resolveBanner(config.banner, {
|
|
34
29
|
locale: locale.value,
|
|
35
|
-
blogPath: blogPath.value,
|
|
36
|
-
blogExists: blogExists.value,
|
|
37
30
|
defaultText: t("banner.text"),
|
|
38
31
|
defaultLinkLabel: t("banner.linkLabel"),
|
|
39
32
|
}),
|
|
@@ -69,18 +62,10 @@ export const useSiteNavigation = () => {
|
|
|
69
62
|
blogExists: blogExists.value,
|
|
70
63
|
docsLabel: t("nav.documentation"),
|
|
71
64
|
blogLabel: t("nav.blog"),
|
|
65
|
+
docsDescription: t("nav.docsDescription"),
|
|
66
|
+
blogDescription: t("nav.blogDescription"),
|
|
72
67
|
}),
|
|
73
68
|
);
|
|
74
69
|
|
|
75
|
-
|
|
76
|
-
product: NavItem[];
|
|
77
|
-
resources: NavItem[];
|
|
78
|
-
company: NavItem[];
|
|
79
|
-
}>(() => ({
|
|
80
|
-
product: [],
|
|
81
|
-
resources: [...socialLinks.value],
|
|
82
|
-
company: [],
|
|
83
|
-
}));
|
|
84
|
-
|
|
85
|
-
return { site, banner, mainNav, footerNav, socialLinks };
|
|
70
|
+
return { site, banner, mainNav, socialLinks };
|
|
86
71
|
};
|
package/app/config/site.utils.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { GinkoDocsLocalizedText } from "../../shared/types/app-config";
|
|
|
2
2
|
import { defaultLocale, type LocaleCode } from "../../i18n/locales";
|
|
3
3
|
|
|
4
4
|
export function getLocalizedSiteText(
|
|
5
|
-
value: GinkoDocsLocalizedText
|
|
5
|
+
value: GinkoDocsLocalizedText,
|
|
6
6
|
locale: string,
|
|
7
7
|
fallbackLocale: LocaleCode = defaultLocale,
|
|
8
8
|
): string {
|
package/app/error.vue
CHANGED
|
@@ -4,7 +4,6 @@ import { messages } from "../i18n/messages/index";
|
|
|
4
4
|
import { normalizeAppError } from "./lib/errors";
|
|
5
5
|
import { computed } from "vue";
|
|
6
6
|
import { clearError, useHead } from "#imports";
|
|
7
|
-
import { useDocsEntryPath } from "#ginko-docs/features/docs/composables/useDocsEntryPath";
|
|
8
7
|
import { localeFromPath, localizedPath } from "../i18n/locales";
|
|
9
8
|
|
|
10
9
|
type NuxtErrorLike = {
|
|
@@ -29,8 +28,8 @@ const copy = computed(() => {
|
|
|
29
28
|
const catalog = messages[locale.value].errors;
|
|
30
29
|
return catalog[normalized.value.kind] ?? catalog.unavailable;
|
|
31
30
|
});
|
|
32
|
-
const docsPath = await useDocsEntryPath();
|
|
33
31
|
const homePath = computed(() => localizedPath(locale.value, localizedRoutes[locale.value].home));
|
|
32
|
+
const docsPath = computed(() => localizedPath(locale.value, localizedRoutes[locale.value].docs));
|
|
34
33
|
const title = computed(() => `${normalized.value.statusCode} - ${copy.value.title}`);
|
|
35
34
|
// Keep the full site chrome for content-level errors (404 and friends); hard
|
|
36
35
|
// server failures fall back to the bare page so the error screen cannot crash.
|
|
@@ -59,9 +58,6 @@ const handleError = () => clearError({ redirect: homePath.value });
|
|
|
59
58
|
{{ normalized.statusCode }}
|
|
60
59
|
</p>
|
|
61
60
|
|
|
62
|
-
<p class="mb-3 text-sm font-medium tracking-wider text-primary uppercase">
|
|
63
|
-
{{ normalized.statusMessage }}
|
|
64
|
-
</p>
|
|
65
61
|
<h1 class="mb-4 text-3xl font-semibold tracking-tight text-foreground sm:text-4xl">
|
|
66
62
|
{{ copy.title }}
|
|
67
63
|
</h1>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from "vue";
|
|
3
|
+
import { cn } from "#ginko-docs/utils";
|
|
4
|
+
import { useI18n } from "#imports";
|
|
5
|
+
|
|
6
|
+
const props = defineProps<{
|
|
7
|
+
items: { title: string; path?: string }[];
|
|
8
|
+
class?: HTMLAttributes["class"];
|
|
9
|
+
}>();
|
|
10
|
+
|
|
11
|
+
const { t } = useI18n();
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<template>
|
|
15
|
+
<nav
|
|
16
|
+
v-if="items.length"
|
|
17
|
+
:class="cn('flex flex-wrap items-center gap-1.5 text-sm text-muted-foreground', props.class)"
|
|
18
|
+
:aria-label="t('docs.breadcrumbs')"
|
|
19
|
+
>
|
|
20
|
+
<template v-for="(item, index) in items" :key="item.path ?? item.title">
|
|
21
|
+
<Icon
|
|
22
|
+
v-if="index > 0"
|
|
23
|
+
name="lucide:chevron-right"
|
|
24
|
+
class="size-3.5 text-border"
|
|
25
|
+
aria-hidden="true"
|
|
26
|
+
/>
|
|
27
|
+
<NuxtLink
|
|
28
|
+
v-if="item.path"
|
|
29
|
+
:to="item.path"
|
|
30
|
+
class="rounded-sm transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
31
|
+
>
|
|
32
|
+
{{ item.title }}
|
|
33
|
+
</NuxtLink>
|
|
34
|
+
<span v-else>{{ item.title }}</span>
|
|
35
|
+
</template>
|
|
36
|
+
</nav>
|
|
37
|
+
</template>
|
|
@@ -2,12 +2,19 @@
|
|
|
2
2
|
import type { GinkoDocsAppConfig } from "../../../../shared/types/app-config";
|
|
3
3
|
import { computed } from "vue";
|
|
4
4
|
import { useAppConfig, useI18n, useRoute } from "#imports";
|
|
5
|
+
import { buildRepoEditUrl, buildRepoIssueUrl } from "#ginko-docs/utils/repository";
|
|
5
6
|
|
|
6
|
-
const props =
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
const props = withDefaults(
|
|
8
|
+
defineProps<{
|
|
9
|
+
stem?: string;
|
|
10
|
+
extension?: string;
|
|
11
|
+
title: string;
|
|
12
|
+
variant?: "article" | "rail";
|
|
13
|
+
}>(),
|
|
14
|
+
{
|
|
15
|
+
variant: "article",
|
|
16
|
+
},
|
|
17
|
+
);
|
|
11
18
|
|
|
12
19
|
const route = useRoute();
|
|
13
20
|
const { t } = useI18n();
|
|
@@ -20,25 +27,28 @@ const sourcePath = computed(() => {
|
|
|
20
27
|
return `${directory}/${props.stem}.${extension}`;
|
|
21
28
|
});
|
|
22
29
|
|
|
23
|
-
const editUrl = computed(() =>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
return `${repository.url.replace(/\/$/, "")}/edit/${encodeURIComponent(branch)}/${sourcePath.value}`;
|
|
27
|
-
});
|
|
30
|
+
const editUrl = computed(() =>
|
|
31
|
+
repository && sourcePath.value ? buildRepoEditUrl(repository, sourcePath.value) : null,
|
|
32
|
+
);
|
|
28
33
|
|
|
29
|
-
const issueUrl = computed(() =>
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
const issueUrl = computed(() =>
|
|
35
|
+
repository
|
|
36
|
+
? buildRepoIssueUrl(repository, {
|
|
37
|
+
title: t("docs.issueTitle", { title: props.title }),
|
|
38
|
+
body: t("docs.issueBody", { path: route.path }),
|
|
39
|
+
})
|
|
40
|
+
: null,
|
|
41
|
+
);
|
|
36
42
|
</script>
|
|
37
43
|
|
|
38
44
|
<template>
|
|
39
45
|
<div
|
|
40
46
|
v-if="repository"
|
|
41
|
-
class="
|
|
47
|
+
:class="
|
|
48
|
+
variant === 'rail'
|
|
49
|
+
? 'flex flex-col gap-2.5 text-sm'
|
|
50
|
+
: 'flex flex-wrap items-center gap-x-4 gap-y-2 text-sm'
|
|
51
|
+
"
|
|
42
52
|
:aria-label="t('docs.contribute')"
|
|
43
53
|
>
|
|
44
54
|
<a
|