@lupinum/ginko-docs 0.4.0-rc.9 → 0.5.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 (304) hide show
  1. package/CHANGELOG.md +141 -0
  2. package/LICENSE +1 -1
  3. package/README.md +300 -53
  4. package/app/app.config.ts +44 -55
  5. package/app/assets/docs.css +619 -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 +113 -0
  10. package/app/components/DocsIcon.vue +12 -0
  11. package/app/components/DocsLanding.vue +58 -0
  12. package/app/components/DocsLanguage.vue +40 -0
  13. package/app/components/DocsNavSheet.vue +37 -0
  14. package/app/components/DocsNavTree.vue +38 -0
  15. package/app/components/DocsPage.vue +88 -0
  16. package/app/components/DocsPageActions.vue +47 -0
  17. package/app/components/DocsPageEnd.ts +12 -0
  18. package/app/components/DocsPost.vue +58 -0
  19. package/app/components/DocsSearch.vue +136 -0
  20. package/app/components/DocsShell.vue +36 -0
  21. package/app/components/DocsSidebar.vue +19 -0
  22. package/app/components/DocsSidebarEnd.ts +4 -0
  23. package/app/components/DocsTable.vue +11 -0
  24. package/app/components/DocsThemeToggle.vue +45 -0
  25. package/app/components/DocsToc.vue +73 -0
  26. package/app/composables/useDocs.ts +53 -0
  27. package/app/composables/useDocsBlog.ts +33 -0
  28. package/app/composables/useDocsCopy.ts +17 -0
  29. package/app/composables/useDocsFrame.ts +11 -0
  30. package/app/composables/useDocsPopover.ts +36 -0
  31. package/app/composables/useDocsSite.ts +31 -0
  32. package/app/docs-pages/blog.vue +55 -0
  33. package/app/docs-pages/changelog.vue +35 -0
  34. package/app/docs-pages/doc.vue +16 -0
  35. package/app/docs-pages/docs.vue +9 -0
  36. package/app/docs-pages/index.vue +12 -0
  37. package/app/docs-pages/post.vue +8 -0
  38. package/app/error.vue +38 -115
  39. package/app/layouts/default.vue +29 -7
  40. package/app/lib/blogTypes.ts +8 -0
  41. package/app/lib/docsFirst.ts +11 -0
  42. package/app/lib/docsInit.ts +18 -0
  43. package/app/lib/docsNav.ts +36 -0
  44. package/app/lib/docsPage.ts +84 -0
  45. package/app/lib/markdownComponents.ts +15 -0
  46. package/app/lib/previewToc.ts +18 -0
  47. package/dist/config.d.mts +252 -0
  48. package/dist/config.d.ts +252 -0
  49. package/dist/config.mjs +83 -0
  50. package/dist/icons.d.mts +38 -0
  51. package/dist/icons.d.ts +38 -0
  52. package/dist/icons.mjs +175 -0
  53. package/dist/pages.d.mts +5 -0
  54. package/dist/pages.d.ts +5 -0
  55. package/dist/pages.mjs +68 -0
  56. package/i18n/de.json +1 -0
  57. package/i18n/en.json +1 -0
  58. package/i18n/fr.json +1 -0
  59. package/icons/README.md +2 -0
  60. package/icons/bluesky.svg +1 -0
  61. package/icons/claude.svg +1 -0
  62. package/icons/discord.svg +1 -0
  63. package/icons/github.svg +1 -0
  64. package/icons/linkedin.svg +1 -0
  65. package/icons/mastodon.svg +1 -0
  66. package/icons/openai.svg +1 -0
  67. package/icons/x.svg +1 -0
  68. package/icons/youtube.svg +1 -0
  69. package/nuxt.config.ts +22 -212
  70. package/package.json +44 -76
  71. package/public/_docs/fonts/LICENSE +188 -0
  72. package/public/_docs/fonts/inter-latin-wght-normal.woff2 +0 -0
  73. package/public/_docs/fonts/jetbrains-mono-latin-400-normal.woff2 +0 -0
  74. package/public/_docs/fonts/jetbrains-mono-latin-500-normal.woff2 +0 -0
  75. package/server/feeds/blog-locale.get.ts +9 -0
  76. package/server/feeds/blog.get.ts +4 -0
  77. package/server/lib/blogFeed.ts +35 -0
  78. package/server/mcp/handler.ts +108 -0
  79. package/server/routes/__ginko/docs-mcp.ts +35 -0
  80. package/shared/layerRoutes.ts +66 -0
  81. package/shared/paths.ts +4 -0
  82. package/app/app.vue +0 -98
  83. package/app/assets/css/prose.css +0 -3240
  84. package/app/assets/css/tailwind.css +0 -394
  85. package/app/assets/css/theme-palettes.css +0 -309
  86. package/app/assets/css/theme-presets.css +0 -141
  87. package/app/components/OgImage/GinkoDocs.satori.vue +0 -238
  88. package/app/components/content/DocumentPageShell.vue +0 -55
  89. package/app/components/content/Feedback.vue +0 -102
  90. package/app/components/content/ImageZoomDialog.vue +0 -84
  91. package/app/components/content/PageMarkdownCopy.vue +0 -104
  92. package/app/components/content/imageZoom.ts +0 -25
  93. package/app/components/mdc/MdcAccordion.vue +0 -67
  94. package/app/components/mdc/MdcAccordionItem.vue +0 -42
  95. package/app/components/mdc/MdcApi.vue +0 -159
  96. package/app/components/mdc/MdcAside.vue +0 -23
  97. package/app/components/mdc/MdcCallout.vue +0 -61
  98. package/app/components/mdc/MdcCard.vue +0 -175
  99. package/app/components/mdc/MdcCards.vue +0 -30
  100. package/app/components/mdc/MdcCenter.vue +0 -71
  101. package/app/components/mdc/MdcCodeGroup.vue +0 -197
  102. package/app/components/mdc/MdcCodeTree.vue +0 -234
  103. package/app/components/mdc/MdcCollapse.vue +0 -61
  104. package/app/components/mdc/MdcColumn.vue +0 -70
  105. package/app/components/mdc/MdcDropcap.vue +0 -84
  106. package/app/components/mdc/MdcError.vue +0 -23
  107. package/app/components/mdc/MdcExcerpt.vue +0 -26
  108. package/app/components/mdc/MdcFigure.vue +0 -85
  109. package/app/components/mdc/MdcFiles.vue +0 -120
  110. package/app/components/mdc/MdcIdea.vue +0 -17
  111. package/app/components/mdc/MdcInfo.vue +0 -17
  112. package/app/components/mdc/MdcInlineToc.vue +0 -51
  113. package/app/components/mdc/MdcKbd.vue +0 -10
  114. package/app/components/mdc/MdcLayout.vue +0 -57
  115. package/app/components/mdc/MdcNote.vue +0 -17
  116. package/app/components/mdc/MdcQuiz.vue +0 -241
  117. package/app/components/mdc/MdcQuizQuestion.vue +0 -221
  118. package/app/components/mdc/MdcReadMore.vue +0 -70
  119. package/app/components/mdc/MdcSteps.vue +0 -59
  120. package/app/components/mdc/MdcSuccess.vue +0 -23
  121. package/app/components/mdc/MdcTab.vue +0 -17
  122. package/app/components/mdc/MdcTabs.vue +0 -150
  123. package/app/components/mdc/MdcTimeline.vue +0 -17
  124. package/app/components/mdc/MdcTimelineItem.vue +0 -40
  125. package/app/components/mdc/MdcWarning.vue +0 -23
  126. package/app/components/mdc/api.utils.ts +0 -132
  127. package/app/components/mdc/code-tree.utils.ts +0 -22
  128. package/app/components/mdc/icons.ts +0 -10
  129. package/app/components/mdc/quiz.utils.ts +0 -38
  130. package/app/components/prose/ProseA.vue +0 -27
  131. package/app/components/prose/ProseBlockquote.vue +0 -30
  132. package/app/components/prose/ProseCode.vue +0 -14
  133. package/app/components/prose/ProseEm.vue +0 -14
  134. package/app/components/prose/ProseH1.vue +0 -18
  135. package/app/components/prose/ProseH2.vue +0 -29
  136. package/app/components/prose/ProseH3.vue +0 -29
  137. package/app/components/prose/ProseH4.vue +0 -29
  138. package/app/components/prose/ProseH5.vue +0 -15
  139. package/app/components/prose/ProseH6.vue +0 -15
  140. package/app/components/prose/ProseHr.vue +0 -12
  141. package/app/components/prose/ProseImg.vue +0 -55
  142. package/app/components/prose/ProseLi.vue +0 -14
  143. package/app/components/prose/ProseOl.vue +0 -14
  144. package/app/components/prose/ProseP.vue +0 -14
  145. package/app/components/prose/ProsePre.vue +0 -180
  146. package/app/components/prose/ProseStrong.vue +0 -14
  147. package/app/components/prose/ProseTable.vue +0 -18
  148. package/app/components/prose/ProseTbody.vue +0 -14
  149. package/app/components/prose/ProseTd.vue +0 -14
  150. package/app/components/prose/ProseTh.vue +0 -14
  151. package/app/components/prose/ProseThead.vue +0 -14
  152. package/app/components/prose/ProseTr.vue +0 -14
  153. package/app/components/prose/ProseUl.vue +0 -14
  154. package/app/components/site/ModeToggle.vue +0 -81
  155. package/app/components/site/SiteBanner.vue +0 -97
  156. package/app/components/site/SiteFooter.vue +0 -90
  157. package/app/components/site/SiteHeader.vue +0 -371
  158. package/app/components/site/SiteHeroCode.vue +0 -173
  159. package/app/components/site/SiteInteractionLayer.vue +0 -42
  160. package/app/components/site/SiteLocaleSwitcher.vue +0 -190
  161. package/app/components/site/SiteLogoMark.vue +0 -12
  162. package/app/components/site/SiteSkipLink.vue +0 -14
  163. package/app/components/site/SiteSocialLinks.vue +0 -33
  164. package/app/components/site/header-utils.ts +0 -3
  165. package/app/components/site/mode-toggle.utils.ts +0 -18
  166. package/app/components/ui/badge/Badge.vue +0 -28
  167. package/app/components/ui/badge/index.ts +0 -24
  168. package/app/components/ui/button/Button.vue +0 -31
  169. package/app/components/ui/button/index.ts +0 -35
  170. package/app/components/ui/collapsible/Collapsible.vue +0 -15
  171. package/app/components/ui/collapsible/CollapsibleContent.vue +0 -25
  172. package/app/components/ui/collapsible/CollapsibleTrigger.vue +0 -12
  173. package/app/components/ui/collapsible/index.ts +0 -3
  174. package/app/components/ui/dropdown-menu/DropdownMenu.vue +0 -15
  175. package/app/components/ui/dropdown-menu/DropdownMenuContent.vue +0 -50
  176. package/app/components/ui/dropdown-menu/DropdownMenuItem.vue +0 -41
  177. package/app/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +0 -15
  178. package/app/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +0 -37
  179. package/app/components/ui/dropdown-menu/DropdownMenuSeparator.vue +0 -23
  180. package/app/components/ui/dropdown-menu/DropdownMenuTrigger.vue +0 -14
  181. package/app/components/ui/dropdown-menu/index.ts +0 -7
  182. package/app/components/ui/kbd/Kbd.vue +0 -23
  183. package/app/components/ui/kbd/index.ts +0 -21
  184. package/app/components/ui/scroll-area/ScrollArea.vue +0 -39
  185. package/app/components/ui/scroll-area/ScrollBar.vue +0 -33
  186. package/app/components/ui/scroll-area/index.ts +0 -2
  187. package/app/components/ui/separator/Separator.vue +0 -27
  188. package/app/components/ui/separator/index.ts +0 -1
  189. package/app/components/ui/sheet/Sheet.vue +0 -15
  190. package/app/components/ui/sheet/SheetContent.vue +0 -59
  191. package/app/components/ui/sheet/SheetDescription.vue +0 -21
  192. package/app/components/ui/sheet/SheetOverlay.vue +0 -26
  193. package/app/components/ui/sheet/SheetTitle.vue +0 -21
  194. package/app/components/ui/sheet/SheetTrigger.vue +0 -12
  195. package/app/components/ui/sheet/index.ts +0 -5
  196. package/app/components/ui/tabs/Tabs.vue +0 -24
  197. package/app/components/ui/tabs/TabsList.vue +0 -26
  198. package/app/components/ui/tabs/TabsTrigger.vue +0 -28
  199. package/app/components/ui/tabs/index.ts +0 -3
  200. package/app/composables/site-navigation.utils.ts +0 -133
  201. package/app/composables/useCanonicalUrl.ts +0 -9
  202. package/app/composables/useContentRouteAlternates.ts +0 -35
  203. package/app/composables/useGinkoAnalytics.ts +0 -52
  204. package/app/composables/useGinkoDocsConfig.ts +0 -6
  205. package/app/composables/useGinkoOgImage.ts +0 -20
  206. package/app/composables/useLocalizedPath.ts +0 -12
  207. package/app/composables/useLocalizedRouteSwitch.ts +0 -31
  208. package/app/composables/useMetaKey.ts +0 -18
  209. package/app/composables/usePageMarkdownActions.ts +0 -79
  210. package/app/composables/useProseAppearance.ts +0 -24
  211. package/app/composables/useSchemaJsonLd.ts +0 -25
  212. package/app/composables/useSiteNavigation.ts +0 -64
  213. package/app/config/site.utils.ts +0 -36
  214. package/app/features/docs/components/DocsBreadcrumb.vue +0 -37
  215. package/app/features/docs/components/DocsContributeLinks.vue +0 -75
  216. package/app/features/docs/components/DocsMobileToc.vue +0 -108
  217. package/app/features/docs/components/DocsPageContent.vue +0 -234
  218. package/app/features/docs/components/DocsPageNav.vue +0 -57
  219. package/app/features/docs/components/DocsSidebar.vue +0 -145
  220. package/app/features/docs/components/DocsSidebarDropdown.vue +0 -70
  221. package/app/features/docs/components/DocsSidebarItem.vue +0 -122
  222. package/app/features/docs/components/DocsSidebarList.vue +0 -35
  223. package/app/features/docs/components/DocsSidebarRow.vue +0 -27
  224. package/app/features/docs/components/DocsSidebarTabs.vue +0 -59
  225. package/app/features/docs/components/DocsToc.vue +0 -106
  226. package/app/features/docs/composables/useDocsNavigation.ts +0 -29
  227. package/app/features/docs/composables/useDocsNavigationData.ts +0 -18
  228. package/app/features/docs/composables/useRevealActive.ts +0 -58
  229. package/app/features/docs/composables/useScrollspy.ts +0 -135
  230. package/app/features/docs/docs-navigation.ts +0 -157
  231. package/app/features/docs/toc-context.ts +0 -6
  232. package/app/features/search/command-center.ts +0 -110
  233. package/app/features/search/components/SiteCommandCenter.vue +0 -359
  234. package/app/features/search/components/SiteSearchPageHighlight.vue +0 -126
  235. package/app/features/search/useCommandCenter.ts +0 -292
  236. package/app/layouts/blog.vue +0 -15
  237. package/app/layouts/docs.vue +0 -20
  238. package/app/lib/errors.ts +0 -37
  239. package/app/lib/schema-org.ts +0 -38
  240. package/app/pages/blog/[slug].vue +0 -228
  241. package/app/pages/blog/index.vue +0 -130
  242. package/app/pages/docs/[...slug].vue +0 -10
  243. package/app/pages/docs/index.vue +0 -19
  244. package/app/pages/index.vue +0 -278
  245. package/app/plugins/ginko-docs-theme.ts +0 -14
  246. package/app/plugins/ssr-width.ts +0 -6
  247. package/app/utils/content.ts +0 -67
  248. package/app/utils/file-icons.ts +0 -90
  249. package/app/utils/index.ts +0 -7
  250. package/app/utils/repository.ts +0 -20
  251. package/components.ts +0 -9
  252. package/content-collections.ts +0 -89
  253. package/content.js +0 -200
  254. package/content.ts +0 -104
  255. package/i18n/i18n.config.ts +0 -10
  256. package/i18n/locales.ts +0 -81
  257. package/i18n/messages/global/banner.ts +0 -8
  258. package/i18n/messages/global/blog.ts +0 -18
  259. package/i18n/messages/global/command.ts +0 -49
  260. package/i18n/messages/global/docs.ts +0 -36
  261. package/i18n/messages/global/errors.ts +0 -36
  262. package/i18n/messages/global/feedback.ts +0 -11
  263. package/i18n/messages/global/index.ts +0 -21
  264. package/i18n/messages/global/nav.ts +0 -26
  265. package/i18n/messages/global/site.ts +0 -4
  266. package/i18n/messages/global/theme.ts +0 -9
  267. package/i18n/messages/index.ts +0 -20
  268. package/i18n/messages/localize.ts +0 -35
  269. package/i18n/routes.ts +0 -33
  270. package/icon-bundle.ts +0 -116
  271. package/index.d.ts +0 -37
  272. package/modules/analytics-boundary.ts +0 -23
  273. package/modules/feature-routing.ts +0 -68
  274. package/modules/syntax-highlighting.ts +0 -120
  275. package/public/fonts/public-sans/LICENSE +0 -93
  276. package/public/fonts/public-sans/README.md +0 -12
  277. package/public/fonts/public-sans/public-sans-400-normal-latin.woff +0 -0
  278. package/public/fonts/public-sans/public-sans-500-normal-latin.woff +0 -0
  279. package/public/fonts/public-sans/public-sans-600-normal-latin.woff +0 -0
  280. package/public/fonts/public-sans/public-sans-700-normal-latin.woff +0 -0
  281. package/runtime/generate-favicons.mjs +0 -124
  282. package/runtime/server/agent-markdown.ts +0 -19
  283. package/server/api/_ginko-docs/redirects.get.ts +0 -28
  284. package/server/mcp/tools/get-page.ts +0 -14
  285. package/server/mcp/tools/list-pages.ts +0 -10
  286. package/server/middleware/redirects.ts +0 -22
  287. package/server/plugins/agent-markdown.ts +0 -6
  288. package/server/plugins/sitemap-policy.ts +0 -12
  289. package/server/routes/.well-known/ai-catalog.json.get.ts +0 -10
  290. package/server/routes/[locale]/blog/rss.xml.get.ts +0 -13
  291. package/server/routes/blog/rss.xml.get.ts +0 -5
  292. package/server/routes/mcp/server-card.get.ts +0 -14
  293. package/server/utils/blog-feed.ts +0 -51
  294. package/server/utils/feed.ts +0 -70
  295. package/server/utils/mcp-server-card.ts +0 -45
  296. package/server/utils/redirects.ts +0 -38
  297. package/server/utils/redirects.utils.ts +0 -58
  298. package/server/utils/sitemap.ts +0 -45
  299. package/shared/route-slugs.ts +0 -5
  300. package/shared/theme-palettes.ts +0 -37
  301. package/shared/theme-presets.ts +0 -3
  302. package/shared/types/app-config.ts +0 -172
  303. package/shared/types/nuxt-config.ts +0 -14
  304. package/tags.ts +0 -192
