@lupinum/ginko-docs 0.4.0-rc.9 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (296) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/LICENSE +1 -1
  3. package/README.md +206 -54
  4. package/app/app.config.ts +42 -55
  5. package/app/assets/docs.css +555 -0
  6. package/app/components/DocsBanner.vue +29 -0
  7. package/app/components/DocsExample.vue +43 -0
  8. package/app/components/DocsFooter.vue +19 -0
  9. package/app/components/DocsHeader.vue +112 -0
  10. package/app/components/DocsLanding.vue +55 -0
  11. package/app/components/DocsLanguage.vue +29 -0
  12. package/app/components/DocsNavTree.vue +38 -0
  13. package/app/components/DocsPage.vue +84 -0
  14. package/app/components/DocsPageActions.vue +47 -0
  15. package/app/components/DocsPost.vue +58 -0
  16. package/app/components/DocsSearch.vue +134 -0
  17. package/app/components/DocsShell.vue +20 -0
  18. package/app/components/DocsSidebar.vue +18 -0
  19. package/app/components/DocsTable.vue +11 -0
  20. package/app/components/DocsThemeToggle.vue +45 -0
  21. package/app/components/DocsToc.vue +73 -0
  22. package/app/composables/useDocs.ts +52 -0
  23. package/app/composables/useDocsBlog.ts +32 -0
  24. package/app/composables/useDocsCopy.ts +17 -0
  25. package/app/composables/useDocsPopover.ts +36 -0
  26. package/app/composables/useDocsSite.ts +10 -0
  27. package/app/docs-pages/blog.vue +47 -0
  28. package/app/docs-pages/changelog.vue +27 -0
  29. package/app/docs-pages/doc.vue +14 -0
  30. package/app/docs-pages/docs.vue +9 -0
  31. package/app/docs-pages/index.vue +12 -0
  32. package/app/docs-pages/post.vue +8 -0
  33. package/app/error.vue +23 -115
  34. package/app/layouts/default.vue +25 -7
  35. package/app/lib/blogTypes.ts +8 -0
  36. package/app/lib/docsFirst.ts +11 -0
  37. package/app/lib/docsInit.ts +18 -0
  38. package/app/lib/docsNav.ts +36 -0
  39. package/app/lib/docsPage.ts +44 -0
  40. package/app/lib/markdownComponents.ts +16 -0
  41. package/app/lib/previewToc.ts +18 -0
  42. package/dist/config.d.mts +232 -0
  43. package/dist/config.d.ts +232 -0
  44. package/dist/config.mjs +114 -0
  45. package/dist/pages.d.mts +5 -0
  46. package/dist/pages.d.ts +5 -0
  47. package/dist/pages.mjs +36 -0
  48. package/dist/shared/ginko-docs.BwbF7JBR.mjs +4 -0
  49. package/i18n/de.json +1 -0
  50. package/i18n/en.json +1 -0
  51. package/icons/README.md +2 -0
  52. package/icons/bluesky.svg +1 -0
  53. package/icons/claude.svg +1 -0
  54. package/icons/discord.svg +1 -0
  55. package/icons/github.svg +1 -0
  56. package/icons/linkedin.svg +1 -0
  57. package/icons/mastodon.svg +1 -0
  58. package/icons/openai.svg +1 -0
  59. package/icons/x.svg +1 -0
  60. package/icons/youtube.svg +1 -0
  61. package/nuxt.config.ts +34 -209
  62. package/package.json +43 -76
  63. package/public/_docs/fonts/LICENSE +188 -0
  64. package/public/_docs/fonts/inter-latin-wght-normal.woff2 +0 -0
  65. package/public/_docs/fonts/jetbrains-mono-latin-400-normal.woff2 +0 -0
  66. package/public/_docs/fonts/jetbrains-mono-latin-500-normal.woff2 +0 -0
  67. package/server/feeds/blog-locale.get.ts +9 -0
  68. package/server/feeds/blog.get.ts +4 -0
  69. package/server/lib/blogFeed.ts +35 -0
  70. package/server/lib/rss.ts +57 -0
  71. package/server/mcp/handler.ts +108 -0
  72. package/server/routes/__ginko/docs-mcp.ts +35 -0
  73. package/shared/paths.ts +4 -0
  74. package/app/app.vue +0 -98
  75. package/app/assets/css/prose.css +0 -3240
  76. package/app/assets/css/tailwind.css +0 -394
  77. package/app/assets/css/theme-palettes.css +0 -309
  78. package/app/assets/css/theme-presets.css +0 -141
  79. package/app/components/OgImage/GinkoDocs.satori.vue +0 -238
  80. package/app/components/content/DocumentPageShell.vue +0 -55
  81. package/app/components/content/Feedback.vue +0 -102
  82. package/app/components/content/ImageZoomDialog.vue +0 -84
  83. package/app/components/content/PageMarkdownCopy.vue +0 -104
  84. package/app/components/content/imageZoom.ts +0 -25
  85. package/app/components/mdc/MdcAccordion.vue +0 -67
  86. package/app/components/mdc/MdcAccordionItem.vue +0 -42
  87. package/app/components/mdc/MdcApi.vue +0 -159
  88. package/app/components/mdc/MdcAside.vue +0 -23
  89. package/app/components/mdc/MdcCallout.vue +0 -61
  90. package/app/components/mdc/MdcCard.vue +0 -175
  91. package/app/components/mdc/MdcCards.vue +0 -30
  92. package/app/components/mdc/MdcCenter.vue +0 -71
  93. package/app/components/mdc/MdcCodeGroup.vue +0 -197
  94. package/app/components/mdc/MdcCodeTree.vue +0 -234
  95. package/app/components/mdc/MdcCollapse.vue +0 -61
  96. package/app/components/mdc/MdcColumn.vue +0 -70
  97. package/app/components/mdc/MdcDropcap.vue +0 -84
  98. package/app/components/mdc/MdcError.vue +0 -23
  99. package/app/components/mdc/MdcExcerpt.vue +0 -26
  100. package/app/components/mdc/MdcFigure.vue +0 -85
  101. package/app/components/mdc/MdcFiles.vue +0 -120
  102. package/app/components/mdc/MdcIdea.vue +0 -17
  103. package/app/components/mdc/MdcInfo.vue +0 -17
  104. package/app/components/mdc/MdcInlineToc.vue +0 -51
  105. package/app/components/mdc/MdcKbd.vue +0 -10
  106. package/app/components/mdc/MdcLayout.vue +0 -57
  107. package/app/components/mdc/MdcNote.vue +0 -17
  108. package/app/components/mdc/MdcQuiz.vue +0 -241
  109. package/app/components/mdc/MdcQuizQuestion.vue +0 -221
  110. package/app/components/mdc/MdcReadMore.vue +0 -70
  111. package/app/components/mdc/MdcSteps.vue +0 -59
  112. package/app/components/mdc/MdcSuccess.vue +0 -23
  113. package/app/components/mdc/MdcTab.vue +0 -17
  114. package/app/components/mdc/MdcTabs.vue +0 -150
  115. package/app/components/mdc/MdcTimeline.vue +0 -17
  116. package/app/components/mdc/MdcTimelineItem.vue +0 -40
  117. package/app/components/mdc/MdcWarning.vue +0 -23
  118. package/app/components/mdc/api.utils.ts +0 -132
  119. package/app/components/mdc/code-tree.utils.ts +0 -22
  120. package/app/components/mdc/icons.ts +0 -10
  121. package/app/components/mdc/quiz.utils.ts +0 -38
  122. package/app/components/prose/ProseA.vue +0 -27
  123. package/app/components/prose/ProseBlockquote.vue +0 -30
  124. package/app/components/prose/ProseCode.vue +0 -14
  125. package/app/components/prose/ProseEm.vue +0 -14
  126. package/app/components/prose/ProseH1.vue +0 -18
  127. package/app/components/prose/ProseH2.vue +0 -29
  128. package/app/components/prose/ProseH3.vue +0 -29
  129. package/app/components/prose/ProseH4.vue +0 -29
  130. package/app/components/prose/ProseH5.vue +0 -15
  131. package/app/components/prose/ProseH6.vue +0 -15
  132. package/app/components/prose/ProseHr.vue +0 -12
  133. package/app/components/prose/ProseImg.vue +0 -55
  134. package/app/components/prose/ProseLi.vue +0 -14
  135. package/app/components/prose/ProseOl.vue +0 -14
  136. package/app/components/prose/ProseP.vue +0 -14
  137. package/app/components/prose/ProsePre.vue +0 -180
  138. package/app/components/prose/ProseStrong.vue +0 -14
  139. package/app/components/prose/ProseTable.vue +0 -18
  140. package/app/components/prose/ProseTbody.vue +0 -14
  141. package/app/components/prose/ProseTd.vue +0 -14
  142. package/app/components/prose/ProseTh.vue +0 -14
  143. package/app/components/prose/ProseThead.vue +0 -14
  144. package/app/components/prose/ProseTr.vue +0 -14
  145. package/app/components/prose/ProseUl.vue +0 -14
  146. package/app/components/site/ModeToggle.vue +0 -81
  147. package/app/components/site/SiteBanner.vue +0 -97
  148. package/app/components/site/SiteFooter.vue +0 -90
  149. package/app/components/site/SiteHeader.vue +0 -371
  150. package/app/components/site/SiteHeroCode.vue +0 -173
  151. package/app/components/site/SiteInteractionLayer.vue +0 -42
  152. package/app/components/site/SiteLocaleSwitcher.vue +0 -190
  153. package/app/components/site/SiteLogoMark.vue +0 -12
  154. package/app/components/site/SiteSkipLink.vue +0 -14
  155. package/app/components/site/SiteSocialLinks.vue +0 -33
  156. package/app/components/site/header-utils.ts +0 -3
  157. package/app/components/site/mode-toggle.utils.ts +0 -18
  158. package/app/components/ui/badge/Badge.vue +0 -28
  159. package/app/components/ui/badge/index.ts +0 -24
  160. package/app/components/ui/button/Button.vue +0 -31
  161. package/app/components/ui/button/index.ts +0 -35
  162. package/app/components/ui/collapsible/Collapsible.vue +0 -15
  163. package/app/components/ui/collapsible/CollapsibleContent.vue +0 -25
  164. package/app/components/ui/collapsible/CollapsibleTrigger.vue +0 -12
  165. package/app/components/ui/collapsible/index.ts +0 -3
  166. package/app/components/ui/dropdown-menu/DropdownMenu.vue +0 -15
  167. package/app/components/ui/dropdown-menu/DropdownMenuContent.vue +0 -50
  168. package/app/components/ui/dropdown-menu/DropdownMenuItem.vue +0 -41
  169. package/app/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +0 -15
  170. package/app/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +0 -37
  171. package/app/components/ui/dropdown-menu/DropdownMenuSeparator.vue +0 -23
  172. package/app/components/ui/dropdown-menu/DropdownMenuTrigger.vue +0 -14
  173. package/app/components/ui/dropdown-menu/index.ts +0 -7
  174. package/app/components/ui/kbd/Kbd.vue +0 -23
  175. package/app/components/ui/kbd/index.ts +0 -21
  176. package/app/components/ui/scroll-area/ScrollArea.vue +0 -39
  177. package/app/components/ui/scroll-area/ScrollBar.vue +0 -33
  178. package/app/components/ui/scroll-area/index.ts +0 -2
  179. package/app/components/ui/separator/Separator.vue +0 -27
  180. package/app/components/ui/separator/index.ts +0 -1
  181. package/app/components/ui/sheet/Sheet.vue +0 -15
  182. package/app/components/ui/sheet/SheetContent.vue +0 -59
  183. package/app/components/ui/sheet/SheetDescription.vue +0 -21
  184. package/app/components/ui/sheet/SheetOverlay.vue +0 -26
  185. package/app/components/ui/sheet/SheetTitle.vue +0 -21
  186. package/app/components/ui/sheet/SheetTrigger.vue +0 -12
  187. package/app/components/ui/sheet/index.ts +0 -5
  188. package/app/components/ui/tabs/Tabs.vue +0 -24
  189. package/app/components/ui/tabs/TabsList.vue +0 -26
  190. package/app/components/ui/tabs/TabsTrigger.vue +0 -28
  191. package/app/components/ui/tabs/index.ts +0 -3
  192. package/app/composables/site-navigation.utils.ts +0 -133
  193. package/app/composables/useCanonicalUrl.ts +0 -9
  194. package/app/composables/useContentRouteAlternates.ts +0 -35
  195. package/app/composables/useGinkoAnalytics.ts +0 -52
  196. package/app/composables/useGinkoDocsConfig.ts +0 -6
  197. package/app/composables/useGinkoOgImage.ts +0 -20
  198. package/app/composables/useLocalizedPath.ts +0 -12
  199. package/app/composables/useLocalizedRouteSwitch.ts +0 -31
  200. package/app/composables/useMetaKey.ts +0 -18
  201. package/app/composables/usePageMarkdownActions.ts +0 -79
  202. package/app/composables/useProseAppearance.ts +0 -24
  203. package/app/composables/useSchemaJsonLd.ts +0 -25
  204. package/app/composables/useSiteNavigation.ts +0 -64
  205. package/app/config/site.utils.ts +0 -36
  206. package/app/features/docs/components/DocsBreadcrumb.vue +0 -37
  207. package/app/features/docs/components/DocsContributeLinks.vue +0 -75
  208. package/app/features/docs/components/DocsMobileToc.vue +0 -108
  209. package/app/features/docs/components/DocsPageContent.vue +0 -234
  210. package/app/features/docs/components/DocsPageNav.vue +0 -57
  211. package/app/features/docs/components/DocsSidebar.vue +0 -145
  212. package/app/features/docs/components/DocsSidebarDropdown.vue +0 -70
  213. package/app/features/docs/components/DocsSidebarItem.vue +0 -122
  214. package/app/features/docs/components/DocsSidebarList.vue +0 -35
  215. package/app/features/docs/components/DocsSidebarRow.vue +0 -27
  216. package/app/features/docs/components/DocsSidebarTabs.vue +0 -59
  217. package/app/features/docs/components/DocsToc.vue +0 -106
  218. package/app/features/docs/composables/useDocsNavigation.ts +0 -29
  219. package/app/features/docs/composables/useDocsNavigationData.ts +0 -18
  220. package/app/features/docs/composables/useRevealActive.ts +0 -58
  221. package/app/features/docs/composables/useScrollspy.ts +0 -135
  222. package/app/features/docs/docs-navigation.ts +0 -157
  223. package/app/features/docs/toc-context.ts +0 -6
  224. package/app/features/search/command-center.ts +0 -110
  225. package/app/features/search/components/SiteCommandCenter.vue +0 -359
  226. package/app/features/search/components/SiteSearchPageHighlight.vue +0 -126
  227. package/app/features/search/useCommandCenter.ts +0 -292
  228. package/app/layouts/blog.vue +0 -15
  229. package/app/layouts/docs.vue +0 -20
  230. package/app/lib/errors.ts +0 -37
  231. package/app/lib/schema-org.ts +0 -38
  232. package/app/pages/blog/[slug].vue +0 -228
  233. package/app/pages/blog/index.vue +0 -130
  234. package/app/pages/docs/[...slug].vue +0 -10
  235. package/app/pages/docs/index.vue +0 -19
  236. package/app/pages/index.vue +0 -278
  237. package/app/plugins/ginko-docs-theme.ts +0 -14
  238. package/app/plugins/ssr-width.ts +0 -6
  239. package/app/utils/content.ts +0 -67
  240. package/app/utils/file-icons.ts +0 -90
  241. package/app/utils/index.ts +0 -7
  242. package/app/utils/repository.ts +0 -20
  243. package/components.ts +0 -9
  244. package/content-collections.ts +0 -89
  245. package/content.js +0 -200
  246. package/content.ts +0 -104
  247. package/i18n/i18n.config.ts +0 -10
  248. package/i18n/locales.ts +0 -81
  249. package/i18n/messages/global/banner.ts +0 -8
  250. package/i18n/messages/global/blog.ts +0 -18
  251. package/i18n/messages/global/command.ts +0 -49
  252. package/i18n/messages/global/docs.ts +0 -36
  253. package/i18n/messages/global/errors.ts +0 -36
  254. package/i18n/messages/global/feedback.ts +0 -11
  255. package/i18n/messages/global/index.ts +0 -21
  256. package/i18n/messages/global/nav.ts +0 -26
  257. package/i18n/messages/global/site.ts +0 -4
  258. package/i18n/messages/global/theme.ts +0 -9
  259. package/i18n/messages/index.ts +0 -20
  260. package/i18n/messages/localize.ts +0 -35
  261. package/i18n/routes.ts +0 -33
  262. package/icon-bundle.ts +0 -116
  263. package/index.d.ts +0 -37
  264. package/modules/analytics-boundary.ts +0 -23
  265. package/modules/feature-routing.ts +0 -68
  266. package/modules/syntax-highlighting.ts +0 -120
  267. package/public/fonts/public-sans/LICENSE +0 -93
  268. package/public/fonts/public-sans/README.md +0 -12
  269. package/public/fonts/public-sans/public-sans-400-normal-latin.woff +0 -0
  270. package/public/fonts/public-sans/public-sans-500-normal-latin.woff +0 -0
  271. package/public/fonts/public-sans/public-sans-600-normal-latin.woff +0 -0
  272. package/public/fonts/public-sans/public-sans-700-normal-latin.woff +0 -0
  273. package/runtime/generate-favicons.mjs +0 -124
  274. package/runtime/server/agent-markdown.ts +0 -19
  275. package/server/api/_ginko-docs/redirects.get.ts +0 -28
  276. package/server/mcp/tools/get-page.ts +0 -14
  277. package/server/mcp/tools/list-pages.ts +0 -10
  278. package/server/middleware/redirects.ts +0 -22
  279. package/server/plugins/agent-markdown.ts +0 -6
  280. package/server/plugins/sitemap-policy.ts +0 -12
  281. package/server/routes/.well-known/ai-catalog.json.get.ts +0 -10
  282. package/server/routes/[locale]/blog/rss.xml.get.ts +0 -13
  283. package/server/routes/blog/rss.xml.get.ts +0 -5
  284. package/server/routes/mcp/server-card.get.ts +0 -14
  285. package/server/utils/blog-feed.ts +0 -51
  286. package/server/utils/feed.ts +0 -70
  287. package/server/utils/mcp-server-card.ts +0 -45
  288. package/server/utils/redirects.ts +0 -38
  289. package/server/utils/redirects.utils.ts +0 -58
  290. package/server/utils/sitemap.ts +0 -45
  291. package/shared/route-slugs.ts +0 -5
  292. package/shared/theme-palettes.ts +0 -37
  293. package/shared/theme-presets.ts +0 -3
  294. package/shared/types/app-config.ts +0 -172
  295. package/shared/types/nuxt-config.ts +0 -14
  296. package/tags.ts +0 -192
