@lupinum/ginko-docs 0.2.2 → 0.2.5
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 +15 -13
- package/app/app.vue +4 -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 +34 -99
- 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 +266 -132
- package/app/components/site/SiteHeroCode.vue +164 -0
- package/app/components/site/SiteLocaleSwitcher.vue +25 -9
- package/app/components/site/SiteSocialLinks.vue +31 -0
- 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 +69 -12
- 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 +10 -40
- 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 +93 -47
- package/app/features/docs/components/DocsPageNav.vue +1 -1
- package/app/features/docs/components/DocsSidebar.vue +37 -21
- 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 +48 -48
- package/app/layouts/docs.vue +1 -1
- package/app/lib/errors.ts +2 -49
- package/app/pages/blog/[slug].vue +26 -9
- package/app/pages/blog/index.vue +38 -14
- package/app/pages/docs/index.vue +10 -14
- package/app/pages/index.vue +180 -61
- 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 +68 -50
- package/content.ts +51 -32
- package/i18n/messages/global/blog.ts +4 -0
- package/i18n/messages/global/command.ts +6 -2
- package/i18n/messages/global/docs.ts +4 -0
- package/i18n/messages/global/nav.ts +6 -3
- package/i18n/messages/index.ts +3 -3
- package/icon-bundle.ts +9 -56
- package/index.d.ts +7 -1
- package/modules/feature-routing.ts +15 -0
- package/nuxt.config.ts +21 -7
- package/package.json +29 -26
- package/runtime/server/agent-markdown.ts +0 -2
- package/server/api/_ginko-docs/redirects.get.ts +28 -0
- package/server/middleware/redirects.ts +22 -0
- package/server/routes/[locale]/blog/rss.xml.get.ts +13 -0
- package/server/routes/blog/rss.xml.get.ts +5 -0
- package/server/utils/blog-feed.ts +49 -0
- package/server/utils/feed.ts +70 -0
- package/server/utils/redirects.ts +38 -0
- package/server/utils/redirects.utils.ts +58 -0
- package/shared/theme-palettes.ts +37 -0
- package/shared/types/app-config.ts +75 -10
- 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
|
@@ -7,13 +7,13 @@ import {
|
|
|
7
7
|
DropdownMenuItem,
|
|
8
8
|
DropdownMenuTrigger,
|
|
9
9
|
} from "#ginko-docs/components/ui/dropdown-menu";
|
|
10
|
-
import { cn } from "#ginko-docs/
|
|
10
|
+
import { cn } from "#ginko-docs/utils";
|
|
11
11
|
import { computed } from "vue";
|
|
12
12
|
import { useI18n } from "#imports";
|
|
13
13
|
import { useLocalizedRouteSwitch } from "#ginko-docs/composables/useLocalizedRouteSwitch";
|
|
14
14
|
import { locales as configuredLocales } from "../../../i18n/locales";
|
|
15
15
|
|
|
16
|
-
type LocaleSwitcherVariant = "dropdown" | "menu-row" | "menu-tile" | "segmented";
|
|
16
|
+
type LocaleSwitcherVariant = "dropdown" | "menu-row" | "menu-tile" | "segmented" | "pill";
|
|
17
17
|
|
|
18
18
|
type LocaleEntry = {
|
|
19
19
|
code: string;
|
|
@@ -105,7 +105,7 @@ function trackLocaleNavigation(_entry: { code: string; current: boolean; to: unk
|
|
|
105
105
|
<ClientOnly>
|
|
106
106
|
<DropdownMenu>
|
|
107
107
|
<DropdownMenuTrigger as-child>
|
|
108
|
-
<Button variant="
|
|
108
|
+
<Button variant="ghost" class="h-9 gap-1.5 px-2.5" :aria-label="t('nav.language')">
|
|
109
109
|
<Icon
|
|
110
110
|
v-if="currentLocale?.flagIcon"
|
|
111
111
|
:name="currentLocale.flagIcon"
|
|
@@ -151,21 +151,37 @@ function trackLocaleNavigation(_entry: { code: string; current: boolean; to: unk
|
|
|
151
151
|
</DropdownMenu>
|
|
152
152
|
|
|
153
153
|
<template #fallback>
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
aria-hidden="true"
|
|
157
|
-
/>
|
|
154
|
+
<!-- Reserves the trigger's box before hydration. -->
|
|
155
|
+
<span class="inline-flex h-9 w-[4.25rem] rounded-md" aria-hidden="true" />
|
|
158
156
|
</template>
|
|
159
157
|
</ClientOnly>
|
|
160
158
|
</div>
|
|
161
159
|
|
|
162
160
|
<div
|
|
163
|
-
v-else-if="
|
|
161
|
+
v-else-if="
|
|
162
|
+
localeLinks.length > 1 &&
|
|
163
|
+
(variant === 'menu-row' || variant === 'menu-tile' || variant === 'pill')
|
|
164
|
+
"
|
|
164
165
|
:class="cn('items-center', props.class)"
|
|
165
166
|
>
|
|
166
167
|
<DropdownMenu>
|
|
167
168
|
<DropdownMenuTrigger as-child>
|
|
168
169
|
<Button
|
|
170
|
+
v-if="variant === 'pill'"
|
|
171
|
+
variant="outline"
|
|
172
|
+
class="h-9 gap-2 rounded-full px-4 text-sm font-semibold"
|
|
173
|
+
:aria-label="t('nav.language')"
|
|
174
|
+
>
|
|
175
|
+
<Icon
|
|
176
|
+
v-if="currentLocale?.flagIcon"
|
|
177
|
+
:name="currentLocale.flagIcon"
|
|
178
|
+
class="size-4 rounded-full"
|
|
179
|
+
aria-hidden="true"
|
|
180
|
+
/>
|
|
181
|
+
<span>{{ currentLocale?.shortLabel }}</span>
|
|
182
|
+
</Button>
|
|
183
|
+
<Button
|
|
184
|
+
v-else
|
|
169
185
|
variant="ghost"
|
|
170
186
|
:class="
|
|
171
187
|
cn(
|
|
@@ -204,7 +220,7 @@ function trackLocaleNavigation(_entry: { code: string; current: boolean; to: unk
|
|
|
204
220
|
/>
|
|
205
221
|
</Button>
|
|
206
222
|
</DropdownMenuTrigger>
|
|
207
|
-
<DropdownMenuContent align="end" class="w-44">
|
|
223
|
+
<DropdownMenuContent align="end" class="w-44" portal-disabled>
|
|
208
224
|
<DropdownMenuItem v-for="entry in localeLinks" :key="entry.code" as-child>
|
|
209
225
|
<NuxtLink
|
|
210
226
|
:to="entry.to"
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { Button } from "#ginko-docs/components/ui/button";
|
|
3
|
+
import { useSiteNavigation } from "#ginko-docs/composables/useSiteNavigation";
|
|
4
|
+
|
|
5
|
+
const { socialLinks } = useSiteNavigation();
|
|
6
|
+
|
|
7
|
+
defineEmits<{ navigate: [] }>();
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<div v-if="socialLinks.length" class="flex items-center">
|
|
12
|
+
<Button
|
|
13
|
+
v-for="link in socialLinks"
|
|
14
|
+
:key="link.href"
|
|
15
|
+
as-child
|
|
16
|
+
variant="ghost"
|
|
17
|
+
size="icon"
|
|
18
|
+
class="text-muted-foreground hover:text-foreground"
|
|
19
|
+
>
|
|
20
|
+
<NuxtLink
|
|
21
|
+
:to="link.href"
|
|
22
|
+
target="_blank"
|
|
23
|
+
rel="noopener noreferrer"
|
|
24
|
+
:aria-label="link.label"
|
|
25
|
+
@click="$emit('navigate')"
|
|
26
|
+
>
|
|
27
|
+
<Icon :name="link.icon ?? 'lucide:link'" class="size-[18px]" aria-hidden="true" />
|
|
28
|
+
</NuxtLink>
|
|
29
|
+
</Button>
|
|
30
|
+
</div>
|
|
31
|
+
</template>
|
|
@@ -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
|
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
GinkoDocsAppConfig,
|
|
3
|
+
GinkoDocsLink,
|
|
4
|
+
GinkoDocsSocialPlatform,
|
|
5
|
+
} from "../../shared/types/app-config";
|
|
2
6
|
import { getLocalizedSiteText } from "../config/site.utils";
|
|
3
7
|
|
|
4
8
|
export interface NavItem {
|
|
@@ -6,6 +10,9 @@ export interface NavItem {
|
|
|
6
10
|
href: string;
|
|
7
11
|
external?: boolean;
|
|
8
12
|
icon?: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
/** Set on social links so features can find a platform without matching its icon. */
|
|
15
|
+
platform?: GinkoDocsSocialPlatform;
|
|
9
16
|
}
|
|
10
17
|
|
|
11
18
|
export interface MainNavContext {
|
|
@@ -15,6 +22,8 @@ export interface MainNavContext {
|
|
|
15
22
|
blogExists: boolean;
|
|
16
23
|
docsLabel: string;
|
|
17
24
|
blogLabel: string;
|
|
25
|
+
docsDescription?: string;
|
|
26
|
+
blogDescription?: string;
|
|
18
27
|
}
|
|
19
28
|
|
|
20
29
|
const isExternalHref = (href: string) => /^https?:\/\//.test(href);
|
|
@@ -30,21 +39,68 @@ export function resolveMainNav(
|
|
|
30
39
|
label: getLocalizedSiteText(link.label, ctx.locale),
|
|
31
40
|
href,
|
|
32
41
|
external: isExternalHref(href),
|
|
42
|
+
icon: link.icon,
|
|
43
|
+
description: link.description
|
|
44
|
+
? getLocalizedSiteText(link.description, ctx.locale)
|
|
45
|
+
: undefined,
|
|
33
46
|
};
|
|
34
47
|
});
|
|
35
48
|
}
|
|
36
49
|
|
|
37
|
-
const items: NavItem[] = [
|
|
50
|
+
const items: NavItem[] = [
|
|
51
|
+
{
|
|
52
|
+
label: ctx.docsLabel,
|
|
53
|
+
href: ctx.docsPath,
|
|
54
|
+
icon: "lucide:book-open",
|
|
55
|
+
description: ctx.docsDescription,
|
|
56
|
+
},
|
|
57
|
+
];
|
|
38
58
|
if (ctx.blogExists) {
|
|
39
|
-
items.push({
|
|
59
|
+
items.push({
|
|
60
|
+
label: ctx.blogLabel,
|
|
61
|
+
href: ctx.blogPath,
|
|
62
|
+
icon: "lucide:file-text",
|
|
63
|
+
description: ctx.blogDescription,
|
|
64
|
+
});
|
|
40
65
|
}
|
|
41
66
|
return items;
|
|
42
67
|
}
|
|
43
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Brand names are not translated, so the labels are literals. The icons are
|
|
71
|
+
* bundled defaults — Lucide has no Discord mark, so chat is the closest generic
|
|
72
|
+
* stand-in and sites that ship the real one override `icon` per entry.
|
|
73
|
+
*/
|
|
74
|
+
const socialDefaults: Record<GinkoDocsSocialPlatform, { label: string; icon: string }> = {
|
|
75
|
+
github: { label: "GitHub", icon: "lucide:github" },
|
|
76
|
+
discord: { label: "Discord", icon: "lucide:message-circle" },
|
|
77
|
+
linkedin: { label: "LinkedIn", icon: "lucide:linkedin" },
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
export function resolveSocialLinks(social: GinkoDocsAppConfig["social"]): NavItem[] {
|
|
81
|
+
// Config order is render order, so a site can list Discord ahead of GitHub.
|
|
82
|
+
return Object.entries(social).flatMap<NavItem>(([key, entry]) => {
|
|
83
|
+
const platform = key as GinkoDocsSocialPlatform;
|
|
84
|
+
const defaults = socialDefaults[platform];
|
|
85
|
+
if (!defaults || !entry) return [];
|
|
86
|
+
|
|
87
|
+
const link = typeof entry === "string" ? { href: entry } : entry;
|
|
88
|
+
if (!link.href) return [];
|
|
89
|
+
|
|
90
|
+
return [
|
|
91
|
+
{
|
|
92
|
+
label: link.label ?? defaults.label,
|
|
93
|
+
href: link.href,
|
|
94
|
+
external: true,
|
|
95
|
+
icon: link.icon ?? defaults.icon,
|
|
96
|
+
platform,
|
|
97
|
+
},
|
|
98
|
+
];
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
44
102
|
export interface BannerContext {
|
|
45
103
|
locale: string;
|
|
46
|
-
blogPath: string;
|
|
47
|
-
blogExists: boolean;
|
|
48
104
|
defaultText: string;
|
|
49
105
|
defaultLinkLabel: string;
|
|
50
106
|
}
|
|
@@ -65,16 +121,17 @@ export function resolveBanner(
|
|
|
65
121
|
config: GinkoDocsAppConfig["banner"],
|
|
66
122
|
ctx: BannerContext,
|
|
67
123
|
): ResolvedBanner {
|
|
68
|
-
const show = config.enabled === "auto" ? ctx.blogExists : config.enabled;
|
|
69
124
|
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;
|
|
125
|
+
const linkHref = config.link?.to ? getLocalizedSiteText(config.link.to, ctx.locale) : undefined;
|
|
75
126
|
const linkLabel = config.link?.label
|
|
76
127
|
? getLocalizedSiteText(config.link.label, ctx.locale)
|
|
77
128
|
: ctx.defaultLinkLabel;
|
|
78
129
|
|
|
79
|
-
return {
|
|
130
|
+
return {
|
|
131
|
+
show: config.enabled,
|
|
132
|
+
text,
|
|
133
|
+
linkLabel,
|
|
134
|
+
linkHref,
|
|
135
|
+
storageKey: bannerStorageKey(config.id),
|
|
136
|
+
};
|
|
80
137
|
}
|
|
@@ -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
|
+
}
|