@lupinum/ginko-docs 0.3.0-rc.5 → 0.3.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.
@@ -11,9 +11,10 @@ import { cn } from "#ginko-docs/utils";
11
11
  import { computed } from "vue";
12
12
  import { useI18n } from "#imports";
13
13
  import { useLocalizedRouteSwitch } from "#ginko-docs/composables/useLocalizedRouteSwitch";
14
+ import { headerUtilityButtonClass } from "#ginko-docs/components/site/header-utils";
14
15
  import { locales as configuredLocales } from "../../../i18n/locales";
15
16
 
16
- type LocaleSwitcherVariant = "dropdown" | "menu-row" | "menu-tile" | "segmented" | "pill";
17
+ type LocaleSwitcherVariant = "dropdown" | "menu-row";
17
18
 
18
19
  type LocaleEntry = {
19
20
  code: string;
@@ -21,7 +22,6 @@ type LocaleEntry = {
21
22
  name?: string;
22
23
  nativeName?: string;
23
24
  shortLabel?: string;
24
- flagIcon?: string;
25
25
  };
26
26
 
27
27
  const props = withDefaults(
@@ -56,7 +56,6 @@ function normalizeLocale(entry: string | LocaleEntry) {
56
56
  name: configured?.name ?? entry.toUpperCase(),
57
57
  nativeName: configured?.nativeName ?? configured?.name ?? entry.toUpperCase(),
58
58
  shortLabel: configured?.shortLabel ?? entry.toUpperCase(),
59
- flagIcon: configured?.flagIcon,
60
59
  };
61
60
  }
62
61
 
@@ -68,7 +67,6 @@ function normalizeLocale(entry: string | LocaleEntry) {
68
67
  nativeName:
69
68
  entry.nativeName ?? entry.name ?? configured?.nativeName ?? entry.code.toUpperCase(),
70
69
  shortLabel: entry.shortLabel ?? configured?.shortLabel ?? entry.code.toUpperCase(),
71
- flagIcon: entry.flagIcon ?? configured?.flagIcon,
72
70
  };
73
71
  }
74
72
 