package/dist/icons.mjs ADDED
@@ -0,0 +1,175 @@
1
+ import { existsSync, readdirSync, statSync, readFileSync } from 'node:fs';
2
+ import { createRequire } from 'node:module';
3
+ import { join, relative, resolve, extname } from 'node:path';
4
+ import { defineNuxtModule, createResolver, useLogger, addComponent, addTemplate, addTypeTemplate, updateTemplates } from '@nuxt/kit';
5
+ import { getIconData, iconToSVG } from '@iconify/utils';
6
+
7
+ const SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", ".git", ".nuxt", ".output", "dist"]);
8
+ const walk = (dir, extensions, out = []) => {
9
+ if (!existsSync(dir)) return out;
10
+ for (const name of readdirSync(dir)) {
11
+ if (SKIP_DIRS.has(name) || name.startsWith(".")) continue;
12
+ const path = join(dir, name);
13
+ if (statSync(path).isDirectory()) walk(path, extensions, out);
14
+ else if (extensions.includes(extname(name))) out.push(path);
15
+ }
16
+ return out;
17
+ };
18
+ const OWN_NAME = /['"`]((?:lucide|docs):[a-z0-9]+(?:-[a-z0-9]+)*)['"`]/g;
19
+ const NAME = "[a-z0-9]+(?:-[a-z0-9]+)*(?::[a-z0-9]+(?:-[a-z0-9]+)*)?";
20
+ const QUOTED_NAME = new RegExp(`\\bicon\\??\\s*:\\s*['"](${NAME})['"]`, "g");
21
+ const YAML_NAME = new RegExp(`\\bicon["']?\\s*:\\s*["']?(${NAME})["']?(?=\\s|$|,|\\}|\\))`, "gm");
22
+ const ATTR_NAME = new RegExp(`(?<![\\w-])(?::icon=["']['"]|(?<!:)icon=["'])(${NAME})["']`, "g");
23
+ const ICON_TAG = new RegExp(`<Icon\\b[^>]*?\\s(?::name=["']['"]|name=["'])(${NAME})["']`, "g");
24
+ const matches = (re, source) => [...source.matchAll(re)].map((m) => m[1].includes(":") ? m[1] : `lucide:${m[1]}`);
25
+ const without = (source, open, close) => {
26
+ let out = "";
27
+ let at = 0;
28
+ for (; ; ) {
29
+ const start = source.indexOf(open, at);
30
+ const end = start === -1 ? -1 : source.indexOf(close, start + open.length);
31
+ if (end === -1) return out + source.slice(at);
32
+ out += source.slice(at, start);
33
+ at = end + close.length;
34
+ }
35
+ };
36
+ const mapScripts = (source, fn) => {
37
+ let out = "";
38
+ let at = 0;
39
+ for (; ; ) {
40
+ const tag = source.indexOf("<script", at);
41
+ const open = tag === -1 ? -1 : source.indexOf(">", tag);
42
+ const close = open === -1 ? -1 : source.indexOf("<\/script>", open);
43
+ if (close === -1) return out + source.slice(at);
44
+ out += source.slice(at, open + 1) + fn(source.slice(open + 1, close));
45
+ at = close;
46
+ }
47
+ };
48
+ const cutLine = (line) => {
49
+ for (let i = line.indexOf("//"); i !== -1; i = line.indexOf("//", i + 2)) if (i === 0 || /\s/.test(line[i - 1])) return line.slice(0, i);
50
+ return line;
51
+ };
52
+ const stripCode = (code) => without(code, "/*", "*/").split("\n").map(cutLine).join("\n");
53
+ const stripComments = (source, file = "") => file.endsWith(".vue") ? mapScripts(without(source, "<!--", "-->"), stripCode) : stripCode(source);
54
+ const codeIconNames = (source, file) => {
55
+ const code = stripComments(source, file);
56
+ return file.endsWith(".vue") ? [...matches(ICON_TAG, code), ...matches(ATTR_NAME, code)] : matches(QUOTED_NAME, code);
57
+ };
58
+ const contentIconNames = (source, file) => {
59
+ if (!file.endsWith(".md")) return matches(YAML_NAME, source);
60
+ const front = /^---\r?\n([\s\S]*?)\r?\n---/.exec(source);
61
+ const body = (front ? source.slice(front[0].length) : source).replace(/^(```|~~~)[^\n]*\n[\s\S]*?^\1[^\n]*$/gm, "").replace(/`[^`\n]*`/g, "");
62
+ const names = front ? matches(YAML_NAME, front[1]) : [];
63
+ for (const m of body.matchAll(/:{1,}[a-z][\w-]*(?:\[[^\]\n]*\])?\{([^}\n]*)\}/g)) names.push(...matches(ATTR_NAME, m[1]));
64
+ for (const m of body.matchAll(/^:{2,}[\w-]+[^\n]*\n---\r?\n([\s\S]*?)\r?\n---/gm)) names.push(...matches(YAML_NAME, m[1]));
65
+ return names;
66
+ };
67
+ const readIcon = (name, roots, customDir, sets = /* @__PURE__ */ new Map()) => {
68
+ const [prefix = "", icon = ""] = name.split(":");
69
+ if (prefix === "docs") {
70
+ const file = join(customDir, `${icon}.svg`);
71
+ if (!existsSync(file)) return;
72
+ const svg2 = readFileSync(file, "utf8");
73
+ const body = /<svg[^>]*>([\s\S]*)<\/svg>/.exec(svg2)?.[1]?.trim();
74
+ const viewBox = /viewBox="([^"]+)"/.exec(svg2)?.[1];
75
+ return body && viewBox ? [body, viewBox] : void 0;
76
+ }
77
+ if (!sets.has(prefix)) {
78
+ for (const from of roots) {
79
+ try {
80
+ sets.set(prefix, JSON.parse(readFileSync(createRequire(join(from, "noop.js")).resolve(`@iconify-json/${prefix}/icons.json`), "utf8")));
81
+ break;
82
+ } catch {
83
+ }
84
+ }
85
+ if (!sets.has(prefix)) sets.set(prefix, void 0);
86
+ }
87
+ const set = sets.get(prefix);
88
+ const data = set && getIconData(set, icon);
89
+ if (!data) return;
90
+ const svg = iconToSVG(data);
91
+ return [svg.body, svg.attributes.viewBox];
92
+ };
93
+ const collectIcons = (o) => {
94
+ const found = /* @__PURE__ */ new Map();
95
+ const add = (name, file) => found.set(name, (found.get(name) ?? /* @__PURE__ */ new Set()).add(file));
96
+ const read = (file) => readFileSync(file, "utf8");
97
+ for (const file of walk(join(o.layerRoot, "app"), [".vue", ".ts"])) {
98
+ for (const m of stripComments(read(file), file).matchAll(OWN_NAME)) add(m[1], relative(o.layerRoot, file));
99
+ }
100
+ for (const root of o.roots) {
101
+ const files = [
102
+ ...walk(join(root, "content"), [".md", ".yml", ".yaml", ".json"]),
103
+ ...["app/app.config.ts", "app.config.ts"].map((f) => join(root, f)).filter(existsSync)
104
+ ];
105
+ for (const file of files) {
106
+ const names = file.endsWith(".ts") ? codeIconNames(read(file), file) : contentIconNames(read(file), file);
107
+ for (const name of names) add(name, relative(o.relativeTo, file));
108
+ }
109
+ if (resolve(root) !== resolve(o.layerRoot)) {
110
+ for (const file of walk(join(root, "app"), [".vue"])) {
111
+ for (const name of codeIconNames(read(file), file)) add(name, relative(o.relativeTo, file));
112
+ }
113
+ }
114
+ }
115
+ const sets = /* @__PURE__ */ new Map();
116
+ const customDir = join(o.layerRoot, "icons");
117
+ const icons = {};
118
+ const warnings = [];
119
+ for (const name of [...found.keys()].sort()) {
120
+ const entry = readIcon(name, o.resolveFrom, customDir, sets);
121
+ if (entry) icons[name] = entry;
122
+ else warnings.push(`Icon "${name}" (${[...found.get(name)][0]}) is not in an installed Iconify set; it renders nothing.`);
123
+ }
124
+ return { icons, warnings };
125
+ };
126
+ const docsIcons = defineNuxtModule({
127
+ meta: { name: "@lupinum/ginko-docs/icons" },
128
+ setup(_, nuxt) {
129
+ const { resolve: here } = createResolver(import.meta.url);
130
+ const logger = useLogger("@lupinum/ginko-docs");
131
+ const layerRoot = here("..");
132
+ addComponent({ name: "Icon", filePath: here("../app/components/DocsIcon.vue"), global: true, priority: -1 });
133
+ const warned = /* @__PURE__ */ new Set();
134
+ const collect = () => {
135
+ const { icons, warnings } = collectIcons({
136
+ layerRoot,
137
+ roots: nuxt.options._layers.map((layer) => layer.config.rootDir ?? layer.cwd),
138
+ resolveFrom: [nuxt.options.rootDir, layerRoot],
139
+ relativeTo: nuxt.options.rootDir
140
+ });
141
+ for (const warning of warnings) if (!warned.has(warning)) {
142
+ warned.add(warning);
143
+ logger.warn(warning);
144
+ }
145
+ return icons;
146
+ };
147
+ const template = addTemplate({
148
+ filename: "docs-icons.mjs",
149
+ write: true,
150
+ getContents: () => `export default ${JSON.stringify(collect())}
151
+ `
152
+ });
153
+ nuxt.options.alias["#docs-icons"] = template.dst;
154
+ addTypeTemplate({
155
+ filename: "types/docs-icons.d.ts",
156
+ getContents: () => `declare module '#docs-icons' {
157
+ const icons: Record<string, [body: string, viewBox: string]>
158
+ export default icons
159
+ }
160
+ `
161
+ });
162
+ nuxt.hook("build:manifest", (manifest) => {
163
+ for (const [key, item] of Object.entries(manifest)) {
164
+ if ([key, item.file, item.name, item.src].some((s) => s && /DocsIcon|docs-icons/.test(s))) item.prefetch = false;
165
+ }
166
+ });
167
+ if (nuxt.options.dev) {
168
+ nuxt.hook("builder:watch", async (_event, path) => {
169
+ if (/\.(md|ya?ml|json|vue)$|app\.config\.ts$/.test(path)) await updateTemplates({ filter: (t) => t.filename === "docs-icons.mjs" });
170
+ });
171
+ }
172
+ }
173
+ });
174
+
175
+ export { codeIconNames, collectIcons, contentIconNames, docsIcons as default, readIcon, stripComments };
@@ -0,0 +1,5 @@
1
+ import { NuxtModule } from 'nuxt/schema';
2
+
3
+ declare const docsPages: NuxtModule;
4
+
5
+ export { docsPages as default };
@@ -0,0 +1,5 @@
1
+ import { NuxtModule } from 'nuxt/schema';
2
+
3
+ declare const docsPages: NuxtModule;
4
+
5
+ export { docsPages as default };
package/dist/pages.mjs ADDED
@@ -0,0 +1,68 @@
1
+ import { defineNuxtModule, createResolver, useLogger, addServerHandler } from '@nuxt/kit';
2
+
3
+ function listPath(route) {
4
+ if (!route) return void 0;
5
+ const list = route.replace(/\/\[slug\]$/, "");
6
+ return list.includes("[") ? void 0 : list || "/";
7
+ }
8
+ function addressesOf(page, main) {
9
+ const mapped = page.meta?.i18n && page.meta.i18n.paths?.[main];
10
+ return mapped ? [page.path, mapped] : [page.path];
11
+ }
12
+ function layerRoutes(site, pages) {
13
+ const bricks = site?.bricks ?? {};
14
+ const main = site?.locales?.[0] ?? "";
15
+ const taken = /* @__PURE__ */ new Set();
16
+ for (const page of pages) for (const path of addressesOf(page, main)) taken.add(path);
17
+ const docsBase = bricks.docs?.route?.[main]?.replace(/\/\[slug\]$/, "") ?? "/docs";
18
+ const blog = bricks.posts ? listPath(bricks.posts.route?.[main]) : void 0;
19
+ const changelog = bricks.changelog ? listPath(bricks.changelog.route?.[main]) ?? site?.pages?.changelog?.[main] : void 0;
20
+ const free = (path) => path && !taken.has(path) ? path : void 0;
21
+ const noAddress = [...bricks.posts && !blog ? ["posts"] : [], ...bricks.changelog && !changelog ? ["changelog"] : []];
22
+ const addedBlog = free(blog);
23
+ const addedChangelog = free(changelog);
24
+ const wanted = [
25
+ { name: "docs-slug", path: `${docsBase}/:slug()`, file: "doc.vue" },
26
+ { name: "docs", path: docsBase, file: "docs.vue" },
27
+ { name: "index", path: "/", file: "index.vue" },
28
+ addedBlog ? { name: "blog", path: addedBlog, file: "blog.vue" } : void 0,
29
+ addedBlog ? { name: "blog-slug", path: `${addedBlog}/:slug()`, file: "post.vue" } : void 0,
30
+ addedChangelog ? { name: "changelog", path: addedChangelog, file: "changelog.vue" } : void 0
31
+ ];
32
+ return {
33
+ docs: { base: docsBase },
34
+ addresses: { ...blog && { blog }, ...changelog && { changelog } },
35
+ pages: wanted.filter((page) => !!page && !taken.has(page.path)),
36
+ ...addedBlog && { blog: addedBlog },
37
+ ...addedChangelog && { changelog: addedChangelog },
38
+ noAddress
39
+ };
40
+ }
41
+
42
+ const docsPages = defineNuxtModule({
43
+ meta: { name: "@lupinum/ginko-docs/pages" },
44
+ setup(_, nuxt) {
45
+ const { resolve } = createResolver(import.meta.url);
46
+ const logger = useLogger("ginko-docs");
47
+ const site = nuxt.options.ginko;
48
+ const { addresses } = layerRoutes(site, []);
49
+ nuxt.options.runtimeConfig.public.ginkoDocs = { blog: addresses.blog ?? "", changelog: addresses.changelog ?? "" };
50
+ let announced = false;
51
+ nuxt.hook("pages:resolved", (pages) => {
52
+ const r = layerRoutes(site, pages);
53
+ for (const page of r.pages) pages.push({ ...page, file: resolve(`../app/docs-pages/${page.file}`) });
54
+ if (announced) return;
55
+ announced = true;
56
+ if (r.blog) {
57
+ addServerHandler({ route: `${r.blog}/rss.xml`, method: "get", handler: resolve("../server/feeds/blog.get") });
58
+ addServerHandler({ route: `/:locale${r.blog}/rss.xml`, method: "get", handler: resolve("../server/feeds/blog-locale.get") });
59
+ if (!site?.pages?.blog) logger.warn(`The layer adds the blog at ${r.blog} but the site has no \`blog: blogPages({ locales })\` in \`pages\`: the blog list is missing from the sitemap and the static build.`);
60
+ }
61
+ if (r.changelog && !site?.pages?.changelog) logger.warn(`The layer adds the changelog at ${r.changelog} but the site has no \`changelog: changelogPages({ locales })\` in \`pages\`: it is missing from the sitemap and the static build.`);
62
+ for (const brick of r.noAddress)
63
+ logger.warn(brick === "changelog" ? "The changelog brick has no address: give it a `route` or add `changelog: changelogPages({ locales })` to `pages`. No changelog page is added." : "The posts brick has no `route` for the main language, so the layer adds no blog page.");
64
+ });
65
+ }
66
+ });
67
+
68
+ export { docsPages as default };
package/i18n/de.json ADDED
@@ -0,0 +1 @@
1
+ {"docs":{"docs":"Doku","edit":"Seite bearbeiten","issue":"Fehler melden","top":"Nach oben","updated":"Zuletzt geändert am","copyPage":"Seite kopieren","copied":"Kopiert","copyFailed":"Kopieren nicht möglich","table":"Tabelle, scrollbar","installCommand":"Installationsbefehl","searchResults":"Suchergebnisse","copyCommand":"Befehl kopieren","moreActions":"Weitere Seitenaktionen","viewMarkdown":"Als Markdown ansehen","viewMarkdownHint":"Die Seite als reiner Text","openChatGpt":"In ChatGPT öffnen","openClaude":"In Claude öffnen","askHint":"Fragen zu dieser Seite stellen","askPrompt":"Lies {url} und beantworte Fragen dazu.","pageActions":"Seitenaktionen","skip":"Zum Inhalt","nav":"Doku-Navigation","contents":"Inhalt","onThisPage":"Auf dieser Seite","search":"Suchen","searchPlaceholder":"Doku durchsuchen …","searchHint":"Tippe, um Seiten und Abschnitte zu finden.","noResults":"Nichts gefunden für „{query}“.","searchMove":"wählen","searchOpen":"öffnen","close":"Schließen","previous":"Zurück","next":"Weiter","pager":"Vorige und nächste Seite","language":"Sprache","sections":"Bereiche","breadcrumb":"Pfad","theme":{"label":"Darstellung","auto":"Auto","light":"Hell","dark":"Dunkel","toggle":"Zwischen hell und dunkel wechseln"},"bannerClose":"Hinweis schließen","footerNav":"Fußzeile","builtWith":"Erstellt mit Ginko","toggle":"Unterseiten von {title} ein- oder ausklappen","blog":"Blog","changelog":"Änderungen","by":"Von","rss":"RSS-Feed","siteLinks":"Hauptbereiche","siteMenu":"Hauptmenü","blogLead":"Neuigkeiten, Anleitungen und Einblicke.","changelogLead":"Was sich mit jeder Version geändert hat.","changelogEmpty":"Noch keine Versionen. Lege die erste als Markdown-Datei in content/changelog an.","draft":"Entwurf","readMore":"Weiterlesen","example":{"preview":"Vorschau","source":"Markdown"},"notFound":{"title":"Seite nicht gefunden","text":"Diese Seite gibt es nicht oder sie ist umgezogen.","home":"Zur Startseite","mainLanguage":"Auf {language} versuchen"},"error":{"title":"Etwas ist schiefgelaufen","text":"Die Seite konnte nicht geladen werden. Versuche es gleich noch einmal."},"untranslated":"Nicht übersetzt: öffnet die Startseite"}}
package/i18n/en.json ADDED
@@ -0,0 +1 @@
1
+ {"docs":{"docs":"Docs","edit":"Edit this page","issue":"Report an issue","top":"Back to top","updated":"Last updated","copyPage":"Copy page","copied":"Copied","copyFailed":"Could not copy","table":"Table, scrollable","installCommand":"Install command","searchResults":"Search results","copyCommand":"Copy command","moreActions":"More page actions","viewMarkdown":"View as Markdown","viewMarkdownHint":"The page as plain text","openChatGpt":"Open in ChatGPT","openClaude":"Open in Claude","askHint":"Ask questions about this page","askPrompt":"Read {url} and answer questions about it.","pageActions":"Page actions","skip":"Skip to content","nav":"Docs navigation","contents":"Contents","onThisPage":"On this page","search":"Search","searchPlaceholder":"Search the docs…","searchHint":"Type to search pages and sections.","noResults":"No results for “{query}”.","searchMove":"to move","searchOpen":"to open","close":"Close","previous":"Previous","next":"Next","pager":"Previous and next page","language":"Language","sections":"Sections","breadcrumb":"Breadcrumb","theme":{"label":"Appearance","auto":"Auto","light":"Light","dark":"Dark","toggle":"Switch between light and dark"},"bannerClose":"Dismiss notice","footerNav":"Footer","builtWith":"Built with Ginko","toggle":"Show or hide subpages of {title}","blog":"Blog","changelog":"Changelog","by":"By","rss":"RSS feed","siteLinks":"Main","siteMenu":"Main menu","blogLead":"News, guides and insights.","changelogLead":"What changed with each version.","changelogEmpty":"No releases yet. Add the first as a Markdown file in content/changelog.","draft":"Draft","readMore":"Read more","example":{"preview":"Preview","source":"Markdown"},"notFound":{"title":"Page not found","text":"This page does not exist or has moved.","home":"Go to the home page","mainLanguage":"Try in {language}"},"error":{"title":"Something went wrong","text":"The page could not be loaded. Please try again in a moment."},"untranslated":"Not translated: opens the start page"}}
package/i18n/fr.json ADDED
@@ -0,0 +1 @@
1
+ {"docs":{"docs":"Documentation","edit":"Modifier cette page","issue":"Signaler un problème","top":"Retour en haut","updated":"Dernière mise à jour","copyPage":"Copier la page","copied":"Copié","copyFailed":"Impossible de copier","table":"Tableau, défilement horizontal","installCommand":"Commande d’installation","searchResults":"Résultats de recherche","copyCommand":"Copier la commande","moreActions":"Autres actions sur la page","viewMarkdown":"Voir en Markdown","viewMarkdownHint":"La page en texte brut","openChatGpt":"Ouvrir dans ChatGPT","openClaude":"Ouvrir dans Claude","askHint":"Poser des questions sur cette page","askPrompt":"Lis {url} et réponds à mes questions sur cette page.","pageActions":"Actions de la page","skip":"Aller au contenu","nav":"Navigation de la documentation","contents":"Sommaire","onThisPage":"Sur cette page","search":"Rechercher","searchPlaceholder":"Rechercher dans la documentation…","searchHint":"Saisissez un mot pour chercher dans les pages et les sections.","noResults":"Aucun résultat pour « {query} ».","searchMove":"pour naviguer","searchOpen":"pour ouvrir","close":"Fermer","previous":"Précédent","next":"Suivant","pager":"Page précédente et page suivante","language":"Langue","sections":"Rubriques","breadcrumb":"Fil d’Ariane","theme":{"label":"Apparence","auto":"Auto","light":"Clair","dark":"Sombre","toggle":"Basculer entre clair et sombre"},"bannerClose":"Fermer le message","footerNav":"Pied de page","builtWith":"Réalisé avec Ginko","toggle":"Afficher ou masquer les sous-pages de {title}","blog":"Blog","changelog":"Nouveautés","by":"Par","rss":"Flux RSS","siteLinks":"Navigation principale","siteMenu":"Menu principal","blogLead":"Actualités, guides et analyses.","changelogLead":"Ce qui a changé à chaque version.","changelogEmpty":"Aucune version pour l’instant. Ajoutez la première sous forme de fichier Markdown dans content/changelog.","draft":"Brouillon","readMore":"Lire la suite","example":{"preview":"Aperçu","source":"Markdown"},"notFound":{"title":"Page introuvable","text":"Cette page n’existe pas ou a été déplacée.","home":"Aller à la page d’accueil","mainLanguage":"Lire en {language}"},"error":{"title":"Une erreur est survenue","text":"La page n’a pas pu être chargée. Réessayez dans un instant."},"untranslated":"Page non traduite : ouvre la page d’accueil"}}
@@ -0,0 +1,2 @@
1
+ Brand icons of the `docs` icon collection (`docs:github`, `docs:openai`, ...), from Simple Icons
2
+ (@iconify-json/simple-icons 1.2.99, CC0 1.0). Brand names and logos belong to their owners.
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M5.202 2.857C7.954 4.922 10.913 9.11 12 11.358c1.087-2.247 4.046-6.436 6.798-8.501C20.783 1.366 24 .213 24 3.883c0 .732-.42 6.156-.667 7.037c-.856 3.061-3.978 3.842-6.755 3.37c4.854.826 6.089 3.562 3.422 6.299c-5.065 5.196-7.28-1.304-7.847-2.97c-.104-.305-.152-.448-.153-.327c0-.121-.05.022-.153.327c-.568 1.666-2.782 8.166-7.847 2.97c-2.667-2.737-1.432-5.473 3.422-6.3c-2.777.473-5.899-.308-6.755-3.369C.42 10.04 0 4.615 0 3.883c0-3.67 3.217-2.517 5.202-1.026"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="m4.714 15.956l4.718-2.648l.079-.23l-.08-.128h-.23l-.79-.048l-2.695-.073l-2.337-.097l-2.265-.122l-.57-.121l-.535-.704l.055-.353l.48-.321l.685.06l1.518.104l2.277.157l1.651.098l2.447.255h.389l.054-.158l-.133-.097l-.103-.098l-2.356-1.596l-2.55-1.688l-1.336-.972l-.722-.491L2 6.223l-.158-1.008l.656-.722l.88.06l.224.061l.893.686l1.906 1.476l2.49 1.833l.364.304l.146-.104l.018-.072l-.164-.274l-1.354-2.446l-1.445-2.49l-.644-1.032l-.17-.619a3 3 0 0 1-.103-.729L6.287.133L6.7 0l.995.134l.42.364l.619 1.415L9.735 4.14l1.555 3.03l.455.898l.243.832l.09.255h.159V9.01l.127-1.706l.237-2.095l.23-2.695l.08-.76l.376-.91l.747-.492l.583.28l.48.685l-.067.444l-.286 1.851l-.558 2.903l-.365 1.942h.213l.243-.242l.983-1.306l1.652-2.064l.728-.82l.85-.904l.547-.431h1.032l.759 1.129l-.34 1.166l-1.063 1.347l-.88 1.142l-1.263 1.7l-.79 1.36l.074.11l.188-.02l2.853-.606l1.542-.28l1.84-.315l.832.388l.09.395l-.327.807l-1.967.486l-2.307.462l-3.436.813l-.043.03l.049.061l1.548.146l.662.036h1.62l3.018.225l.79.522l.473.638l-.08.485l-1.213.62l-1.64-.389l-3.825-.91l-1.31-.329h-.183v.11l1.093 1.068l2.003 1.81l2.508 2.33l.127.578l-.321.455l-.34-.049l-2.204-1.657l-.85-.747l-1.925-1.62h-.127v.17l.443.649l2.343 3.521l.122 1.08l-.17.353l-.607.213l-.668-.122l-1.372-1.924l-1.415-2.168l-1.141-1.943l-.14.08l-.674 7.254l-.316.37l-.728.28l-.607-.461l-.322-.747l.322-1.476l.388-1.924l.316-1.53l.285-1.9l.17-.632l-.012-.042l-.14.018l-1.432 1.967l-2.18 2.945l-1.724 1.845l-.413.164l-.716-.37l.066-.662l.401-.589l2.386-3.036l1.439-1.882l.929-1.086l-.006-.158h-.055L4.138 18.56l-1.13.146l-.485-.456l.06-.746l.231-.243l1.907-1.312Z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M20.317 4.37a19.8 19.8 0 0 0-4.885-1.515a.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.3 18.3 0 0 0-5.487 0a13 13 0 0 0-.617-1.25a.08.08 0 0 0-.079-.037A19.7 19.7 0 0 0 3.677 4.37a.1.1 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.08.08 0 0 0 .031.057a19.9 19.9 0 0 0 5.993 3.03a.08.08 0 0 0 .084-.028a14 14 0 0 0 1.226-1.994a.076.076 0 0 0-.041-.106a13 13 0 0 1-1.872-.892a.077.077 0 0 1-.008-.128a10 10 0 0 0 .372-.292a.07.07 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.07.07 0 0 1 .078.01q.181.149.373.292a.077.077 0 0 1-.006.127a12.3 12.3 0 0 1-1.873.892a.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.08.08 0 0 0 .084.028a19.8 19.8 0 0 0 6.002-3.03a.08.08 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.06.06 0 0 0-.031-.03M8.02 15.33c-1.182 0-2.157-1.085-2.157-2.419c0-1.333.956-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.956 2.418-2.157 2.418m7.975 0c-1.183 0-2.157-1.085-2.157-2.419c0-1.333.955-2.419 2.157-2.419c1.21 0 2.176 1.096 2.157 2.42c0 1.333-.946 2.418-2.157 2.418"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M12 .297c-6.63 0-12 5.373-12 12c0 5.303 3.438 9.8 8.205 11.385c.6.113.82-.258.82-.577c0-.285-.01-1.04-.015-2.04c-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729c1.205.084 1.838 1.236 1.838 1.236c1.07 1.835 2.809 1.305 3.495.998c.108-.776.417-1.305.76-1.605c-2.665-.3-5.466-1.332-5.466-5.93c0-1.31.465-2.38 1.235-3.22c-.135-.303-.54-1.523.105-3.176c0 0 1.005-.322 3.3 1.23c.96-.267 1.98-.399 3-.405c1.02.006 2.04.138 3 .405c2.28-1.552 3.285-1.23 3.285-1.23c.645 1.653.24 2.873.12 3.176c.765.84 1.23 1.91 1.23 3.22c0 4.61-2.805 5.625-5.475 5.92c.42.36.81 1.096.81 2.22c0 1.606-.015 2.896-.015 3.286c0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037c-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85c3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.06 2.06 0 0 1-2.063-2.065a2.064 2.064 0 1 1 2.063 2.065m1.782 13.019H3.555V9h3.564zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127C.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611c.118 1.24.325 2.47.62 3.68c.55 2.237 2.777 4.098 4.96 4.857c2.336.792 4.849.923 7.256.38q.398-.092.786-.213c.585-.184 1.27-.39 1.774-.753a.06.06 0 0 0 .023-.043v-1.809a.05.05 0 0 0-.02-.041a.05.05 0 0 0-.046-.01a20.3 20.3 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.6 5.6 0 0 1-.319-1.433a.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546c.376 0 .75 0 1.125-.01c1.57-.044 3.224-.124 4.768-.422q.059-.011.11-.024c2.435-.464 4.753-1.92 4.989-5.604c.008-.145.03-1.52.03-1.67c.002-.512.167-3.63-.024-5.545m-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976c-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35c-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102q0-1.965 1.011-3.12c.696-.77 1.608-1.164 2.74-1.164c1.311 0 2.302.5 2.962 1.498l.638 1.06l.638-1.06c.66-.999 1.65-1.498 2.96-1.498c1.13 0 2.043.395 2.74 1.164q1.012 1.155 1.012 3.12z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M22.282 9.821a6 6 0 0 0-.516-4.91a6.05 6.05 0 0 0-6.51-2.9A6.065 6.065 0 0 0 4.981 4.18a6 6 0 0 0-3.998 2.9a6.05 6.05 0 0 0 .743 7.097a5.98 5.98 0 0 0 .51 4.911a6.05 6.05 0 0 0 6.515 2.9A6 6 0 0 0 13.26 24a6.06 6.06 0 0 0 5.772-4.206a6 6 0 0 0 3.997-2.9a6.06 6.06 0 0 0-.747-7.073M13.26 22.43a4.48 4.48 0 0 1-2.876-1.04l.141-.081l4.779-2.758a.8.8 0 0 0 .392-.681v-6.737l2.02 1.168a.07.07 0 0 1 .038.052v5.583a4.504 4.504 0 0 1-4.494 4.494M3.6 18.304a4.47 4.47 0 0 1-.535-3.014l.142.085l4.783 2.759a.77.77 0 0 0 .78 0l5.843-3.369v2.332a.08.08 0 0 1-.033.062L9.74 19.95a4.5 4.5 0 0 1-6.14-1.646M2.34 7.896a4.5 4.5 0 0 1 2.366-1.973V11.6a.77.77 0 0 0 .388.677l5.815 3.354l-2.02 1.168a.08.08 0 0 1-.071 0l-4.83-2.786A4.504 4.504 0 0 1 2.34 7.872zm16.597 3.855l-5.833-3.387L15.119 7.2a.08.08 0 0 1 .071 0l4.83 2.791a4.494 4.494 0 0 1-.676 8.105v-5.678a.79.79 0 0 0-.407-.667m2.01-3.023l-.141-.085l-4.774-2.782a.78.78 0 0 0-.785 0L9.409 9.23V6.897a.07.07 0 0 1 .028-.061l4.83-2.787a4.5 4.5 0 0 1 6.68 4.66zm-12.64 4.135l-2.02-1.164a.08.08 0 0 1-.038-.057V6.075a4.5 4.5 0 0 1 7.375-3.453l-.142.08L8.704 5.46a.8.8 0 0 0-.393.681zm1.097-2.365l2.602-1.5l2.607 1.5v2.999l-2.597 1.5l-2.607-1.5Z"/></svg>
package/icons/x.svg ADDED
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M14.234 10.162L22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299l-.929-1.329L3.076 1.56h3.182l5.965 8.532l.929 1.329l7.754 11.09h-3.182z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M23.498 6.186a3.02 3.02 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.02 3.02 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.02 3.02 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.02 3.02 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814M9.545 15.568V8.432L15.818 12z"/></svg>
package/nuxt.config.ts CHANGED
@@ -1,218 +1,28 @@
1
- import { fileURLToPath } from "node:url";
2
- import { dirname, join } from "node:path";
3
- import { readFileSync } from "node:fs";
4
- import tailwindcss from "@tailwindcss/vite";
5
- import { transformerNotationDiff, transformerNotationHighlight } from "@shikijs/transformers";
6
- import darkPlus from "shiki/dist/themes/dark-plus.mjs";
7
- import lightPlus from "shiki/dist/themes/light-plus.mjs";
8
- import { contentComponentPolicy, contentComponentTags } from "./tags";
9
- import { i18nPages } from "./i18n/routes";
10
- import { defaultLocale, localeCodes, locales, localizedPath } from "./i18n/locales";
11
- import { routeSlugs } from "./shared/route-slugs";
12
- import { layerIconCollections, layerIconNames } from "./icon-bundle";
13
- import packageMetadata from "./package.json" with { type: "json" };
1
+ // The docs layer. A site extends it and brings ginko.config.ts (with docsCollection), content/ and branding:
2
+ // export default defineNuxtConfig({ extends: ['@lupinum/ginko-docs'], modules: ['@lupinum/ginko/nuxt'], ginko })
3
+ // Standalone it is a whole docs site; inside a larger site (`extends` next to the site's own pages and layout) it
4
+ // adds only the docs pages, styled from the site's shadcn-style tokens (README: "Inside an existing site").
5
+ import { fileURLToPath } from 'node:url'
14
6
 
