@lupinum/ginko-docs 0.4.0-rc.8 → 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,12 +0,0 @@
1
- <script setup lang="ts">
2
- import type { HTMLAttributes } from "vue";
3
- import { cn } from "../../utils";
4
-
5
- const props = defineProps<{
6
- class?: HTMLAttributes["class"];
7
- }>();
8
- </script>
9
-
10
- <template>
11
- <hr :class="cn(props.class)" />
12
- </template>
@@ -1,55 +0,0 @@
1
- <script setup lang="ts">
2
- import type { HTMLAttributes } from "vue";
3
- import { computed, resolveComponent } from "vue";
4
- import { Motion } from "motion-v";
5
- import { useI18n } from "#imports";
6
- import ImageZoomDialog from "#ginko-docs/components/content/ImageZoomDialog.vue";
7
- import { useGinkoDocsConfig } from "#ginko-docs/composables/useGinkoDocsConfig";
8
- import { cn } from "../../utils";
9
-
10
- const props = defineProps<{
11
- src?: string;
12
- alt?: string;
13
- title?: string;
14
- width?: string | number;
15
- height?: string | number;
16
- class?: HTMLAttributes["class"];
17
- }>();
18
-
19
- const { t } = useI18n();
20
- const config = useGinkoDocsConfig();
21
- const zoomEnabled = computed(() => config.images?.zoom !== false);
22
-
23
- // External images skip NuxtImg; the layer ships no ipx domain allowlist.
24
- const isLocalAsset = computed(() => Boolean(props.src?.startsWith("/")));
25
- const imageComponent = computed(() => (isLocalAsset.value ? resolveComponent("NuxtImg") : "img"));
26
- const imageAttrs = computed(() => ({
27
- src: props.src,
28
- alt: props.alt ?? "",
29
- title: props.title,
30
- width: props.width,
31
- height: props.height,
32
- loading: "lazy" as const,
33
- decoding: "async" as const,
34
- class: cn("content-prose-image", props.class),
35
- ...(isLocalAsset.value ? { sizes: "100vw md:704px" } : {}),
36
- }));
37
- </script>
38
-
39
- <template>
40
- <ImageZoomDialog v-if="src && zoomEnabled" :src="src" :alt="alt" :label="title">
41
- <template #trigger="{ layoutId, transition }">
42
- <!-- A button is phrasing content, so a bare markdown image stays valid inside its paragraph. -->
43
- <button
44
- type="button"
45
- class="block max-w-full cursor-zoom-in rounded-[var(--radius)] focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none"
46
- :aria-label="`${t('docs.zoomImage')}: ${alt ?? ''}`"
47
- >
48
- <Motion as-child :layout-id="layoutId" :transition="transition">
49
- <component :is="imageComponent" v-bind="imageAttrs" />
50
- </Motion>
51
- </button>
52
- </template>
53
- </ImageZoomDialog>
54
- <component :is="imageComponent" v-else-if="src" v-bind="imageAttrs" />
55
- </template>
@@ -1,14 +0,0 @@
1
- <script setup lang="ts">
2
- import type { HTMLAttributes } from "vue";
3
- import { cn } from "../../utils";
4
-
5
- const props = defineProps<{
6
- class?: HTMLAttributes["class"];
7
- }>();
8
- </script>
9
-
10
- <template>
11
- <li :class="cn(props.class)">
12
- <slot />
13
- </li>
14
- </template>
@@ -1,14 +0,0 @@
1
- <script setup lang="ts">
2
- import type { HTMLAttributes } from "vue";
3
- import { cn } from "../../utils";
4
-
5
- const props = defineProps<{
6
- class?: HTMLAttributes["class"];
7
- }>();
8
- </script>
9
-
10
- <template>
11
- <ol :class="cn(props.class)">
12
- <slot />
13
- </ol>
14
- </template>
@@ -1,14 +0,0 @@
1
- <script setup lang="ts">
2
- import type { HTMLAttributes } from "vue";
3
- import { cn } from "../../utils";
4
-
5
- const props = defineProps<{
6
- class?: HTMLAttributes["class"];
7
- }>();
8
- </script>
9
-
10
- <template>
11
- <p :class="cn(props.class)">
12
- <slot />
13
- </p>
14
- </template>
@@ -1,180 +0,0 @@
1
- <script setup lang="ts">
2
- import type { ComputedRef, HTMLAttributes } from "vue";
3
- import { computed, inject, onMounted, ref, useId } from "vue";
4
- import { useClipboard, useEventListener, useResizeObserver } from "@vueuse/core";
5
- import { useI18n } from "#imports";
6
- import { cn } from "../../utils";
7
- import { useProseAppearance } from "../../composables/useProseAppearance";
8
- import {
9
- EXTENSION_ICONS,
10
- FALLBACK_FILE_ICON,
11
- FILENAME_ICONS,
12
- LANGUAGE_ICONS,
13
- filenameExtension,
14
- normalizedFilename,
15
- } from "../../utils/file-icons";
16
-
17
- const props = defineProps<{
18
- code?: string;
19
- language?: string | null;
20
- filename?: string | null;
21
- highlights?: number[];
22
- meta?: string | null;
23
- icon?: string | null;
24
- inGroup?: boolean;
25
- class?: HTMLAttributes["class"];
26
- appearance?: "quiet" | "tint";
27
- }>();
28
- // Instance prop wins, then a surrounding ::collapse wrapper, then config.
29
- const wrapperAppearance = inject<ComputedRef<"quiet" | "tint"> | null>(
30
- "contentCodeAppearance",
31
- null,
32
- );
33
- const appearance = useProseAppearance("code", () => props.appearance ?? wrapperAppearance?.value);
34
-
35
- const { copy, copied } = useClipboard();
36
- const { t } = useI18n();
37
- const codeElement = ref<HTMLElement | null>(null);
38
- // Landmarks with role="region" need unique accessible names; the same
39
- // filename can appear in several code blocks on one page.
40
- const regionId = useId();
41
-
42
- const HIDDEN_LANGUAGES = new Set(["text", "plaintext", "txt", "plain"]);
43
-
44
- function parseIconFromMeta(meta: string | null | undefined): string | null {
45
- if (!meta) return null;
46
- const match = meta.match(/(?:^|\s)icon=(\S+)/);
47
- return match?.[1] ?? null;
48
- }
49
-
50
- function normalizedLanguage(language: string | null | undefined): string | null {
51
- return language?.trim().toLowerCase() || null;
52
- }
53
-
54
- const label = computed(() => {
55
- if (props.filename) return props.filename;
56
-
57
- const language = normalizedLanguage(props.language);
58
- if (language && !HIDDEN_LANGUAGES.has(language)) return props.language;
59
-
60
- return "";
61
- });
62
-
63
- const iconName = computed(() => {
64
- const explicitIcon = props.icon || parseIconFromMeta(props.meta);
65
- if (explicitIcon) return explicitIcon;
66
-
67
- const filename = normalizedFilename(props.filename);
68
- if (filename && FILENAME_ICONS[filename]) return FILENAME_ICONS[filename];
69
-
70
- const extension = filenameExtension(props.filename);
71
- if (extension && EXTENSION_ICONS[extension]) return EXTENSION_ICONS[extension];
72
-
73
- const language = normalizedLanguage(props.language);
74
- if (language && LANGUAGE_ICONS[language]) return LANGUAGE_ICONS[language];
75
-
76
- return FALLBACK_FILE_ICON;
77
- });
78
-
79
- async function copyCode() {
80
- await copy(props.code || codeElement.value?.innerText || "");
81
- }
82
-
83
- // A right-edge fade signals horizontally clipped code; it disappears once the
84
- // reader reaches the end of the line.
85
- const scrollElement = ref<HTMLElement | null>(null);
86
- const canScrollRight = ref(false);
87
-
88
- function measureOverflow() {
89
- const el = scrollElement.value;
90
- if (!el) return;
91
- canScrollRight.value =
92
- el.scrollWidth - el.clientWidth > 2 && el.scrollLeft + el.clientWidth < el.scrollWidth - 2;
93
- }
94
-
95
- onMounted(measureOverflow);
96
- useEventListener(scrollElement, "scroll", measureOverflow, { passive: true });
97
- useResizeObserver(scrollElement, measureOverflow);
98
- </script>
99
-
100
- <template>
101
- <figure
102
- dir="ltr"
103
- data-fd-codeblock
104
- :data-appearance="appearance"
105
- tabindex="-1"
106
- :class="
107
- cn(
108
- 'content-codeblock group shiki not-prose relative',
109
- props.inGroup
110
- ? 'content-codeblock-in-group'
111
- : label
112
- ? 'content-codeblock-with-caption'
113
- : 'content-codeblock-plain',
114
- )
115
- "
116
- >
117
- <figcaption v-if="label && !props.inGroup" data-fd-caption>
118
- <Icon :name="iconName" mode="svg" class="content-codeblock-caption-icon" aria-hidden="true" />
119
- <span class="flex-1 truncate">{{ label }}</span>
120
- <button
121
- type="button"
122
- class="content-codeblock-copy-button ml-auto"
123
- :aria-label="copied ? t('docs.copiedText') : t('docs.copyText')"
124
- @click="copyCode"
125
- >
126
- <Icon
127
- :name="copied ? 'lucide:check' : 'lucide:clipboard'"
128
- mode="svg"
129
- class="size-3.5"
130
- aria-hidden="true"
131
- />
132
- </button>
133
- </figcaption>
134
-
135
- <div v-if="!label && !props.inGroup" class="absolute top-2 right-2 z-10" data-fd-copy-float>
136
- <button
137
- type="button"
138
- class="content-codeblock-copy-button content-codeblock-copy-button-floating"
139
- :aria-label="copied ? t('docs.copiedText') : t('docs.copyText')"
140
- @click="copyCode"
141
- >
142
- <Icon
143
- :name="copied ? 'lucide:check' : 'lucide:clipboard'"
144
- mode="svg"
145
- class="size-3.5"
146
- aria-hidden="true"
147
- />
148
- </button>
149
- </div>
150
-
151
- <div class="content-codeblock-scroll-wrap">
152
- <div
153
- ref="scrollElement"
154
- role="region"
155
- tabindex="0"
156
- :aria-label="
157
- (label ? `${t('docs.codeSample')}: ${label}` : t('docs.codeSample')) + ` (${regionId})`
158
- "
159
- :class="
160
- cn(
161
- 'fd-scroll-container max-h-[600px] overflow-auto focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none focus-visible:ring-inset',
162
- !label && !props.inGroup && 'content-codeblock-inline-copy',
163
- )
164
- "
165
- >
166
- <pre
167
- ref="codeElement"
168
- :class="cn('w-max min-w-full', props.class)"
169
- v-bind="$attrs"
170
- ><slot /></pre>
171
- </div>
172
-
173
- <div
174
- class="content-codeblock-overflow-fade"
175
- :data-hidden="!canScrollRight"
176
- aria-hidden="true"
177
- />
178
- </div>
179
- </figure>
180
- </template>
@@ -1,14 +0,0 @@
1
- <script setup lang="ts">
2
- import type { HTMLAttributes } from "vue";
3
- import { cn } from "../../utils";
4
-
5
- const props = defineProps<{
6
- class?: HTMLAttributes["class"];
7
- }>();
8
- </script>
9
-
10
- <template>
11
- <strong :class="cn(props.class)">
12
- <slot />
13
- </strong>
14
- </template>
@@ -1,18 +0,0 @@
1
- <script setup lang="ts">
2
- import type { HTMLAttributes } from "vue";
3
- import { cn } from "../../utils";
4
-
5
- const props = defineProps<{
6
- class?: HTMLAttributes["class"];
7
- }>();
8
- </script>
9
-
10
- <template>
11
- <div :class="cn('content-table', props.class)">
12
- <div class="content-table-scroll">
13
- <table>
14
- <slot />
15
- </table>
16
- </div>
17
- </div>
18
- </template>
@@ -1,14 +0,0 @@
1
- <script setup lang="ts">
2
- import type { HTMLAttributes } from "vue";
3
- import { cn } from "../../utils";
4
-
5
- const props = defineProps<{
6
- class?: HTMLAttributes["class"];
7
- }>();
8
- </script>
9
-
10
- <template>
11
- <tbody :class="cn(props.class)">
12
- <slot />
13
- </tbody>
14
- </template>
@@ -1,14 +0,0 @@
1
- <script setup lang="ts">
2
- import type { HTMLAttributes } from "vue";
3
- import { cn } from "../../utils";
4
-
5
- const props = defineProps<{
6
- class?: HTMLAttributes["class"];
7
- }>();
8
- </script>
9
-
10
- <template>
11
- <td :class="cn(props.class)">
12
- <slot />
13
- </td>
14
- </template>
@@ -1,14 +0,0 @@
1
- <script setup lang="ts">
2
- import type { HTMLAttributes } from "vue";
3
- import { cn } from "../../utils";
4
-
5
- const props = defineProps<{
6
- class?: HTMLAttributes["class"];
7
- }>();
8
- </script>
9
-
10
- <template>
11
- <th :class="cn(props.class)">
12
- <slot />
13
- </th>
14
- </template>
@@ -1,14 +0,0 @@
1
- <script setup lang="ts">
2
- import type { HTMLAttributes } from "vue";
3
- import { cn } from "../../utils";
4
-
5
- const props = defineProps<{
6
- class?: HTMLAttributes["class"];
7
- }>();
8
- </script>
9
-
10
- <template>
11
- <thead :class="cn(props.class)">
12
- <slot />
13
- </thead>
14
- </template>
@@ -1,14 +0,0 @@
1
- <script setup lang="ts">
2
- import type { HTMLAttributes } from "vue";
3
- import { cn } from "../../utils";
4
-
5
- const props = defineProps<{
6
- class?: HTMLAttributes["class"];
7
- }>();
8
- </script>
9
-
10
- <template>
11
- <tr :class="cn(props.class)">
12
- <slot />
13
- </tr>
14
- </template>
@@ -1,14 +0,0 @@
1
- <script setup lang="ts">
2
- import type { HTMLAttributes } from "vue";
3
- import { cn } from "../../utils";
4
-
5
- const props = defineProps<{
6
- class?: HTMLAttributes["class"];
7
- }>();
8
- </script>
9
-
10
- <template>
11
- <ul :class="cn(props.class)">
12
- <slot />
13
- </ul>
14
- </template>
@@ -1,81 +0,0 @@
1
- <script setup lang="ts">
2
- import type { HTMLAttributes } from "vue";
3
- import { computed } from "vue";
4
- import { useColorMode, useI18n } from "#imports";
5
- import { cn } from "#ginko-docs/utils";
6
- import { headerUtilityButtonClass } from "#ginko-docs/components/site/header-utils";
7
- import {
8
- nextColorModePreference,
9
- themeToggleIcon,
10
- themeToggleLabelKey,
11
- } from "#ginko-docs/components/site/mode-toggle.utils";
12
-
13
- const props = withDefaults(
14
- defineProps<{
15
- variant?: "icon" | "menu-row";
16
- class?: HTMLAttributes["class"];
17
- }>(),
18
- {
19
- variant: "icon",
20
- },
21
- );
22
-
23
- const colorMode = useColorMode();
24
- const { t } = useI18n();
25
-
26
- const isDark = computed(() => colorMode.value === "dark");
27
- const toggleIcon = computed(() => themeToggleIcon(isDark.value));
28
- const toggleLabel = computed(() => t(themeToggleLabelKey(isDark.value)));
29
-
30
- function toggleColorMode() {
31
- const currentRendered = isDark.value ? "dark" : "light";
32
- colorMode.preference = nextColorModePreference(currentRendered);
33
- }
34
- </script>
35
-
36
- <template>
37
- <button
38
- v-if="variant === 'menu-row'"
39
- type="button"
40
- role="switch"
41
- :aria-checked="isDark"
42
- :aria-label="toggleLabel"
43
- :class="
44
- cn(
45
- 'flex h-14 w-full items-center justify-between rounded-none px-5 text-base font-semibold hover:bg-transparent',
46
- props.class,
47
- )
48
- "
49
- @click="toggleColorMode"
50
- >
51
- <span class="flex min-w-0 items-center gap-4">
52
- <span
53
- class="flex size-11 shrink-0 items-center justify-center rounded-lg bg-muted/60 text-foreground"
54
- >
55
- <Icon :name="toggleIcon" class="size-5" aria-hidden="true" />
56
- </span>
57
- <span class="truncate">{{ t("theme.label") }}</span>
58
- </span>
59
- <span
60
- class="relative inline-flex h-6 w-11 shrink-0 rounded-full border border-border bg-muted/60 transition-colors"
61
- :class="isDark ? 'bg-foreground/80' : ''"
62
- aria-hidden="true"
63
- >
64
- <span
65
- class="absolute top-0.5 size-5 rounded-full bg-background shadow-xs transition-transform motion-reduce:transition-none"
66
- :class="isDark ? 'translate-x-[1.375rem]' : 'translate-x-0.5'"
67
- />
68
- </span>
69
- </button>
70
- <button
71
- v-else
72
- type="button"
73
- role="switch"
74
- :aria-checked="isDark"
75
- :aria-label="toggleLabel"
76
- :class="cn(headerUtilityButtonClass, props.class)"
77
- @click="toggleColorMode"
78
- >
79
- <Icon :name="toggleIcon" class="size-[18px]" aria-hidden="true" />
80
- </button>
81
- </template>
@@ -1,97 +0,0 @@
1
- <script setup lang="ts">
2
- import { useLocalStorage } from "@vueuse/core";
3
- import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from "vue";
4
- import { useI18n } from "#imports";
5
- import { useGinkoDocsConfig } from "#ginko-docs/composables/useGinkoDocsConfig";
6
- import { useSiteNavigation } from "#ginko-docs/composables/useSiteNavigation";
7
-
8
- const props = defineProps<{
9
- landing?: boolean;
10
- }>();
11
-
12
- const { banner } = useSiteNavigation();
13
- const { t } = useI18n();
14
- const config = useGinkoDocsConfig();
15
-
16
- const dismissed = useLocalStorage(banner.value.storageKey, false);
17
- // Avoid a hydration mismatch: localStorage is client-only, so reveal after mount.
18
- const hydrated = ref(false);
19
- onMounted(() => {
20
- hydrated.value = true;
21
- });
22
- const visible = computed(
23
- () =>
24
- banner.value.show &&
25
- (!props.landing || config.banner.showOnLanding) &&
26
- (!hydrated.value ? true : !dismissed.value),
27
- );
28
-
29
- // The banner scrolls away above the sticky header, so sticky consumers
30
- // (docs sidebar/TOC heights, mobile menu top) need its *currently visible*
31
- // height. This component is the single writer of --site-banner-height.
32
- const bannerElement = ref<HTMLElement | null>(null);
33
- let rafId: number | null = null;
34
- let lastHeight = -1;
35
-
36
- function updateBannerHeightVar() {
37
- rafId = null;
38
- const element = bannerElement.value;
39
- const height = element
40
- ? Math.max(0, Math.min(element.getBoundingClientRect().bottom, element.offsetHeight))
41
- : 0;
42
- if (height === lastHeight) return;
43
- lastHeight = height;
44
- document.documentElement.style.setProperty("--site-banner-height", `${height}px`);
45
- }
46
-
47
- function scheduleBannerHeightVar() {
48
- if (rafId !== null) return;
49
- rafId = requestAnimationFrame(updateBannerHeightVar);
50
- }
51
-
52
- watch(visible, () => {
53
- void nextTick(scheduleBannerHeightVar);
54
- });
55
-
56
- onMounted(() => {
57
- window.addEventListener("scroll", scheduleBannerHeightVar, { passive: true });
58
- window.addEventListener("resize", scheduleBannerHeightVar, { passive: true });
59
- scheduleBannerHeightVar();
60
- });
61
-
62
- onBeforeUnmount(() => {
63
- window.removeEventListener("scroll", scheduleBannerHeightVar);
64
- window.removeEventListener("resize", scheduleBannerHeightVar);
65
- if (rafId !== null) cancelAnimationFrame(rafId);
66
- document.documentElement.style.setProperty("--site-banner-height", "0px");
67
- });
68
- </script>
69
-
70
- <template>
71
- <div
72
- v-if="visible"
73
- ref="bannerElement"
74
- role="region"
75
- :aria-label="banner.text"
76
- class="relative z-30 bg-brand px-10 py-2.5 text-center text-sm leading-5 font-medium text-brand-foreground"
77
- >
78
- <span class="mx-auto block max-w-[min(100%,52rem)]">
79
- {{ banner.text }}
80
- <NuxtLink
81
- v-if="banner.linkHref"
82
- :to="banner.linkHref"
83
- class="ml-1.5 inline-block underline underline-offset-2 opacity-90 transition-opacity hover:opacity-100"
84
- >
85
- {{ banner.linkLabel }}
86
- </NuxtLink>
87
- </span>
88
- <button
89
- type="button"
90
- class="absolute top-1/2 right-2 flex size-8 -translate-y-1/2 items-center justify-center rounded p-1 opacity-70 transition-opacity hover:opacity-100 focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-brand-foreground/50 focus-visible:outline-none"
91
- :aria-label="t('banner.dismiss')"
92
- @click="dismissed = true"
93
- >
94
- <Icon name="lucide:x" class="size-3.5" aria-hidden="true" />
95
- </button>
96
- </div>
97
- </template>