@lupinum/ginko-docs 0.2.2

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 (240) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +112 -0
  3. package/app/app.config.ts +49 -0
  4. package/app/app.vue +71 -0
  5. package/app/assets/css/prose.css +1154 -0
  6. package/app/assets/css/tailwind.css +365 -0
  7. package/app/components/OgImage/GinkoDocs.satori.vue +117 -0
  8. package/app/components/content/DocumentPageShell.vue +55 -0
  9. package/app/components/content/Feedback.vue +97 -0
  10. package/app/components/content/PageMarkdownCopy.vue +102 -0
  11. package/app/components/mdc/MdcAccordion.vue +64 -0
  12. package/app/components/mdc/MdcAccordionItem.vue +51 -0
  13. package/app/components/mdc/MdcAlert.vue +34 -0
  14. package/app/components/mdc/MdcAside.vue +27 -0
  15. package/app/components/mdc/MdcCallout.vue +62 -0
  16. package/app/components/mdc/MdcCard.vue +186 -0
  17. package/app/components/mdc/MdcCardGroup.vue +47 -0
  18. package/app/components/mdc/MdcCenter.vue +71 -0
  19. package/app/components/mdc/MdcCodeGroup.vue +193 -0
  20. package/app/components/mdc/MdcColumn.vue +70 -0
  21. package/app/components/mdc/MdcDocImg.vue +25 -0
  22. package/app/components/mdc/MdcDropcap.vue +84 -0
  23. package/app/components/mdc/MdcError.vue +16 -0
  24. package/app/components/mdc/MdcField.vue +62 -0
  25. package/app/components/mdc/MdcFieldGroup.vue +18 -0
  26. package/app/components/mdc/MdcFigure.vue +51 -0
  27. package/app/components/mdc/MdcIdea.vue +16 -0
  28. package/app/components/mdc/MdcInfo.vue +16 -0
  29. package/app/components/mdc/MdcLayout.vue +57 -0
  30. package/app/components/mdc/MdcNote.vue +16 -0
  31. package/app/components/mdc/MdcPassage.vue +32 -0
  32. package/app/components/mdc/MdcQuiz.vue +281 -0
  33. package/app/components/mdc/MdcQuizOption.vue +91 -0
  34. package/app/components/mdc/MdcQuizQuestion.vue +226 -0
  35. package/app/components/mdc/MdcReadMore.vue +90 -0
  36. package/app/components/mdc/MdcReadMoreGroup.vue +18 -0
  37. package/app/components/mdc/MdcShortcut.vue +46 -0
  38. package/app/components/mdc/MdcStep.vue +42 -0
  39. package/app/components/mdc/MdcSteps.vue +25 -0
  40. package/app/components/mdc/MdcSuccess.vue +16 -0
  41. package/app/components/mdc/MdcTab.vue +17 -0
  42. package/app/components/mdc/MdcTabs.vue +132 -0
  43. package/app/components/mdc/MdcTimeline.vue +14 -0
  44. package/app/components/mdc/MdcTimelineItem.vue +49 -0
  45. package/app/components/mdc/MdcWarning.vue +16 -0
  46. package/app/components/mdc/icons.ts +10 -0
  47. package/app/components/prose/ProseA.vue +27 -0
  48. package/app/components/prose/ProseBlockquote.vue +14 -0
  49. package/app/components/prose/ProseCode.vue +14 -0
  50. package/app/components/prose/ProseEm.vue +14 -0
  51. package/app/components/prose/ProseH1.vue +18 -0
  52. package/app/components/prose/ProseH2.vue +24 -0
  53. package/app/components/prose/ProseH3.vue +24 -0
  54. package/app/components/prose/ProseH4.vue +14 -0
  55. package/app/components/prose/ProseHr.vue +12 -0
  56. package/app/components/prose/ProseImg.vue +120 -0
  57. package/app/components/prose/ProseLi.vue +14 -0
  58. package/app/components/prose/ProseOl.vue +14 -0
  59. package/app/components/prose/ProseP.vue +14 -0
  60. package/app/components/prose/ProsePre.vue +217 -0
  61. package/app/components/prose/ProseStrong.vue +14 -0
  62. package/app/components/prose/ProseTable.vue +16 -0
  63. package/app/components/prose/ProseTbody.vue +14 -0
  64. package/app/components/prose/ProseTd.vue +14 -0
  65. package/app/components/prose/ProseTh.vue +14 -0
  66. package/app/components/prose/ProseThead.vue +14 -0
  67. package/app/components/prose/ProseTr.vue +14 -0
  68. package/app/components/prose/ProseUl.vue +14 -0
  69. package/app/components/site/ModeToggle.vue +123 -0
  70. package/app/components/site/SiteBanner.vue +56 -0
  71. package/app/components/site/SiteFooter.vue +80 -0
  72. package/app/components/site/SiteHeader.vue +250 -0
  73. package/app/components/site/SiteInteractionLayer.vue +35 -0
  74. package/app/components/site/SiteLocaleSwitcher.vue +268 -0
  75. package/app/components/site/SiteLogoMark.vue +12 -0
  76. package/app/components/site/SiteSkipLink.vue +14 -0
  77. package/app/components/ui/accordion/Accordion.vue +15 -0
  78. package/app/components/ui/accordion/AccordionContent.vue +23 -0
  79. package/app/components/ui/accordion/AccordionItem.vue +24 -0
  80. package/app/components/ui/accordion/AccordionTrigger.vue +35 -0
  81. package/app/components/ui/accordion/index.ts +4 -0
  82. package/app/components/ui/alert/Alert.vue +21 -0
  83. package/app/components/ui/alert/AlertDescription.vue +22 -0
  84. package/app/components/ui/alert/AlertTitle.vue +22 -0
  85. package/app/components/ui/alert/index.ts +34 -0
  86. package/app/components/ui/badge/Badge.vue +28 -0
  87. package/app/components/ui/badge/index.ts +24 -0
  88. package/app/components/ui/button/Button.vue +31 -0
  89. package/app/components/ui/button/index.ts +35 -0
  90. package/app/components/ui/card/Card.vue +16 -0
  91. package/app/components/ui/card/CardAction.vue +17 -0
  92. package/app/components/ui/card/CardContent.vue +14 -0
  93. package/app/components/ui/card/CardDescription.vue +14 -0
  94. package/app/components/ui/card/CardFooter.vue +14 -0
  95. package/app/components/ui/card/CardHeader.vue +22 -0
  96. package/app/components/ui/card/CardTitle.vue +14 -0
  97. package/app/components/ui/card/card-variants.ts +15 -0
  98. package/app/components/ui/card/index.ts +8 -0
  99. package/app/components/ui/checkbox/Checkbox.vue +35 -0
  100. package/app/components/ui/checkbox/index.ts +1 -0
  101. package/app/components/ui/collapsible/Collapsible.vue +15 -0
  102. package/app/components/ui/collapsible/CollapsibleContent.vue +25 -0
  103. package/app/components/ui/collapsible/CollapsibleTrigger.vue +12 -0
  104. package/app/components/ui/collapsible/index.ts +3 -0
  105. package/app/components/ui/dialog/Dialog.vue +15 -0
  106. package/app/components/ui/dialog/DialogClose.vue +12 -0
  107. package/app/components/ui/dialog/DialogContent.vue +69 -0
  108. package/app/components/ui/dialog/DialogDescription.vue +21 -0
  109. package/app/components/ui/dialog/DialogFooter.vue +15 -0
  110. package/app/components/ui/dialog/DialogHeader.vue +12 -0
  111. package/app/components/ui/dialog/DialogOverlay.vue +26 -0
  112. package/app/components/ui/dialog/DialogPortal.vue +12 -0
  113. package/app/components/ui/dialog/DialogTitle.vue +21 -0
  114. package/app/components/ui/dialog/DialogTrigger.vue +12 -0
  115. package/app/components/ui/dialog/index.ts +10 -0
  116. package/app/components/ui/dropdown-menu/DropdownMenu.vue +15 -0
  117. package/app/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +36 -0
  118. package/app/components/ui/dropdown-menu/DropdownMenuContent.vue +40 -0
  119. package/app/components/ui/dropdown-menu/DropdownMenuGroup.vue +12 -0
  120. package/app/components/ui/dropdown-menu/DropdownMenuItem.vue +41 -0
  121. package/app/components/ui/dropdown-menu/DropdownMenuLabel.vue +25 -0
  122. package/app/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +15 -0
  123. package/app/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +37 -0
  124. package/app/components/ui/dropdown-menu/DropdownMenuSeparator.vue +23 -0
  125. package/app/components/ui/dropdown-menu/DropdownMenuShortcut.vue +17 -0
  126. package/app/components/ui/dropdown-menu/DropdownMenuSub.vue +15 -0
  127. package/app/components/ui/dropdown-menu/DropdownMenuSubContent.vue +29 -0
  128. package/app/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +31 -0
  129. package/app/components/ui/dropdown-menu/DropdownMenuTrigger.vue +14 -0
  130. package/app/components/ui/dropdown-menu/index.ts +16 -0
  131. package/app/components/ui/input/Input.vue +23 -0
  132. package/app/components/ui/input/index.ts +1 -0
  133. package/app/components/ui/kbd/Kbd.vue +23 -0
  134. package/app/components/ui/kbd/KbdGroup.vue +14 -0
  135. package/app/components/ui/kbd/index.ts +22 -0
  136. package/app/components/ui/label/Label.vue +14 -0
  137. package/app/components/ui/label/index.ts +1 -0
  138. package/app/components/ui/scroll-area/ScrollArea.vue +39 -0
  139. package/app/components/ui/scroll-area/ScrollBar.vue +33 -0
  140. package/app/components/ui/scroll-area/index.ts +2 -0
  141. package/app/components/ui/separator/Separator.vue +27 -0
  142. package/app/components/ui/separator/index.ts +1 -0
  143. package/app/components/ui/sheet/Sheet.vue +15 -0
  144. package/app/components/ui/sheet/SheetClose.vue +12 -0
  145. package/app/components/ui/sheet/SheetContent.vue +59 -0
  146. package/app/components/ui/sheet/SheetDescription.vue +21 -0
  147. package/app/components/ui/sheet/SheetFooter.vue +12 -0
  148. package/app/components/ui/sheet/SheetHeader.vue +12 -0
  149. package/app/components/ui/sheet/SheetOverlay.vue +26 -0
  150. package/app/components/ui/sheet/SheetTitle.vue +21 -0
  151. package/app/components/ui/sheet/SheetTrigger.vue +12 -0
  152. package/app/components/ui/sheet/index.ts +8 -0
  153. package/app/components/ui/switch/Switch.vue +39 -0
  154. package/app/components/ui/switch/index.ts +1 -0
  155. package/app/components/ui/tabs/Tabs.vue +24 -0
  156. package/app/components/ui/tabs/TabsContent.vue +21 -0
  157. package/app/components/ui/tabs/TabsList.vue +26 -0
  158. package/app/components/ui/tabs/TabsTrigger.vue +28 -0
  159. package/app/components/ui/tabs/index.ts +4 -0
  160. package/app/components/ui/textarea/Textarea.vue +31 -0
  161. package/app/components/ui/textarea/index.ts +1 -0
  162. package/app/composables/site-navigation.utils.ts +80 -0
  163. package/app/composables/useCanonicalUrl.ts +9 -0
  164. package/app/composables/useContentRouteAlternates.ts +43 -0
  165. package/app/composables/useGinkoAnalytics.ts +37 -0
  166. package/app/composables/useGinkoDocsConfig.ts +6 -0
  167. package/app/composables/useGinkoOgImage.ts +20 -0
  168. package/app/composables/useLocalizedPath.ts +12 -0
  169. package/app/composables/useLocalizedRouteSwitch.ts +31 -0
  170. package/app/composables/usePageMarkdownActions.ts +79 -0
  171. package/app/composables/useSchemaJsonLd.ts +25 -0
  172. package/app/composables/useSiteNavigation.ts +86 -0
  173. package/app/config/site.utils.ts +36 -0
  174. package/app/error.vue +125 -0
  175. package/app/features/docs/components/DocsContributeLinks.vue +65 -0
  176. package/app/features/docs/components/DocsMobileToc.vue +104 -0
  177. package/app/features/docs/components/DocsPageContent.vue +188 -0
  178. package/app/features/docs/components/DocsPageNav.vue +57 -0
  179. package/app/features/docs/components/DocsSidebar.vue +129 -0
  180. package/app/features/docs/components/DocsSidebarDropdown.vue +70 -0
  181. package/app/features/docs/components/DocsSidebarItem.vue +169 -0
  182. package/app/features/docs/components/DocsSidebarList.vue +35 -0
  183. package/app/features/docs/components/DocsSidebarTabs.vue +35 -0
  184. package/app/features/docs/components/DocsToc.vue +60 -0
  185. package/app/features/docs/composables/useDocsEntryPath.ts +13 -0
  186. package/app/features/docs/composables/useDocsNavigation.ts +29 -0
  187. package/app/features/docs/composables/useDocsNavigationData.ts +15 -0
  188. package/app/features/docs/composables/useScrollspy.ts +67 -0
  189. package/app/features/docs/docs-navigation.ts +170 -0
  190. package/app/features/search/command-center.ts +156 -0
  191. package/app/features/search/components/SiteCommandCenter.vue +323 -0
  192. package/app/features/search/components/SiteSearchPageHighlight.vue +124 -0
  193. package/app/features/search/useCommandCenter.ts +300 -0
  194. package/app/layouts/blog.vue +15 -0
  195. package/app/layouts/default.vue +12 -0
  196. package/app/layouts/docs.vue +20 -0
  197. package/app/lib/errors.ts +84 -0
  198. package/app/lib/schema-org.ts +38 -0
  199. package/app/lib/utils.ts +7 -0
  200. package/app/pages/blog/[slug].vue +211 -0
  201. package/app/pages/blog/index.vue +106 -0
  202. package/app/pages/docs/[...slug].vue +10 -0
  203. package/app/pages/docs/index.vue +23 -0
  204. package/app/pages/index.vue +140 -0
  205. package/app/plugins/ssr-width.ts +6 -0
  206. package/app/utils/content.ts +56 -0
  207. package/app/utils/index.ts +1 -0
  208. package/components.ts +9 -0
  209. package/content.js +175 -0
  210. package/content.ts +148 -0
  211. package/i18n/i18n.config.ts +10 -0
  212. package/i18n/locales.ts +81 -0
  213. package/i18n/messages/global/banner.ts +8 -0
  214. package/i18n/messages/global/blog.ts +14 -0
  215. package/i18n/messages/global/command.ts +44 -0
  216. package/i18n/messages/global/docs.ts +32 -0
  217. package/i18n/messages/global/errors.ts +36 -0
  218. package/i18n/messages/global/feedback.ts +11 -0
  219. package/i18n/messages/global/index.ts +21 -0
  220. package/i18n/messages/global/nav.ts +18 -0
  221. package/i18n/messages/global/site.ts +4 -0
  222. package/i18n/messages/global/theme.ts +7 -0
  223. package/i18n/messages/index.ts +20 -0
  224. package/i18n/messages/localize.ts +35 -0
  225. package/i18n/messages/source.ts +5 -0
  226. package/i18n/routes.ts +33 -0
  227. package/icon-bundle.ts +141 -0
  228. package/index.d.ts +13 -0
  229. package/modules/feature-routing.ts +32 -0
  230. package/nuxt.config.ts +194 -0
  231. package/package.json +91 -0
  232. package/runtime/markdown/inline-code-highlight.ts +155 -0
  233. package/runtime/server/agent-markdown.ts +21 -0
  234. package/runtime/utils.ts +7 -0
  235. package/server/mcp/tools/get-page.ts +14 -0
  236. package/server/mcp/tools/list-pages.ts +10 -0
  237. package/server/plugins/agent-markdown.ts +6 -0
  238. package/shared/route-slugs.ts +5 -0
  239. package/shared/types/app-config.ts +100 -0
  240. package/tags.ts +204 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Matthias Amon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,112 @@
