@lupinum/ginko-docs 0.4.0-rc.3 → 0.4.0-rc.5

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.
package/README.md CHANGED
@@ -29,7 +29,7 @@ Use this package when a Nuxt application needs documentation routes, navigation,
29
29
  ## Installation
30
30
 
31
31
  ```bash
32
- pnpm add -D @lupinum/ginko-docs@0.4.0-rc.3 @lupinum/ginko-content@1.0.0-beta.5
32
+ pnpm add -D @lupinum/ginko-docs@0.4.0-rc.5 @lupinum/ginko-content@1.0.0-beta.5
33
33
  ```
34
34
 
35
35
  ```ts
package/app/app.config.ts CHANGED
@@ -2,6 +2,7 @@ import type { GinkoDocsAppConfig } from "../shared/types/app-config";
2
2
  export default {
3
3
  ginkoDocs: {
4
4
  theme: {
5
+ preset: "default",
5
6
  neutral: "zinc",
6
7
  primary: "neutral",
7
8
  codeBlocks: "dark",
@@ -1,6 +1,7 @@
1
1
  @import "tailwindcss";
2
2
  @import "tw-animate-css";
3
3
  @import "./theme-palettes.css";
4
+ @import "./theme-presets.css";
4
5
  @source "../../**/*.{vue,ts}";
5
6
 
6
7
  @custom-variant dark (&:is(.dark *));
@@ -29,6 +30,8 @@
29
30
  --color-popover-foreground: var(--popover-foreground);
30
31
  --color-primary: var(--primary);
31
32
  --color-primary-foreground: var(--primary-foreground);
33
+ --color-brand: var(--brand);
34
+ --color-brand-foreground: var(--brand-foreground);
32
35
  --color-secondary: var(--secondary);
33
36
  --color-secondary-foreground: var(--secondary-foreground);
34
37
  --color-muted: var(--muted);
@@ -147,6 +150,8 @@
147
150
  --popover-foreground: var(--theme-neutral-950);
148
151
  --primary: var(--theme-primary-light);
149
152
  --primary-foreground: var(--theme-primary-light-foreground);
153
+ --brand: var(--primary);
154
+ --brand-foreground: var(--primary-foreground);
150
155
  --secondary: var(--theme-neutral-100);
151
156
  --secondary-foreground: var(--theme-neutral-900);
152
157
  --muted: var(--theme-neutral-100);
@@ -223,6 +228,8 @@
223
228
  --popover-foreground: var(--theme-neutral-50);
224
229
  --primary: var(--theme-primary-dark);
225
230
  --primary-foreground: var(--theme-primary-dark-foreground);
231
+ --brand: var(--primary);
232
+ --brand-foreground: var(--primary-foreground);
226
233
  --secondary: var(--theme-neutral-800);
227
234
  --secondary-foreground: var(--theme-neutral-50);
228
235
  --muted: var(--theme-neutral-800);
@@ -0,0 +1,141 @@
1
+ /* Complete visual systems. Presets intentionally override palette selection;
2
+ use the default preset when neutral and primary must be configured alone. */
3
+
4
+ html[data-theme-preset="nuxt"] {
5
+ /* Official Nuxt green scale. */
6
+ --nuxt-green-50: #effdf5;
7
+ --nuxt-green-100: #d9fbe8;
8
+ --nuxt-green-200: #b3f5d1;
9
+ --nuxt-green-300: #75edae;
10
+ --nuxt-green-400: #00dc82;
11
+ --nuxt-green-500: #00c16a;
12
+ --nuxt-green-600: #00a155;
13
+ --nuxt-green-700: #007f45;
14
+ --nuxt-green-800: #016538;
15
+ --nuxt-green-900: #0a5331;
16
+ --nuxt-green-950: #052e16;
17
+
18
+ /* Nuxt uses Slate for neutral surfaces. */
19
+ --theme-neutral-50: var(--color-slate-50);
20
+ --theme-neutral-100: var(--color-slate-100);
21
+ --theme-neutral-200: var(--color-slate-200);
22
+ --theme-neutral-300: var(--color-slate-300);
23
+ --theme-neutral-400: var(--color-slate-400);
24
+ --theme-neutral-500: var(--color-slate-500);
25
+ --theme-neutral-600: var(--color-slate-600);
26
+ --theme-neutral-700: var(--color-slate-700);
27
+ --theme-neutral-800: var(--color-slate-800);
28
+ --theme-neutral-900: var(--color-slate-900);
29
+ --theme-neutral-950: var(--color-slate-950);
30
+
31
+ /* Normal-size text needs the darker green in light mode. */
32
+ --theme-primary-light: var(--nuxt-green-700);
33
+ --theme-primary-light-foreground: #ffffff;
34
+ --theme-primary-light-ring: var(--nuxt-green-600);
35
+ --theme-primary-dark: var(--nuxt-green-400);
36
+ --theme-primary-dark-foreground: var(--nuxt-green-950);
37
+ --theme-primary-dark-ring: var(--nuxt-green-400);
38
+
39
+ /* Brand surfaces can use Nuxt green with its high-contrast navy foreground. */
40
+ --brand: var(--nuxt-green-400);
41
+ --brand-foreground: #020420;
42
+
43
+ --background: #ffffff;
44
+ --foreground: var(--color-slate-900);
45
+ --card: #ffffff;
46
+ --card-foreground: var(--color-slate-900);
47
+ --popover: #ffffff;
48
+ --popover-foreground: var(--color-slate-900);
49
+ --primary: var(--theme-primary-light);
50
+ --primary-foreground: var(--theme-primary-light-foreground);
51
+ --secondary: var(--color-slate-50);
52
+ --secondary-foreground: var(--color-slate-900);
53
+ --muted: var(--color-slate-50);
54
+ --muted-foreground: var(--color-slate-500);
55
+ --accent: var(--color-slate-100);
56
+ --accent-foreground: var(--color-slate-900);
57
+ --border: var(--color-slate-200);
58
+ --input: var(--color-slate-200);
59
+ --ring: var(--nuxt-green-600);
60
+ --code: var(--color-slate-50);
61
+ --code-foreground: var(--color-slate-900);
62
+ --code-border: var(--color-slate-200);
63
+
64
+ --hero-bg: #ffffff;
65
+ --hero-bg-muted: var(--color-slate-50);
66
+ --hero-blue: var(--nuxt-green-400);
67
+ --hero-blue-light: var(--nuxt-green-300);
68
+ --hero-blue-dark: var(--nuxt-green-700);
69
+ --hero-blue-muted: var(--nuxt-green-50);
70
+ --hero-mint: var(--nuxt-green-400);
71
+ --hero-mint-dark: var(--nuxt-green-700);
72
+ --hero-mint-muted: var(--nuxt-green-50);
73
+ --hero-mint-text: var(--nuxt-green-700);
74
+ --hero-yellow: var(--nuxt-green-400);
75
+ --hero-yellow-hover: var(--nuxt-green-500);
76
+ --hero-yellow-dark: var(--nuxt-green-700);
77
+ --hero-yellow-muted: var(--nuxt-green-50);
78
+ --hero-coral: var(--nuxt-green-400);
79
+ --hero-coral-light: var(--nuxt-green-300);
80
+ --hero-coral-dark: var(--nuxt-green-700);
81
+ --hero-coral-muted: var(--nuxt-green-50);
82
+ --hero-coral-text: var(--nuxt-green-700);
83
+ --hero-check: var(--nuxt-green-400);
84
+ --hero-white: #ffffff;
85
+
86
+ --agent-background: var(--color-slate-950);
87
+ --agent-foreground: var(--color-slate-100);
88
+ --agent-muted: var(--color-slate-400);
89
+
90
+ /* Nuxt UI-compatible aliases for consumer-owned examples. */
91
+ --ui-bg: var(--background);
92
+ --ui-bg-muted: var(--muted);
93
+ --ui-bg-elevated: var(--card);
94
+ --ui-bg-accented: var(--accent);
95
+ --ui-border: var(--border);
96
+ --ui-border-muted: var(--border);
97
+ --ui-border-accented: var(--border);
98
+ --ui-text: var(--foreground);
99
+ --ui-text-default: var(--foreground);
100
+ --ui-text-highlighted: var(--foreground);
101
+ --ui-text-muted: var(--muted-foreground);
102
+ --ui-text-dimmed: var(--muted-foreground);
103
+ --ui-text-toned: var(--muted-foreground);
104
+ --ui-primary: var(--primary);
105
+ }
106
+
107
+ html.dark[data-theme-preset="nuxt"] {
108
+ --background: var(--color-slate-950);
109
+ --foreground: var(--color-slate-50);
110
+ --card: var(--color-slate-900);
111
+ --card-foreground: var(--color-slate-50);
112
+ --popover: var(--color-slate-900);
113
+ --popover-foreground: var(--color-slate-50);
114
+ --primary: var(--nuxt-green-400);
115
+ --primary-foreground: var(--nuxt-green-950);
116
+ --secondary: var(--color-slate-900);
117
+ --secondary-foreground: var(--color-slate-50);
118
+ --muted: var(--color-slate-900);
119
+ --muted-foreground: var(--color-slate-400);
120
+ --accent: var(--color-slate-800);
121
+ --accent-foreground: var(--color-slate-50);
122
+ --border: var(--color-slate-800);
123
+ --input: var(--color-slate-700);
124
+ --ring: var(--nuxt-green-400);
125
+ --code: var(--color-slate-900);
126
+ --code-foreground: var(--color-slate-50);
127
+ --code-border: var(--color-slate-800);
128
+
129
+ --hero-bg: var(--color-slate-950);
130
+ --hero-bg-muted: var(--color-slate-900);
131
+ --hero-blue-dark: var(--nuxt-green-400);
132
+ --hero-mint-dark: var(--nuxt-green-400);
133
+ --hero-yellow-dark: var(--nuxt-green-400);
134
+ --hero-coral-dark: var(--nuxt-green-400);
135
+ --hero-blue-muted: color-mix(in oklab, var(--nuxt-green-400) 12%, var(--color-slate-900));
136
+ --hero-mint-muted: var(--hero-blue-muted);
137
+ --hero-yellow-muted: var(--hero-blue-muted);
138
+ --hero-coral-muted: var(--hero-blue-muted);
139
+ --hero-mint-text: var(--nuxt-green-300);
140
+ --hero-coral-text: var(--nuxt-green-300);
141
+ }
@@ -73,7 +73,7 @@ onBeforeUnmount(() => {
73
73
  ref="bannerElement"
74
74
  role="region"
75
75
  :aria-label="banner.text"
76
- class="relative z-30 bg-primary px-10 py-2.5 text-center text-sm leading-5 font-medium text-primary-foreground"
76
+ class="relative z-30 bg-brand px-10 py-2.5 text-center text-sm leading-5 font-medium text-brand-foreground"
77
77
  >
78
78
  <span class="mx-auto block max-w-[min(100%,52rem)]">
79
79
  {{ banner.text }}
@@ -87,7 +87,7 @@ onBeforeUnmount(() => {
87
87
  </span>
88
88
  <button
89
89
  type="button"
90
- class="absolute top-1/2 right-2 flex size-8 -translate-y-1/2 items-center justify-center rounded p-1 opacity-70 transition-opacity hover:opacity-100 focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-primary-foreground/50 focus-visible:outline-none"
90
+ class="absolute top-1/2 right-2 flex size-8 -translate-y-1/2 items-center justify-center rounded p-1 opacity-70 transition-opacity hover:opacity-100 focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-brand-foreground/50 focus-visible:outline-none"
91
91
  :aria-label="t('banner.dismiss')"
92
92
  @click="dismissed = true"
93
93
  >
@@ -127,7 +127,7 @@ useSeoMeta({
127
127
  <div class="mt-10 flex flex-wrap items-center gap-3">
128
128
  <NuxtLink
129
129
  :to="landing.primary.to"
130
- class="inline-flex h-11 items-center gap-2 rounded-md bg-primary px-5 text-sm font-semibold text-primary-foreground transition-transform hover:-translate-y-0.5"
130
+ class="inline-flex h-11 items-center gap-2 rounded-md bg-brand px-5 text-sm font-semibold text-brand-foreground transition-transform hover:-translate-y-0.5"
131
131
  >
132
132
  {{ landing.primary.label }}
133
133
  <Icon name="lucide:arrow-right" class="size-4" aria-hidden="true" />
@@ -240,7 +240,7 @@ useSeoMeta({
240
240
  <div class="mt-9 flex flex-wrap items-center justify-center gap-3">
241
241
  <NuxtLink
242
242
  :to="landing.cta.primary.to"
243
- class="inline-flex h-11 items-center gap-2 rounded-md bg-primary px-5 text-sm font-semibold text-primary-foreground transition-transform hover:-translate-y-0.5"
243
+ class="inline-flex h-11 items-center gap-2 rounded-md bg-brand px-5 text-sm font-semibold text-brand-foreground transition-transform hover:-translate-y-0.5"
244
244
  >
245
245
  {{ landing.cta.primary.label }}
246
246
  <Icon name="lucide:arrow-right" class="size-4" aria-hidden="true" />
@@ -5,6 +5,7 @@ export default defineNuxtPlugin(() => {
5
5
 
6
6
  useHead({
7
7
  htmlAttrs: {
8
+ "data-theme-preset": theme.preset ?? "default",
8
9
  "data-neutral": theme.neutral,
9
10
  "data-primary": theme.primary,
10
11
  "data-code-blocks": theme.codeBlocks,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lupinum/ginko-docs",
3
- "version": "0.4.0-rc.3",
3
+ "version": "0.4.0-rc.5",
4
4
  "description": "A Nuxt documentation layer powered by Ginko Content.",
5
5
  "keywords": [
6
6
  "content",
@@ -74,6 +74,7 @@
74
74
  "@vueuse/core": "^14.4.0",
75
75
  "class-variance-authority": "^0.7.1",
76
76
  "clsx": "^2.1.1",
77
+ "h3": "1.15.11",
77
78
  "motion-v": "^2.3.0",
78
79
  "nitropack": "^2.13.4",
79
80
  "nuxt-og-image": "^6.7.8",
@@ -1,13 +1,10 @@
1
- import { setResponseHeaders } from "h3";
2
1
  import { useAppConfig } from "#imports";
3
2
  import { createGinkoDocsAiCatalog } from "../../utils/mcp-server-card";
4
3
 
5
4
  export default defineEventHandler((event) => {
6
- setResponseHeaders(event, {
7
- "access-control-allow-origin": "*",
8
- "cache-control": "public, max-age=3600",
9
- "content-type": "application/ai-catalog+json; charset=utf-8",
10
- });
5
+ event.node.res.setHeader("access-control-allow-origin", "*");
6
+ event.node.res.setHeader("cache-control", "public, max-age=3600");
7
+ event.node.res.setHeader("content-type", "application/ai-catalog+json; charset=utf-8");
11
8
 
12
9
  return createGinkoDocsAiCatalog(useAppConfig().ginkoDocs.site.url);
13
10
  });
@@ -1,14 +1,11 @@
1
- import { setResponseHeaders } from "h3";
2
1
  import { useAppConfig } from "#imports";
3
2
  import packageMetadata from "../../../package.json" with { type: "json" };
4
3
  import { createGinkoDocsServerCard } from "../../utils/mcp-server-card";
5
4
 
6
5
  export default defineEventHandler((event) => {
7
- setResponseHeaders(event, {
8
- "access-control-allow-origin": "*",
9
- "cache-control": "public, max-age=3600",
10
- "content-type": "application/mcp-server-card+json; charset=utf-8",
11
- });
6
+ event.node.res.setHeader("access-control-allow-origin", "*");
7
+ event.node.res.setHeader("cache-control", "public, max-age=3600");
8
+ event.node.res.setHeader("content-type", "application/mcp-server-card+json; charset=utf-8");
12
9
 
13
10
  return createGinkoDocsServerCard({
14
11
  origin: useAppConfig().ginkoDocs.site.url,
@@ -0,0 +1,3 @@
1
+ export const GINKO_DOCS_THEME_PRESETS = ["default", "nuxt"] as const;
2
+
3
+ export type GinkoDocsThemePreset = (typeof GINKO_DOCS_THEME_PRESETS)[number];
@@ -1,5 +1,7 @@
1
1
  export type { GinkoDocsNeutralPalette, GinkoDocsPrimaryPalette } from "../theme-palettes";
2
+ export type { GinkoDocsThemePreset } from "../theme-presets";
2
3
  import type { GinkoDocsNeutralPalette, GinkoDocsPrimaryPalette } from "../theme-palettes";
4
+ import type { GinkoDocsThemePreset } from "../theme-presets";
3
5
 
4
6
  export type GinkoDocsLocalizedText = string | { en: string; de?: string };
5
7
 
@@ -61,6 +63,8 @@ export type GinkoDocsHeroMedia =
61
63
 
62
64
  export interface GinkoDocsAppConfig {
63
65
  theme: {
66
+ /** Coordinated visual system. A non-default preset owns palette and surface tokens. */
67
+ preset?: GinkoDocsThemePreset;
64
68
  neutral: GinkoDocsNeutralPalette;
65
69
  primary: GinkoDocsPrimaryPalette;
66
70
  codeBlocks: GinkoDocsCodeBlockTheme;