15
- const root = dirname(fileURLToPath(import.meta.url));
16
- const app = join(root, "app");
17
- const publicSansDirectory = join(root, "public/fonts/public-sans");
18
- const publicSansFamilies = [400, 500, 600, 700].map((weight) => ({
19
- name: "Public Sans",
20
- global: true,
21
- display: "swap" as const,
22
- weight,
23
- style: "normal",
24
- src: `data:font/woff;base64,${readFileSync(
25
- join(publicSansDirectory, `public-sans-${weight}-normal-latin.woff`),
26
- ).toString("base64")}`,
27
- }));
7
+ const here = (path: string) => fileURLToPath(new URL(path, import.meta.url))
28
8
 
29
9
  export default defineNuxtConfig({
30
- build: {
31
- transpile: ["@lupinum/ginko-docs"],
32
- },
33
- $meta: { name: "ginko-docs" },
34
- compatibilityDate: "2025-07-15",
35
- alias: { "#ginko-docs": app },
36
- css: [join(app, "assets/css/tailwind.css"), join(app, "assets/css/prose.css")],
37
- modules: [
38
- join(root, "modules/syntax-highlighting"),
39
- join(root, "modules/feature-routing"),
40
- "@nuxt/icon",
41
- "@nuxt/fonts",
42
- "@lupinum/ginko-content",
43
- "@nuxt/image",
44
- "@nuxt/scripts",
45
- join(root, "modules/analytics-boundary"),
46
- "nuxt-og-image",
47
- "@nuxtjs/sitemap",
48
- "@nuxtjs/robots",
49
- "@nuxtjs/color-mode",
50
- "@nuxtjs/mcp-toolkit",
51
- ],
52
- ogImage: {
53
- zeroRuntime: true,
54
- // Satori renders queue up behind page prerendering on modest build
55
- // machines; the default 15s budget is too tight under that contention.
56
- security: { renderTimeout: 120_000 },
57
- },
58
- mcp: {
59
- name: "Ginko Docs",
60
- version: packageMetadata.version,
61
- },
62
- components: {
63
- dirs: [
64
- {
65
- path: join(app, "components/site"),
66
- pathPrefix: false,
67
- global: true,
68
- pattern: [
69
- "SiteBanner.vue",
70
- "SiteFooter.vue",
71
- "SiteHeader.vue",
72
- "SiteInteractionLayer.vue",
73
- "SiteLocaleSwitcher.vue",
74
- "SiteLogoMark.vue",
75
- "SiteSkipLink.vue",
76
- "SiteSocialLinks.vue",
77
- ],
78
- },
79
- {
80
- path: join(app, "features/docs/components"),
81
- pathPrefix: false,
82
- global: true,
83
- pattern: "DocsSidebar.vue",
84
- },
85
- { path: join(app, "components/mdc"), pathPrefix: false, global: true },
86
- { path: join(app, "components/prose"), pathPrefix: false, global: true },
87
- ],
88
- },
89
- colorMode: { classSuffix: "" },
90
- icon: {
91
- provider: "none",
92
- fallbackToApi: false,
93
- customCollections: layerIconCollections,
94
- clientBundle: {
95
- icons: [...layerIconNames],
96
- includeCustomCollections: false,
97
- scan: {
98
- globInclude: [
99
- "**/*.{vue,js,mjs,cjs,ts,jsx,tsx,md,mdc,mdx,yml,yaml}",
100
- "**/.navigation.{yml,yaml}",
101
- ],
102
- globExclude: [
103
- ".git",
104
- ".nuxt",
105
- ".output",
106
- ".cache",
107
- "node_modules",
108
- "dist",
109
- "build",
110
- "coverage",
111
- "test",
112
- "tests",
113
- ],
114
- },
115
- },
116
- },
117
- fonts: {
118
- families: publicSansFamilies,
119
- providers: {
120
- adobe: false,
121
- bunny: false,
122
- fontshare: false,
123
- fontsource: false,
124
- google: false,
125
- googleicons: false,
126
- npm: false,
127
- },
128
- },
129
- i18n: {
130
- customRoutes: "config",
131
- defaultLocale: "en",
132
- detectBrowserLanguage: false,
133
- locales: locales
134
- .filter((locale) => locale.code === defaultLocale)
135
- .map(({ code, language, name }) => ({ code, language, name })),
136
- pages: i18nPages,
137
- strategy: "prefix_except_default",
138
- vueI18n: join(root, "i18n/i18n.config.ts"),
139
- },
140
- content: {
141
- componentPolicy: contentComponentPolicy,
142
- // Broken internal links and missing #anchors fail the build instead of
143
- // only landing in the validation report.
144
- validation: "error",
145
- i18n: {
146
- translatedSlugs: true,
147
- },
148
- markdown: {
149
- plugins: [
150
- [
151
- "shiki",
152
- {
153
- preStyles: false,
154
- transformers: [transformerNotationDiff(), transformerNotationHighlight()],
155
- themes: { light: lightPlus, dark: darkPlus },
156
- },
157
- ],
158
- ["toc", { depth: 4, searchDepth: 4 }],
159
- "summary",
160
- ["footnotes", { label: "" }],
161
- ],
162
- tags: contentComponentTags,
163
- anchorLinks: { depth: 4, exclude: [1] },
164
- },
165
- search: { engine: "minisearch" },
166
- sitemap: true,
167
- agent: { routes: true, linkHeaders: true, delivery: "static" },
168
- },
169
- sitemap: {
170
- excludeAppSources: ["nuxt:prerender"],
171
- // The docs roots prerender as redirects to the first docs page; a sitemap
172
- // must not list redirecting URLs.
173
- exclude: localeCodes.map((locale) => localizedPath(locale, routeSlugs.docs[locale])),
174
- },
175
- app: {
176
- head: {
177
- charset: "utf-8",
178
- htmlAttrs: { lang: "en" },
179
- viewport: "width=device-width, initial-scale=1",
180
- meta: [{ name: "color-scheme", content: "light dark" }],
181
- },
182
- },
183
- hooks: {
184
- "components:dirs"(dirs) {
185
- const defaultComponentsDir = join(app, "components").replaceAll("\\", "/");
186
- const filtered = dirs.filter((entry) => {
187
- const path = (typeof entry === "string" ? entry : entry.path).replaceAll("\\", "/");
188
- return path !== defaultComponentsDir;
189
- });
190
- dirs.splice(0, dirs.length, ...filtered);
191
- },
192
- },
193
- nitro: {
194
- prerender: {
195
- // OG images render through a Resvg worker. Parallel prerenders can
196
- // terminate that worker under load and leave otherwise valid pages with
197
- // 408/500 social-image routes, so package builds must stay serialized.
198
- concurrency: 1,
199
- crawlLinks: true,
200
- failOnError: true,
201
- routes: [
202
- "/llms.txt",
203
- "/llms-full.txt",
204
- "/sitemap.xml",
205
- "/robots.txt",
206
- // Link page over every authored redirectFrom source; crawling it
207
- // materializes the redirect stubs.
208
- "/api/_ginko-docs/redirects",
209
- ],
210
- },
211
- },
10
+ modules: ['@lupinum/ginko-components', '@lupinum/ginko-docs/pages', '@lupinum/ginko-docs/icons'],
11
+ // Tells @lupinum/ginko to keep each page's repository path (`source`) in the served bundle, for "Edit this page".
12
+ // A config hook, not one in modules/pages.ts: it is registered before any module runs, whatever the module order.
13
+ hooks: { 'ginko:files': (options) => { options.keepSource = true } },
14
+ css: [here('./app/assets/docs.css')],
15
+ // The diagram engine (mermaid + ELK, 462 kB gzip) is loaded only by a page with a ```mermaid block. Left alone, Rolldown
16
+ // could put its small shared module helper into that chunk, and every page importing the helper downloaded the engine. A named group of its own keeps the helper out of it (e2e/docs.spec.ts checks).
212
17
  vite: {
213
- resolve: {
214
- dedupe: ["@lupinum/ginko-content", "vue", "vue-router"],
18
+ build: {
19
+ rolldownOptions: {
20
+ output: {
21
+ codeSplitting: {
22
+ groups: [{ name: 'mermaid', test: /[\\/]node_modules[\\/](beautiful-mermaid|elkjs|mermaid)[\\/]/, includeDependenciesRecursively: false }],
23
+ },
24
+ },
25
+ },
215
26
  },
216
- plugins: [tailwindcss()],
217
27
  },
218
- });
28
+ })