@@ -86,11 +84,6 @@ const localeLinks = computed(() =>
86
84
  const currentLocale = computed(
87
85
  () => localeLinks.value.find((entry) => entry.current) ?? localeLinks.value[0],
88
86
  );
89
- const currentMobileLocaleLabel = computed(() => {
90
- const code = currentLocale.value?.code;
91
- if (!code) return "";
92
- return currentLocale.value?.name ?? code.toUpperCase();
93
- });
94
87
 
95
88
  function trackLocaleNavigation(_entry: { code: string; current: boolean; to: unknown }) {
96
89
  emit("navigate");
@@ -105,22 +98,11 @@ function trackLocaleNavigation(_entry: { code: string; current: boolean; to: unk
105
98
  <ClientOnly>
106
99
  <DropdownMenu>
107
100
  <DropdownMenuTrigger as-child>
108
- <Button variant="ghost" class="h-9 gap-1.5 px-2.5" :aria-label="t('nav.language')">
109
- <Icon
110
- v-if="currentLocale?.flagIcon"
111
- :name="currentLocale.flagIcon"
112
- class="size-4 rounded-full"
113
- aria-hidden="true"
114
- />
115
- <span class="text-xs font-semibold">{{ currentLocale?.shortLabel }}</span>
116
- <Icon
117
- name="lucide:chevron-down"
118
- class="size-3.5 text-muted-foreground"
119
- aria-hidden="true"
120
- />
121
- </Button>
101
+ <button type="button" :class="headerUtilityButtonClass" :aria-label="t('nav.language')">
102
+ <Icon name="lucide:languages" class="size-[18px]" aria-hidden="true" />
103
+ </button>
122
104
  </DropdownMenuTrigger>
123
- <DropdownMenuContent align="end" class="w-44">
105
+ <DropdownMenuContent align="end" class="w-52">
124
106
  <DropdownMenuItem v-for="entry in localeLinks" :key="entry.code" as-child>
125
107
  <NuxtLink
126
108
  :to="entry.to"
@@ -128,17 +110,13 @@ function trackLocaleNavigation(_entry: { code: string; current: boolean; to: unk
128
110
  :lang="entry.code"
129
111
  :aria-label="entry.name"
130
112
  :aria-current="entry.current ? 'page' : undefined"
131
- class="flex w-full items-center gap-2"
113
+ class="flex w-full items-center gap-3"
132
114
  @click="trackLocaleNavigation(entry)"
133
115
  >
134
- <Icon
135
- v-if="entry.flagIcon"
136
- :name="entry.flagIcon"
137
- class="size-4 rounded-full"
138
- aria-hidden="true"
139
- />
116
+ <span class="w-7 text-xs font-semibold tracking-wide text-muted-foreground">{{
117
+ entry.shortLabel
118
+ }}</span>
140
119
  <span class="flex-1">{{ entry.nativeName }}</span>
141
- <span class="text-xs text-muted-foreground">{{ entry.shortLabel }}</span>
142
120
  <Icon
143
121
  v-if="entry.current"
144
122
  name="lucide:check"
@@ -151,76 +129,39 @@ function trackLocaleNavigation(_entry: { code: string; current: boolean; to: unk
151
129
  </DropdownMenu>
152
130
 
153
131
  <template #fallback>
154
- <!-- Reserves the trigger's box before hydration. -->
155
- <span class="inline-flex h-9 w-[4.25rem] rounded-md" aria-hidden="true" />
132
+ <span class="inline-flex size-9 shrink-0 rounded-lg" aria-hidden="true" />
156
133
  </template>
157
134
  </ClientOnly>
158
135
  </div>
159
136
 
160
137
  <div
161
- v-else-if="
162
- localeLinks.length > 1 &&
163
- (variant === 'menu-row' || variant === 'menu-tile' || variant === 'pill')
164
- "
138
+ v-else-if="localeLinks.length > 1 && variant === 'menu-row'"
165
139
  :class="cn('items-center', props.class)"
166
140
  >
167
141
  <DropdownMenu>
168
142
  <DropdownMenuTrigger as-child>
169
143
  <Button
170
- v-if="variant === 'pill'"
171
- variant="outline"
172
- class="h-9 gap-2 rounded-full px-4 text-sm font-semibold"
173
- :aria-label="t('nav.language')"
174
- >
175
- <Icon
176
- v-if="currentLocale?.flagIcon"
177
- :name="currentLocale.flagIcon"
178
- class="size-4 rounded-full"
179
- aria-hidden="true"
180
- />
181
- <span>{{ currentLocale?.shortLabel }}</span>
182
- </Button>
183
- <Button
184
- v-else
185
144
  variant="ghost"
186
- :class="
187
- cn(
188
- variant === 'menu-tile'
189
- ? 'h-14 w-full justify-between rounded-none px-3.5 text-sm font-semibold hover:bg-muted/40'
190
- : 'h-[4.25rem] w-full justify-between rounded-none px-5 text-base font-semibold hover:bg-transparent',
191
- )
192
- "
145
+ class="h-14 w-full justify-between rounded-none px-5 text-base font-semibold hover:bg-transparent"
193
146
  :aria-label="t('nav.language')"
194
147
  >
195
- <span
196
- class="flex min-w-0 items-center"
197
- :class="variant === 'menu-tile' ? 'gap-3' : 'gap-4'"
198
- >
148
+ <span class="flex min-w-0 items-center gap-4">
199
149
  <span
200
- v-if="variant === 'menu-tile' && currentLocale?.flagIcon"
201
- class="flex size-8 shrink-0 items-center justify-center rounded-lg bg-muted/60"
150
+ class="flex size-11 shrink-0 items-center justify-center rounded-lg bg-muted/60 text-foreground"
202
151
  >
203
- <Icon :name="currentLocale.flagIcon" class="size-5 rounded-full" aria-hidden="true" />
204
- </span>
205
- <Icon
206
- v-else-if="currentLocale?.flagIcon"
207
- :name="currentLocale.flagIcon"
208
- class="size-7 shrink-0 rounded-full"
209
- aria-hidden="true"
210
- />
211
- <span class="truncate">
212
- {{ variant === "menu-tile" ? currentMobileLocaleLabel : currentLocale?.shortLabel }}
152
+ <Icon name="lucide:languages" class="size-5" aria-hidden="true" />
213
153
  </span>
154
+ <span class="truncate">{{ t("nav.languageLabel") }}</span>
155
+ </span>
156
+ <span class="flex items-center gap-2 text-muted-foreground">
157
+ <span class="text-sm font-semibold text-foreground">{{
158
+ currentLocale?.nativeName
159
+ }}</span>
160
+ <Icon name="lucide:chevron-down" class="size-5" aria-hidden="true" />
214
161
  </span>
215
- <Icon
216
- name="lucide:chevron-down"
217
- class="text-muted-foreground"
218
- :class="variant === 'menu-tile' ? 'size-4' : 'size-5'"
219
- aria-hidden="true"
220
- />
221
162
  </Button>
222
163
  </DropdownMenuTrigger>
223
- <DropdownMenuContent align="end" class="w-44" portal-disabled>
164
+ <DropdownMenuContent align="end" class="w-52" portal-disabled>
224
165
  <DropdownMenuItem v-for="entry in localeLinks" :key="entry.code" as-child>
225
166
  <NuxtLink
226
167
  :to="entry.to"
@@ -228,17 +169,13 @@ function trackLocaleNavigation(_entry: { code: string; current: boolean; to: unk
228
169
  :lang="entry.code"
229
170
  :aria-label="entry.name"
230
171
  :aria-current="entry.current ? 'page' : undefined"
231
- class="flex w-full items-center gap-2"
172
+ class="flex w-full items-center gap-3"
232
173
  @click="trackLocaleNavigation(entry)"
233
174
  >
234
- <Icon
235
- v-if="entry.flagIcon"
236
- :name="entry.flagIcon"
237
- class="size-4 rounded-full"
238
- aria-hidden="true"
239
- />
175
+ <span class="w-7 text-xs font-semibold tracking-wide text-muted-foreground">{{
176
+ entry.shortLabel
177
+ }}</span>
240
178
  <span class="flex-1">{{ entry.nativeName }}</span>
241
- <span class="text-xs text-muted-foreground">{{ entry.shortLabel }}</span>
242
179
  <Icon
243
180
  v-if="entry.current"
244
181
  name="lucide:check"
@@ -250,35 +187,4 @@ function trackLocaleNavigation(_entry: { code: string; current: boolean; to: unk
250
187
  </DropdownMenuContent>
251
188
  </DropdownMenu>
252
189
  </div>
253
-
254
- <div
255
- v-else-if="localeLinks.length > 1"
256
- :class="cn('items-center gap-1 rounded-md border border-border p-0.5', props.class)"
257
- :aria-label="t('nav.language')"
258
- >
259
- <NuxtLink
260
- v-for="entry in localeLinks"
261
- :key="entry.code"
262
- :to="entry.to"
263
- :hreflang="entry.language"
264
- :lang="entry.code"
265
- :aria-label="entry.name"
266
- :aria-current="entry.current ? 'page' : undefined"
267
- class="inline-flex h-8 items-center gap-1.5 rounded px-2 text-xs font-medium transition-colors"
268
- :class="
269
- entry.current
270
- ? 'bg-muted text-foreground'
271
- : 'text-muted-foreground hover:bg-muted/60 hover:text-foreground'
272
- "
273
- @click="trackLocaleNavigation(entry)"
274
- >
275
- <Icon
276
- v-if="entry.flagIcon"
277
- :name="entry.flagIcon"
278
- class="size-4 rounded-full"
279
- aria-hidden="true"
280
- />
281
- <span>{{ entry.shortLabel }}</span>
282
- </NuxtLink>
283
- </div>
284
190
  </template>
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
- import { Button } from "#ginko-docs/components/ui/button";
3
2
  import { useSiteNavigation } from "#ginko-docs/composables/useSiteNavigation";
3
+ import { headerUtilityButtonClass } from "#ginko-docs/components/site/header-utils";
4
4
 
5
5
  const { socialLinks } = useSiteNavigation();
6
6
 
@@ -9,23 +9,17 @@ defineEmits<{ navigate: [] }>();
9
9
 
10
10
  <template>
11
11
  <div v-if="socialLinks.length" class="flex items-center">
12
- <Button
12
+ <NuxtLink
13
13
  v-for="link in socialLinks"
14
14
  :key="link.href"
15
- as-child
16
- variant="ghost"
17
- size="icon"
18
- class="text-muted-foreground hover:text-foreground"
15
+ :to="link.href"
16
+ target="_blank"
17
+ rel="noopener noreferrer"
18
+ :aria-label="link.label"
19
+ :class="headerUtilityButtonClass"
20
+ @click="$emit('navigate')"
19
21
  >
20
- <NuxtLink
21
- :to="link.href"
22
- target="_blank"
23
- rel="noopener noreferrer"
24
- :aria-label="link.label"
25
- @click="$emit('navigate')"
26
- >
27
- <Icon :name="link.icon ?? 'lucide:link'" class="size-[18px]" aria-hidden="true" />
28
- </NuxtLink>
29
- </Button>
22
+ <Icon :name="link.icon ?? 'lucide:link'" class="size-[18px]" aria-hidden="true" />
23
+ </NuxtLink>
30
24
  </div>
31
25
  </template>
@@ -0,0 +1,3 @@
1
+ /** Shared ghost geometry for header utility controls (theme, locale, social). */
2
+ export const headerUtilityButtonClass =
3
+ "inline-flex size-9 shrink-0 items-center justify-center rounded-lg text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring outline-none";
@@ -0,0 +1,18 @@
1
+ export type RenderedColorMode = "light" | "dark";
2
+ /**
3
+ * Next stored preference for a two-state theme toggle.
4
+ *
5
+ * The page follows the operating system until the first interaction. After
6
+ * that interaction, the reader's explicit light or dark choice remains fixed.
7
+ */
8
+ export function nextColorModePreference(currentRendered: RenderedColorMode): RenderedColorMode {
9
+ return currentRendered === "dark" ? "light" : "dark";
10
+ }
11
+
12
+ export function themeToggleIcon(isDark: boolean) {
13
+ return isDark ? "lucide:moon" : "lucide:sun";
14
+ }
15
+
16
+ export function themeToggleLabelKey(isDark: boolean) {
17
+ return isDark ? "theme.switchToLight" : "theme.switchToDark";
18
+ }
@@ -1,7 +1,7 @@
1
1
  import { useLocalStorage } from "@vueuse/core";
2
2
  import { useContentSearch } from "@lupinum/ginko-content/client";
3
3
  import { computed, watch } from "vue";
4
- import { navigateTo, useI18n, useRoute, useState } from "#imports";
4
+ import { navigateTo, useI18n, useState } from "#imports";
5
5
  import { useLocalizedPath } from "#ginko-docs/composables/useLocalizedPath";
6
6
  import { useSiteNavigation } from "#ginko-docs/composables/useSiteNavigation";
7
7
  import {
@@ -56,7 +56,6 @@ function flattenNavItems(items: DocsNavigationItem[]): DocsNavigationItem[] {
56
56
  }
57
57
 
58
58
  export async function useCommandCenter() {
59
- const route = useRoute();
60
59
  const { locale, t } = useI18n();
61
60
  const localizedPath = useLocalizedPath();
62
61
  const {
@@ -279,13 +278,6 @@ export async function useCommandCenter() {
279
278
  searchQuery.value = value;
280
279
  });
281
280
 
282
- watch(
283
- () => route.fullPath,
284
- () => {
285
- closeCommandCenter();
286
- },
287
- );
288
-
289
281
  return {
290
282
  open,
291
283
  query,
@@ -7,6 +7,7 @@ export default defineNuxtPlugin(() => {
7
7
  htmlAttrs: {
8
8
  "data-neutral": theme.neutral,
9
9
  "data-primary": theme.primary,
10
+ "data-code-blocks": theme.codeBlocks,
10
11
  },
11
12
  });
12
13
  });
@@ -13,6 +13,11 @@ export const nav = {
13
13
  openMenu: { de: "Menü öffnen", en: "Open menu" },
14
14
  closeMenu: { de: "Menü schließen", en: "Close menu" },
15
15
  search: { de: "Suchen", en: "Search" },
16
+ searchDocumentation: {
17
+ de: "Dokumentation durchsuchen…",
18
+ en: "Search documentation…",
19
+ },
20
+ languageLabel: { de: "Sprache", en: "Language" },
16
21
  resources: { de: "Ressourcen", en: "Resources" },
17
22
  company: { de: "Unternehmen", en: "Company" },
18
23
  documentation: { de: "Dokumentation", en: "Documentation" },
@@ -1,6 +1,8 @@
1
1
  export const theme = {
2
2
  label: { de: "Darstellung", en: "Appearance" },
3
3
  toggle: { de: "Darstellung umschalten", en: "Toggle theme" },
4
+ switchToDark: { de: "Zu Dunkelmodus wechseln", en: "Switch to dark mode" },
5
+ switchToLight: { de: "Zu Hellmodus wechseln", en: "Switch to light mode" },
4
6
  light: { de: "Hell", en: "Light" },
5
7
  dark: { de: "Dunkel", en: "Dark" },
6
8
  system: { de: "System", en: "System" },
package/icon-bundle.ts CHANGED
@@ -4,6 +4,7 @@ export const layerIconNames = [
4
4
  "circle-flags:de",
5
5
  "circle-flags:us",
6
6
  "logos:bun",
7
+ "logos:discord-icon",
7
8
  "logos:npm-icon",
8
9
  "logos:nuxt-icon",
9
10
  "logos:pnpm",
@@ -52,6 +53,7 @@ export const layerIconNames = [
52
53
  "lucide:info",
53
54
  "lucide:lightbulb",
54
55
  "lucide:link",
56
+ "lucide:languages",
55
57
  "lucide:linkedin",
56
58
  "lucide:loader-circle",
57
59
  "lucide:list",
package/index.d.ts CHANGED
@@ -1,4 +1,8 @@
1
1
  import type { GinkoDocsAppConfig } from "./shared/types/app-config";
2
+ import type {
3
+ GinkoDocsNuxtConfig,
4
+ GinkoDocsSyntaxHighlightingConfig,
5
+ } from "./shared/types/nuxt-config";
2
6
 
3
7
  type GinkoDocsAppConfigInput<T> = T extends readonly unknown[]
4
8
  ? T
@@ -14,6 +18,20 @@ declare module "nuxt/schema" {
14
18
  interface AppConfigInput {
15
19
  ginkoDocs?: GinkoDocsAppConfigInput<GinkoDocsAppConfig>;
16
20
  }
21
+
22
+ interface NuxtConfig {
23
+ ginkoDocs?: GinkoDocsNuxtConfig;
24
+ }
25
+
26
+ interface NuxtOptions {
27
+ ginkoDocs?: GinkoDocsNuxtConfig;
28
+ }
29
+
30
+ interface PublicRuntimeConfig {
31
+ ginkoDocs?: {
32
+ syntaxHighlighting?: GinkoDocsSyntaxHighlightingConfig;
33
+ };
34
+ }
17
35
  }
18
36
 
19
37
  export {};
@@ -0,0 +1,120 @@
1
+ import { defineNuxtModule } from "@nuxt/kit";
2
+ import { bundledThemes } from "shiki";
3
+ import type { BundledTheme } from "shiki";
4
+ import type {
5
+ GinkoDocsSyntaxHighlightingConfig,
6
+ GinkoDocsNuxtConfig,
7
+ } from "../shared/types/nuxt-config";
8
+
9
+ export const DEFAULT_SYNTAX_THEMES = {
10
+ light: "light-plus",
11
+ dark: "dark-plus",
12
+ } as const satisfies GinkoDocsSyntaxHighlightingConfig["themes"];
13
+
14
+ type ShikiPluginOptions = {
15
+ preStyles?: boolean;
16
+ transformers?: unknown[];
17
+ themes?: { light: unknown; dark: unknown };
18
+ };
19
+
20
+ type MarkdownPlugin = string | [string, Record<string, unknown>?];
21
+
22
+ export async function resolveBundledTheme(name: string, configPath: string) {
23
+ const loader = bundledThemes[name as BundledTheme];
24
+ if (!loader) {
25
+ throw new Error(
26
+ `Invalid Ginko Docs syntax theme "${name}".\n\nExpected a bundled Shiki theme name at:\n${configPath}`,
27
+ );
28
+ }
29
+
30
+ const mod = await loader();
31
+ return mod.default ?? mod;
32
+ }
33
+
34
+ export function findShikiPlugin(plugins: MarkdownPlugin[]) {
35
+ for (let index = 0; index < plugins.length; index += 1) {
36
+ const plugin = plugins[index];
37
+ if (plugin === "shiki") {
38
+ return { index, options: {} as ShikiPluginOptions };
39
+ }
40
+ if (Array.isArray(plugin) && plugin[0] === "shiki") {
41
+ return { index, options: (plugin[1] ?? {}) as ShikiPluginOptions };
42
+ }
43
+ }
44
+ return null;
45
+ }
46
+
47
+ export function countShikiPlugins(plugins: MarkdownPlugin[]) {
48
+ return plugins.filter(
49
+ (plugin) => plugin === "shiki" || (Array.isArray(plugin) && plugin[0] === "shiki"),
50
+ ).length;
51
+ }
52
+
53
+ export async function patchShikiThemes(
54
+ plugins: MarkdownPlugin[],
55
+ themes: GinkoDocsSyntaxHighlightingConfig["themes"],
56
+ ) {
57
+ const shiki = findShikiPlugin(plugins);
58
+ if (!shiki) {
59
+ throw new Error("Ginko Docs could not locate the Shiki Markdown plugin to patch.");
60
+ }
61
+
62
+ const [light, dark] = await Promise.all([
63
+ resolveBundledTheme(themes.light, "ginkoDocs.syntaxHighlighting.themes.light"),
64
+ resolveBundledTheme(themes.dark, "ginkoDocs.syntaxHighlighting.themes.dark"),
65
+ ]);
66
+
67
+ shiki.options.themes = { light, dark };
68
+
69
+ const plugin = plugins[shiki.index];
70
+ if (Array.isArray(plugin)) {
71
+ plugin[1] = shiki.options;
72
+ } else {
73
+ plugins[shiki.index] = ["shiki", shiki.options];
74
+ }
75
+ }
76
+
77
+ export function mergeSyntaxRuntimeConfig(
78
+ current: Record<string, unknown> | undefined,
79
+ themes: GinkoDocsSyntaxHighlightingConfig["themes"],
80
+ ) {
81
+ return {
82
+ ...current,
83
+ syntaxHighlighting: {
84
+ themes: {
85
+ light: themes.light,
86
+ dark: themes.dark,
87
+ },
88
+ },
89
+ };
90
+ }
91
+
92
+ export default defineNuxtModule<GinkoDocsNuxtConfig>({
93
+ meta: {
94
+ name: "ginko-docs-syntax-highlighting",
95
+ configKey: "ginkoDocs",
96
+ },
97
+ async setup(options, nuxt) {
98
+ const themes = options.syntaxHighlighting?.themes ?? DEFAULT_SYNTAX_THEMES;
99
+
100
+ nuxt.options.runtimeConfig.public.ginkoDocs = mergeSyntaxRuntimeConfig(
101
+ nuxt.options.runtimeConfig.public.ginkoDocs,
102
+ themes,
103
+ );
104
+
105
+ if (!options.syntaxHighlighting) return;
106
+
107
+ const content = nuxt.options.content;
108
+ if (!content) {
109
+ throw new Error("Ginko Docs could not locate the content module configuration.");
110
+ }
111
+
112
+ content.markdown ??= {};
113
+ content.markdown.plugins ??= [];
114
+
115
+ await patchShikiThemes(
116
+ content.markdown.plugins as MarkdownPlugin[],
117
+ options.syntaxHighlighting.themes,
118
+ );
119
+ },
120
+ });
package/nuxt.config.ts CHANGED
@@ -34,6 +34,7 @@ export default defineNuxtConfig({
34
34
  alias: { "#ginko-docs": app },
35
35
  css: [join(app, "assets/css/tailwind.css"), join(app, "assets/css/prose.css")],
36
36
  modules: [
37
+ join(root, "modules/syntax-highlighting"),
37
38
  join(root, "modules/feature-routing"),
38
39
  "@nuxt/icon",
39
40
  "@nuxt/fonts",
@@ -55,7 +56,7 @@ export default defineNuxtConfig({
55
56
  },
56
57
  mcp: {
57
58
  name: "Ginko Docs",
58
- version: "0.3.0-rc.5",
59
+ version: "0.3.0",
59
60
  },
60
61
  components: {
61
62
  dirs: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lupinum/ginko-docs",
3
- "version": "0.3.0-rc.5",
3
+ "version": "0.3.0",
4
4
  "description": "A Nuxt documentation layer powered by Ginko Content.",
5
5
  "keywords": [
6
6
  "content",
@@ -48,7 +48,8 @@
48
48
  "default": "./content.js"
49
49
  },
50
50
  "./app-config": "./shared/types/app-config.ts",
51
- "./components": "./components.ts"
51
+ "./components": "./components.ts",
52
+ "./nuxt-config": "./shared/types/nuxt-config.ts"
52
53
  },
53
54
  "publishConfig": {
54
55
  "access": "public"
@@ -4,6 +4,7 @@ import type { GinkoDocsNeutralPalette, GinkoDocsPrimaryPalette } from "../theme-
4
4
  export type GinkoDocsLocalizedText = string | { en: string; de?: string };
5
5
 
6
6
  export type GinkoDocsProseAppearance = "quiet" | "tint";
7
+ export type GinkoDocsCodeBlockTheme = "dark" | "adaptive";
7
8
  export type GinkoDocsProseFamily =
8
9
  | "callout"
9
10
  | "aside"
@@ -62,6 +63,7 @@ export interface GinkoDocsAppConfig {
62
63
  theme: {
63
64
  neutral: GinkoDocsNeutralPalette;
64
65
  primary: GinkoDocsPrimaryPalette;
66
+ codeBlocks: GinkoDocsCodeBlockTheme;
65
67
  };
66
68
  prose: GinkoDocsProseConfig;
67
69
  site: {
@@ -0,0 +1,14 @@
1
+ import type { BundledTheme } from "shiki";
2
+
3
+ export type GinkoDocsSyntaxTheme = BundledTheme;
4
+
5
+ export interface GinkoDocsSyntaxHighlightingConfig {
6
+ themes: {
7
+ light: GinkoDocsSyntaxTheme;
8
+ dark: GinkoDocsSyntaxTheme;
9
+ };
10
+ }
11
+
12
+ export interface GinkoDocsNuxtConfig {
13
+ syntaxHighlighting?: GinkoDocsSyntaxHighlightingConfig;
14
+ }