1
+ # Ginko Docs
2
+
3
+ Ginko Docs is a publishable Nuxt layer for focused, searchable, multilingual documentation sites. It combines a polished application shell with Ginko Content collections, navigation, search, SEO, localized routes, and agent-readable Markdown surfaces.
4
+
5
+ The package currently lives in the Ginko Docs development repository. Repository links may move to the Lupinum organization without changing the package name or consumer API.
6
+
7
+ ## Install
8
+
9
+ ```sh
10
+ pnpm add -D @lupinum/ginko-docs
11
+ ```
12
+
13
+ Extend the layer from `nuxt.config.ts`:
14
+
15
+ ```ts
16
+ export default defineNuxtConfig({
17
+ extends: ["@lupinum/ginko-docs"],
18
+ });
19
+ ```
20
+
21
+ Define the site’s content collections in `content.config.ts`:
22
+
23
+ ```ts
24
+ import { defineGinkoDocsConfig } from "@lupinum/ginko-docs/content";
25
+
26
+ export default defineGinkoDocsConfig({
27
+ site: {
28
+ name: "Example Docs",
29
+ description: "Documentation for Example.",
30
+ url: "https://docs.example.com",
31
+ },
32
+ locales: ["en"],
33
+ defaultLocale: "en",
34
+ blog: false,
35
+ });
36
+ ```
37
+
38
+ The content configuration is the source of truth for whether the optional blog exists. The layer removes blog routes when no blog collection is configured and derives navigation visibility from the resulting router.
39
+
40
+ Add public presentation settings in `app/app.config.ts`:
41
+
42
+ ```ts
43
+ export default {
44
+ ginkoDocs: {
45
+ site: {
46
+ name: { en: "Example Docs" },
47
+ description: { en: "Documentation for Example." },
48
+ url: "https://docs.example.com",
49
+ logo: { light: "/logo.svg", dark: "/logo-dark.svg" },
50
+ },
51
+ },
52
+ };
53
+ ```
54
+
55
+ ## Public exports
56
+
57
+ - `@lupinum/ginko-docs` — Nuxt layer entry
58
+ - `@lupinum/ginko-docs/content` — typed content configuration factory
59
+ - `@lupinum/ginko-docs/app-config` — application-configuration types
60
+ - `@lupinum/ginko-docs/components` — default MDC tag map and related types
61
+
62
+ ## Customize
63
+
64
+ Consumers use Nuxt's ordinary override rules. Add `app/pages/index.vue` or a layout to replace a
65
+ page or layout. Add a same-named `SiteHeader`, `SiteFooter`, `SiteBanner`, `SiteLogoMark`,
66
+ `SiteLocaleSwitcher`, `SiteInteractionLayer`, or `DocsSidebar` component to replace that shell
67
+ piece. Import consumer theme CSS from an app plugin so it augments rather than replaces the layer's
68
+ styles. Add or replace MDC components in `app/components/mdc` and extend
69
+ `ginkoDocsComponentTags` from `@lupinum/ginko-docs/components` in `content.markdown.tags`. Register
70
+ custom MDC components globally with a Nuxt plugin or Nuxt's `.global.vue` filename suffix, because
71
+ MDC resolves tag targets dynamically. Each new tag must also declare its narrow static prop and slot
72
+ contract in `content.componentPolicy`; Nuxt merges that consumer entry with the layer's built-in
73
+ policy.
74
+
75
+ Custom agent Markdown is deliberately separate: register serializers through
76
+ `@lupinum/ginko-content/agent-registry` in a Nitro plugin.
77
+
78
+ ## Configuration
79
+
80
+ All features are configured under the `ginkoDocs` key in `app/app.config.ts` and ship with safe
81
+ defaults:
82
+
83
+ - `nav.links` — `"auto"` (Docs + Blog when present) or an array of localized links.
84
+ - `banner` — announcement bar with persisted dismissal (`enabled: "auto" | boolean`, `id`, `text`,
85
+ `link`, `showOnLanding`).
86
+ - `analytics.plausible` — Plausible via Nuxt Scripts; disabled until `domain` is set
87
+ (`scriptSrc` for self-hosted, `extensions` default `["outbound-links"]`).
88
+ - `feedback.enabled` — "Was this page helpful?" widget; votes fire the `docs-feedback` Plausible
89
+ event and negative votes link to a prefilled GitHub issue when `repository` is configured.
90
+ - `ogImage` — build-time PNG social cards (`enabled`, `component`); override the template by
91
+ shadowing `app/components/OgImage/GinkoDocs.satori.vue`.
92
+ - `markdownActions` — toggle ChatGPT / Claude / MCP entries in the Copy Markdown menu.
93
+ - `images.zoom` — click-to-zoom lightbox for prose images.
94
+ - `toc.depth` — table-of-contents depth (2–4).
95
+ - `landing.hero.media` — optional hero visual (`{ type: "code" }` or `{ type: "image" }`).
96
+ - `repository` — enables "Edit this page" / "Report an issue" links.
97
+
98
+ The bare docs root (e.g. `/docs`) redirects to the first documentation page, and the 404 page
99
+ renders with the full site chrome.
100
+
101
+ ## Agent surfaces
102
+
103
+ The layer can expose canonical content through raw Markdown negotiation, `/raw/**`, `/llms.txt`, `/llms-full.txt`, and read-only MCP tools. These surfaces use the same Ginko Content route and document model as rendered pages.
104
+
105
+ ## Requirements
106
+
107
+ - Nuxt 4.4 or newer
108
+ - A package manager supported by Nuxt
109
+
110
+ ## License
111
+
112
+ [MIT](./LICENSE)
@@ -0,0 +1,49 @@
1
+ import type { GinkoDocsAppConfig } from "../shared/types/app-config";
2
+ export default {
3
+ ginkoDocs: {
4
+ site: {
5
+ name: { en: "Ginko Docs", de: "Ginko Docs" },
6
+ description: {
7
+ en: "Beautiful documentation sites built with Nuxt and ginko-content.",
8
+ de: "Schöne Dokumentations-Websites auf Basis von Nuxt und ginko-content.",
9
+ },
10
+ url: "http://localhost:3000",
11
+ logo: { light: "/logo.svg", dark: "/logo-dark.svg" },
12
+ localeSwitcher: "dropdown",
13
+ docsSidebarSwitcher: "tabs",
14
+ lupinumAttribution: true,
15
+ },
16
+ nav: { links: "auto" },
17
+ banner: {
18
+ enabled: "auto",
19
+ id: "default",
20
+ showOnLanding: true,
21
+ },
22
+ social: {},
23
+ feedback: { enabled: false },
24
+ ogImage: { enabled: true, component: "GinkoDocs" },
25
+ markdownActions: { chatGpt: true, claude: true, mcp: true },
26
+ images: { zoom: true },
27
+ toc: { depth: 3 },
28
+ repository: undefined,
29
+ landing: {
30
+ eyebrow: {
31
+ en: "Documentation for humans and agents",
32
+ de: "Dokumentation für Menschen und Agenten",
33
+ },
34
+ title: {
35
+ en: "Documentation that feels finished.",
36
+ de: "Dokumentation, die sich fertig anfühlt.",
37
+ },
38
+ description: {
39
+ en: "A focused Nuxt layer for fast, searchable, multilingual documentation sites.",
40
+ de: "Ein fokussierter Nuxt-Layer für schnelle, durchsuchbare, mehrsprachige Dokumentations-Websites.",
41
+ },
42
+ primary: {
43
+ label: { en: "Get started", de: "Erste Schritte" },
44
+ to: { en: "/docs", de: "/de/dokumentation" },
45
+ },
46
+ features: [],
47
+ },
48
+ } satisfies GinkoDocsAppConfig,
49
+ };
package/app/app.vue ADDED
@@ -0,0 +1,71 @@
1
+ <script setup lang="ts">
2
+ import { getLocalizedSiteText } from "#ginko-docs/config/site.utils";
3
+ import { useAppConfig, useHead, useI18n, useRoute, useSeoMeta } from "#imports";
4
+ import { useLocalizedRouteSwitch } from "#ginko-docs/composables/useLocalizedRouteSwitch";
5
+ import { useCanonicalUrl } from "#ginko-docs/composables/useCanonicalUrl";
6
+ import { useGinkoAnalytics } from "#ginko-docs/composables/useGinkoAnalytics";
7
+ import { useGinkoOgImage } from "#ginko-docs/composables/useGinkoOgImage";
8
+ import { useSchemaJsonLd } from "#ginko-docs/composables/useSchemaJsonLd";
9
+ import { defaultLocale } from "../i18n/locales";
10
+
11
+ const canonicalUrl = useCanonicalUrl();
12
+ const { locale, locales } = useI18n();
13
+ const route = useRoute();
14
+ const { switchPathname } = useLocalizedRouteSwitch();
15
+ const docsConfig = useAppConfig().ginkoDocs;
16
+ const siteUrl = docsConfig.site.url;
17
+
18
+ useSeoMeta({
19
+ ogUrl: canonicalUrl,
20
+ twitterCard: "summary_large_image",
21
+ });
22
+
23
+ // Site-wide baseline: every route gets a generated PNG social card, with the
24
+ // title/description auto-derived from the page's own useSeoMeta values.
25
+ useGinkoOgImage({ locale: locale.value });
26
+ useGinkoAnalytics();
27
+
28
+ useSchemaJsonLd(() => [
29
+ {
30
+ "@type": "WebSite",
31
+ name: getLocalizedSiteText(docsConfig.site.name, locale.value),
32
+ description: getLocalizedSiteText(docsConfig.site.description, locale.value),
33
+ url: siteUrl,
34
+ inLanguage: locale.value,
35
+ },
36
+ ]);
37
+
38
+ useHead(() => ({
39
+ htmlAttrs: {
40
+ lang: locale.value,
41
+ },
42
+ link: [
43
+ { key: "canonical", rel: "canonical", href: canonicalUrl.value },
44
+ ...locales.value.map((entry) => {
45
+ const code = typeof entry === "string" ? entry : entry.code;
46
+ const language = typeof entry === "string" ? entry : (entry.language ?? entry.code);
47
+ return {
48
+ key: `alternate-${code}`,
49
+ rel: "alternate",
50
+ hreflang: language,
51
+ href: new URL(switchPathname(code) || route.path, siteUrl).toString(),
52
+ };
53
+ }),
54
+ {
55
+ key: "alternate-x-default",
56
+ rel: "alternate",
57
+ hreflang: "x-default",
58
+ href: new URL(switchPathname(defaultLocale) || route.path, siteUrl).toString(),
59
+ },
60
+ ],
61
+ }));
62
+ </script>
63
+
64
+ <template>
65
+ <div role="region" aria-label="Route announcements" aria-live="polite" class="sr-only">
66
+ <NuxtRouteAnnouncer />
67
+ </div>
68
+ <NuxtLayout>
69
+ <NuxtPage />
70
+ </NuxtLayout>
71
+ </template>