@baybreezy/docd 0.0.1
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/app/app.config.ts +239 -0
- package/app/app.vue +19 -0
- package/app/assets/css/tailwind.css +335 -0
- package/app/assets/css/theme.css +1171 -0
- package/app/components/OgImage/Docs.takumi.vue +69 -0
- package/app/components/OgImage/Landing.takumi.vue +64 -0
- package/app/components/OgImage/Site.takumi.vue +32 -0
- package/app/components/Ui/Avatar/Avatar.vue +75 -0
- package/app/components/Ui/Avatar/Badge.vue +34 -0
- package/app/components/Ui/Avatar/Fallback.vue +30 -0
- package/app/components/Ui/Avatar/Group.vue +29 -0
- package/app/components/Ui/Avatar/GroupCount.vue +29 -0
- package/app/components/Ui/Avatar/Image.vue +29 -0
- package/app/components/Ui/Badge.vue +86 -0
- package/app/components/Ui/BadgeGroup.vue +314 -0
- package/app/components/Ui/BgPattern/Grid.vue +137 -0
- package/app/components/Ui/BorderBeam.vue +97 -0
- package/app/components/Ui/Breadcrumbs.vue +103 -0
- package/app/components/Ui/Button.vue +169 -0
- package/app/components/Ui/ButtonGroup/ButtonGroup.vue +54 -0
- package/app/components/Ui/ButtonGroup/Separator.vue +38 -0
- package/app/components/Ui/ButtonGroup/Text.vue +33 -0
- package/app/components/Ui/Card/Action.vue +31 -0
- package/app/components/Ui/Card/Card.vue +58 -0
- package/app/components/Ui/Card/Content.vue +34 -0
- package/app/components/Ui/Card/Description.vue +36 -0
- package/app/components/Ui/Card/Footer.vue +31 -0
- package/app/components/Ui/Card/Header.vue +31 -0
- package/app/components/Ui/Card/Title.vue +37 -0
- package/app/components/Ui/Collapsible/Collapsible.vue +16 -0
- package/app/components/Ui/Collapsible/Content.vue +27 -0
- package/app/components/Ui/Collapsible/Trigger.vue +13 -0
- package/app/components/Ui/Command/Command.vue +115 -0
- package/app/components/Ui/Command/Dialog.vue +65 -0
- package/app/components/Ui/Command/Empty.vue +32 -0
- package/app/components/Ui/Command/Footer.vue +40 -0
- package/app/components/Ui/Command/Group.vue +58 -0
- package/app/components/Ui/Command/Input.vue +57 -0
- package/app/components/Ui/Command/Item.vue +102 -0
- package/app/components/Ui/Command/List.vue +33 -0
- package/app/components/Ui/Command/Separator.vue +30 -0
- package/app/components/Ui/Command/Shortcut.vue +28 -0
- package/app/components/Ui/Container.vue +46 -0
- package/app/components/Ui/ContextMenu/Arrow.vue +43 -0
- package/app/components/Ui/ContextMenu/CheckboxItem.vue +42 -0
- package/app/components/Ui/ContextMenu/Content.vue +53 -0
- package/app/components/Ui/ContextMenu/ContextMenu.vue +14 -0
- package/app/components/Ui/ContextMenu/Group.vue +12 -0
- package/app/components/Ui/ContextMenu/Item.vue +65 -0
- package/app/components/Ui/ContextMenu/ItemIndicator.vue +30 -0
- package/app/components/Ui/ContextMenu/Label.vue +35 -0
- package/app/components/Ui/ContextMenu/Portal.vue +12 -0
- package/app/components/Ui/ContextMenu/RadioGroup.vue +16 -0
- package/app/components/Ui/ContextMenu/RadioItem.vue +40 -0
- package/app/components/Ui/ContextMenu/Separator.vue +25 -0
- package/app/components/Ui/ContextMenu/Shortcut.vue +30 -0
- package/app/components/Ui/ContextMenu/Sub.vue +15 -0
- package/app/components/Ui/ContextMenu/SubContent.vue +55 -0
- package/app/components/Ui/ContextMenu/SubTrigger.vue +42 -0
- package/app/components/Ui/ContextMenu/Trigger.vue +12 -0
- package/app/components/Ui/Dialog/Close.vue +12 -0
- package/app/components/Ui/Dialog/Content.vue +79 -0
- package/app/components/Ui/Dialog/Description.vue +29 -0
- package/app/components/Ui/Dialog/Dialog.vue +14 -0
- package/app/components/Ui/Dialog/Footer.vue +32 -0
- package/app/components/Ui/Dialog/Header.vue +32 -0
- package/app/components/Ui/Dialog/Overlay.vue +25 -0
- package/app/components/Ui/Dialog/Portal.vue +12 -0
- package/app/components/Ui/Dialog/Title.vue +29 -0
- package/app/components/Ui/Dialog/Trigger.vue +12 -0
- package/app/components/Ui/Divider.vue +102 -0
- package/app/components/Ui/Drawer/Close.vue +12 -0
- package/app/components/Ui/Drawer/Content.vue +67 -0
- package/app/components/Ui/Drawer/Description.vue +33 -0
- package/app/components/Ui/Drawer/Drawer.vue +17 -0
- package/app/components/Ui/Drawer/Footer.vue +35 -0
- package/app/components/Ui/Drawer/Header.vue +34 -0
- package/app/components/Ui/Drawer/Overlay.vue +20 -0
- package/app/components/Ui/Drawer/Portal.vue +12 -0
- package/app/components/Ui/Drawer/Title.vue +35 -0
- package/app/components/Ui/Drawer/Trigger.vue +12 -0
- package/app/components/Ui/DropdownMenu/Arrow.vue +43 -0
- package/app/components/Ui/DropdownMenu/CheckboxItem.vue +41 -0
- package/app/components/Ui/DropdownMenu/Content.vue +56 -0
- package/app/components/Ui/DropdownMenu/DropdownMenu.vue +15 -0
- package/app/components/Ui/DropdownMenu/Group.vue +12 -0
- package/app/components/Ui/DropdownMenu/Item.vue +64 -0
- package/app/components/Ui/DropdownMenu/ItemIndicator.vue +32 -0
- package/app/components/Ui/DropdownMenu/Label.vue +34 -0
- package/app/components/Ui/DropdownMenu/Portal.vue +12 -0
- package/app/components/Ui/DropdownMenu/RadioGroup.vue +16 -0
- package/app/components/Ui/DropdownMenu/RadioItem.vue +40 -0
- package/app/components/Ui/DropdownMenu/Separator.vue +25 -0
- package/app/components/Ui/DropdownMenu/Shortcut.vue +44 -0
- package/app/components/Ui/DropdownMenu/Sub.vue +14 -0
- package/app/components/Ui/DropdownMenu/SubContent.vue +56 -0
- package/app/components/Ui/DropdownMenu/SubTrigger.vue +47 -0
- package/app/components/Ui/DropdownMenu/Trigger.vue +12 -0
- package/app/components/Ui/FancyIcon.vue +243 -0
- package/app/components/Ui/GradientDivider.vue +26 -0
- package/app/components/Ui/IframeLazy.vue +97 -0
- package/app/components/Ui/Input.vue +97 -0
- package/app/components/Ui/InputGroup/Addon.vue +66 -0
- package/app/components/Ui/InputGroup/Button.vue +50 -0
- package/app/components/Ui/InputGroup/Input.vue +25 -0
- package/app/components/Ui/InputGroup/InputGroup.vue +44 -0
- package/app/components/Ui/InputGroup/Text.vue +33 -0
- package/app/components/Ui/InputGroup/Textarea.vue +25 -0
- package/app/components/Ui/Kbd/Group.vue +32 -0
- package/app/components/Ui/Kbd/Kbd.vue +62 -0
- package/app/components/Ui/Label.vue +40 -0
- package/app/components/Ui/Popover/Anchor.vue +13 -0
- package/app/components/Ui/Popover/Arrow.vue +42 -0
- package/app/components/Ui/Popover/Close.vue +13 -0
- package/app/components/Ui/Popover/Content.vue +55 -0
- package/app/components/Ui/Popover/Popover.vue +15 -0
- package/app/components/Ui/Popover/Portal.vue +13 -0
- package/app/components/Ui/Popover/Trigger.vue +12 -0
- package/app/components/Ui/Popover/X.vue +38 -0
- package/app/components/Ui/ScrollArea/Corner.vue +12 -0
- package/app/components/Ui/ScrollArea/ScrollArea.vue +38 -0
- package/app/components/Ui/ScrollArea/Scrollbar.vue +39 -0
- package/app/components/Ui/ScrollArea/Thumb.vue +39 -0
- package/app/components/Ui/ScrollArea/Viewport.vue +27 -0
- package/app/components/Ui/Scrollspy.vue +61 -0
- package/app/components/Ui/Separator.vue +40 -0
- package/app/components/Ui/Skeleton.vue +39 -0
- package/app/components/Ui/Sonner.vue +25 -0
- package/app/components/Ui/Tabs/Content.vue +27 -0
- package/app/components/Ui/Tabs/Indicator.vue +37 -0
- package/app/components/Ui/Tabs/List.vue +37 -0
- package/app/components/Ui/Tabs/Tabs.vue +25 -0
- package/app/components/Ui/Tabs/Trigger.vue +41 -0
- package/app/components/Ui/Textarea.vue +81 -0
- package/app/components/Ui/Tooltip/Arrow.vue +30 -0
- package/app/components/Ui/Tooltip/Content.vue +50 -0
- package/app/components/Ui/Tooltip/Portal.vue +12 -0
- package/app/components/Ui/Tooltip/Provider.vue +14 -0
- package/app/components/Ui/Tooltip/Tooltip.vue +25 -0
- package/app/components/Ui/Tooltip/Trigger.vue +12 -0
- package/app/components/Ui/Tree/Item.vue +15 -0
- package/app/components/Ui/Tree/Tree.vue +15 -0
- package/app/components/Ui/Tree/Virtualizer.vue +13 -0
- package/app/components/component-api/ComponentApiSection.vue +135 -0
- package/app/components/content/docs/Callout/DocsCallout.vue +99 -0
- package/app/components/content/prose/ProseA.global.vue +31 -0
- package/app/components/content/prose/ProseBlockquote.global.vue +28 -0
- package/app/components/content/prose/ProseCallout.global.vue +306 -0
- package/app/components/content/prose/ProseCard.global.vue +100 -0
- package/app/components/content/prose/ProseCodeCollapse.global.vue +125 -0
- package/app/components/content/prose/ProseCodeCopy.global.vue +67 -0
- package/app/components/content/prose/ProseCodeGroup.global.vue +104 -0
- package/app/components/content/prose/ProseCodeTree.global.vue +277 -0
- package/app/components/content/prose/ProseCollapsible.global.vue +64 -0
- package/app/components/content/prose/ProseColorModeImage.global.vue +58 -0
- package/app/components/content/prose/ProseComponentApi.global.vue +104 -0
- package/app/components/content/prose/ProseComponentEvents.global.vue +27 -0
- package/app/components/content/prose/ProseComponentExposed.global.vue +27 -0
- package/app/components/content/prose/ProseComponentProps.global.vue +27 -0
- package/app/components/content/prose/ProseComponentSlots.global.vue +27 -0
- package/app/components/content/prose/ProseEm.global.vue +5 -0
- package/app/components/content/prose/ProseField.global.vue +118 -0
- package/app/components/content/prose/ProseFieldGroup.global.vue +62 -0
- package/app/components/content/prose/ProseH1.global.vue +58 -0
- package/app/components/content/prose/ProseH2.global.vue +58 -0
- package/app/components/content/prose/ProseH3.global.vue +58 -0
- package/app/components/content/prose/ProseH4.global.vue +58 -0
- package/app/components/content/prose/ProseH5.global.vue +47 -0
- package/app/components/content/prose/ProseH6.global.vue +47 -0
- package/app/components/content/prose/ProseHr.global.vue +33 -0
- package/app/components/content/prose/ProseIconList.global.vue +113 -0
- package/app/components/content/prose/ProseImg.global.vue +119 -0
- package/app/components/content/prose/ProseLead.global.vue +28 -0
- package/app/components/content/prose/ProseLi.global.vue +25 -0
- package/app/components/content/prose/ProseMermaid.global.vue +127 -0
- package/app/components/content/prose/ProseOl.global.vue +25 -0
- package/app/components/content/prose/ProseP.global.vue +25 -0
- package/app/components/content/prose/ProsePmInstall.global.vue +60 -0
- package/app/components/content/prose/ProsePmRun.global.vue +51 -0
- package/app/components/content/prose/ProsePmX.global.vue +56 -0
- package/app/components/content/prose/ProsePre.global.vue +181 -0
- package/app/components/content/prose/ProseShowCase.global.vue +56 -0
- package/app/components/content/prose/ProseSmartIcon.global.vue +54 -0
- package/app/components/content/prose/ProseStep.global.vue +22 -0
- package/app/components/content/prose/ProseSteps.global.vue +22 -0
- package/app/components/content/prose/ProseStrong.global.vue +34 -0
- package/app/components/content/prose/ProseTable.global.vue +34 -0
- package/app/components/content/prose/ProseTabs.global.vue +104 -0
- package/app/components/content/prose/ProseTabsInner.global.vue +274 -0
- package/app/components/content/prose/ProseTbody.global.vue +5 -0
- package/app/components/content/prose/ProseTd.global.vue +25 -0
- package/app/components/content/prose/ProseTh.global.vue +25 -0
- package/app/components/content/prose/ProseThead.global.vue +9 -0
- package/app/components/content/prose/ProseTr.global.vue +35 -0
- package/app/components/content/prose/ProseUl.global.vue +25 -0
- package/app/components/docs/DocsExtraStuff.vue +39 -0
- package/app/components/docs/DocsGithubLink.vue +11 -0
- package/app/components/docs/DocsHeader.vue +3 -0
- package/app/components/docs/DocsLogo.vue +74 -0
- package/app/components/docs/DocsMobileBar.vue +26 -0
- package/app/components/docs/DocsMobileNav.vue +49 -0
- package/app/components/docs/DocsNav.vue +161 -0
- package/app/components/docs/DocsPageTransition.vue +32 -0
- package/app/components/docs/DocsSearch.vue +220 -0
- package/app/components/docs/DocsSearchButton.vue +20 -0
- package/app/components/docs/DocsThemeCustomizer.vue +229 -0
- package/app/components/docs/DocsThemeToggler.vue +98 -0
- package/app/components/docs/DocsTocRail.vue +162 -0
- package/app/components/docs/DocsToclink.vue +52 -0
- package/app/components/docs/DocsZigZagRail.vue +70 -0
- package/app/components/landing/Hero.vue +222 -0
- package/app/components/page/PageFooter.vue +49 -0
- package/app/components/page/PageHeader.vue +68 -0
- package/app/components/page/PageHeaderLinks.vue +138 -0
- package/app/components/page/PageMobileToc.vue +162 -0
- package/app/components/page/PageToc.vue +33 -0
- package/app/composables/useDefaultSlotItems.ts +90 -0
- package/app/composables/useDocPage.ts +66 -0
- package/app/composables/useDocSearch.ts +23 -0
- package/app/composables/useDocd.ts +107 -0
- package/app/composables/useLogoAssets.ts +319 -0
- package/app/composables/usePm.ts +73 -0
- package/app/composables/useProseComponentMeta.ts +30 -0
- package/app/composables/useScrollspy.ts +327 -0
- package/app/composables/useSeo.ts +240 -0
- package/app/composables/useUIConfig.ts +36 -0
- package/app/layouts/default.vue +5 -0
- package/app/layouts/docs.vue +64 -0
- package/app/middleware/colorMode.global.ts +8 -0
- package/app/middleware/doc-page-layout.ts +11 -0
- package/app/middleware/landing-page-layout.ts +11 -0
- package/app/pages/[...slug].vue +63 -0
- package/app/plugins/mermaid.client.ts +35 -0
- package/app/plugins/navigation-direction.client.ts +15 -0
- package/app/plugins/theme-restore.client.ts +7 -0
- package/app/templates/landing.vue +40 -0
- package/app/transitions/presets.ts +71 -0
- package/app/types/prose-component-meta.d.ts +4 -0
- package/app/utils/og.ts +26 -0
- package/app/utils/prerender.ts +9 -0
- package/app/utils/translucent.ts +56 -0
- package/app/utils/tw-helper.ts +4 -0
- package/content.config.ts +81 -0
- package/index.d.ts +25 -0
- package/modules/config.ts +89 -0
- package/modules/custom-icons.ts +17 -0
- package/modules/markdown-rewrite.ts +96 -0
- package/modules/prose-component-meta.ts +150 -0
- package/modules/routing.ts +22 -0
- package/modules/skills/index.ts +167 -0
- package/modules/skills/runtime/server/routes/skills-files.ts +49 -0
- package/modules/skills/runtime/server/routes/skills-index.ts +8 -0
- package/nuxt.config.ts +96 -0
- package/nuxt.schema.ts +288 -0
- package/package.json +95 -0
- package/server/mcp/tools/get-page.ts +66 -0
- package/server/mcp/tools/list-pages.ts +61 -0
- package/server/routes/sitemap.xml.ts +73 -0
- package/server/utils/content.ts +3 -0
- package/tailwind.config.cjs +55 -0
- package/utils/component-api-content.ts +467 -0
- package/utils/component-api-discovery.ts +165 -0
- package/utils/component-api-schema.ts +28 -0
- package/utils/component-api.ts +243 -0
- package/utils/generate-prose-component-meta.ts +303 -0
- package/utils/git.ts +123 -0
- package/utils/meta.ts +40 -0
- package/utils/pages.ts +21 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<UiTooltip>
|
|
3
|
+
<UiTooltipTrigger as-child>
|
|
4
|
+
<UiButton
|
|
5
|
+
variant="ghost"
|
|
6
|
+
size="icon-xs"
|
|
7
|
+
:aria-label="copied ? 'Copied' : 'Copy to clipboard'"
|
|
8
|
+
:disabled="copied"
|
|
9
|
+
v-bind="$attrs"
|
|
10
|
+
@click="onCopy"
|
|
11
|
+
>
|
|
12
|
+
<AnimatePresence mode="wait">
|
|
13
|
+
<Motion
|
|
14
|
+
v-if="!copied"
|
|
15
|
+
as-child
|
|
16
|
+
as="svg"
|
|
17
|
+
:initial="{ opacity: 0, scale: 0.8 }"
|
|
18
|
+
:animate="{ opacity: 1, scale: 1 }"
|
|
19
|
+
:exit="{ opacity: 0, scale: 0.8 }"
|
|
20
|
+
:transition="{ duration: 0.2 }"
|
|
21
|
+
>
|
|
22
|
+
<Icon name="lucide:clipboard" aria-hidden="true" class="size-4 text-muted-foreground" />
|
|
23
|
+
</Motion>
|
|
24
|
+
<Motion
|
|
25
|
+
v-if="copied"
|
|
26
|
+
as-child
|
|
27
|
+
as="svg"
|
|
28
|
+
:initial="{ opacity: 0, scale: 0.8 }"
|
|
29
|
+
:animate="{ opacity: 1, scale: 1 }"
|
|
30
|
+
:exit="{ opacity: 0, scale: 0.8 }"
|
|
31
|
+
:transition="{ duration: 0.2 }"
|
|
32
|
+
>
|
|
33
|
+
<Icon name="lucide:check" aria-hidden="true" class="size-4 text-emerald-500" />
|
|
34
|
+
</Motion>
|
|
35
|
+
</AnimatePresence>
|
|
36
|
+
</UiButton>
|
|
37
|
+
</UiTooltipTrigger>
|
|
38
|
+
<UiTooltipContent>
|
|
39
|
+
<p>Copy to clipboard</p>
|
|
40
|
+
<UiTooltipArrow />
|
|
41
|
+
</UiTooltipContent>
|
|
42
|
+
</UiTooltip>
|
|
43
|
+
</template>
|
|
44
|
+
|
|
45
|
+
<script lang="ts" setup>
|
|
46
|
+
const props = defineProps<{
|
|
47
|
+
/**
|
|
48
|
+
* The code that should be copied
|
|
49
|
+
*/
|
|
50
|
+
code?: string;
|
|
51
|
+
}>();
|
|
52
|
+
|
|
53
|
+
defineOptions({ inheritAttrs: false });
|
|
54
|
+
|
|
55
|
+
const { copied, copy } = useClipboard();
|
|
56
|
+
|
|
57
|
+
const emit = defineEmits<{
|
|
58
|
+
codeCopied: [];
|
|
59
|
+
}>();
|
|
60
|
+
|
|
61
|
+
const onCopy = () => {
|
|
62
|
+
if (!props.code) return;
|
|
63
|
+
copy(props.code);
|
|
64
|
+
useSonner("Copied to clipboard!");
|
|
65
|
+
emit("codeCopied");
|
|
66
|
+
};
|
|
67
|
+
</script>
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<ClientOnly>
|
|
3
|
+
<render />
|
|
4
|
+
</ClientOnly>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<script setup lang="ts">
|
|
8
|
+
import { normalizeClass } from "vue";
|
|
9
|
+
import type { SetupContext } from "vue";
|
|
10
|
+
|
|
11
|
+
import { ProseTabs } from "#components";
|
|
12
|
+
|
|
13
|
+
const props = withDefaults(
|
|
14
|
+
defineProps<{
|
|
15
|
+
/**
|
|
16
|
+
* Whether the code group is in a stack layout
|
|
17
|
+
* @default false
|
|
18
|
+
*/
|
|
19
|
+
inStack?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Sync identifier for syncing with other tab groups
|
|
22
|
+
*/
|
|
23
|
+
sync?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Whether to add padding around the tabs
|
|
26
|
+
* @default true
|
|
27
|
+
*/
|
|
28
|
+
padded?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Disable the search functionality
|
|
31
|
+
* @default false
|
|
32
|
+
*/
|
|
33
|
+
disableSearch?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Placeholder text for the search input
|
|
36
|
+
* @default 'Search Tab...'
|
|
37
|
+
*/
|
|
38
|
+
searchPlaceholder?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Text to display when no tab is found
|
|
41
|
+
* @default 'No tab found.'
|
|
42
|
+
*/
|
|
43
|
+
searchEmpty?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Whether the combobox should take the full width of the container
|
|
46
|
+
* @default false
|
|
47
|
+
*/
|
|
48
|
+
comboBoxFullWidth?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Additional classes to add to the wrapper
|
|
51
|
+
*/
|
|
52
|
+
class?: string;
|
|
53
|
+
}>(),
|
|
54
|
+
{
|
|
55
|
+
inStack: false,
|
|
56
|
+
padded: true,
|
|
57
|
+
disableSearch: false,
|
|
58
|
+
searchPlaceholder: "Search Tab...",
|
|
59
|
+
searchEmpty: "No tab found.",
|
|
60
|
+
comboBoxFullWidth: false,
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
const _slots: SetupContext["slots"] = useSlots();
|
|
65
|
+
const { items: slotItems } = useDefaultSlotItems({
|
|
66
|
+
slots: _slots,
|
|
67
|
+
mapMeta: ({ props, index }) => ({
|
|
68
|
+
id: props.filename ?? `tab-${index}`,
|
|
69
|
+
label: props.label ?? props.filename ?? `Tab ${index + 1}`,
|
|
70
|
+
icon: props.icon,
|
|
71
|
+
}),
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const isMobile = useMediaQuery("(max-width: 640px)", {
|
|
75
|
+
ssrWidth: 639,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Determine the variant based on number of tabs and screen size
|
|
79
|
+
// If there are 5 or more tabs, use the combobox variant
|
|
80
|
+
// If on mobile and more than 4 tabs, use the combobox variant
|
|
81
|
+
const variant = computed(() => {
|
|
82
|
+
if (slotItems.value.length >= 5) return "combobox";
|
|
83
|
+
if (isMobile.value && slotItems.value.length > 4) return "combobox";
|
|
84
|
+
return "card";
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
function render() {
|
|
88
|
+
return h(
|
|
89
|
+
ProseTabs,
|
|
90
|
+
{
|
|
91
|
+
variant: variant.value,
|
|
92
|
+
inStack: props.inStack,
|
|
93
|
+
sync: props.sync,
|
|
94
|
+
padded: props.padded,
|
|
95
|
+
disableSearch: props.disableSearch,
|
|
96
|
+
searchPlaceholder: props.searchPlaceholder,
|
|
97
|
+
searchEmpty: props.searchEmpty,
|
|
98
|
+
comboBoxFullWidth: props.comboBoxFullWidth,
|
|
99
|
+
class: normalizeClass(props.class) || undefined,
|
|
100
|
+
},
|
|
101
|
+
() => slotItems.value.map(({ vnode }) => vnode)
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
</script>
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<define-tree-child v-slot="{ items: childItems, level }">
|
|
3
|
+
<li v-for="item in childItems" :key="item.path">
|
|
4
|
+
<TreeItem v-slot="{ isExpanded, isSelected }" as-child :level="level" :value="item">
|
|
5
|
+
<button
|
|
6
|
+
type="button"
|
|
7
|
+
:aria-expanded="item.children?.length ? isExpanded : undefined"
|
|
8
|
+
:aria-label="item.children?.length ? `${item.label} folder` : `${item.label} file`"
|
|
9
|
+
class="inline-flex w-full items-center gap-2 rounded-md px-2 py-1.5 text-sm transition-colors hover:bg-muted focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none"
|
|
10
|
+
:class="[
|
|
11
|
+
isSelected || lastSelectedItem?.path === item.path ? 'bg-muted text-primary' : '',
|
|
12
|
+
]"
|
|
13
|
+
>
|
|
14
|
+
<!-- Folder/File Icon -->
|
|
15
|
+
<img
|
|
16
|
+
v-if="item.children?.length"
|
|
17
|
+
:src="getMaterialFolderIcon(item.label, isExpanded)"
|
|
18
|
+
:alt="`${item.label} folder ${isExpanded ? 'expanded' : 'collapsed'}`"
|
|
19
|
+
class="size-4 shrink-0"
|
|
20
|
+
/>
|
|
21
|
+
<img
|
|
22
|
+
v-else
|
|
23
|
+
:src="getMaterialFileIcon(item.label)"
|
|
24
|
+
:alt="`${item.label} file`"
|
|
25
|
+
class="size-4 shrink-0"
|
|
26
|
+
/>
|
|
27
|
+
|
|
28
|
+
<!-- Label -->
|
|
29
|
+
<span class="truncate">{{ item.label }}</span>
|
|
30
|
+
|
|
31
|
+
<!-- Chevron for folders -->
|
|
32
|
+
<Icon
|
|
33
|
+
v-if="item.children?.length"
|
|
34
|
+
name="lucide:chevron-down"
|
|
35
|
+
class="ml-auto size-4 shrink-0 text-muted-foreground transition-transform"
|
|
36
|
+
:class="[isExpanded ? 'rotate-0' : '-rotate-90']"
|
|
37
|
+
aria-hidden="true"
|
|
38
|
+
/>
|
|
39
|
+
</button>
|
|
40
|
+
|
|
41
|
+
<!-- Nested children -->
|
|
42
|
+
<ul v-if="item.children?.length && isExpanded" role="group" class="pl-4">
|
|
43
|
+
<TreeChild :items="item.children" :level="level + 1" />
|
|
44
|
+
</ul>
|
|
45
|
+
</TreeItem>
|
|
46
|
+
</li>
|
|
47
|
+
</define-tree-child>
|
|
48
|
+
|
|
49
|
+
<div
|
|
50
|
+
data-slot="prose-code-tree"
|
|
51
|
+
class="grid overflow-hidden rounded-lg border lg:grid-cols-3"
|
|
52
|
+
:class="props.class"
|
|
53
|
+
>
|
|
54
|
+
<nav class="not-prose h-full overflow-hidden px-2" aria-label="File tree navigation">
|
|
55
|
+
<template v-if="props.title">
|
|
56
|
+
<div class="p-2 py-4 text-sm font-medium">
|
|
57
|
+
<span>
|
|
58
|
+
{{ props.title }}
|
|
59
|
+
</span>
|
|
60
|
+
</div>
|
|
61
|
+
<UiGradientDivider />
|
|
62
|
+
</template>
|
|
63
|
+
<!-- Tree Navigation -->
|
|
64
|
+
<div class="max-h-[520px] overflow-y-auto py-2">
|
|
65
|
+
<TreeRoot
|
|
66
|
+
v-model="selectedItem"
|
|
67
|
+
:items="treeItems"
|
|
68
|
+
:get-key="(item) => item.path"
|
|
69
|
+
:default-expanded="expandedPaths"
|
|
70
|
+
>
|
|
71
|
+
<ul class="space-y-1" role="tree">
|
|
72
|
+
<TreeChild :items="treeItems" :level="0" />
|
|
73
|
+
</ul>
|
|
74
|
+
</TreeRoot>
|
|
75
|
+
</div>
|
|
76
|
+
</nav>
|
|
77
|
+
|
|
78
|
+
<!-- Content Display -->
|
|
79
|
+
<div
|
|
80
|
+
class="grid min-h-[240px] grid-cols-1 lg:col-span-2"
|
|
81
|
+
role="region"
|
|
82
|
+
aria-label="File content"
|
|
83
|
+
aria-live="polite"
|
|
84
|
+
>
|
|
85
|
+
<component
|
|
86
|
+
:is="lastSelectedItem?.component"
|
|
87
|
+
v-if="lastSelectedItem"
|
|
88
|
+
meta="noFormat"
|
|
89
|
+
class="mt-0 data-[slot=prose-pre-wrapper]:h-full data-[slot=prose-pre-wrapper]:rounded-none data-[slot=prose-pre-wrapper]:border-0 data-[slot=prose-pre-wrapper]:border-t lg:data-[slot=prose-pre-wrapper]:border-t-0 lg:data-[slot=prose-pre-wrapper]:border-l [&_pre]:h-[calc(100%-45px)] [&_pre]:flex-1 [&>*:first-child]:mt-0"
|
|
90
|
+
/>
|
|
91
|
+
<div v-else class="flex h-full items-center justify-center text-sm text-muted-foreground">
|
|
92
|
+
Select a file to view its content
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
</template>
|
|
97
|
+
|
|
98
|
+
<script lang="ts" setup>
|
|
99
|
+
import { getMaterialFileIcon, getMaterialFolderIcon } from "@baybreezy/file-extension-icon";
|
|
100
|
+
import type { HTMLAttributes } from "vue";
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* TreeItem represents a node in the file tree structure
|
|
104
|
+
*/
|
|
105
|
+
type TreeItem = {
|
|
106
|
+
/** Display label for the node */
|
|
107
|
+
label: string;
|
|
108
|
+
/** Full path from root */
|
|
109
|
+
path: string;
|
|
110
|
+
/** Child nodes (only for directories) */
|
|
111
|
+
children?: TreeItem[];
|
|
112
|
+
/** Vue component to render when selected (only for files) */
|
|
113
|
+
component?: any;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const props = withDefaults(
|
|
117
|
+
defineProps<{
|
|
118
|
+
/**
|
|
119
|
+
* Default file path to select on mount
|
|
120
|
+
* @example "src/components/Button.vue"
|
|
121
|
+
*/
|
|
122
|
+
defaultValue?: string;
|
|
123
|
+
/**
|
|
124
|
+
* Expand all directories by default instead of just the path to defaultValue
|
|
125
|
+
* @default false
|
|
126
|
+
*/
|
|
127
|
+
expandAll?: boolean;
|
|
128
|
+
/**
|
|
129
|
+
* Optional title displayed above the file tree
|
|
130
|
+
* @example "Project Structure"
|
|
131
|
+
*/
|
|
132
|
+
title?: string;
|
|
133
|
+
/**
|
|
134
|
+
* Additional CSS classes for the root container
|
|
135
|
+
*/
|
|
136
|
+
class?: HTMLAttributes["class"];
|
|
137
|
+
}>(),
|
|
138
|
+
{
|
|
139
|
+
defaultValue: undefined,
|
|
140
|
+
expandAll: false,
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const [DefineTreeChild, TreeChild] = createReusableTemplate<{
|
|
145
|
+
items: TreeItem[];
|
|
146
|
+
level: number;
|
|
147
|
+
}>();
|
|
148
|
+
|
|
149
|
+
const selectedItem = ref<TreeItem>();
|
|
150
|
+
const lastSelectedItem = ref<TreeItem>();
|
|
151
|
+
const rerenderCount = ref(0);
|
|
152
|
+
|
|
153
|
+
// Get slot items from default slot - these are the code blocks passed as children
|
|
154
|
+
const { items: slotItems } = useDefaultSlotItems({
|
|
155
|
+
slots: useSlots(),
|
|
156
|
+
mapMeta: ({ props, vnode }) => ({
|
|
157
|
+
path: props.path || props.filename || props.label,
|
|
158
|
+
icon: props.icon,
|
|
159
|
+
component: vnode,
|
|
160
|
+
}),
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Build hierarchical tree structure from flat slot items
|
|
165
|
+
* Converts flat file paths like "src/components/Button.vue" into nested tree nodes
|
|
166
|
+
*/
|
|
167
|
+
const treeItems = computed(() => {
|
|
168
|
+
// Trigger rerender when slots change
|
|
169
|
+
void rerenderCount.value;
|
|
170
|
+
|
|
171
|
+
const flatItems = slotItems.value.map((item) => ({
|
|
172
|
+
label: item.meta.path,
|
|
173
|
+
icon: item.meta.icon,
|
|
174
|
+
component: item.meta.component,
|
|
175
|
+
}));
|
|
176
|
+
|
|
177
|
+
return buildTree(flatItems);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Build tree structure from flat file paths
|
|
182
|
+
* Automatically creates parent directory nodes and sorts alphabetically
|
|
183
|
+
*/
|
|
184
|
+
function buildTree(items: { label: string; icon?: string; component?: any }[]): TreeItem[] {
|
|
185
|
+
const map = new Map<string, TreeItem>();
|
|
186
|
+
const root: TreeItem[] = [];
|
|
187
|
+
|
|
188
|
+
items.forEach((item) => {
|
|
189
|
+
const parts = item.label.split("/");
|
|
190
|
+
let path = "";
|
|
191
|
+
|
|
192
|
+
parts.forEach((part, i) => {
|
|
193
|
+
path = path ? `${path}/${part}` : part;
|
|
194
|
+
|
|
195
|
+
if (!map.has(path)) {
|
|
196
|
+
const isLeaf = i === parts.length - 1;
|
|
197
|
+
const node: TreeItem = {
|
|
198
|
+
label: part,
|
|
199
|
+
path,
|
|
200
|
+
...(isLeaf ? { component: item.component, icon: item.icon } : { children: [] }),
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
map.set(path, node);
|
|
204
|
+
|
|
205
|
+
if (i === 0) {
|
|
206
|
+
root.push(node);
|
|
207
|
+
} else {
|
|
208
|
+
const parentPath = parts.slice(0, i).join("/");
|
|
209
|
+
map.get(parentPath)?.children?.push(node);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// Sort function
|
|
216
|
+
const sort = (nodes: TreeItem[]): TreeItem[] =>
|
|
217
|
+
nodes
|
|
218
|
+
.sort((a, b) =>
|
|
219
|
+
!!a.children === !!b.children ? a.label.localeCompare(b.label) : a.children ? -1 : 1
|
|
220
|
+
)
|
|
221
|
+
.map((n) => ({ ...n, children: n.children && sort(n.children) }));
|
|
222
|
+
|
|
223
|
+
return sort(root);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Calculate which paths should be expanded based on the selected item or expandAll prop
|
|
228
|
+
*/
|
|
229
|
+
const expandedPaths = computed(() => {
|
|
230
|
+
if (props.expandAll) {
|
|
231
|
+
const allPaths = new Set<string>();
|
|
232
|
+
slotItems.value.forEach((item) => {
|
|
233
|
+
const parts = item.meta.path.split("/");
|
|
234
|
+
for (let i = 1; i < parts.length; i++) {
|
|
235
|
+
allPaths.add(parts.slice(0, i).join("/"));
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
return Array.from(allPaths);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const path = selectedItem.value?.path || props.defaultValue;
|
|
242
|
+
if (!path) return [];
|
|
243
|
+
|
|
244
|
+
const parts = path.split("/");
|
|
245
|
+
return parts.slice(0, -1).map((_, i) => parts.slice(0, i + 1).join("/"));
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Watch for selection changes and update lastSelectedItem if a file (not folder) is selected
|
|
250
|
+
*/
|
|
251
|
+
watch(selectedItem, (newVal) => {
|
|
252
|
+
if (newVal && !newVal.children?.length) {
|
|
253
|
+
lastSelectedItem.value = newVal;
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Set initial selection on mount if defaultValue is provided
|
|
259
|
+
*/
|
|
260
|
+
onMounted(() => {
|
|
261
|
+
if (props.defaultValue) {
|
|
262
|
+
const findItem = (items: TreeItem[]): TreeItem | undefined => {
|
|
263
|
+
for (const item of items) {
|
|
264
|
+
if (item.path === props.defaultValue) return item;
|
|
265
|
+
if (item.children) {
|
|
266
|
+
const found = findItem(item.children);
|
|
267
|
+
if (found) return found;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
};
|
|
271
|
+
const initial = findItem(treeItems.value);
|
|
272
|
+
if (initial) {
|
|
273
|
+
selectedItem.value = initial;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
</script>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<UiCollapsible v-slot="{ open }" :default-open="defaultOpen" class="my-4">
|
|
3
|
+
<UiCollapsibleTrigger
|
|
4
|
+
class="group relative inline-flex items-center gap-1.5 rounded-xs text-sm text-muted-foreground transition-colors hover:text-foreground focus:outline-none focus-visible:ring-2 focus-visible:ring-primary"
|
|
5
|
+
:class="triggerClass"
|
|
6
|
+
>
|
|
7
|
+
<ProseSmartIcon v-if="open ? openIcon : closeIcon" :name="open ? openIcon! : closeIcon!" />
|
|
8
|
+
<span>{{ open ? closeTitle : openTitle }}</span>
|
|
9
|
+
</UiCollapsibleTrigger>
|
|
10
|
+
<UiCollapsibleContent :class="contentClass" class="*:my-1.5 *:first:mt-2 *:last:mb-0">
|
|
11
|
+
<slot />
|
|
12
|
+
</UiCollapsibleContent>
|
|
13
|
+
</UiCollapsible>
|
|
14
|
+
</template>
|
|
15
|
+
|
|
16
|
+
<script lang="ts">
|
|
17
|
+
import type { HTMLAttributes } from "vue";
|
|
18
|
+
|
|
19
|
+
export type ProseCollapsibleProps = {
|
|
20
|
+
/**
|
|
21
|
+
* Icon to show when collapsible is open
|
|
22
|
+
* @default "lucide:minus"
|
|
23
|
+
*/
|
|
24
|
+
openIcon?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Icon to show when collapsible is closed
|
|
27
|
+
* @default "lucide:plus"
|
|
28
|
+
*/
|
|
29
|
+
closeIcon?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Text to show when collapsible is closed (trigger to open)
|
|
32
|
+
* @default "Show more"
|
|
33
|
+
*/
|
|
34
|
+
openTitle?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Text to show when collapsible is open (trigger to close)
|
|
37
|
+
* @default "Show less"
|
|
38
|
+
*/
|
|
39
|
+
closeTitle?: string;
|
|
40
|
+
/**
|
|
41
|
+
* Whether the collapsible should be open by default
|
|
42
|
+
* @default false
|
|
43
|
+
*/
|
|
44
|
+
defaultOpen?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Additional CSS classes for the trigger button
|
|
47
|
+
*/
|
|
48
|
+
triggerClass?: HTMLAttributes["class"];
|
|
49
|
+
/**
|
|
50
|
+
* Additional CSS classes for the content area
|
|
51
|
+
*/
|
|
52
|
+
contentClass?: HTMLAttributes["class"];
|
|
53
|
+
};
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<script lang="ts" setup>
|
|
57
|
+
withDefaults(defineProps<ProseCollapsibleProps>(), {
|
|
58
|
+
openIcon: "lucide:minus",
|
|
59
|
+
closeIcon: "lucide:plus",
|
|
60
|
+
openTitle: "Show more",
|
|
61
|
+
closeTitle: "Show less",
|
|
62
|
+
defaultOpen: false,
|
|
63
|
+
});
|
|
64
|
+
</script>
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="not-first:mt-6">
|
|
3
|
+
<div class="dark:hidden">
|
|
4
|
+
<ProseImg v-bind="forwarded" :src="srcLight" />
|
|
5
|
+
</div>
|
|
6
|
+
<div class="hidden dark:block">
|
|
7
|
+
<ProseImg v-bind="forwarded" :src="srcDark" />
|
|
8
|
+
</div>
|
|
9
|
+
</div>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script lang="ts">
|
|
13
|
+
import type { HTMLAttributes } from "vue";
|
|
14
|
+
|
|
15
|
+
export type ProseColorModeImageProps = {
|
|
16
|
+
/**
|
|
17
|
+
* Source URL for light mode image
|
|
18
|
+
*/
|
|
19
|
+
srcLight?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Source URL for dark mode image
|
|
22
|
+
*/
|
|
23
|
+
srcDark?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Alt text for the image
|
|
26
|
+
*/
|
|
27
|
+
alt?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Width of the image
|
|
30
|
+
*/
|
|
31
|
+
width?: string | number;
|
|
32
|
+
/**
|
|
33
|
+
* Height of the image
|
|
34
|
+
*/
|
|
35
|
+
height?: string | number;
|
|
36
|
+
/**
|
|
37
|
+
* Whether the image should have a lifted style
|
|
38
|
+
*/
|
|
39
|
+
lifted?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Whether the image should have zoom effect on hover
|
|
42
|
+
* @default true
|
|
43
|
+
*/
|
|
44
|
+
zoom?: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* Additional CSS classes for the image element
|
|
47
|
+
*/
|
|
48
|
+
class?: HTMLAttributes["class"];
|
|
49
|
+
};
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<script setup lang="ts">
|
|
53
|
+
const props = withDefaults(defineProps<ProseColorModeImageProps>(), {
|
|
54
|
+
zoom: true,
|
|
55
|
+
lifted: false,
|
|
56
|
+
});
|
|
57
|
+
const forwarded = reactiveOmit(props, "srcLight", "srcDark");
|
|
58
|
+
</script>
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div v-if="resolvedMeta" class="not-prose">
|
|
3
|
+
<div v-if="title" class="mb-4">
|
|
4
|
+
<p class="text-lg font-semibold tracking-tight text-foreground">{{ title }}</p>
|
|
5
|
+
</div>
|
|
6
|
+
|
|
7
|
+
<ProseTabs v-if="sectionCount > 1" :variant="tabsVariant">
|
|
8
|
+
<div
|
|
9
|
+
v-for="section in visibleSections"
|
|
10
|
+
:key="section.kind"
|
|
11
|
+
:label="section.label"
|
|
12
|
+
:icon="section.icon"
|
|
13
|
+
class="[&>*:first-child]:mt-0"
|
|
14
|
+
>
|
|
15
|
+
<component :is="section.component" :items="section.items" :layout="layout" />
|
|
16
|
+
</div>
|
|
17
|
+
</ProseTabs>
|
|
18
|
+
|
|
19
|
+
<div v-else-if="visibleSections[0]" class="space-y-6">
|
|
20
|
+
<component
|
|
21
|
+
:is="visibleSections[0]?.component"
|
|
22
|
+
:items="visibleSections[0].items"
|
|
23
|
+
:layout="layout"
|
|
24
|
+
/>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
<p v-else class="text-sm text-muted-foreground">
|
|
28
|
+
No matching component API sections were found.
|
|
29
|
+
</p>
|
|
30
|
+
</div>
|
|
31
|
+
|
|
32
|
+
<p v-else class="not-prose text-sm text-muted-foreground">
|
|
33
|
+
No component metadata was found for <code>{{ path }}</code
|
|
34
|
+
>.
|
|
35
|
+
</p>
|
|
36
|
+
</template>
|
|
37
|
+
|
|
38
|
+
<script lang="ts">
|
|
39
|
+
import type { ComponentApiSectionKind } from "../../../../utils/component-api";
|
|
40
|
+
import type {
|
|
41
|
+
ProseComponentApiLayout,
|
|
42
|
+
ProseComponentMetaEntry,
|
|
43
|
+
} from "../../../../utils/generate-prose-component-meta";
|
|
44
|
+
import type { ProseTabsProps } from "./ProseTabs.global.vue";
|
|
45
|
+
|
|
46
|
+
export type ProseComponentApiProps = {
|
|
47
|
+
path?: string;
|
|
48
|
+
meta?: ProseComponentMetaEntry | null;
|
|
49
|
+
layout?: ProseComponentApiLayout;
|
|
50
|
+
sections?: ComponentApiSectionKind[] | string;
|
|
51
|
+
title?: string;
|
|
52
|
+
tabsVariant?: ProseTabsProps["variant"];
|
|
53
|
+
};
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<script lang="ts" setup>
|
|
57
|
+
import { normalizeComponentApiSections } from "../../../../utils/component-api";
|
|
58
|
+
|
|
59
|
+
const props = withDefaults(defineProps<ProseComponentApiProps>(), {
|
|
60
|
+
layout: "table",
|
|
61
|
+
tabsVariant: "line",
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const resolvedMeta = computed(() => props.meta ?? resolveProseComponentMeta(props.path));
|
|
65
|
+
const requestedSections = computed(() => normalizeComponentApiSections(props.sections));
|
|
66
|
+
const sectionDefinitions = {
|
|
67
|
+
props: {
|
|
68
|
+
label: "Props",
|
|
69
|
+
icon: "lucide:sliders-horizontal",
|
|
70
|
+
component: "ProseComponentProps",
|
|
71
|
+
},
|
|
72
|
+
slots: {
|
|
73
|
+
label: "Slots",
|
|
74
|
+
icon: "lucide:panel-top",
|
|
75
|
+
component: "ProseComponentSlots",
|
|
76
|
+
},
|
|
77
|
+
events: {
|
|
78
|
+
label: "Events",
|
|
79
|
+
icon: "lucide:zap",
|
|
80
|
+
component: "ProseComponentEvents",
|
|
81
|
+
},
|
|
82
|
+
exposed: {
|
|
83
|
+
label: "Exposed",
|
|
84
|
+
icon: "lucide:square-function",
|
|
85
|
+
component: "ProseComponentExposed",
|
|
86
|
+
},
|
|
87
|
+
} as const;
|
|
88
|
+
|
|
89
|
+
const visibleSections = computed(() => {
|
|
90
|
+
if (!resolvedMeta.value) {
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return requestedSections.value
|
|
95
|
+
.map((kind) => ({
|
|
96
|
+
kind,
|
|
97
|
+
...sectionDefinitions[kind],
|
|
98
|
+
items: resolvedMeta.value?.[kind] || [],
|
|
99
|
+
}))
|
|
100
|
+
.filter((section) => section.items.length);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
const sectionCount = computed(() => visibleSections.value.length);
|
|
104
|
+
</script>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<ComponentApiSection kind="events" :items="resolvedItems" :layout="layout" />
|
|
3
|
+
</template>
|
|
4
|
+
|
|
5
|
+
<script lang="ts">
|
|
6
|
+
import type {
|
|
7
|
+
ProseComponentApiLayout,
|
|
8
|
+
ProseComponentMetaEntry,
|
|
9
|
+
ProseComponentMetaEvent,
|
|
10
|
+
} from "../../../../utils/generate-prose-component-meta";
|
|
11
|
+
|
|
12
|
+
export type ProseComponentEventsProps = {
|
|
13
|
+
path?: string;
|
|
14
|
+
meta?: ProseComponentMetaEntry | null;
|
|
15
|
+
items?: ProseComponentMetaEvent[];
|
|
16
|
+
layout?: ProseComponentApiLayout;
|
|
17
|
+
};
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<script lang="ts" setup>
|
|
21
|
+
const props = withDefaults(defineProps<ProseComponentEventsProps>(), {
|
|
22
|
+
layout: "field",
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const resolvedMeta = computed(() => props.meta ?? resolveProseComponentMeta(props.path));
|
|
26
|
+
const resolvedItems = computed(() => props.items ?? resolvedMeta.value?.events ?? []);
|
|
27
|
+
</script>
|