skrypt-ai 0.8.0 → 0.8.1
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/dist/auth/index.js +6 -0
- package/dist/binding/binder.d.ts +5 -0
- package/dist/binding/binder.js +63 -0
- package/dist/binding/detector.d.ts +5 -0
- package/dist/binding/detector.js +51 -0
- package/dist/binding/doc-parser.d.ts +9 -0
- package/dist/binding/doc-parser.js +138 -0
- package/dist/binding/extractor.d.ts +14 -0
- package/dist/binding/extractor.js +39 -0
- package/dist/binding/index.d.ts +5 -0
- package/dist/binding/index.js +5 -0
- package/dist/binding/types.d.ts +74 -0
- package/dist/binding/types.js +1 -0
- package/dist/claims/extractor.d.ts +13 -0
- package/dist/claims/extractor.js +138 -0
- package/dist/claims/index.d.ts +4 -0
- package/dist/claims/index.js +4 -0
- package/dist/claims/reporter.d.ts +9 -0
- package/dist/claims/reporter.js +65 -0
- package/dist/claims/store.d.ts +13 -0
- package/dist/claims/store.js +51 -0
- package/dist/claims/types.d.ts +34 -0
- package/dist/claims/types.js +1 -0
- package/dist/cli.js +516 -56
- package/dist/commands/bind.d.ts +2 -0
- package/dist/commands/bind.js +139 -0
- package/dist/commands/claims.d.ts +2 -0
- package/dist/commands/claims.js +84 -0
- package/dist/commands/coverage.d.ts +2 -0
- package/dist/commands/coverage.js +61 -0
- package/dist/commands/generate/index.js +5 -0
- package/dist/commands/generate/scan.js +33 -14
- package/dist/commands/generate/write.d.ts +7 -0
- package/dist/commands/generate/write.js +65 -1
- package/dist/commands/import.js +12 -3
- package/dist/commands/init.js +68 -5
- package/dist/commands/monitor.d.ts +15 -0
- package/dist/commands/monitor.js +2 -2
- package/dist/commands/mutate.d.ts +2 -0
- package/dist/commands/mutate.js +177 -0
- package/dist/config/types.js +2 -2
- package/dist/coverage/calculator.d.ts +7 -0
- package/dist/coverage/calculator.js +86 -0
- package/dist/coverage/index.d.ts +3 -0
- package/dist/coverage/index.js +3 -0
- package/dist/coverage/reporter.d.ts +9 -0
- package/dist/coverage/reporter.js +65 -0
- package/dist/coverage/types.d.ts +36 -0
- package/dist/coverage/types.js +1 -0
- package/dist/generator/generator.d.ts +3 -1
- package/dist/generator/generator.js +137 -23
- package/dist/generator/mdx-serializer.js +3 -2
- package/dist/generator/organizer.d.ts +5 -1
- package/dist/generator/organizer.js +29 -14
- package/dist/generator/types.d.ts +6 -0
- package/dist/generator/writer.js +7 -2
- package/dist/github/org-discovery.js +5 -0
- package/dist/importers/mintlify.js +4 -3
- package/dist/llm/anthropic-client.js +1 -0
- package/dist/llm/index.d.ts +15 -0
- package/dist/llm/index.js +148 -29
- package/dist/llm/openai-client.js +2 -0
- package/dist/mutation/index.d.ts +4 -0
- package/dist/mutation/index.js +4 -0
- package/dist/mutation/mutator.d.ts +5 -0
- package/dist/mutation/mutator.js +101 -0
- package/dist/mutation/reporter.d.ts +14 -0
- package/dist/mutation/reporter.js +66 -0
- package/dist/mutation/runner.d.ts +9 -0
- package/dist/mutation/runner.js +70 -0
- package/dist/mutation/types.d.ts +51 -0
- package/dist/mutation/types.js +1 -0
- package/dist/qa/checks.d.ts +1 -0
- package/dist/qa/checks.js +47 -0
- package/dist/qa/index.js +2 -1
- package/dist/scanner/index.js +78 -11
- package/dist/scanner/typescript.js +42 -31
- package/dist/sentry.d.ts +3 -0
- package/dist/sentry.js +28 -0
- package/dist/template/docs.json +6 -3
- package/dist/template/next.config.mjs +15 -1
- package/dist/template/package.json +4 -3
- package/dist/template/public/docs-schema.json +257 -0
- package/dist/template/sentry.client.config.ts +12 -0
- package/dist/template/sentry.edge.config.ts +7 -0
- package/dist/template/sentry.server.config.ts +7 -0
- package/dist/template/src/app/docs/[...slug]/page.tsx +11 -5
- package/dist/template/src/app/docs/layout.tsx +2 -4
- package/dist/template/src/app/global-error.tsx +60 -0
- package/dist/template/src/app/layout.tsx +7 -16
- package/dist/template/src/app/page.tsx +2 -5
- package/dist/template/src/components/ai-chat-impl.tsx +1 -1
- package/dist/template/src/components/docs-layout.tsx +1 -15
- package/dist/template/src/components/footer.tsx +95 -19
- package/dist/template/src/components/header.tsx +1 -1
- package/dist/template/src/components/search-dialog.tsx +5 -0
- package/dist/template/src/instrumentation.ts +11 -0
- package/dist/template/src/lib/docs-config.ts +235 -0
- package/dist/template/src/lib/fonts.ts +3 -3
- package/dist/testing/runner.js +8 -1
- package/package.json +2 -1
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "Skrypt docs.json",
|
|
4
|
+
"description": "Configuration file for Skrypt documentation sites. Controls site name, navigation, theme, fonts, and footer.",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["name", "navigation"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"$schema": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"description": "Path to the JSON Schema file for IDE autocomplete."
|
|
11
|
+
},
|
|
12
|
+
"name": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"description": "The site name displayed in the header, browser tab, and meta tags.",
|
|
15
|
+
"minLength": 1
|
|
16
|
+
},
|
|
17
|
+
"description": {
|
|
18
|
+
"type": "string",
|
|
19
|
+
"description": "A short description of the documentation site, used in meta tags and the landing page hero."
|
|
20
|
+
},
|
|
21
|
+
"favicon": {
|
|
22
|
+
"type": "string",
|
|
23
|
+
"description": "Path to the favicon file relative to the public directory (e.g. \"/favicon.svg\")."
|
|
24
|
+
},
|
|
25
|
+
"siteUrl": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"description": "The canonical base URL of the site (e.g. \"https://docs.example.com\"). Used for meta tags and JSON-LD."
|
|
28
|
+
},
|
|
29
|
+
"logo": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"description": "Path to a logo image displayed in the header instead of the site name."
|
|
32
|
+
},
|
|
33
|
+
"headerLinks": {
|
|
34
|
+
"type": "array",
|
|
35
|
+
"description": "Extra navigation links shown in the top header bar.",
|
|
36
|
+
"items": {
|
|
37
|
+
"type": "object",
|
|
38
|
+
"required": ["title", "path"],
|
|
39
|
+
"properties": {
|
|
40
|
+
"title": {
|
|
41
|
+
"type": "string",
|
|
42
|
+
"description": "Display text for the link."
|
|
43
|
+
},
|
|
44
|
+
"path": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"description": "URL or path the link navigates to."
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"additionalProperties": false
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"fonts": {
|
|
53
|
+
"type": "object",
|
|
54
|
+
"description": "Google Fonts to use for the site. Unrecognized font names fall back to defaults.",
|
|
55
|
+
"properties": {
|
|
56
|
+
"sans": {
|
|
57
|
+
"type": "string",
|
|
58
|
+
"description": "Sans-serif body font. Default: \"Inter\".",
|
|
59
|
+
"enum": [
|
|
60
|
+
"Inter",
|
|
61
|
+
"Plus Jakarta Sans",
|
|
62
|
+
"DM Sans",
|
|
63
|
+
"Geist",
|
|
64
|
+
"Outfit",
|
|
65
|
+
"Space Grotesk",
|
|
66
|
+
"Manrope",
|
|
67
|
+
"Sora",
|
|
68
|
+
"Instrument Sans",
|
|
69
|
+
"Albert Sans"
|
|
70
|
+
]
|
|
71
|
+
},
|
|
72
|
+
"mono": {
|
|
73
|
+
"type": "string",
|
|
74
|
+
"description": "Monospace font for code blocks. Default: \"JetBrains Mono\".",
|
|
75
|
+
"enum": [
|
|
76
|
+
"JetBrains Mono",
|
|
77
|
+
"Fira Code",
|
|
78
|
+
"Source Code Pro",
|
|
79
|
+
"IBM Plex Mono",
|
|
80
|
+
"Geist Mono",
|
|
81
|
+
"Space Mono",
|
|
82
|
+
"Roboto Mono",
|
|
83
|
+
"Inconsolata"
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"additionalProperties": false
|
|
88
|
+
},
|
|
89
|
+
"theme": {
|
|
90
|
+
"type": "object",
|
|
91
|
+
"description": "Visual theme settings.",
|
|
92
|
+
"properties": {
|
|
93
|
+
"primaryColor": {
|
|
94
|
+
"type": "string",
|
|
95
|
+
"description": "Primary brand color in hex format (e.g. \"#171717\"). Used for buttons, links, and accents.",
|
|
96
|
+
"pattern": "^#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?$"
|
|
97
|
+
},
|
|
98
|
+
"font": {
|
|
99
|
+
"type": "string",
|
|
100
|
+
"description": "Legacy: sans-serif font name. Prefer using \"fonts.sans\" instead."
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
"additionalProperties": false
|
|
104
|
+
},
|
|
105
|
+
"navigation": {
|
|
106
|
+
"description": "Sidebar navigation structure. Can be a flat list of groups or a tabbed layout.",
|
|
107
|
+
"oneOf": [
|
|
108
|
+
{
|
|
109
|
+
"type": "array",
|
|
110
|
+
"description": "Flat navigation: an array of groups.",
|
|
111
|
+
"items": { "$ref": "#/$defs/navGroup" },
|
|
112
|
+
"minItems": 1
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"type": "array",
|
|
116
|
+
"description": "Tabbed navigation: an array of tabs, each containing groups.",
|
|
117
|
+
"items": { "$ref": "#/$defs/navTab" },
|
|
118
|
+
"minItems": 1
|
|
119
|
+
}
|
|
120
|
+
]
|
|
121
|
+
},
|
|
122
|
+
"footer": {
|
|
123
|
+
"type": "object",
|
|
124
|
+
"description": "Footer configuration with external links and social accounts.",
|
|
125
|
+
"properties": {
|
|
126
|
+
"links": {
|
|
127
|
+
"type": "array",
|
|
128
|
+
"description": "Links displayed in the footer.",
|
|
129
|
+
"items": {
|
|
130
|
+
"type": "object",
|
|
131
|
+
"required": ["title", "url"],
|
|
132
|
+
"properties": {
|
|
133
|
+
"title": {
|
|
134
|
+
"type": "string",
|
|
135
|
+
"description": "Display text for the footer link."
|
|
136
|
+
},
|
|
137
|
+
"url": {
|
|
138
|
+
"type": "string",
|
|
139
|
+
"description": "URL the footer link navigates to."
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
"additionalProperties": false
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
"social": {
|
|
146
|
+
"type": "object",
|
|
147
|
+
"description": "Social media URLs.",
|
|
148
|
+
"properties": {
|
|
149
|
+
"github": { "type": "string", "description": "GitHub profile or repository URL." },
|
|
150
|
+
"twitter": { "type": "string", "description": "Twitter/X profile URL." },
|
|
151
|
+
"discord": { "type": "string", "description": "Discord invite URL." }
|
|
152
|
+
},
|
|
153
|
+
"additionalProperties": true
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
"additionalProperties": false
|
|
157
|
+
},
|
|
158
|
+
"editLink": {
|
|
159
|
+
"type": "object",
|
|
160
|
+
"description": "Configuration for \"Edit this page\" links that point to the source repository.",
|
|
161
|
+
"properties": {
|
|
162
|
+
"repoUrl": {
|
|
163
|
+
"type": "string",
|
|
164
|
+
"description": "Base URL of the repository (e.g. \"https://github.com/org/repo\")."
|
|
165
|
+
},
|
|
166
|
+
"branch": {
|
|
167
|
+
"type": "string",
|
|
168
|
+
"description": "Git branch name. Default: \"main\"."
|
|
169
|
+
},
|
|
170
|
+
"docsPath": {
|
|
171
|
+
"type": "string",
|
|
172
|
+
"description": "Path within the repo to the docs content directory (e.g. \"content/docs\")."
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
"additionalProperties": false
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
"additionalProperties": false,
|
|
179
|
+
"$defs": {
|
|
180
|
+
"navPage": {
|
|
181
|
+
"type": "object",
|
|
182
|
+
"description": "A single documentation page in the sidebar.",
|
|
183
|
+
"required": ["title", "path"],
|
|
184
|
+
"properties": {
|
|
185
|
+
"title": {
|
|
186
|
+
"type": "string",
|
|
187
|
+
"description": "Display title in the sidebar."
|
|
188
|
+
},
|
|
189
|
+
"path": {
|
|
190
|
+
"type": "string",
|
|
191
|
+
"description": "URL path to the page (e.g. \"/docs/getting-started\")."
|
|
192
|
+
},
|
|
193
|
+
"description": {
|
|
194
|
+
"type": "string",
|
|
195
|
+
"description": "Short description shown in tooltips or page headers."
|
|
196
|
+
},
|
|
197
|
+
"pages": {
|
|
198
|
+
"type": "array",
|
|
199
|
+
"description": "Nested sub-pages for hierarchical navigation.",
|
|
200
|
+
"items": { "$ref": "#/$defs/navPage" }
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
"additionalProperties": false
|
|
204
|
+
},
|
|
205
|
+
"navGroup": {
|
|
206
|
+
"type": "object",
|
|
207
|
+
"description": "A group of pages in the sidebar with a section heading.",
|
|
208
|
+
"required": ["group", "pages"],
|
|
209
|
+
"properties": {
|
|
210
|
+
"group": {
|
|
211
|
+
"type": "string",
|
|
212
|
+
"description": "Section heading displayed in the sidebar."
|
|
213
|
+
},
|
|
214
|
+
"icon": {
|
|
215
|
+
"type": "string",
|
|
216
|
+
"description": "Lucide icon name for the group heading (e.g. \"BookOpen\", \"Code\")."
|
|
217
|
+
},
|
|
218
|
+
"pages": {
|
|
219
|
+
"type": "array",
|
|
220
|
+
"description": "Pages and nested groups within this section.",
|
|
221
|
+
"items": {
|
|
222
|
+
"oneOf": [
|
|
223
|
+
{ "$ref": "#/$defs/navPage" },
|
|
224
|
+
{ "$ref": "#/$defs/navGroup" }
|
|
225
|
+
]
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
"additionalProperties": false
|
|
230
|
+
},
|
|
231
|
+
"navTab": {
|
|
232
|
+
"type": "object",
|
|
233
|
+
"description": "A top-level navigation tab containing groups.",
|
|
234
|
+
"required": ["tab", "groups"],
|
|
235
|
+
"properties": {
|
|
236
|
+
"tab": {
|
|
237
|
+
"type": "string",
|
|
238
|
+
"description": "Tab label displayed in the header."
|
|
239
|
+
},
|
|
240
|
+
"icon": {
|
|
241
|
+
"type": "string",
|
|
242
|
+
"description": "Lucide icon name for the tab."
|
|
243
|
+
},
|
|
244
|
+
"href": {
|
|
245
|
+
"type": "string",
|
|
246
|
+
"description": "Direct link URL for the tab (overrides group-based routing)."
|
|
247
|
+
},
|
|
248
|
+
"groups": {
|
|
249
|
+
"type": "array",
|
|
250
|
+
"description": "Navigation groups shown when this tab is active.",
|
|
251
|
+
"items": { "$ref": "#/$defs/navGroup" }
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
"additionalProperties": false
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as Sentry from '@sentry/nextjs'
|
|
2
|
+
|
|
3
|
+
Sentry.init({
|
|
4
|
+
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN || 'https://5192fcdbb58de60661cfa103b00d5a91@o4511084239781888.ingest.us.sentry.io/4511084256362496',
|
|
5
|
+
environment: process.env.NEXT_PUBLIC_VERCEL_ENV || 'development',
|
|
6
|
+
|
|
7
|
+
tracesSampleRate: 0.1,
|
|
8
|
+
|
|
9
|
+
replaysSessionSampleRate: 0,
|
|
10
|
+
replaysOnErrorSampleRate: 1.0,
|
|
11
|
+
integrations: [Sentry.replayIntegration()],
|
|
12
|
+
})
|
|
@@ -5,6 +5,7 @@ import { compileMDX } from 'next-mdx-remote/rsc'
|
|
|
5
5
|
import remarkGfm from 'remark-gfm'
|
|
6
6
|
import * as mdxComponents from '@/components/mdx'
|
|
7
7
|
import { findPageInNavigation, type Navigation } from '@/lib/navigation'
|
|
8
|
+
import { loadDocsConfig } from '@/lib/docs-config'
|
|
8
9
|
import { Children, isValidElement, type ReactNode } from 'react'
|
|
9
10
|
|
|
10
11
|
/** Wrapper for <pre> that routes mermaid code blocks to the Mermaid component */
|
|
@@ -52,9 +53,9 @@ const components = {
|
|
|
52
53
|
h3: mdxComponents.H3,
|
|
53
54
|
h4: mdxComponents.H4,
|
|
54
55
|
a: AnchorOrLink,
|
|
56
|
+
// Map TabItem (Docusaurus-style) to TabPanel (our Tabs component API)
|
|
57
|
+
TabItem: mdxComponents.TabPanel,
|
|
55
58
|
// Passthrough for JSX tags that appear in generated code examples
|
|
56
|
-
Tabs: Passthrough,
|
|
57
|
-
TabItem: Passthrough,
|
|
58
59
|
Details: Passthrough,
|
|
59
60
|
}
|
|
60
61
|
import type { Metadata } from 'next'
|
|
@@ -69,9 +70,7 @@ interface Frontmatter {
|
|
|
69
70
|
}
|
|
70
71
|
|
|
71
72
|
function getDocsConfig() {
|
|
72
|
-
|
|
73
|
-
const configPath = join(process.cwd(), 'docs.json')
|
|
74
|
-
return JSON.parse(fs.readFileSync(configPath, 'utf-8'))
|
|
73
|
+
return loadDocsConfig()
|
|
75
74
|
}
|
|
76
75
|
|
|
77
76
|
async function getContent(slug: string[]) {
|
|
@@ -172,12 +171,19 @@ export default async function DocPage({ params }: PageProps) {
|
|
|
172
171
|
// Strip empty <a id="..."></a> anchors from generated content — headings already have IDs
|
|
173
172
|
const cleanedSource = result.content.replace(/<a\s+id="[^"]*"\s*><\/a>\s*/g, '')
|
|
174
173
|
|
|
174
|
+
// Use format: 'md' for .md files so curly braces in code blocks are treated as
|
|
175
|
+
// literal text instead of JSX expressions (avoids "Could not parse expression
|
|
176
|
+
// with acorn" errors from unescaped { } in TypeScript/Python code examples).
|
|
177
|
+
// .mdx files keep format: 'mdx' for full MDX expression support.
|
|
178
|
+
const isMdx = result.path.endsWith('.mdx')
|
|
179
|
+
|
|
175
180
|
const { content } = await compileMDX({
|
|
176
181
|
source: cleanedSource,
|
|
177
182
|
components: components as any,
|
|
178
183
|
options: {
|
|
179
184
|
parseFrontmatter: true,
|
|
180
185
|
mdxOptions: {
|
|
186
|
+
format: isMdx ? 'mdx' : 'md',
|
|
181
187
|
remarkPlugins: [remarkGfm],
|
|
182
188
|
},
|
|
183
189
|
},
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { DocsLayout } from '@/components/docs-layout'
|
|
2
|
-
import {
|
|
3
|
-
import { join } from 'path'
|
|
2
|
+
import { loadDocsConfig } from '@/lib/docs-config'
|
|
4
3
|
|
|
5
4
|
function getDocsConfig() {
|
|
6
|
-
|
|
7
|
-
return JSON.parse(readFileSync(configPath, 'utf-8'))
|
|
5
|
+
return loadDocsConfig()
|
|
8
6
|
}
|
|
9
7
|
|
|
10
8
|
export default function Layout({
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as Sentry from '@sentry/nextjs'
|
|
4
|
+
import { useEffect } from 'react'
|
|
5
|
+
|
|
6
|
+
export default function GlobalError({
|
|
7
|
+
error,
|
|
8
|
+
reset,
|
|
9
|
+
}: {
|
|
10
|
+
error: Error & { digest?: string }
|
|
11
|
+
reset: () => void
|
|
12
|
+
}) {
|
|
13
|
+
useEffect(() => {
|
|
14
|
+
Sentry.captureException(error)
|
|
15
|
+
}, [error])
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<html lang="en">
|
|
19
|
+
<body>
|
|
20
|
+
<div style={{
|
|
21
|
+
minHeight: '100vh',
|
|
22
|
+
display: 'flex',
|
|
23
|
+
alignItems: 'center',
|
|
24
|
+
justifyContent: 'center',
|
|
25
|
+
padding: '1rem',
|
|
26
|
+
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
27
|
+
}}>
|
|
28
|
+
<div style={{ maxWidth: '28rem', width: '100%', textAlign: 'center' }}>
|
|
29
|
+
<h1 style={{ fontSize: '1.5rem', fontWeight: 700, marginBottom: '0.5rem' }}>
|
|
30
|
+
Something went wrong
|
|
31
|
+
</h1>
|
|
32
|
+
<p style={{ color: '#6b7280', marginBottom: '1.5rem' }}>
|
|
33
|
+
A critical error occurred. Please try again.
|
|
34
|
+
</p>
|
|
35
|
+
{error.digest && (
|
|
36
|
+
<p style={{ fontSize: '0.75rem', color: '#9ca3af', marginBottom: '1rem' }}>
|
|
37
|
+
Error ID: {error.digest}
|
|
38
|
+
</p>
|
|
39
|
+
)}
|
|
40
|
+
<button
|
|
41
|
+
onClick={reset}
|
|
42
|
+
style={{
|
|
43
|
+
padding: '0.5rem 1rem',
|
|
44
|
+
backgroundColor: '#3b82f6',
|
|
45
|
+
color: '#fff',
|
|
46
|
+
border: 'none',
|
|
47
|
+
borderRadius: '0.5rem',
|
|
48
|
+
cursor: 'pointer',
|
|
49
|
+
fontSize: '0.875rem',
|
|
50
|
+
fontWeight: 500,
|
|
51
|
+
}}
|
|
52
|
+
>
|
|
53
|
+
Try again
|
|
54
|
+
</button>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
</body>
|
|
58
|
+
</html>
|
|
59
|
+
)
|
|
60
|
+
}
|
|
@@ -1,24 +1,15 @@
|
|
|
1
1
|
import type { Metadata } from 'next'
|
|
2
|
-
import { Inter } from 'next/font/google'
|
|
2
|
+
import { Inter, JetBrains_Mono } from 'next/font/google'
|
|
3
3
|
import '@/styles/globals.css'
|
|
4
4
|
import { SyntaxThemeProvider } from '@/contexts/syntax-theme'
|
|
5
|
-
import { readFileSync } from 'fs'
|
|
6
|
-
import { join } from 'path'
|
|
7
5
|
import { derivePrimaryColors } from '@/lib/theme-utils'
|
|
8
6
|
import { resolveFonts, buildGoogleFontsUrl } from '@/lib/fonts'
|
|
7
|
+
import { loadDocsConfig } from '@/lib/docs-config'
|
|
9
8
|
|
|
10
9
|
const inter = Inter({ subsets: ['latin'] })
|
|
10
|
+
const jetbrainsMono = JetBrains_Mono({ subsets: ['latin'], variable: '--font-jetbrains-mono' })
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
const configPath = join(process.cwd(), 'docs.json')
|
|
14
|
-
try {
|
|
15
|
-
return JSON.parse(readFileSync(configPath, 'utf-8'))
|
|
16
|
-
} catch {
|
|
17
|
-
return {}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const docsConfig = getDocsConfig()
|
|
12
|
+
const docsConfig = loadDocsConfig()
|
|
22
13
|
const siteUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://docs.example.com'
|
|
23
14
|
const siteName = docsConfig.name || 'Documentation'
|
|
24
15
|
const siteDescription = docsConfig.description || 'Documentation'
|
|
@@ -40,7 +31,7 @@ const themeStyles = `
|
|
|
40
31
|
--color-primary-light: ${primaryLight};
|
|
41
32
|
--color-primary-foreground: ${primaryForeground};
|
|
42
33
|
--font-body: "${sans.name}", "Inter", ui-sans-serif, system-ui, sans-serif;
|
|
43
|
-
--font-mono: "${mono.name}", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
|
|
34
|
+
--font-mono: ${mono.name === 'JetBrains Mono' ? 'var(--font-jetbrains-mono)' : `"${mono.name}"`}, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
|
|
44
35
|
}
|
|
45
36
|
`
|
|
46
37
|
|
|
@@ -67,7 +58,7 @@ export const metadata: Metadata = {
|
|
|
67
58
|
images: ['/og-image.png'],
|
|
68
59
|
},
|
|
69
60
|
icons: {
|
|
70
|
-
icon: '/favicon.svg',
|
|
61
|
+
icon: docsConfig.favicon || '/favicon.svg',
|
|
71
62
|
},
|
|
72
63
|
robots: {
|
|
73
64
|
index: true,
|
|
@@ -112,7 +103,7 @@ export default function RootLayout({
|
|
|
112
103
|
</>
|
|
113
104
|
)}
|
|
114
105
|
</head>
|
|
115
|
-
<body className={inter.className}>
|
|
106
|
+
<body className={`${inter.className} ${jetbrainsMono.variable}`}>
|
|
116
107
|
<a href="#main-content" className="skip-to-content">Skip to content</a>
|
|
117
108
|
<SyntaxThemeProvider>
|
|
118
109
|
{children}
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import Link from 'next/link'
|
|
2
|
-
import { readFileSync } from 'fs'
|
|
3
|
-
import { join } from 'path'
|
|
4
2
|
import { ArrowRight, BookOpen, Zap, Code } from 'lucide-react'
|
|
5
3
|
import { hasTabs, getAllPagesFlat, type Navigation } from '@/lib/navigation'
|
|
4
|
+
import { loadDocsConfig } from '@/lib/docs-config'
|
|
6
5
|
|
|
7
6
|
function getDocsConfig() {
|
|
8
|
-
|
|
9
|
-
const content = readFileSync(configPath, 'utf-8')
|
|
10
|
-
return JSON.parse(content)
|
|
7
|
+
return loadDocsConfig()
|
|
11
8
|
}
|
|
12
9
|
|
|
13
10
|
/** Get flat groups for display on the home page (works with both formats) */
|
|
@@ -168,7 +168,7 @@ export function AIChat({
|
|
|
168
168
|
|
|
169
169
|
{error && (
|
|
170
170
|
<div className="flex justify-start">
|
|
171
|
-
<div className="rounded-2xl bg-red-
|
|
171
|
+
<div className="rounded-2xl bg-red-500/10 px-4 py-2 text-sm text-red-600 dark:text-red-400">
|
|
172
172
|
Something went wrong. Please try again.
|
|
173
173
|
</div>
|
|
174
174
|
</div>
|
|
@@ -24,21 +24,7 @@ import {
|
|
|
24
24
|
type NavTab,
|
|
25
25
|
type NavGroup,
|
|
26
26
|
} from '@/lib/navigation'
|
|
27
|
-
|
|
28
|
-
interface DocsConfig {
|
|
29
|
-
name?: string
|
|
30
|
-
headerLinks?: Array<{ title: string; path: string }>
|
|
31
|
-
logo?: string
|
|
32
|
-
navigation: Navigation
|
|
33
|
-
footer?: {
|
|
34
|
-
links?: Array<{ title: string; url: string }>
|
|
35
|
-
}
|
|
36
|
-
editLink?: {
|
|
37
|
-
repoUrl?: string
|
|
38
|
-
branch?: string
|
|
39
|
-
docsPath?: string
|
|
40
|
-
}
|
|
41
|
-
}
|
|
27
|
+
import type { DocsConfig } from '@/lib/docs-config'
|
|
42
28
|
|
|
43
29
|
function PrevNextNav({ docsConfig }: { docsConfig: DocsConfig }) {
|
|
44
30
|
const pathname = usePathname()
|
|
@@ -1,41 +1,117 @@
|
|
|
1
|
+
import { Github } from 'lucide-react'
|
|
2
|
+
|
|
3
|
+
interface FooterSocial {
|
|
4
|
+
github?: string
|
|
5
|
+
twitter?: string
|
|
6
|
+
discord?: string
|
|
7
|
+
linkedin?: string
|
|
8
|
+
}
|
|
9
|
+
|
|
1
10
|
interface FooterProps {
|
|
2
11
|
docsConfig: {
|
|
3
12
|
footer?: {
|
|
4
13
|
links?: Array<{ title: string; url: string }>
|
|
14
|
+
social?: FooterSocial
|
|
15
|
+
copyright?: string
|
|
5
16
|
}
|
|
6
17
|
}
|
|
7
18
|
}
|
|
8
19
|
|
|
20
|
+
function TwitterIcon({ size = 16 }: { size?: number }) {
|
|
21
|
+
return (
|
|
22
|
+
<svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor">
|
|
23
|
+
<path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />
|
|
24
|
+
</svg>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function DiscordIcon({ size = 16 }: { size?: number }) {
|
|
29
|
+
return (
|
|
30
|
+
<svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor">
|
|
31
|
+
<path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.095 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.095 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z" />
|
|
32
|
+
</svg>
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function LinkedInIcon({ size = 16 }: { size?: number }) {
|
|
37
|
+
return (
|
|
38
|
+
<svg width={size} height={size} viewBox="0 0 24 24" fill="currentColor">
|
|
39
|
+
<path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-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.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065 2.064 2.064 0 1 1 2.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.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 0h.003z" />
|
|
40
|
+
</svg>
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const socialEntries: Array<{
|
|
45
|
+
key: keyof FooterSocial
|
|
46
|
+
icon: React.ComponentType<{ size?: number }>
|
|
47
|
+
label: string
|
|
48
|
+
}> = [
|
|
49
|
+
{ key: 'github', icon: Github, label: 'GitHub' },
|
|
50
|
+
{ key: 'twitter', icon: TwitterIcon, label: 'Twitter' },
|
|
51
|
+
{ key: 'discord', icon: DiscordIcon, label: 'Discord' },
|
|
52
|
+
{ key: 'linkedin', icon: LinkedInIcon, label: 'LinkedIn' },
|
|
53
|
+
]
|
|
54
|
+
|
|
9
55
|
export function Footer({ docsConfig }: FooterProps) {
|
|
10
56
|
const links = docsConfig.footer?.links || []
|
|
57
|
+
const social = docsConfig.footer?.social
|
|
58
|
+
const copyright = docsConfig.footer?.copyright
|
|
11
59
|
|
|
12
60
|
return (
|
|
13
61
|
<footer className="border-t border-[var(--color-border)] lg:ml-[var(--sidebar-width)]">
|
|
14
|
-
<div className="max-w-[var(--content-max-width)] mx-auto px-6 md:px-10 py-6 flex
|
|
15
|
-
<div className="flex items-center gap-
|
|
16
|
-
|
|
62
|
+
<div className="max-w-[var(--content-max-width)] mx-auto px-6 md:px-10 py-6 flex flex-col gap-4">
|
|
63
|
+
<div className="flex items-center justify-between flex-wrap gap-4">
|
|
64
|
+
<div className="flex items-center gap-6">
|
|
65
|
+
{links.map((link) => (
|
|
66
|
+
<a
|
|
67
|
+
key={link.url}
|
|
68
|
+
href={link.url}
|
|
69
|
+
target="_blank"
|
|
70
|
+
rel="noopener noreferrer"
|
|
71
|
+
className="text-[0.8125rem] text-[var(--color-text-tertiary)] hover:text-[var(--color-text)] transition-colors"
|
|
72
|
+
>
|
|
73
|
+
{link.title}
|
|
74
|
+
</a>
|
|
75
|
+
))}
|
|
76
|
+
</div>
|
|
77
|
+
<div className="flex items-center gap-4">
|
|
78
|
+
{social &&
|
|
79
|
+
socialEntries.map(({ key, icon: Icon, label }) => {
|
|
80
|
+
const url = social[key]
|
|
81
|
+
if (!url) return null
|
|
82
|
+
return (
|
|
83
|
+
<a
|
|
84
|
+
key={key}
|
|
85
|
+
href={url}
|
|
86
|
+
target="_blank"
|
|
87
|
+
rel="noopener noreferrer"
|
|
88
|
+
aria-label={label}
|
|
89
|
+
className="text-[var(--color-text-tertiary)] hover:text-[var(--color-text)] transition-colors"
|
|
90
|
+
>
|
|
91
|
+
<Icon size={16} />
|
|
92
|
+
</a>
|
|
93
|
+
)
|
|
94
|
+
})}
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
<div className="flex items-center justify-between flex-wrap gap-2">
|
|
98
|
+
{copyright && (
|
|
99
|
+
<span className="text-[0.75rem] text-[var(--color-text-tertiary)]">
|
|
100
|
+
{copyright}
|
|
101
|
+
</span>
|
|
102
|
+
)}
|
|
103
|
+
<span className={`text-[0.6875rem] text-[var(--color-text-tertiary)] opacity-60${copyright ? '' : ' ml-auto'}`}>
|
|
104
|
+
Built with{' '}
|
|
17
105
|
<a
|
|
18
|
-
|
|
19
|
-
href={link.url}
|
|
106
|
+
href="https://skrypt.sh"
|
|
20
107
|
target="_blank"
|
|
21
108
|
rel="noopener noreferrer"
|
|
22
|
-
className="
|
|
109
|
+
className="hover:text-[var(--color-text-secondary)] transition-colors"
|
|
23
110
|
>
|
|
24
|
-
|
|
111
|
+
Skrypt
|
|
25
112
|
</a>
|
|
26
|
-
|
|
113
|
+
</span>
|
|
27
114
|
</div>
|
|
28
|
-
<span className="text-[0.75rem] text-[var(--color-text-tertiary)]">
|
|
29
|
-
Built with{' '}
|
|
30
|
-
<a
|
|
31
|
-
href="https://skrypt.sh"
|
|
32
|
-
target="_blank"
|
|
33
|
-
rel="noopener noreferrer"
|
|
34
|
-
className="text-[var(--color-text-secondary)] hover:text-[var(--color-primary)] transition-colors"
|
|
35
|
-
>
|
|
36
|
-
Skrypt
|
|
37
|
-
</a>
|
|
38
|
-
</span>
|
|
39
115
|
</div>
|
|
40
116
|
</footer>
|
|
41
117
|
)
|
|
@@ -58,7 +58,7 @@ export function Header({ onMenuToggle, menuOpen, siteName = 'Docs', navLinks, lo
|
|
|
58
58
|
{/* Mobile menu button */}
|
|
59
59
|
<button
|
|
60
60
|
onClick={onMenuToggle}
|
|
61
|
-
className="
|
|
61
|
+
className="lg:hidden p-1.5 -ml-1.5 rounded-lg text-[var(--color-text-secondary)] hover:text-[var(--color-text)] hover:bg-[var(--color-bg-secondary)]"
|
|
62
62
|
aria-label={menuOpen ? 'Close menu' : 'Open menu'}
|
|
63
63
|
aria-expanded={menuOpen}
|
|
64
64
|
>
|