@@ -1,71 +0,0 @@
1
- <script setup lang="ts">
2
- import { computed, type HTMLAttributes } from "vue";
3
- import { cn } from "../../utils";
4
-
5
- type ValueProp<T extends string> = T | { value?: T | string };
6
- type CenterSize = "sm" | "md" | "lg";
7
- type CenterType = "default" | "card" | "border" | "border-dashed" | "outline" | "outline-dashed";
8
-
9
- const props = withDefaults(
10
- defineProps<{
11
- size?: ValueProp<CenterSize>;
12
- max?: CenterSize;
13
- type?: ValueProp<CenterType>;
14
- class?: HTMLAttributes["class"];
15
- }>(),
16
- {
17
- size: "md",
18
- type: "default",
19
- },
20
- );
21
-
22
- const centerTypeValue = computed<CenterType>(() => {
23
- if (typeof props.type === "string") return props.type;
24
- return (props.type?.value as CenterType | undefined) ?? "default";
25
- });
26
-
27
- const sizeValue = computed<CenterSize>(() => {
28
- if (props.max) return props.max;
29
- if (typeof props.size === "string") return props.size;
30
- return (props.size?.value as CenterSize | undefined) ?? "md";
31
- });
32
-
33
- const centerSizeClass = {
34
- sm: "max-w-sm",
35
- md: "max-w-md",
36
- lg: "max-w-lg",
37
- } as const;
38
- </script>
39
-
40
- <template>
41
- <div :class="cn('mx-auto flex justify-center p-2', props.class)">
42
- <div
43
- v-if="centerTypeValue === 'card'"
44
- :class="
45
- cn(
46
- 'mx-auto w-full rounded-lg border bg-card p-6 text-center shadow-xs',
47
- centerSizeClass[sizeValue],
48
- )
49
- "
50
- >
51
- <slot />
52
- </div>
53
- <div
54
- v-else
55
- :class="
56
- cn(
57
- 'mx-auto w-full text-center',
58
- centerSizeClass[sizeValue],
59
- centerTypeValue !== 'default' && 'rounded-lg p-4',
60
- centerTypeValue === 'border' && 'border border-border',
61
- centerTypeValue === 'border-dashed' && 'border border-dashed border-border',
62
- centerTypeValue === 'outline' && 'outline outline-1 outline-offset-2 outline-border',
63
- centerTypeValue === 'outline-dashed' &&
64
- 'outline-1 outline-offset-2 outline-border outline-dashed',
65
- )
66
- "
67
- >
68
- <slot />
69
- </div>
70
- </div>
71
- </template>
@@ -1,197 +0,0 @@
1
- <script setup lang="ts">
2
- import type { VNode } from "vue";
3
- import { Comment, cloneVNode, computed, h, ref, resolveComponent, useSlots } from "vue";
4
- import { useClipboard } from "@vueuse/core";
5
- import { useI18n } from "#imports";
6
- import { cn } from "../../utils";
7
- import { useProseAppearance } from "../../composables/useProseAppearance";
8
-
9
- type CodeBlockProps = {
10
- code?: string;
11
- filename?: string | null;
12
- language?: string | null;
13
- meta?: string | null;
14
- };
15
-
16
- type CodeGroupItem = {
17
- code: string;
18
- icon?: string;
19
- label: string;
20
- node: VNode;
21
- value: string;
22
- };
23
-
24
- const slots = useSlots();
25
- const activeValue = ref("");
26
- const { copy, copied } = useClipboard();
27
- const { t } = useI18n();
28
- const props = defineProps<{ appearance?: "quiet" | "tint" }>();
29
- const appearance = useProseAppearance("code", () => props.appearance);
30
-
31
- const PACKAGE_ICONS: Record<string, string> = {
32
- bun: "logos:bun",
33
- npm: "logos:npm-icon",
34
- pnpm: "logos:pnpm",
35
- yarn: "logos:yarn",
36
- };
37
-
38
- function isRenderableNode(node: VNode) {
39
- return node.type !== Comment;
40
- }
41
-
42
- function textFromNode(input: unknown): string {
43
- if (typeof input === "string") return input;
44
- if (Array.isArray(input)) return input.map(textFromNode).join("");
45
- if (input && typeof input === "object" && "children" in input) {
46
- return textFromNode((input as VNode).children);
47
- }
48
-
49
- return "";
50
- }
51
-
52
- function cleanLabel(input: string | null | undefined): string {
53
- return (
54
- input
55
- ?.trim()
56
- .replace(/^\[(.*)]$/, "$1")
57
- .trim() || ""
58
- );
59
- }
60
-
61
- function labelFromMeta(meta: string | null | undefined): string {
62
- const match = meta?.match(/\[([^\]]+)]/);
63
- return cleanLabel(match?.[1]);
64
- }
65
-
66
- function nodeProps(node: VNode): CodeBlockProps {
67
- return (node.props || {}) as CodeBlockProps;
68
- }
69
-
70
- function nodeLabel(node: VNode, index: number): string {
71
- const props = nodeProps(node);
72
-
73
- return (
74
- cleanLabel(props.filename) ||
75
- labelFromMeta(props.meta) ||
76
- cleanLabel(props.language) ||
77
- `Code ${index + 1}`
78
- );
79
- }
80
-
81
- const items = computed<CodeGroupItem[]>(() =>
82
- (slots.default?.() || []).filter(isRenderableNode).map((node, index) => {
83
- const label = nodeLabel(node, index);
84
- const value = `${label}-${index}`;
85
- const normalizedLabel = label.toLowerCase();
86
- const props = nodeProps(node);
87
-
88
- return {
89
- code: props.code || textFromNode(node.children),
90
- icon: PACKAGE_ICONS[normalizedLabel],
91
- label,
92
- node,
93
- value,
94
- };
95
- }),
96
- );
97
-
98
- const activeItem = computed(() => {
99
- const current = items.value.find((item) => item.value === activeValue.value);
100
- return current || items.value[0];
101
- });
102
-
103
- function selectItem(value: string) {
104
- activeValue.value = value;
105
- }
106
-
107
- async function copyActiveCode() {
108
- await copy(activeItem.value?.code || "");
109
- }
110
-
111
- function renderCodeGroup() {
112
- if (!items.value.length) return null;
113
- const Icon = resolveComponent("Icon");
114
-
115
- return h(
116
- "div",
117
- {
118
- class: "content-codegroup not-prose group",
119
- "data-appearance": appearance.value,
120
- },
121
- [
122
- h("div", { class: "content-codegroup-header" }, [
123
- h(
124
- "div",
125
- {
126
- class: "content-codegroup-tabs",
127
- role: "tablist",
128
- },
129
- items.value.map((item) =>
130
- h(
131
- "button",
132
- {
133
- key: item.value,
134
- type: "button",
135
- role: "tab",
136
- "aria-selected": activeItem.value?.value === item.value ? "true" : "false",
137
- class: cn(
138
- "content-codegroup-tab",
139
- activeItem.value?.value === item.value && "content-codegroup-tab-active",
140
- ),
141
- onClick: () => selectItem(item.value),
142
- },
143
- [
144
- item.icon
145
- ? h(Icon, {
146
- name: item.icon,
147
- class: "content-codegroup-tab-icon",
148
- "aria-hidden": "true",
149
- })
150
- : null,
151
- item.label,
152
- ],
153
- ),
154
- ),
155
- ),
156
- h(
157
- "button",
158
- {
159
- type: "button",
160
- class: "content-codeblock-copy-button content-codegroup-copy-button",
161
- "aria-label": copied.value ? t("docs.copiedText") : t("docs.copyText"),
162
- onClick: copyActiveCode,
163
- },
164
- [
165
- h(Icon, {
166
- name: copied.value ? "lucide:check" : "lucide:clipboard",
167
- class: "size-3.5",
168
- "aria-hidden": "true",
169
- }),
170
- ],
171
- ),
172
- ]),
173
- h(
174
- "div",
175
- {
176
- class: "content-codegroup-panels",
177
- },
178
- items.value.map((item) =>
179
- h(
180
- "div",
181
- {
182
- key: item.value,
183
- role: "tabpanel",
184
- style: activeItem.value?.value === item.value ? undefined : { display: "none" },
185
- },
186
- [cloneVNode(item.node, { inGroup: true })],
187
- ),
188
- ),
189
- ),
190
- ],
191
- );
192
- }
193
- </script>
194
-
195
- <template>
196
- <component :is="renderCodeGroup" />
197
- </template>
@@ -1,234 +0,0 @@
1
- <script setup lang="ts">
2
- import type { VNode } from "vue";
3
- import { Comment, cloneVNode, h, ref, resolveComponent, useSlots } from "vue";
4
- import { cn } from "../../utils";
5
- import { resolveFileIcon } from "../../utils/file-icons";
6
- import { useProseAppearance } from "../../composables/useProseAppearance";
7
- import { validateCodeTreePaths } from "./code-tree.utils";
8
-
9
- type CodeBlockProps = {
10
- code?: string;
11
- filename?: string | null;
12
- language?: string | null;
13
- meta?: string | null;
14
- };
15
-
16
- type TreeLeaf = {
17
- path: string;
18
- node: VNode;
19
- };
20
-
21
- type TreeNode = {
22
- label: string;
23
- path: string;
24
- children?: TreeNode[];
25
- };
26
-
27
- const props = defineProps<{
28
- /** Path of the file to show initially, e.g. "app/app.config.ts". */
29
- defaultValue?: string;
30
- expandAll?: boolean;
31
- appearance?: "quiet" | "tint";
32
- }>();
33
- const appearance = useProseAppearance("code", () => props.appearance);
34
-
35
- const slots = useSlots();
36
-
37
- function isRenderableNode(node: VNode) {
38
- return node.type !== Comment;
39
- }
40
-
41
- function cleanLabel(input: string | null | undefined): string {
42
- return (
43
- input
44
- ?.trim()
45
- .replace(/^\[(.*)]$/, "$1")
46
- .trim() || ""
47
- );
48
- }
49
-
50
- function labelFromMeta(meta: string | null | undefined): string {
51
- const match = meta?.match(/\[([^\]]+)]/);
52
- return cleanLabel(match?.[1]);
53
- }
54
-
55
- function resolveLeaves(): TreeLeaf[] {
56
- const leaves = (slots.default?.() || []).filter(isRenderableNode).map((node) => {
57
- const nodeProps = (node.props || {}) as CodeBlockProps;
58
- const path = cleanLabel(nodeProps.filename) || labelFromMeta(nodeProps.meta);
59
- if (!path) throw new TypeError("Every code tree block requires a filename label");
60
- return { path, node };
61
- });
62
- validateCodeTreePaths(
63
- leaves.map((leaf) => leaf.path),
64
- props.defaultValue,
65
- );
66
- return leaves;
67
- }
68
-
69
- function buildTree(paths: string[]): TreeNode[] {
70
- const map = new Map<string, TreeNode>();
71
- const root: TreeNode[] = [];
72
-
73
- for (const fullPath of paths) {
74
- const parts = fullPath.split("/");
75
- let path = "";
76
-
77
- parts.forEach((part, i) => {
78
- path = path ? `${path}/${part}` : part;
79
- if (map.has(path)) return;
80
-
81
- const node: TreeNode = { label: part, path, ...(i < parts.length - 1 && { children: [] }) };
82
- map.set(path, node);
83
- if (i === 0) root.push(node);
84
- else map.get(parts.slice(0, i).join("/"))?.children?.push(node);
85
- });
86
- }
87
-
88
- const sort = (nodes: TreeNode[]): TreeNode[] =>
89
- nodes
90
- .sort((a, b) =>
91
- !!a.children === !!b.children ? a.label.localeCompare(b.label) : b.children ? 1 : -1,
92
- )
93
- .map((node) => ({ ...node, children: node.children && sort(node.children) }));
94
-
95
- return sort(root);
96
- }
97
-
98
- function ancestorsOf(path: string): string[] {
99
- const parts = path.split("/");
100
- return parts.slice(0, -1).map((_, i) => parts.slice(0, i + 1).join("/"));
101
- }
102
-
103
- const selectedPath = ref(props.defaultValue ?? "");
104
- const expanded = ref(new Set<string>());
105
- const expansionChanged = ref(false);
106
-
107
- function toggleDir(path: string, initial: Set<string>) {
108
- if (!expansionChanged.value) {
109
- expanded.value = new Set(initial);
110
- expansionChanged.value = true;
111
- }
112
- if (expanded.value.has(path)) expanded.value.delete(path);
113
- else expanded.value.add(path);
114
- }
115
-
116
- const rowClass = "content-code-tree-row";
117
-
118
- function renderRows(
119
- nodes: TreeNode[],
120
- openPaths: Set<string>,
121
- activePath: string,
122
- ): (VNode | null)[] {
123
- const Icon = resolveComponent("Icon");
124
-
125
- return nodes.map((node) => {
126
- if (node.children) {
127
- const isOpen = openPaths.has(node.path);
128
- return h("li", { key: node.path, role: "none" }, [
129
- h(
130
- "button",
131
- {
132
- type: "button",
133
- class: rowClass,
134
- "aria-expanded": isOpen ? "true" : "false",
135
- onClick: () => toggleDir(node.path, openPaths),
136
- },
137
- [
138
- h(Icon, {
139
- name: "lucide:chevron-right",
140
- class: "content-code-tree-chevron",
141
- "data-open": isOpen ? "true" : undefined,
142
- "aria-hidden": "true",
143
- }),
144
- h(Icon, {
145
- name: isOpen ? "lucide:folder-open" : "lucide:folder",
146
- class: "content-code-tree-icon",
147
- "aria-hidden": "true",
148
- }),
149
- h("span", { class: "content-code-tree-label" }, node.label),
150
- ],
151
- ),
152
- isOpen
153
- ? h(
154
- "ul",
155
- { role: "group", class: "content-code-tree-branch" },
156
- renderRows(node.children, openPaths, activePath),
157
- )
158
- : null,
159
- ]);
160
- }
161
-
162
- const isSelected = activePath === node.path;
163
- return h("li", { key: node.path, role: "none" }, [
164
- h(
165
- "button",
166
- {
167
- type: "button",
168
- class: cn(rowClass, isSelected && "content-code-tree-row-active"),
169
- "aria-current": isSelected ? "true" : undefined,
170
- onClick: () => (selectedPath.value = node.path),
171
- },
172
- [
173
- h("span", { class: "content-code-tree-spacer", "aria-hidden": "true" }),
174
- h(resolveComponent("Icon"), {
175
- name: resolveFileIcon(node.label),
176
- class: "content-code-tree-icon",
177
- "aria-hidden": "true",
178
- }),
179
- h("span", { class: "content-code-tree-label" }, node.label),
180
- ],
181
- ),
182
- ]);
183
- });
184
- }
185
-
186
- function renderCodeTree() {
187
- const leaves = resolveLeaves();
188
- if (!leaves.length) return null;
189
- const activePath = leaves.some((leaf) => leaf.path === selectedPath.value)
190
- ? selectedPath.value
191
- : leaves[0]!.path;
192
- const initialOpenPaths = new Set(
193
- props.expandAll ? leaves.flatMap((leaf) => ancestorsOf(leaf.path)) : ancestorsOf(activePath),
194
- );
195
- const openPaths = expansionChanged.value ? expanded.value : initialOpenPaths;
196
- const tree = buildTree(leaves.map((leaf) => leaf.path));
197
-
198
- return h(
199
- "div",
200
- {
201
- class: "content-code-tree not-prose",
202
- "data-appearance": appearance.value,
203
- },
204
- [
205
- h(
206
- "ul",
207
- {
208
- class: "content-code-tree-list",
209
- },
210
- renderRows(tree, openPaths, activePath),
211
- ),
212
- h(
213
- "div",
214
- { class: "content-code-tree-pane" },
215
- leaves.map((leaf) =>
216
- h(
217
- "div",
218
- {
219
- key: leaf.path,
220
- class: "content-code-tree-panel",
221
- style: activePath === leaf.path ? undefined : { display: "none" },
222
- },
223
- [cloneVNode(leaf.node)],
224
- ),
225
- ),
226
- ),
227
- ],
228
- );
229
- }
230
- </script>
231
-
232
- <template>
233
- <component :is="renderCodeTree" />
234
- </template>
@@ -1,61 +0,0 @@
1
- <script setup lang="ts">
2
- import { computed, onMounted, provide, ref, useId } from "vue";
3
- import { useResizeObserver } from "@vueuse/core";
4
- import { useI18n } from "#imports";
5
- import { useProseAppearance } from "../../composables/useProseAppearance";
6
-
7
- const props = defineProps<{ appearance?: "quiet" | "tint" }>();
8
- const appearance = useProseAppearance("code", () => props.appearance);
9
- // The clipped code block must render on the surface the collapse declares.
10
- provide("contentCodeAppearance", appearance);
11
-
12
- // Clips tall authored content (usually a long code block) at a fixed height
13
- // until the reader expands it. Expanding removes the cap entirely, so the page
14
- // owns scrolling instead of a nested scroll area.
15
- const { t } = useI18n();
16
- const regionId = useId();
17
- const region = ref<HTMLElement | null>(null);
18
- const expanded = ref(false);
19
- const overflows = ref(false);
20
- const lineCount = ref(0);
21
-
22
- function measure() {
23
- const el = region.value;
24
- if (!el) return;
25
- overflows.value = el.scrollHeight - el.clientHeight > 2;
26
- }
27
-
28
- onMounted(() => {
29
- lineCount.value = region.value?.querySelectorAll("pre .line").length ?? 0;
30
- measure();
31
- });
32
- useResizeObserver(region, measure);
33
-
34
- const label = computed(() =>
35
- lineCount.value ? t("docs.showAllLines", { count: lineCount.value }) : t("docs.showMore"),
36
- );
37
- </script>
38
-
39
- <template>
40
- <div class="content-collapse" :data-appearance="appearance">
41
- <div
42
- :id="regionId"
43
- ref="region"
44
- class="content-collapse-region"
45
- :data-collapsed="!expanded || undefined"
46
- >
47
- <slot />
48
- </div>
49
- <div v-if="!expanded && overflows" class="content-collapse-fade">
50
- <button
51
- type="button"
52
- class="content-collapse-button"
53
- :aria-controls="regionId"
54
- aria-expanded="false"
55
- @click="expanded = true"
56
- >
57
- {{ label }}
58
- </button>
59
- </div>
60
- </div>
61
- </template>
@@ -1,70 +0,0 @@
1
- <script setup lang="ts">
2
- import { computed, inject, nextTick, onMounted, ref, type HTMLAttributes } from "vue";
3
- import { cn } from "../../utils";
4
-
5
- type ValueProp<T extends string> = T | { value?: T | string };
6
- type ColumnSize = "sm" | "md" | "lg";
7
-
8
- const props = withDefaults(
9
- defineProps<{
10
- size?: ValueProp<ColumnSize>;
11
- class?: HTMLAttributes["class"];
12
- }>(),
13
- {
14
- size: "md",
15
- },
16
- );
17
-
18
- const parentLayoutType = inject(
19
- "mdc-layout-type",
20
- computed(() => "default"),
21
- );
22
-
23
- const sizeValue = computed<ColumnSize>(() => {
24
- if (typeof props.size === "string") return props.size;
25
- return (props.size?.value as ColumnSize | undefined) ?? "md";
26
- });
27
-
28
- const columnSizeClass = {
29
- sm: "content-layout-column-sm",
30
- md: "content-layout-column-md",
31
- lg: "content-layout-column-lg",
32
- } as const;
33
-
34
- const isLastColumn = ref(false);
35
- const columnRef = ref<HTMLElement | null>(null);
36
-
37
- onMounted(() => {
38
- nextTick(() => {
39
- if (columnRef.value?.parentElement) {
40
- const siblings = Array.from(columnRef.value.parentElement.children);
41
- isLastColumn.value = siblings.indexOf(columnRef.value) === siblings.length - 1;
42
- }
43
- });
44
- });
45
-
46
- const showDivider = computed(
47
- () => !isLastColumn.value && ["border", "border-dashed"].includes(parentLayoutType.value),
48
- );
49
- </script>
50
-
51
- <template>
52
- <div
53
- ref="columnRef"
54
- :class="
55
- cn(
56
- 'content-layout-column',
57
- columnSizeClass[sizeValue],
58
- showDivider && 'content-layout-column-divider',
59
- showDivider &&
60
- parentLayoutType === 'border-dashed' &&
61
- 'content-layout-column-divider-dashed',
62
- props.class,
63
- )
64
- "
65
- >
66
- <div class="content-layout-column-inner">
67
- <slot />
68
- </div>
69
- </div>
70
- </template>