radiant-docs 0.1.54 → 0.1.57
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/index.js +3 -75
- package/package.json +2 -4
- package/template/astro.config.mjs +16 -26
- package/template/package-lock.json +18 -0
- package/template/package.json +1 -1
- package/template/scripts/generate-og-metadata.mjs +8 -4
- package/template/src/components/Footer.astro +13 -4
- package/template/src/components/Header.astro +26 -6
- package/template/src/components/SidebarLink.astro +3 -2
- package/template/src/components/SidebarSubgroup.astro +14 -13
- package/template/src/components/sidebar/SidebarEndpointLink.astro +13 -3
- package/template/src/components/sidebar/SidebarOpenApi.astro +2 -0
- package/template/src/components/sidebar/SidebarOpenApiPageLink.astro +1 -0
- package/template/src/components/user/Accordion.astro +0 -13
- package/template/src/components/user/Callout.astro +0 -29
- package/template/src/components/user/Card.astro +31 -204
- package/template/src/components/user/CardGradient.astro +8 -1
- package/template/src/components/user/Column.astro +0 -17
- package/template/src/components/user/Columns.astro +4 -153
- package/template/src/components/user/Image.astro +0 -28
- package/template/src/components/user/Step.astro +0 -10
- package/template/src/components/user/Tab.astro +0 -12
- package/template/src/components/user/Tabs.astro +2 -9
- package/template/src/content.config.ts +1 -1
- package/template/src/lib/code/code-block.ts +1 -1
- package/template/src/lib/mdx/remark-code-block-component.ts +1 -20
- package/template/src/lib/mdx/remark-resolve-internal-links.ts +150 -204
- package/template/src/lib/routes.ts +150 -29
- package/template/src/lib/utils.ts +127 -12
- package/template/src/lib/validation.ts +5 -2826
- package/template/src/pages/[...slug].astro +16 -0
- package/template/src/lib/code/shiki-theme-config.ts +0 -16
- package/template/src/lib/component-error.ts +0 -202
- package/template/src/lib/frontmatter-schema.ts +0 -10
package/dist/index.js
CHANGED
|
@@ -36,7 +36,7 @@ var log = {
|
|
|
36
36
|
),
|
|
37
37
|
blank: () => console.log("")
|
|
38
38
|
};
|
|
39
|
-
var SUPPORTED_COMMANDS = /* @__PURE__ */ new Set(["dev"
|
|
39
|
+
var SUPPORTED_COMMANDS = /* @__PURE__ */ new Set(["dev"]);
|
|
40
40
|
function getUserDocsDir() {
|
|
41
41
|
return process.cwd();
|
|
42
42
|
}
|
|
@@ -187,66 +187,6 @@ async function runAstroSync(cacheDir) {
|
|
|
187
187
|
} catch {
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
|
-
function toCommandOutput(value) {
|
|
191
|
-
if (!value) return "";
|
|
192
|
-
if (Buffer.isBuffer(value)) return value.toString("utf-8");
|
|
193
|
-
return String(value);
|
|
194
|
-
}
|
|
195
|
-
function getCommandOutput(error) {
|
|
196
|
-
return [
|
|
197
|
-
toCommandOutput(error?.stdout),
|
|
198
|
-
toCommandOutput(error?.stderr),
|
|
199
|
-
toCommandOutput(error?.message)
|
|
200
|
-
].filter(Boolean).join("\n");
|
|
201
|
-
}
|
|
202
|
-
function extractUserErrors(output) {
|
|
203
|
-
const errors = [];
|
|
204
|
-
for (const line of output.split("\n")) {
|
|
205
|
-
if (!line.includes("[USER_ERROR]")) continue;
|
|
206
|
-
const message = line.split("[USER_ERROR]:")[1]?.trim() || line.trim();
|
|
207
|
-
if (message && !errors.includes(message)) {
|
|
208
|
-
errors.push(message);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
return errors;
|
|
212
|
-
}
|
|
213
|
-
function getOutputTail(output, maxLines = 40) {
|
|
214
|
-
return output.split("\n").map((line) => line.trim()).filter(Boolean).slice(-maxLines).join("\n");
|
|
215
|
-
}
|
|
216
|
-
function runFrameworkCheck(cacheDir) {
|
|
217
|
-
log.info("Checking documentation...");
|
|
218
|
-
try {
|
|
219
|
-
execSync("npm run check", {
|
|
220
|
-
cwd: cacheDir,
|
|
221
|
-
stdio: "pipe",
|
|
222
|
-
env: {
|
|
223
|
-
...process.env,
|
|
224
|
-
RADIANT_CHECK: "1"
|
|
225
|
-
},
|
|
226
|
-
encoding: "utf-8"
|
|
227
|
-
});
|
|
228
|
-
log.success("Documentation check passed.");
|
|
229
|
-
} catch (error) {
|
|
230
|
-
const output = getCommandOutput(error);
|
|
231
|
-
const userErrors = extractUserErrors(output);
|
|
232
|
-
log.blank();
|
|
233
|
-
log.error("Documentation check failed.");
|
|
234
|
-
if (userErrors.length > 0) {
|
|
235
|
-
log.blank();
|
|
236
|
-
for (const userError of userErrors) {
|
|
237
|
-
log.error(userError);
|
|
238
|
-
}
|
|
239
|
-
} else {
|
|
240
|
-
const outputTail = getOutputTail(output);
|
|
241
|
-
if (outputTail) {
|
|
242
|
-
log.blank();
|
|
243
|
-
console.log(outputTail);
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
log.blank();
|
|
247
|
-
process.exit(typeof error?.status === "number" ? error.status : 1);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
190
|
function startDevServer(cacheDir) {
|
|
251
191
|
const child = spawn("npm", ["run", "dev"], {
|
|
252
192
|
cwd: cacheDir,
|
|
@@ -352,14 +292,12 @@ ${colors.bright}${colors.cyan}\u25C6 Radiant${colors.reset} v${VERSION}
|
|
|
352
292
|
${colors.bright}Usage:${colors.reset}
|
|
353
293
|
radiant Start the dev server
|
|
354
294
|
radiant dev Start the dev server
|
|
355
|
-
radiant check Validate and build the docs once
|
|
356
|
-
radiant prepare Prepare cached framework dependencies
|
|
357
295
|
radiant --help Show this help message
|
|
358
296
|
radiant --version Show version
|
|
359
297
|
|
|
360
298
|
${colors.bright}Description:${colors.reset}
|
|
361
299
|
Run this command from your documentation folder (containing docs.json)
|
|
362
|
-
to preview your docs locally with hot reload
|
|
300
|
+
to preview your docs locally with hot reload.
|
|
363
301
|
`);
|
|
364
302
|
}
|
|
365
303
|
async function run() {
|
|
@@ -386,25 +324,15 @@ async function run() {
|
|
|
386
324
|
const docsDir = getUserDocsDir();
|
|
387
325
|
const cacheDir = getCacheDir(docsDir);
|
|
388
326
|
const contentDir = getContentDir(cacheDir);
|
|
389
|
-
|
|
390
|
-
await validateUserDocs(docsDir);
|
|
391
|
-
}
|
|
327
|
+
await validateUserDocs(docsDir);
|
|
392
328
|
const needsInstall = await setupCache(cacheDir);
|
|
393
329
|
if (needsInstall) {
|
|
394
330
|
await installDependencies(cacheDir);
|
|
395
331
|
}
|
|
396
|
-
if (command === "prepare") {
|
|
397
|
-
log.success("Radiant framework cache is ready.");
|
|
398
|
-
return;
|
|
399
|
-
}
|
|
400
332
|
log.info("Syncing your documentation...");
|
|
401
333
|
await syncContent(docsDir, contentDir);
|
|
402
334
|
await runAstroSync(cacheDir);
|
|
403
335
|
log.success("Content synced.");
|
|
404
|
-
if (command === "check") {
|
|
405
|
-
runFrameworkCheck(cacheDir);
|
|
406
|
-
return;
|
|
407
|
-
}
|
|
408
336
|
log.info("Starting dev server...");
|
|
409
337
|
const devServer = startDevServer(cacheDir);
|
|
410
338
|
const watcher = watchUserContent(docsDir, contentDir, async () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "radiant-docs",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.57",
|
|
4
4
|
"description": "CLI tool for previewing Radiant documentation locally",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -11,9 +11,7 @@
|
|
|
11
11
|
"build": "tsup src/index.ts --format esm --clean && npm run bundle-template",
|
|
12
12
|
"dev": "tsup src/index.ts --format esm --watch",
|
|
13
13
|
"prepublishOnly": "npm run build",
|
|
14
|
-
"release": "npm version patch && npm publish"
|
|
15
|
-
"sync-docs-agent-version": "node scripts/sync-docs-agent-version.js",
|
|
16
|
-
"version": "npm run sync-docs-agent-version && git add ../workers/docs-agent/container/Dockerfile"
|
|
14
|
+
"release": "npm version patch && npm publish"
|
|
17
15
|
},
|
|
18
16
|
"dependencies": {
|
|
19
17
|
"chokidar": "^4.0.3",
|
|
@@ -8,7 +8,11 @@ import preact from "@astrojs/preact";
|
|
|
8
8
|
import icon from "astro-icon";
|
|
9
9
|
import fs from "fs";
|
|
10
10
|
import path from "path";
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
getConfig,
|
|
13
|
+
isPublishableStaticAssetPath,
|
|
14
|
+
validateMdxContent,
|
|
15
|
+
} from "./src/lib/validation";
|
|
12
16
|
import remarkCodeBlockComponent from "./src/lib/mdx/remark-code-block-component";
|
|
13
17
|
import remarkDemoteH1 from "./src/lib/mdx/remark-demote-h1";
|
|
14
18
|
import remarkResolveInternalLinks from "./src/lib/mdx/remark-resolve-internal-links";
|
|
@@ -69,12 +73,10 @@ const headingAnchorContent = {
|
|
|
69
73
|
};
|
|
70
74
|
|
|
71
75
|
const shouldValidateDocs =
|
|
72
|
-
process.env.npm_lifecycle_event === "build"
|
|
73
|
-
process.env.npm_lifecycle_event === "check" ||
|
|
74
|
-
process.env.RADIANT_CHECK === "1";
|
|
76
|
+
process.env.npm_lifecycle_event === "build";
|
|
75
77
|
|
|
76
78
|
if (shouldValidateDocs) {
|
|
77
|
-
// Run validation before Astro's internal validation for
|
|
79
|
+
// Run validation before Astro's internal validation for builds.
|
|
78
80
|
try {
|
|
79
81
|
await getConfig();
|
|
80
82
|
await validateMdxContent();
|
|
@@ -91,24 +93,12 @@ function copyContentAssets() {
|
|
|
91
93
|
const DOCS_DIR = path.join(CWD, "src/content/docs");
|
|
92
94
|
const PUBLIC_DIR = path.join(CWD, "public");
|
|
93
95
|
|
|
94
|
-
const imageExtensions = [
|
|
95
|
-
".svg",
|
|
96
|
-
".png",
|
|
97
|
-
".jpg",
|
|
98
|
-
".jpeg",
|
|
99
|
-
".webp",
|
|
100
|
-
".gif",
|
|
101
|
-
".avif",
|
|
102
|
-
".ico",
|
|
103
|
-
];
|
|
104
|
-
|
|
105
96
|
function shouldCopyFile(filePath) {
|
|
106
|
-
|
|
107
|
-
return imageExtensions.includes(ext);
|
|
97
|
+
return isPublishableStaticAssetPath(filePath);
|
|
108
98
|
}
|
|
109
99
|
|
|
110
|
-
// Build a set of all
|
|
111
|
-
function
|
|
100
|
+
// Build a set of all publishable asset paths in src/content/docs
|
|
101
|
+
function collectAssetPaths(dir, baseDir, pathSet) {
|
|
112
102
|
if (!fs.existsSync(dir)) return;
|
|
113
103
|
|
|
114
104
|
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
@@ -120,7 +110,7 @@ function copyContentAssets() {
|
|
|
120
110
|
if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
|
|
121
111
|
|
|
122
112
|
if (entry.isDirectory()) {
|
|
123
|
-
|
|
113
|
+
collectAssetPaths(entryPath, baseDir, pathSet);
|
|
124
114
|
} else if (entry.isFile() && shouldCopyFile(entryPath)) {
|
|
125
115
|
// Store relative path from baseDir
|
|
126
116
|
const relativePath = path.relative(baseDir, entryPath);
|
|
@@ -213,15 +203,15 @@ function copyContentAssets() {
|
|
|
213
203
|
function syncAssets() {
|
|
214
204
|
if (!fs.existsSync(DOCS_DIR)) return;
|
|
215
205
|
|
|
216
|
-
// Step 1: Collect all valid
|
|
217
|
-
const
|
|
218
|
-
|
|
206
|
+
// Step 1: Collect all valid asset paths from source
|
|
207
|
+
const validAssetPaths = new Set();
|
|
208
|
+
collectAssetPaths(DOCS_DIR, DOCS_DIR, validAssetPaths);
|
|
219
209
|
|
|
220
|
-
// Step 2: Copy all
|
|
210
|
+
// Step 2: Copy all publishable assets from source to public
|
|
221
211
|
copyDirectory(DOCS_DIR, PUBLIC_DIR);
|
|
222
212
|
|
|
223
213
|
// Step 3: Delete orphaned files in public
|
|
224
|
-
deleteOrphanedFiles(PUBLIC_DIR, PUBLIC_DIR,
|
|
214
|
+
deleteOrphanedFiles(PUBLIC_DIR, PUBLIC_DIR, validAssetPaths);
|
|
225
215
|
|
|
226
216
|
// Step 4: Clean up empty directories
|
|
227
217
|
cleanupEmptyDirs(PUBLIC_DIR, PUBLIC_DIR);
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"preact": "^10.29.0",
|
|
44
44
|
"prism-themes": "^1.9.0",
|
|
45
45
|
"prismjs": "^1.30.0",
|
|
46
|
+
"radiant-docs-validator": "^0.1.15",
|
|
46
47
|
"rehype-autolink-headings": "^7.1.0",
|
|
47
48
|
"rehype-slug": "^6.0.0",
|
|
48
49
|
"remark-gfm": "^4.0.1",
|
|
@@ -11631,6 +11632,23 @@
|
|
|
11631
11632
|
],
|
|
11632
11633
|
"license": "MIT"
|
|
11633
11634
|
},
|
|
11635
|
+
"node_modules/radiant-docs-validator": {
|
|
11636
|
+
"version": "0.1.15",
|
|
11637
|
+
"resolved": "https://registry.npmjs.org/radiant-docs-validator/-/radiant-docs-validator-0.1.15.tgz",
|
|
11638
|
+
"integrity": "sha512-sGjkGpMyK47C4KqKt6d51/gu6R4mTQrEFLcv/w0KFbDR+kO22GKRFVj79TK48DOHvmr0prpB6yhEo8EDdjLMDQ==",
|
|
11639
|
+
"license": "MIT",
|
|
11640
|
+
"dependencies": {
|
|
11641
|
+
"@iconify-json/fluent": "^1.2.47",
|
|
11642
|
+
"@iconify-json/lucide": "^1.2.79",
|
|
11643
|
+
"@iconify-json/simple-icons": "^1.2.69",
|
|
11644
|
+
"@mdx-js/mdx": "^3.1.1",
|
|
11645
|
+
"@stoplight/spectral-core": "^1.20.0",
|
|
11646
|
+
"@stoplight/spectral-rulesets": "^1.22.0",
|
|
11647
|
+
"shiki": "^3.20.0",
|
|
11648
|
+
"yaml": "^2.8.2",
|
|
11649
|
+
"zod": "^3.25.76"
|
|
11650
|
+
}
|
|
11651
|
+
},
|
|
11634
11652
|
"node_modules/radix3": {
|
|
11635
11653
|
"version": "1.1.2",
|
|
11636
11654
|
"resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz",
|
package/template/package.json
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "astro dev",
|
|
7
7
|
"start": "tsx runner.ts",
|
|
8
|
-
"check": "astro build",
|
|
9
8
|
"prebuild": "rm -rf public/pagefind",
|
|
10
9
|
"build": "astro build && node scripts/remove-assistant-for-non-pro.mjs && node scripts/generate-og-metadata.mjs && node scripts/generate-og-images.mjs && node scripts/stamp-og-image-versions.mjs && node scripts/stamp-image-versions.mjs && pagefind --site dist && node scripts/stamp-pagefind-runtime-version.mjs && node scripts/generate-proxy-allowed-origins.mjs && node scripts/generate-robots-txt.mjs",
|
|
11
10
|
"preview": "astro preview",
|
|
@@ -48,6 +47,7 @@
|
|
|
48
47
|
"preact": "^10.29.0",
|
|
49
48
|
"prism-themes": "^1.9.0",
|
|
50
49
|
"prismjs": "^1.30.0",
|
|
50
|
+
"radiant-docs-validator": "^0.1.15",
|
|
51
51
|
"rehype-autolink-headings": "^7.1.0",
|
|
52
52
|
"rehype-slug": "^6.0.0",
|
|
53
53
|
"remark-gfm": "^4.0.1",
|
|
@@ -100,6 +100,12 @@ function decodeHtmlEntities(value) {
|
|
|
100
100
|
});
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
function getLogoImagePath(variant) {
|
|
104
|
+
if (typeof variant === "string") return variant.trim();
|
|
105
|
+
if (!variant || typeof variant !== "object") return "";
|
|
106
|
+
return typeof variant.image === "string" ? variant.image.trim() : "";
|
|
107
|
+
}
|
|
108
|
+
|
|
103
109
|
function extractTitle(html) {
|
|
104
110
|
const ogTitle = decodeHtmlEntities(
|
|
105
111
|
matchMetaContent(html, "property", "og:title"),
|
|
@@ -149,10 +155,8 @@ function main() {
|
|
|
149
155
|
defaults: {
|
|
150
156
|
siteName:
|
|
151
157
|
typeof docsConfig.title === "string" ? docsConfig.title.trim() : "",
|
|
152
|
-
logoLight:
|
|
153
|
-
|
|
154
|
-
logoDark:
|
|
155
|
-
typeof logo.dark === "string" ? logo.dark.trim() : "",
|
|
158
|
+
logoLight: getLogoImagePath(logo.light),
|
|
159
|
+
logoDark: getLogoImagePath(logo.dark),
|
|
156
160
|
background:
|
|
157
161
|
typeof docsConfig.ogBackground === "string"
|
|
158
162
|
? docsConfig.ogBackground.trim()
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import Icon from "./ui/Icon.astro";
|
|
3
3
|
import { getConfig } from "../lib/validation";
|
|
4
4
|
import LogoLink from "./LogoLink.astro";
|
|
5
|
-
import {
|
|
5
|
+
import { resolveConfiguredHref } from "../lib/routes";
|
|
6
6
|
|
|
7
7
|
interface Props {
|
|
8
8
|
askAiEnabled?: boolean;
|
|
@@ -33,6 +33,15 @@ const socialIcons: Record<string, string> = {
|
|
|
33
33
|
reddit: "simple-icons:reddit",
|
|
34
34
|
podcast: "lucide:podcast",
|
|
35
35
|
};
|
|
36
|
+
|
|
37
|
+
const footerLinks = footer?.links
|
|
38
|
+
? await Promise.all(
|
|
39
|
+
footer.links.map(async (link) => ({
|
|
40
|
+
...link,
|
|
41
|
+
href: await resolveConfiguredHref(link.href, config.hiddenPageRoutes),
|
|
42
|
+
})),
|
|
43
|
+
)
|
|
44
|
+
: [];
|
|
36
45
|
---
|
|
37
46
|
|
|
38
47
|
<footer class="border-t border-border-light pt-16" data-pagefind-ignore>
|
|
@@ -63,11 +72,11 @@ const socialIcons: Record<string, string> = {
|
|
|
63
72
|
)
|
|
64
73
|
}
|
|
65
74
|
{
|
|
66
|
-
|
|
75
|
+
footerLinks.length > 0 && (
|
|
67
76
|
<div class="flex flex-wrap justify-center gap-x-8 gap-y-3">
|
|
68
|
-
{
|
|
77
|
+
{footerLinks.map((link) => (
|
|
69
78
|
<a
|
|
70
|
-
href={
|
|
79
|
+
href={link.href}
|
|
71
80
|
class="text-sm text-neutral-500 hover:text-neutral-900 dark:text-neutral-400 dark:hover:text-neutral-100 transition-colors duration-300"
|
|
72
81
|
>
|
|
73
82
|
{link.text}
|
|
@@ -3,7 +3,7 @@ import Icon from "./ui/Icon.astro";
|
|
|
3
3
|
import { getConfig, type ThemeColorByMode } from "../lib/validation";
|
|
4
4
|
import Search from "./Search.astro";
|
|
5
5
|
import LogoLink from "./LogoLink.astro";
|
|
6
|
-
import {
|
|
6
|
+
import { resolveConfiguredHref } from "../lib/routes";
|
|
7
7
|
import { getAssistantPanelRuntimeConfig } from "../lib/assistant-panel-config";
|
|
8
8
|
import {
|
|
9
9
|
getDocsBaseColorShade,
|
|
@@ -108,6 +108,26 @@ const navbarPrimaryButtonStyle = navbarPrimaryThemeColors
|
|
|
108
108
|
)}`,
|
|
109
109
|
].join("; ")
|
|
110
110
|
: "";
|
|
111
|
+
const navbarLinks = config.navbar?.links
|
|
112
|
+
? await Promise.all(
|
|
113
|
+
config.navbar.links.map(async (link) => ({
|
|
114
|
+
...link,
|
|
115
|
+
href: await resolveConfiguredHref(link.href, config.hiddenPageRoutes),
|
|
116
|
+
})),
|
|
117
|
+
)
|
|
118
|
+
: [];
|
|
119
|
+
const navbarSecondaryHref = config.navbar?.secondary
|
|
120
|
+
? await resolveConfiguredHref(
|
|
121
|
+
config.navbar.secondary.href,
|
|
122
|
+
config.hiddenPageRoutes,
|
|
123
|
+
)
|
|
124
|
+
: "";
|
|
125
|
+
const navbarPrimaryHref = config.navbar?.primary
|
|
126
|
+
? await resolveConfiguredHref(
|
|
127
|
+
config.navbar.primary.href,
|
|
128
|
+
config.hiddenPageRoutes,
|
|
129
|
+
)
|
|
130
|
+
: "";
|
|
111
131
|
---
|
|
112
132
|
|
|
113
133
|
<header
|
|
@@ -176,7 +196,7 @@ const navbarPrimaryButtonStyle = navbarPrimaryThemeColors
|
|
|
176
196
|
{
|
|
177
197
|
config.navbar && (
|
|
178
198
|
<nav class="hidden xs:flex items-center gap-3">
|
|
179
|
-
{
|
|
199
|
+
{navbarLinks.length > 0 && (
|
|
180
200
|
<div
|
|
181
201
|
class:list={[
|
|
182
202
|
"space-x-1",
|
|
@@ -185,7 +205,7 @@ const navbarPrimaryButtonStyle = navbarPrimaryThemeColors
|
|
|
185
205
|
: "hidden lg:flex",
|
|
186
206
|
]}
|
|
187
207
|
>
|
|
188
|
-
{
|
|
208
|
+
{navbarLinks.map((l, i, a) => (
|
|
189
209
|
<a
|
|
190
210
|
class:list={[
|
|
191
211
|
"items-center gap-1 text-[13px] font-[450] dark:font-normal text-neutral-600/85 hover:text-neutral-600 dark:text-neutral-200/90 dark:hover:text-neutral-200 duration-200 px-1.5 py-[5px] whitespace-nowrap",
|
|
@@ -193,7 +213,7 @@ const navbarPrimaryButtonStyle = navbarPrimaryThemeColors
|
|
|
193
213
|
? "hidden 2xl:flex"
|
|
194
214
|
: "flex",
|
|
195
215
|
]}
|
|
196
|
-
href={
|
|
216
|
+
href={l.href}
|
|
197
217
|
>
|
|
198
218
|
{l.icon && (
|
|
199
219
|
<Icon
|
|
@@ -214,7 +234,7 @@ const navbarPrimaryButtonStyle = navbarPrimaryThemeColors
|
|
|
214
234
|
"h-[33px] items-center gap-1.5 px-[11px] text-[13px] bg-linear-to-br from-neutral-100/70 to-neutral-100/90 dark:bg-none dark:bg-neutral-800/80 text-neutral-900/85 hover:text-neutral-600 dark:text-neutral-200/95 dark:hover:text-neutral-200 rounded-lg [corner-shape:superellipse(1.2)] border-[0.5px] border-neutral-900/10 dark:border-white/5 transition-all whitespace-nowrap",
|
|
215
235
|
config.navbar.primary ? "hidden lg:flex" : "flex",
|
|
216
236
|
]}
|
|
217
|
-
href={
|
|
237
|
+
href={navbarSecondaryHref}
|
|
218
238
|
>
|
|
219
239
|
{config.navbar.secondary.icon && (
|
|
220
240
|
<Icon
|
|
@@ -233,7 +253,7 @@ const navbarPrimaryButtonStyle = navbarPrimaryThemeColors
|
|
|
233
253
|
"navbar-primary-trigger font-[350] dark:font-[450] h-8 flex items-center gap-2 px-3 text-[13px] rounded-lg [corner-shape:superellipse(1.2)] duration-200 transition-all whitespace-nowrap hover:opacity-95",
|
|
234
254
|
]}
|
|
235
255
|
style={navbarPrimaryButtonStyle}
|
|
236
|
-
href={
|
|
256
|
+
href={navbarPrimaryHref}
|
|
237
257
|
>
|
|
238
258
|
{config.navbar.primary.icon && (
|
|
239
259
|
<Icon
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
import {
|
|
2
|
+
import { deriveTitleFromEntryId } from "../lib/utils";
|
|
3
|
+
import { getMdxRouteHref } from "../lib/routes";
|
|
3
4
|
import Icon from "./ui/Icon.astro";
|
|
4
5
|
import Tag from "./ui/Tag.astro";
|
|
5
6
|
import { getCollection } from "astro:content";
|
|
@@ -37,7 +38,7 @@ if (!entry) {
|
|
|
37
38
|
// Use title from docs.json config if provided, otherwise derive from entry id
|
|
38
39
|
const text = configTitle || deriveTitleFromEntryId(entry.id);
|
|
39
40
|
|
|
40
|
-
const href =
|
|
41
|
+
const href = await getMdxRouteHref({
|
|
41
42
|
filePath,
|
|
42
43
|
groupSlug,
|
|
43
44
|
homePath: config.home,
|
|
@@ -2,12 +2,8 @@
|
|
|
2
2
|
import { getConfig, type NavGroup } from "../lib/validation";
|
|
3
3
|
import SidebarLink from "./SidebarLink.astro";
|
|
4
4
|
import SidebarOpenApiPageLink from "./sidebar/SidebarOpenApiPageLink.astro";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
buildOpenApiEndpointHref,
|
|
8
|
-
parseOpenApiEndpoint,
|
|
9
|
-
slugify,
|
|
10
|
-
} from "../lib/utils";
|
|
5
|
+
import { parseOpenApiEndpoint, slugify } from "../lib/utils";
|
|
6
|
+
import { getMdxRouteHref, getOpenApiEndpointRouteHref } from "../lib/routes";
|
|
11
7
|
import Tag from "./ui/Tag.astro";
|
|
12
8
|
import Icon from "./ui/Icon.astro";
|
|
13
9
|
|
|
@@ -26,17 +22,18 @@ const groupId = `group-${currentPrefix}`;
|
|
|
26
22
|
const listId = `list-${groupId}`;
|
|
27
23
|
|
|
28
24
|
// Check if any child page is active (shallow check, no recursion needed)
|
|
29
|
-
|
|
25
|
+
let containsActivePage = false;
|
|
26
|
+
for (const child of item.pages) {
|
|
30
27
|
let href: string | null = null;
|
|
31
28
|
|
|
32
29
|
if (typeof child === "string") {
|
|
33
|
-
href =
|
|
30
|
+
href = await getMdxRouteHref({
|
|
34
31
|
filePath: child,
|
|
35
32
|
groupSlug: currentPrefix,
|
|
36
33
|
homePath: config.home,
|
|
37
34
|
});
|
|
38
35
|
} else if ("page" in child) {
|
|
39
|
-
href =
|
|
36
|
+
href = await getMdxRouteHref({
|
|
40
37
|
filePath: child.page,
|
|
41
38
|
groupSlug: currentPrefix,
|
|
42
39
|
homePath: config.home,
|
|
@@ -44,7 +41,8 @@ const containsActivePage = item.pages.some((child) => {
|
|
|
44
41
|
} else if ("openapi" in child) {
|
|
45
42
|
const parsedEndpoint = parseOpenApiEndpoint(child.openapi.endpoint);
|
|
46
43
|
if (parsedEndpoint) {
|
|
47
|
-
href =
|
|
44
|
+
href = await getOpenApiEndpointRouteHref({
|
|
45
|
+
source: child.openapi.source,
|
|
48
46
|
path: parsedEndpoint.path,
|
|
49
47
|
method: parsedEndpoint.method,
|
|
50
48
|
groupSlug: currentPrefix,
|
|
@@ -52,13 +50,16 @@ const containsActivePage = item.pages.some((child) => {
|
|
|
52
50
|
}
|
|
53
51
|
}
|
|
54
52
|
|
|
55
|
-
if (!href)
|
|
53
|
+
if (!href) continue;
|
|
56
54
|
|
|
57
55
|
// Normalize paths for comparison (remove trailing slashes)
|
|
58
56
|
const normalizedCurrent = Astro.url.pathname.replace(/\/$/, "");
|
|
59
57
|
const normalizedTarget = href.replace(/\/$/, "");
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
if (normalizedCurrent === normalizedTarget) {
|
|
59
|
+
containsActivePage = true;
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
62
63
|
---
|
|
63
64
|
|
|
64
65
|
<div
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Tag from "../ui/Tag.astro";
|
|
3
|
-
import { buildOpenApiEndpointHref } from "../../lib/utils";
|
|
4
3
|
import { methodColors } from "../../lib/utils";
|
|
4
|
+
import { getOpenApiEndpointRouteHref } from "../../lib/routes";
|
|
5
5
|
import type { NavTag } from "../../lib/validation";
|
|
6
6
|
|
|
7
7
|
interface Props {
|
|
8
|
+
source: string;
|
|
8
9
|
method: string;
|
|
9
10
|
path: string;
|
|
10
11
|
summary?: string;
|
|
@@ -13,10 +14,19 @@ interface Props {
|
|
|
13
14
|
parentSlug?: string;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
const {
|
|
17
|
+
const {
|
|
18
|
+
source,
|
|
19
|
+
method,
|
|
20
|
+
path: pathStr,
|
|
21
|
+
summary,
|
|
22
|
+
title,
|
|
23
|
+
tag,
|
|
24
|
+
parentSlug = "",
|
|
25
|
+
} = Astro.props;
|
|
17
26
|
|
|
18
27
|
const normalizedMethod = method.toLowerCase();
|
|
19
|
-
const href =
|
|
28
|
+
const href = await getOpenApiEndpointRouteHref({
|
|
29
|
+
source,
|
|
20
30
|
path: pathStr,
|
|
21
31
|
method: normalizedMethod,
|
|
22
32
|
groupSlug: parentSlug,
|
|
@@ -182,6 +182,7 @@ const sortedTagGroups: TagGroup[] = Array.from(tagGroups.entries())
|
|
|
182
182
|
{group.endpoints.map((endpoint) => (
|
|
183
183
|
<li>
|
|
184
184
|
<SidebarEndpointLink
|
|
185
|
+
source={openApiPath}
|
|
185
186
|
method={endpoint.method}
|
|
186
187
|
path={endpoint.path}
|
|
187
188
|
summary={endpoint.summary}
|
|
@@ -196,6 +197,7 @@ const sortedTagGroups: TagGroup[] = Array.from(tagGroups.entries())
|
|
|
196
197
|
untaggedEndpoints.map((endpoint, index) => (
|
|
197
198
|
<li>
|
|
198
199
|
<SidebarEndpointLink
|
|
200
|
+
source={openApiPath}
|
|
199
201
|
method={endpoint.method}
|
|
200
202
|
path={endpoint.path}
|
|
201
203
|
summary={endpoint.summary}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Icon from "../ui/Icon.astro";
|
|
3
|
-
import { validateProps } from "../../lib/component-error";
|
|
4
3
|
|
|
5
4
|
interface Props {
|
|
6
5
|
title: string;
|
|
@@ -19,18 +18,6 @@ const TITLE_SIZE_CLASS = {
|
|
|
19
18
|
xl: "text-xl",
|
|
20
19
|
"2xl": "text-2xl",
|
|
21
20
|
} as const;
|
|
22
|
-
|
|
23
|
-
validateProps(
|
|
24
|
-
"Accordion",
|
|
25
|
-
{ title, icon, defaultOpen, titleSize },
|
|
26
|
-
{
|
|
27
|
-
title: { required: true, type: "string" },
|
|
28
|
-
icon: { type: "string" },
|
|
29
|
-
defaultOpen: { type: "boolean" },
|
|
30
|
-
titleSize: { enum: ["xs", "sm", "md", "lg", "xl", "2xl"] },
|
|
31
|
-
},
|
|
32
|
-
Astro.url.pathname,
|
|
33
|
-
);
|
|
34
21
|
---
|
|
35
22
|
|
|
36
23
|
<div
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Icon from "../ui/Icon.astro";
|
|
3
|
-
import { validateProps } from "../../lib/component-error";
|
|
4
3
|
|
|
5
4
|
type CalloutType = "warning" | "info" | "tip" | "danger" | "success";
|
|
6
5
|
|
|
@@ -43,36 +42,8 @@ const typeDefaults: Record<
|
|
|
43
42
|
},
|
|
44
43
|
};
|
|
45
44
|
|
|
46
|
-
const rawProps = Astro.props as { icon?: unknown; title?: unknown };
|
|
47
|
-
const rawIcon = rawProps.icon;
|
|
48
|
-
const rawTitle = rawProps.title;
|
|
49
45
|
const { type = "info", title, icon, accent = true, color } = Astro.props;
|
|
50
46
|
|
|
51
|
-
validateProps(
|
|
52
|
-
"Callout",
|
|
53
|
-
{ type, title, icon, accent, color },
|
|
54
|
-
{
|
|
55
|
-
type: { enum: ["warning", "info", "tip", "danger", "success"] },
|
|
56
|
-
title: { type: ["string", "boolean"] },
|
|
57
|
-
icon: { type: ["string", "boolean"] },
|
|
58
|
-
accent: { type: "boolean" },
|
|
59
|
-
color: { type: "string" },
|
|
60
|
-
},
|
|
61
|
-
Astro.url.pathname,
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
if (rawIcon === true) {
|
|
65
|
-
throw new Error(
|
|
66
|
-
`[USER_ERROR]: <Callout>: Invalid prop "icon": expected string or false, got true (in ${Astro.url.pathname})`,
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (rawTitle === true) {
|
|
71
|
-
throw new Error(
|
|
72
|
-
`[USER_ERROR]: <Callout>: Invalid prop "title": expected string or false, got true (in ${Astro.url.pathname})`,
|
|
73
|
-
);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
47
|
const defaults = typeDefaults[type];
|
|
77
48
|
const resolvedTitle = title === false ? null : (title ?? defaults.title);
|
|
78
49
|
const resolvedIcon = icon === false ? null : (icon ?? defaults.icon);
|