cantip 0.1.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 (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +61 -0
  3. package/app/components/CanvasMount.tsx +62 -0
  4. package/app/components/CodeWrapToggle.tsx +78 -0
  5. package/app/components/FindOnPage.tsx +224 -0
  6. package/app/components/MobileBottomBar.tsx +93 -0
  7. package/app/components/MobileProjectsPanel.tsx +113 -0
  8. package/app/components/PageFloatingMenu.tsx +224 -0
  9. package/app/components/ProjectSwitcher.tsx +124 -0
  10. package/app/components/Search.tsx +930 -0
  11. package/app/components/ShortcutsHelp.tsx +113 -0
  12. package/app/components/Sidebar.tsx +1049 -0
  13. package/app/components/TabBar.tsx +227 -0
  14. package/app/components/Toc.tsx +129 -0
  15. package/app/components/TopBar.tsx +74 -0
  16. package/app/components/theme-toggle.tsx +71 -0
  17. package/app/components/ui/button.tsx +56 -0
  18. package/app/components/ui/card.tsx +55 -0
  19. package/app/components/ui/dropdown-menu.tsx +156 -0
  20. package/app/components/ui/input.tsx +21 -0
  21. package/app/entry.client.tsx +12 -0
  22. package/app/entry.server.tsx +155 -0
  23. package/app/generated/site.ts +19 -0
  24. package/app/generated/slots.ts +10 -0
  25. package/app/generated/theme.generated.css +60 -0
  26. package/app/lib/config/config.server.ts +50 -0
  27. package/app/lib/config/defaults.ts +120 -0
  28. package/app/lib/config/load.ts +82 -0
  29. package/app/lib/config/schema.ts +131 -0
  30. package/app/lib/config/site.ts +43 -0
  31. package/app/lib/content.server.ts +105 -0
  32. package/app/lib/projects.ts +86 -0
  33. package/app/lib/sidebar.server.ts +113 -0
  34. package/app/lib/site.ts +27 -0
  35. package/app/lib/slots.tsx +33 -0
  36. package/app/lib/tabs.tsx +128 -0
  37. package/app/lib/useKeyboardShortcuts.ts +149 -0
  38. package/app/lib/utils.ts +17 -0
  39. package/app/root.tsx +171 -0
  40. package/app/routes/$.tsx +158 -0
  41. package/app/routes/_index.tsx +60 -0
  42. package/app/styles/app.css +461 -0
  43. package/app/styles/obsidian.css +83 -0
  44. package/app/styles/tailwind.css +227 -0
  45. package/cli.js +119 -0
  46. package/components.json +21 -0
  47. package/dist/config.mjs +87 -0
  48. package/dist/generate-content.mjs +1665 -0
  49. package/package.json +112 -0
  50. package/scripts/build-search-index.ts +129 -0
  51. package/scripts/canonical.ts +34 -0
  52. package/scripts/canvas-to-md.ts +73 -0
  53. package/scripts/compile.ts +242 -0
  54. package/scripts/emit-config.ts +163 -0
  55. package/scripts/generate-content.ts +197 -0
  56. package/scripts/obsidian/files.ts +222 -0
  57. package/scripts/obsidian/fs.ts +34 -0
  58. package/scripts/obsidian/generate.ts +36 -0
  59. package/scripts/obsidian/html.ts +17 -0
  60. package/scripts/obsidian/logger.ts +10 -0
  61. package/scripts/obsidian/markdown.ts +56 -0
  62. package/scripts/obsidian/obsidian.ts +229 -0
  63. package/scripts/obsidian/path.ts +60 -0
  64. package/scripts/obsidian/rehype.ts +60 -0
  65. package/scripts/obsidian/remark.ts +712 -0
  66. package/scripts/obsidian/types.ts +31 -0
  67. package/vite.config.ts +62 -0
@@ -0,0 +1,227 @@
1
+ @import 'tailwindcss';
2
+ @import 'tw-animate-css';
3
+
4
+ /* Dark mode is class-based: <html class="dark"> toggled by the theme switch. */
5
+ @custom-variant dark (&:where(.dark, .dark *));
6
+
7
+ /* ── shadcn neutral theme (default palette) ─────────────────────────────── */
8
+ :root {
9
+ --radius: 0.625rem;
10
+ /* Brand color (#4C3FB0) — drives interactive elements: links, buttons, focus rings. */
11
+ --brand: oklch(0.42 0.158 286);
12
+ --background: oklch(1 0 0);
13
+ --foreground: oklch(0.145 0 0);
14
+ --card: oklch(1 0 0);
15
+ --card-foreground: oklch(0.145 0 0);
16
+ --popover: oklch(1 0 0);
17
+ --popover-foreground: oklch(0.145 0 0);
18
+ --primary: var(--brand);
19
+ --primary-foreground: oklch(0.985 0 0);
20
+ --secondary: oklch(0.97 0 0);
21
+ --secondary-foreground: oklch(0.205 0 0);
22
+ --muted: oklch(0.97 0 0);
23
+ --muted-foreground: oklch(0.556 0 0);
24
+ --accent: oklch(0.97 0 0);
25
+ --accent-foreground: oklch(0.205 0 0);
26
+ --destructive: oklch(0.577 0.245 27.325);
27
+ --border: oklch(0.922 0 0);
28
+ --input: oklch(0.922 0 0);
29
+ --ring: oklch(0.708 0 0);
30
+ --sidebar: oklch(0.985 0 0);
31
+ --sidebar-foreground: oklch(0.145 0 0);
32
+ --sidebar-primary: oklch(0.205 0 0);
33
+ --sidebar-primary-foreground: oklch(0.985 0 0);
34
+ --sidebar-accent: oklch(0.97 0 0);
35
+ --sidebar-accent-foreground: oklch(0.205 0 0);
36
+ --sidebar-border: oklch(0.922 0 0);
37
+ --sidebar-ring: oklch(0.708 0 0);
38
+ }
39
+
40
+ .dark {
41
+ /* Lightened brand for contrast against the dark background. */
42
+ --brand: oklch(0.68 0.14 286);
43
+ --background: oklch(0.145 0 0);
44
+ --foreground: oklch(0.985 0 0);
45
+ --card: oklch(0.205 0 0);
46
+ --card-foreground: oklch(0.985 0 0);
47
+ --popover: oklch(0.205 0 0);
48
+ --popover-foreground: oklch(0.985 0 0);
49
+ --primary: var(--brand);
50
+ --primary-foreground: oklch(0.205 0 0);
51
+ --secondary: oklch(0.269 0 0);
52
+ --secondary-foreground: oklch(0.985 0 0);
53
+ --muted: oklch(0.269 0 0);
54
+ --muted-foreground: oklch(0.708 0 0);
55
+ --accent: oklch(0.269 0 0);
56
+ --accent-foreground: oklch(0.985 0 0);
57
+ --destructive: oklch(0.704 0.191 22.216);
58
+ --border: oklch(1 0 0 / 10%);
59
+ --input: oklch(1 0 0 / 15%);
60
+ --ring: oklch(0.556 0 0);
61
+ --sidebar: oklch(0.205 0 0);
62
+ --sidebar-foreground: oklch(0.985 0 0);
63
+ --sidebar-primary: oklch(0.488 0.243 264.376);
64
+ --sidebar-primary-foreground: oklch(0.985 0 0);
65
+ --sidebar-accent: oklch(0.269 0 0);
66
+ --sidebar-accent-foreground: oklch(0.985 0 0);
67
+ --sidebar-border: oklch(1 0 0 / 10%);
68
+ --sidebar-ring: oklch(0.556 0 0);
69
+ }
70
+
71
+ @theme inline {
72
+ --radius-sm: calc(var(--radius) - 4px);
73
+ --radius-md: calc(var(--radius) - 2px);
74
+ --radius-lg: var(--radius);
75
+ --radius-xl: calc(var(--radius) + 4px);
76
+ --color-background: var(--background);
77
+ --color-foreground: var(--foreground);
78
+ --color-card: var(--card);
79
+ --color-card-foreground: var(--card-foreground);
80
+ --color-popover: var(--popover);
81
+ --color-popover-foreground: var(--popover-foreground);
82
+ --color-primary: var(--primary);
83
+ --color-primary-foreground: var(--primary-foreground);
84
+ --color-secondary: var(--secondary);
85
+ --color-secondary-foreground: var(--secondary-foreground);
86
+ --color-muted: var(--muted);
87
+ --color-muted-foreground: var(--muted-foreground);
88
+ --color-accent: var(--accent);
89
+ --color-accent-foreground: var(--accent-foreground);
90
+ --color-destructive: var(--destructive);
91
+ --color-border: var(--border);
92
+ --color-input: var(--input);
93
+ --color-ring: var(--ring);
94
+ --color-sidebar: var(--sidebar);
95
+ --color-sidebar-foreground: var(--sidebar-foreground);
96
+ --color-sidebar-primary: var(--sidebar-primary);
97
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
98
+ --color-sidebar-accent: var(--sidebar-accent);
99
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
100
+ --color-sidebar-border: var(--sidebar-border);
101
+ --color-sidebar-ring: var(--sidebar-ring);
102
+ }
103
+
104
+ @layer base {
105
+ * {
106
+ @apply border-border outline-ring/50;
107
+ }
108
+ body {
109
+ @apply bg-background text-foreground;
110
+ }
111
+ :root {
112
+ --mobile-bar-height: 3.25rem;
113
+ }
114
+
115
+ /* Slim, unobtrusive scrollbars. Firefox. */
116
+ * {
117
+ scrollbar-width: thin;
118
+ scrollbar-color: var(--border) transparent;
119
+ }
120
+ /* WebKit/Blink. */
121
+ *::-webkit-scrollbar {
122
+ width: 6px;
123
+ height: 6px;
124
+ }
125
+ *::-webkit-scrollbar-track {
126
+ background: transparent;
127
+ }
128
+ *::-webkit-scrollbar-thumb {
129
+ background-color: transparent;
130
+ border-radius: 9999px;
131
+ }
132
+ /* Reveal the thumb only while hovering the scrollable area. */
133
+ *:hover::-webkit-scrollbar-thumb {
134
+ background-color: var(--border);
135
+ }
136
+ *::-webkit-scrollbar-thumb:hover {
137
+ background-color: var(--muted-foreground);
138
+ }
139
+ *::-webkit-scrollbar-corner {
140
+ background: transparent;
141
+ }
142
+
143
+ /* Fully hide the native scrollbar (no track, no reserved space). Used by the
144
+ tab strip, which renders its own overlay scrollbar that fades in on hover.
145
+ Unlike the slim scrollbars above, this reserves zero layout space, so the
146
+ tab text never shifts when tabs overflow. */
147
+ .scrollbar-none {
148
+ scrollbar-width: none;
149
+ }
150
+ .scrollbar-none::-webkit-scrollbar {
151
+ width: 0;
152
+ height: 0;
153
+ display: none;
154
+ }
155
+ }
156
+
157
+ /* While the theme is being toggled, kill all transitions/animations so every
158
+ element re-colors instantly (the theme-toggle adds `.theme-switching` to <html>
159
+ for one frame). Without this, elements carrying a hover `transition-colors` /
160
+ `transition-all` (search input, project switcher, home cards, buttons) animate
161
+ their color change and visibly lag behind the sidebar/content, which have no
162
+ transition. Unlayered + !important so it beats the utility-class transitions. */
163
+ html.theme-switching *,
164
+ html.theme-switching *::before,
165
+ html.theme-switching *::after {
166
+ transition: none !important;
167
+ animation: none !important;
168
+ }
169
+
170
+ /* Locate pulse: flashes the active sidebar row when "locate" is pressed. */
171
+ .locate-flash {
172
+ animation: locate-pulse 1s ease-out;
173
+ }
174
+ @keyframes locate-pulse {
175
+ 0% {
176
+ background-color: var(--primary);
177
+ }
178
+ 100% {
179
+ background-color: var(--sidebar-accent);
180
+ }
181
+ }
182
+
183
+ /* ── Bridge: legacy --sl-* tokens → shadcn theme ─────────────────────────────
184
+ The generated markdown HTML and obsidian.css (callouts, tags, highlights)
185
+ still reference --sl-* variables. Rather than rewrite that generated content,
186
+ we redefine the tokens in terms of the shadcn neutral palette so the doc body
187
+ tracks the active theme and the dark/light toggle automatically. */
188
+ :root {
189
+ --sl-color-white: var(--foreground);
190
+ --sl-color-gray-1: var(--foreground);
191
+ --sl-color-gray-2: var(--muted-foreground);
192
+ --sl-color-gray-3: var(--muted-foreground);
193
+ --sl-color-gray-4: var(--border);
194
+ --sl-color-gray-5: var(--border);
195
+ --sl-color-gray-6: var(--muted);
196
+ --sl-color-black: var(--background);
197
+
198
+ --sl-color-accent-low: var(--accent);
199
+ --sl-color-accent: var(--primary);
200
+ --sl-color-accent-high: var(--foreground);
201
+
202
+ --sl-color-bg-nav: var(--sidebar);
203
+ --sl-color-bg-sidebar: var(--sidebar);
204
+ --sl-color-bg-inline-code: var(--muted);
205
+ --sl-color-hairline-light: var(--border);
206
+ --sl-color-hairline: var(--border);
207
+ --sl-color-hairline-shade: var(--muted);
208
+ --sl-color-bg: var(--background);
209
+
210
+ /* Semantic colours used by obsidian callouts — kept as fixed hues so notes /
211
+ tips / cautions / dangers stay legible in both themes. */
212
+ --sl-color-green-low: color-mix(in oklab, oklch(0.6 0.16 150) 12%, var(--background));
213
+ --sl-color-green: oklch(0.6 0.16 150);
214
+ --sl-color-green-high: oklch(0.72 0.17 150);
215
+ --sl-color-orange-low: color-mix(in oklab, oklch(0.7 0.16 70) 12%, var(--background));
216
+ --sl-color-orange: oklch(0.72 0.16 70);
217
+ --sl-color-orange-high: oklch(0.8 0.16 75);
218
+ --sl-color-blue-low: color-mix(in oklab, oklch(0.6 0.18 250) 12%, var(--background));
219
+ --sl-color-blue: oklch(0.6 0.18 250);
220
+ --sl-color-blue-high: oklch(0.72 0.16 250);
221
+ --sl-color-red-low: color-mix(in oklab, oklch(0.62 0.2 25) 12%, var(--background));
222
+ --sl-color-red: oklch(0.62 0.2 25);
223
+ --sl-color-red-high: oklch(0.72 0.18 25);
224
+
225
+ --sl-font: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
226
+ --sl-font-system-mono: ui-monospace, SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace;
227
+ }
package/cli.js ADDED
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `cantip` CLI — drives the docs engine from the USER's project directory.
4
+ *
5
+ * The engine (this package) ships the Remix `app/` + build `scripts/`. The CLI
6
+ * runs them with `cwd = the user's project`, so all artifacts (content/,
7
+ * app/generated/, public/, build/) land in the user's repo while the app code
8
+ * stays in node_modules. Vite/Remix always load the engine's vite.config.ts
9
+ * (which points `appDirectory` at the engine app/ and `publicDir`/build at cwd).
10
+ *
11
+ * Subcommands:
12
+ * cantip generate — ingest vaults + compile + emit manifest/config (from docs.config.ts)
13
+ * cantip dev — generate, then remix vite dev server
14
+ * cantip build — generate, then remix vite production build
15
+ * cantip start — serve the built server (build/server/index.js)
16
+ * cantip typecheck — tsc --noEmit against the engine
17
+ */
18
+ import { spawn } from 'node:child_process'
19
+ import { fileURLToPath } from 'node:url'
20
+ import { existsSync } from 'node:fs'
21
+ import path from 'node:path'
22
+ import process from 'node:process'
23
+
24
+ const ENGINE_DIR = path.dirname(fileURLToPath(import.meta.url))
25
+ const VITE_CONFIG = path.join(ENGINE_DIR, 'vite.config.ts')
26
+ // Prefer the precompiled generator (dist/) — required when installed under
27
+ // node_modules, where Node won't strip types from `.ts`. Fall back to the `.ts`
28
+ // source via the strip-types runner in the monorepo dev setup (symlinked, where
29
+ // dist/ may be absent).
30
+ const GENERATE_JS = path.join(ENGINE_DIR, 'dist', 'generate-content.mjs')
31
+ const GENERATE_TS = path.join(ENGINE_DIR, 'scripts', 'generate-content.ts')
32
+
33
+ /** Run a command inheriting stdio; resolve on exit 0, reject otherwise. */
34
+ function run(cmd, args, opts = {}) {
35
+ return new Promise((resolve, reject) => {
36
+ const child = spawn(cmd, args, { stdio: 'inherit', shell: false, ...opts })
37
+ child.on('error', reject)
38
+ child.on('exit', (code) => (code === 0 ? resolve() : reject(new Error(`${cmd} ${args.join(' ')} exited with ${code}`))))
39
+ })
40
+ }
41
+
42
+ /**
43
+ * Resolve a dependency's CLI binary. npm may install it in the engine's local
44
+ * `node_modules/.bin` OR hoist it to an ancestor `node_modules/.bin` (workspaces).
45
+ * Walk up from the engine dir to find the first `.bin/<name>` that exists; fall
46
+ * back to the bare name so PATH resolution can still find it.
47
+ */
48
+ function engineBin(name) {
49
+ let dir = ENGINE_DIR
50
+ while (true) {
51
+ const candidate = path.join(dir, 'node_modules', '.bin', name)
52
+ if (existsSync(candidate)) return candidate
53
+ const parent = path.dirname(dir)
54
+ if (parent === dir) break
55
+ dir = parent
56
+ }
57
+ return name
58
+ }
59
+
60
+ /** Run the content generator from the user's cwd: compiled dist/ if present, else the .ts source. */
61
+ function generate() {
62
+ const args = existsSync(GENERATE_JS)
63
+ ? [GENERATE_JS]
64
+ : ['--experimental-strip-types', GENERATE_TS]
65
+ return run(process.execPath, args, { cwd: process.cwd() })
66
+ }
67
+
68
+ /**
69
+ * Run the Remix Vite CLI with the engine config from the user's cwd. The vite
70
+ * config sets Vite `root` = cwd (so baked asset paths are cwd-relative and
71
+ * remix-serve finds them) and `appDirectory` = the engine app/. The engine ships
72
+ * explicit entry.server/.client, so Remix skips runtime auto-detection — no
73
+ * REMIX_ROOT override needed.
74
+ */
75
+ function remixVite(sub) {
76
+ return run(engineBin('remix'), ['vite:' + sub, '--config', VITE_CONFIG], {
77
+ cwd: process.cwd(),
78
+ })
79
+ }
80
+
81
+ async function main() {
82
+ const command = process.argv[2]
83
+ switch (command) {
84
+ case 'generate':
85
+ await generate()
86
+ break
87
+ case 'dev':
88
+ await generate()
89
+ await remixVite('dev')
90
+ break
91
+ case 'build':
92
+ await generate()
93
+ await remixVite('build')
94
+ break
95
+ case 'start':
96
+ await run(engineBin('remix-serve'), [path.join(process.cwd(), 'build', 'server', 'index.js')], { cwd: process.cwd() })
97
+ break
98
+ case 'typecheck':
99
+ await run(engineBin('tsc'), ['--noEmit'], { cwd: ENGINE_DIR })
100
+ break
101
+ default:
102
+ console.error(
103
+ `cantip — config-driven Remix docs engine\n\n` +
104
+ `Usage: cantip <command>\n\n` +
105
+ `Commands:\n` +
106
+ ` generate Ingest vaults + compile content from docs.config.ts\n` +
107
+ ` dev Generate, then start the dev server\n` +
108
+ ` build Generate, then build for production\n` +
109
+ ` start Serve the production build\n` +
110
+ ` typecheck Type-check the engine\n`,
111
+ )
112
+ process.exit(command ? 1 : 0)
113
+ }
114
+ }
115
+
116
+ main().catch((err) => {
117
+ console.error(err.message ?? err)
118
+ process.exit(1)
119
+ })
@@ -0,0 +1,21 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "new-york",
4
+ "rsc": false,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "config": "",
8
+ "css": "app/styles/tailwind.css",
9
+ "baseColor": "neutral",
10
+ "cssVariables": true,
11
+ "prefix": ""
12
+ },
13
+ "iconLibrary": "lucide",
14
+ "aliases": {
15
+ "components": "~/components",
16
+ "utils": "~/lib/utils",
17
+ "ui": "~/components/ui",
18
+ "lib": "~/lib",
19
+ "hooks": "~/hooks"
20
+ }
21
+ }
@@ -0,0 +1,87 @@
1
+ // app/lib/config/schema.ts
2
+ import { z } from "zod";
3
+ var colorMap = z.record(z.string(), z.string());
4
+ var projectSchema = z.object({
5
+ /** First id segment + output dir name, e.g. `krista`. */
6
+ id: z.string().min(1),
7
+ /** Display name in the switcher / home cards. */
8
+ name: z.string().min(1),
9
+ /** Directory of markdown/canvas files. Submodule, loose folder, or any path. */
10
+ source: z.string().min(1),
11
+ /** Logo under the user's `/public`. Defaults to `/projects/<id>.svg`. */
12
+ logo: z.string().optional(),
13
+ /** Landing URL when switching to this project. Defaults to its first doc. */
14
+ landing: z.string().optional(),
15
+ /** Short blurb, reused on home cards. */
16
+ description: z.string().default(""),
17
+ /** Ingest `.canvas` files from this source too. */
18
+ canvas: z.boolean().default(false),
19
+ /** Globs (relative to `source`) to skip, e.g. `['CLAUDE.md']`. */
20
+ ignore: z.array(z.string()).default([])
21
+ });
22
+ var generalSchema = z.object({
23
+ enabled: z.boolean().default(false),
24
+ name: z.string().default("\u0411\u0435\u0437 \u043F\u0440\u043E\u0435\u043A\u0442\u0430"),
25
+ /** Directory of loose docs. When unset, the bucket has no docs. */
26
+ source: z.string().optional(),
27
+ logo: z.string().default("/projects/general.svg"),
28
+ description: z.string().default(""),
29
+ ignore: z.array(z.string()).default([])
30
+ });
31
+ var siteSchema = z.object({
32
+ title: z.string().default("Docs"),
33
+ /** Home-page blurb under the title. */
34
+ description: z.string().default(""),
35
+ /** BCP-47-ish tag; drives `localeCompare` sorting + Pagefind `forceLanguage`. */
36
+ lang: z.string().default("ru"),
37
+ favicon: z.string().default("/favicon.svg"),
38
+ logo: z.object({
39
+ light: z.string().default("/iti-logo-light.svg"),
40
+ dark: z.string().default("/iti-logo-dark.svg")
41
+ }).prefault({}),
42
+ defaultTheme: z.enum(["dark", "light"]).default("dark")
43
+ });
44
+ var themeSchema = z.object({
45
+ /** OKLCH (or any CSS color) token overrides, merged OVER the shipped defaults. */
46
+ colors: z.object({
47
+ light: colorMap.default({}),
48
+ dark: colorMap.default({})
49
+ }).prefault({})
50
+ });
51
+ var componentsSchema = z.object({
52
+ Home: z.string().optional(),
53
+ DocPage: z.string().optional(),
54
+ Sidebar: z.string().optional(),
55
+ TopBar: z.string().optional(),
56
+ Toc: z.string().optional(),
57
+ Search: z.string().optional(),
58
+ Layout: z.string().optional()
59
+ }).default({});
60
+ var uiSchema = z.record(z.string(), z.string()).default({});
61
+ var docsConfigSchema = z.object({
62
+ site: siteSchema.prefault({}),
63
+ projects: z.array(projectSchema).default([]),
64
+ general: generalSchema.prefault({}),
65
+ theme: themeSchema.prefault({}),
66
+ components: componentsSchema,
67
+ ui: uiSchema,
68
+ /**
69
+ * Reserved for custom remark/rehype plugins + callout types. NOT wired in this
70
+ * phase (the markdown pipeline stays fixed); accepted so configs are
71
+ * forward-compatible.
72
+ */
73
+ markdown: z.unknown().optional()
74
+ });
75
+ function defineConfig(config) {
76
+ return config;
77
+ }
78
+ export {
79
+ componentsSchema,
80
+ defineConfig,
81
+ docsConfigSchema,
82
+ generalSchema,
83
+ projectSchema,
84
+ siteSchema,
85
+ themeSchema,
86
+ uiSchema
87
+ };