radiant-docs 0.1.38 → 0.1.40
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/package.json +1 -1
- package/template/astro.config.mjs +38 -7
- package/template/package-lock.json +19 -7
- package/template/package.json +1 -1
- package/template/scripts/generate-robots-txt.mjs +29 -1
- package/template/scripts/stamp-image-versions.mjs +59 -33
- package/template/src/components/Footer.astro +2 -1
- package/template/src/components/Header.astro +8 -6
- package/template/src/components/LogoLink.astro +2 -1
- package/template/src/components/MdxPage.astro +15 -4
- package/template/src/components/PagePagination.astro +61 -0
- package/template/src/components/SidebarDropdown.astro +12 -8
- package/template/src/components/SidebarGroup.astro +1 -1
- package/template/src/components/SidebarMenu.astro +1 -1
- package/template/src/components/SidebarSegmented.astro +6 -5
- package/template/src/components/TableOfContents.astro +4 -13
- package/template/src/components/chat/AskAiWidget.tsx +274 -39
- package/template/src/components/endpoint/PlaygroundForm.astro +2 -1
- package/template/src/components/user/CodeBlock.astro +8 -5
- package/template/src/components/user/CodeGroup.astro +262 -14
- package/template/src/components/user/ComponentPreviewBlock.astro +4 -3
- package/template/src/components/user/Image.astro +43 -53
- package/template/src/components/user/Tabs.astro +128 -23
- package/template/src/layouts/Layout.astro +217 -7
- package/template/src/lib/base-path.ts +98 -0
- package/template/src/lib/component-error.ts +49 -10
- package/template/src/lib/mdx/remark-resolve-internal-links.ts +128 -18
- package/template/src/lib/pagefind.ts +62 -14
- package/template/src/lib/routes.ts +49 -1
- package/template/src/lib/static-asset-url.ts +3 -1
- package/template/src/lib/utils.ts +12 -4
- package/template/src/lib/validation.ts +376 -36
- package/template/src/pages/404.astro +2 -1
- package/template/src/pages/[...slug].astro +68 -6
- package/template/src/styles/global.css +85 -1
package/package.json
CHANGED
|
@@ -239,7 +239,7 @@ function copyContentAssets() {
|
|
|
239
239
|
if (file.includes("src/content/docs") && shouldCopyFile(file)) {
|
|
240
240
|
const relativePath = path.relative(
|
|
241
241
|
path.join(CWD, "src/content/docs"),
|
|
242
|
-
file
|
|
242
|
+
file,
|
|
243
243
|
);
|
|
244
244
|
const destPath = path.join(PUBLIC_DIR, relativePath);
|
|
245
245
|
const destDir = path.dirname(destPath);
|
|
@@ -254,11 +254,40 @@ function copyContentAssets() {
|
|
|
254
254
|
};
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
257
|
+
function normalizeBasePath(pathname) {
|
|
258
|
+
const normalized = pathname.replace(/\/{2,}/g, "/").replace(/\/+$/, "");
|
|
259
|
+
return normalized === "" ? "/" : normalized;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function resolveDocsSiteConfig() {
|
|
263
|
+
const rawSiteUrl =
|
|
264
|
+
typeof process.env.DOCS_SITE_URL === "string"
|
|
265
|
+
? process.env.DOCS_SITE_URL.trim()
|
|
266
|
+
: "";
|
|
267
|
+
|
|
268
|
+
if (!rawSiteUrl) {
|
|
269
|
+
return {
|
|
270
|
+
site: undefined,
|
|
271
|
+
base: "/",
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
try {
|
|
276
|
+
const parsed = new URL(rawSiteUrl);
|
|
277
|
+
return {
|
|
278
|
+
site: parsed.origin,
|
|
279
|
+
base: normalizeBasePath(parsed.pathname),
|
|
280
|
+
};
|
|
281
|
+
} catch {
|
|
282
|
+
return {
|
|
283
|
+
site: rawSiteUrl,
|
|
284
|
+
base: "/",
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
const docsSiteConfig = resolveDocsSiteConfig();
|
|
290
|
+
globalThis.__RADIANT_DOCS_BASE_PATH__ = docsSiteConfig.base;
|
|
262
291
|
|
|
263
292
|
const configuredStaticAssetHost =
|
|
264
293
|
typeof process.env.STATIC_ASSET_HOST === "string" &&
|
|
@@ -284,7 +313,9 @@ const configuredAssetsPrefix =
|
|
|
284
313
|
|
|
285
314
|
// https://astro.build/config
|
|
286
315
|
export default defineConfig({
|
|
287
|
-
site:
|
|
316
|
+
site: docsSiteConfig.site,
|
|
317
|
+
base: docsSiteConfig.base,
|
|
318
|
+
trailingSlash: "never",
|
|
288
319
|
devToolbar: {
|
|
289
320
|
enabled: false,
|
|
290
321
|
},
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"rehype-slug": "^6.0.0",
|
|
46
46
|
"remark-gfm": "^4.0.1",
|
|
47
47
|
"simple-git": "^3.30.0",
|
|
48
|
-
"tailwindcss": "^4.
|
|
48
|
+
"tailwindcss": "^4.2.2",
|
|
49
49
|
"vaul": "^1.1.2",
|
|
50
50
|
"yaml": "^2.8.2",
|
|
51
51
|
"zod": "^3.25.76"
|
|
@@ -5048,6 +5048,12 @@
|
|
|
5048
5048
|
"tailwindcss": "4.1.17"
|
|
5049
5049
|
}
|
|
5050
5050
|
},
|
|
5051
|
+
"node_modules/@tailwindcss/node/node_modules/tailwindcss": {
|
|
5052
|
+
"version": "4.1.17",
|
|
5053
|
+
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.17.tgz",
|
|
5054
|
+
"integrity": "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==",
|
|
5055
|
+
"license": "MIT"
|
|
5056
|
+
},
|
|
5051
5057
|
"node_modules/@tailwindcss/oxide": {
|
|
5052
5058
|
"version": "4.1.17",
|
|
5053
5059
|
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.17.tgz",
|
|
@@ -5302,6 +5308,12 @@
|
|
|
5302
5308
|
"vite": "^5.2.0 || ^6 || ^7"
|
|
5303
5309
|
}
|
|
5304
5310
|
},
|
|
5311
|
+
"node_modules/@tailwindcss/vite/node_modules/tailwindcss": {
|
|
5312
|
+
"version": "4.1.17",
|
|
5313
|
+
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.17.tgz",
|
|
5314
|
+
"integrity": "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==",
|
|
5315
|
+
"license": "MIT"
|
|
5316
|
+
},
|
|
5305
5317
|
"node_modules/@types/alpinejs": {
|
|
5306
5318
|
"version": "3.13.11",
|
|
5307
5319
|
"resolved": "https://registry.npmjs.org/@types/alpinejs/-/alpinejs-3.13.11.tgz",
|
|
@@ -12763,9 +12775,9 @@
|
|
|
12763
12775
|
"license": "MIT"
|
|
12764
12776
|
},
|
|
12765
12777
|
"node_modules/tailwindcss": {
|
|
12766
|
-
"version": "4.
|
|
12767
|
-
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.
|
|
12768
|
-
"integrity": "sha512-
|
|
12778
|
+
"version": "4.2.2",
|
|
12779
|
+
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.2.tgz",
|
|
12780
|
+
"integrity": "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==",
|
|
12769
12781
|
"license": "MIT"
|
|
12770
12782
|
},
|
|
12771
12783
|
"node_modules/tapable": {
|
|
@@ -14008,9 +14020,9 @@
|
|
|
14008
14020
|
}
|
|
14009
14021
|
},
|
|
14010
14022
|
"node_modules/vite": {
|
|
14011
|
-
"version": "6.4.
|
|
14012
|
-
"resolved": "https://registry.npmjs.org/vite/-/vite-6.4.
|
|
14013
|
-
"integrity": "sha512
|
|
14023
|
+
"version": "6.4.2",
|
|
14024
|
+
"resolved": "https://registry.npmjs.org/vite/-/vite-6.4.2.tgz",
|
|
14025
|
+
"integrity": "sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==",
|
|
14014
14026
|
"license": "MIT",
|
|
14015
14027
|
"dependencies": {
|
|
14016
14028
|
"esbuild": "^0.25.0",
|
package/template/package.json
CHANGED
|
@@ -4,6 +4,24 @@ import path from "node:path";
|
|
|
4
4
|
const CWD = process.cwd();
|
|
5
5
|
const DIST_DIR = path.join(CWD, "dist");
|
|
6
6
|
const ROBOTS_TXT_PATH = path.join(DIST_DIR, "robots.txt");
|
|
7
|
+
const ASTRO_SITEMAP_INDEX_FILENAME = "sitemap-index.xml";
|
|
8
|
+
const PUBLIC_SITEMAP_FILENAME = "sitemap.xml";
|
|
9
|
+
|
|
10
|
+
function buildSitemapUrl() {
|
|
11
|
+
const configuredSiteUrl = process.env.DOCS_SITE_URL?.trim();
|
|
12
|
+
if (!configuredSiteUrl) {
|
|
13
|
+
return `/${PUBLIC_SITEMAP_FILENAME}`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
const baseUrl = configuredSiteUrl.endsWith("/")
|
|
18
|
+
? configuredSiteUrl
|
|
19
|
+
: `${configuredSiteUrl}/`;
|
|
20
|
+
return new URL(PUBLIC_SITEMAP_FILENAME, baseUrl).toString();
|
|
21
|
+
} catch {
|
|
22
|
+
return `/${PUBLIC_SITEMAP_FILENAME}`;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
7
25
|
|
|
8
26
|
function main() {
|
|
9
27
|
if (!fs.existsSync(DIST_DIR)) {
|
|
@@ -11,7 +29,17 @@ function main() {
|
|
|
11
29
|
return;
|
|
12
30
|
}
|
|
13
31
|
|
|
14
|
-
const
|
|
32
|
+
const astroSitemapIndexPath = path.join(
|
|
33
|
+
DIST_DIR,
|
|
34
|
+
ASTRO_SITEMAP_INDEX_FILENAME,
|
|
35
|
+
);
|
|
36
|
+
const publicSitemapPath = path.join(DIST_DIR, PUBLIC_SITEMAP_FILENAME);
|
|
37
|
+
if (fs.existsSync(astroSitemapIndexPath)) {
|
|
38
|
+
fs.copyFileSync(astroSitemapIndexPath, publicSitemapPath);
|
|
39
|
+
console.log("✅ sitemap.xml alias generated.");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const robotsTxt = `User-agent: *\nAllow: /\nSitemap: ${buildSitemapUrl()}\n`;
|
|
15
43
|
fs.writeFileSync(ROBOTS_TXT_PATH, robotsTxt, "utf8");
|
|
16
44
|
console.log("✅ robots.txt generated.");
|
|
17
45
|
}
|
|
@@ -28,6 +28,23 @@ const CONFIGURED_PREFIX =
|
|
|
28
28
|
process.env.R2_BUCKET_PREFIX.trim().length > 0
|
|
29
29
|
? process.env.R2_BUCKET_PREFIX.trim().replace(/^\/+|\/+$/g, "")
|
|
30
30
|
: null;
|
|
31
|
+
const CONFIGURED_BASE_PATH = (() => {
|
|
32
|
+
const raw =
|
|
33
|
+
typeof process.env.DOCS_SITE_URL === "string"
|
|
34
|
+
? process.env.DOCS_SITE_URL.trim()
|
|
35
|
+
: "";
|
|
36
|
+
if (!raw) return null;
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
const parsed = new URL(raw);
|
|
40
|
+
const normalized = parsed.pathname
|
|
41
|
+
.replace(/\/{2,}/g, "/")
|
|
42
|
+
.replace(/\/+$/, "");
|
|
43
|
+
return normalized && normalized !== "/" ? normalized : null;
|
|
44
|
+
} catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
})();
|
|
31
48
|
const VERSIONED_EXTENSIONS = new Set([
|
|
32
49
|
".avif",
|
|
33
50
|
".gif",
|
|
@@ -100,20 +117,25 @@ function getHash(filePath) {
|
|
|
100
117
|
|
|
101
118
|
function normalizePathForDistLookup(pathname) {
|
|
102
119
|
const normalizedPathname = path.posix.normalize(pathname);
|
|
103
|
-
|
|
104
|
-
|
|
120
|
+
|
|
121
|
+
const withoutStaticPrefix = stripPathPrefix(
|
|
122
|
+
normalizedPathname,
|
|
123
|
+
CONFIGURED_PREFIX ? `/${CONFIGURED_PREFIX}` : null,
|
|
124
|
+
);
|
|
125
|
+
return stripPathPrefix(withoutStaticPrefix, CONFIGURED_BASE_PATH);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function stripPathPrefix(pathname, prefix) {
|
|
129
|
+
if (!prefix) {
|
|
130
|
+
return pathname;
|
|
105
131
|
}
|
|
106
132
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
normalizedPathname === prefix ||
|
|
110
|
-
normalizedPathname.startsWith(`${prefix}/`)
|
|
111
|
-
) {
|
|
112
|
-
const stripped = normalizedPathname.slice(prefix.length);
|
|
133
|
+
if (pathname === prefix || pathname.startsWith(`${prefix}/`)) {
|
|
134
|
+
const stripped = pathname.slice(prefix.length);
|
|
113
135
|
return stripped.startsWith("/") ? stripped : `/${stripped}`;
|
|
114
136
|
}
|
|
115
137
|
|
|
116
|
-
return
|
|
138
|
+
return pathname;
|
|
117
139
|
}
|
|
118
140
|
|
|
119
141
|
function resolveLocalImagePath(urlValue, filePath) {
|
|
@@ -133,7 +155,10 @@ function resolveLocalImagePath(urlValue, filePath) {
|
|
|
133
155
|
|
|
134
156
|
let parsed;
|
|
135
157
|
try {
|
|
136
|
-
parsed = new URL(
|
|
158
|
+
parsed = new URL(
|
|
159
|
+
decoded,
|
|
160
|
+
`https://radiant.invalid${htmlBasePathname(filePath)}`,
|
|
161
|
+
);
|
|
137
162
|
} catch {
|
|
138
163
|
return null;
|
|
139
164
|
}
|
|
@@ -158,8 +183,9 @@ function resolveLocalImagePath(urlValue, filePath) {
|
|
|
158
183
|
return null;
|
|
159
184
|
}
|
|
160
185
|
|
|
161
|
-
const normalizedPathname = normalizePathForDistLookup(
|
|
162
|
-
.
|
|
186
|
+
const normalizedPathname = normalizePathForDistLookup(
|
|
187
|
+
parsed.pathname,
|
|
188
|
+
).replace(/^\/+/, "");
|
|
163
189
|
const absolutePath = path.resolve(DIST_DIR, normalizedPathname);
|
|
164
190
|
|
|
165
191
|
if (
|
|
@@ -208,7 +234,8 @@ function stampSrcset(srcsetValue, filePath) {
|
|
|
208
234
|
const whitespaceIndex = trimmed.search(/\s/);
|
|
209
235
|
const urlPart =
|
|
210
236
|
whitespaceIndex === -1 ? trimmed : trimmed.slice(0, whitespaceIndex);
|
|
211
|
-
const descriptor =
|
|
237
|
+
const descriptor =
|
|
238
|
+
whitespaceIndex === -1 ? "" : trimmed.slice(whitespaceIndex);
|
|
212
239
|
|
|
213
240
|
const stamped = stampSingleUrl(urlPart, filePath);
|
|
214
241
|
if (stamped.changed) changed = true;
|
|
@@ -237,20 +264,17 @@ function replaceAttribute(html, filePath, attribute) {
|
|
|
237
264
|
|
|
238
265
|
let changed = false;
|
|
239
266
|
|
|
240
|
-
const nextHtml = html.replace(
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
? stampSrcset(value, filePath)
|
|
246
|
-
: stampSingleUrl(value, filePath);
|
|
267
|
+
const nextHtml = html.replace(pattern, (fullMatch, prefix, value, suffix) => {
|
|
268
|
+
const stamped =
|
|
269
|
+
attribute === "srcset"
|
|
270
|
+
? stampSrcset(value, filePath)
|
|
271
|
+
: stampSingleUrl(value, filePath);
|
|
247
272
|
|
|
248
|
-
|
|
273
|
+
if (!stamped.changed) return fullMatch;
|
|
249
274
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
);
|
|
275
|
+
changed = true;
|
|
276
|
+
return `${prefix}${stamped.value}${suffix}`;
|
|
277
|
+
});
|
|
254
278
|
|
|
255
279
|
return { html: nextHtml, changed };
|
|
256
280
|
}
|
|
@@ -259,17 +283,13 @@ function hasIconRel(tagSource) {
|
|
|
259
283
|
const relMatch = tagSource.match(/\brel\s*=\s*["']([^"']+)["']/i);
|
|
260
284
|
if (!relMatch) return false;
|
|
261
285
|
|
|
262
|
-
const relTokens = relMatch[1]
|
|
263
|
-
.toLowerCase()
|
|
264
|
-
.split(/\s+/)
|
|
265
|
-
.filter(Boolean);
|
|
286
|
+
const relTokens = relMatch[1].toLowerCase().split(/\s+/).filter(Boolean);
|
|
266
287
|
|
|
267
288
|
return relTokens.includes("icon") || relTokens.includes("apple-touch-icon");
|
|
268
289
|
}
|
|
269
290
|
|
|
270
291
|
function replaceIconLinkHref(html, filePath) {
|
|
271
|
-
const pattern =
|
|
272
|
-
/(<link\b[^>]*\bhref\s*=\s*["'])([^"']*)(["'][^>]*>)/gi;
|
|
292
|
+
const pattern = /(<link\b[^>]*\bhref\s*=\s*["'])([^"']*)(["'][^>]*>)/gi;
|
|
273
293
|
let changed = false;
|
|
274
294
|
|
|
275
295
|
const nextHtml = html.replace(pattern, (fullMatch, prefix, value, suffix) => {
|
|
@@ -297,7 +317,9 @@ function main() {
|
|
|
297
317
|
|
|
298
318
|
const htmlFiles = findHtmlFiles(DIST_DIR).sort();
|
|
299
319
|
if (htmlFiles.length === 0) {
|
|
300
|
-
console.warn(
|
|
320
|
+
console.warn(
|
|
321
|
+
"Skipping image version stamping: no HTML files found in dist.",
|
|
322
|
+
);
|
|
301
323
|
return;
|
|
302
324
|
}
|
|
303
325
|
|
|
@@ -307,7 +329,11 @@ function main() {
|
|
|
307
329
|
const sourceHtml = fs.readFileSync(htmlFile, "utf8");
|
|
308
330
|
const srcResult = replaceAttribute(sourceHtml, htmlFile, "src");
|
|
309
331
|
const srcSetResult = replaceAttribute(srcResult.html, htmlFile, "srcset");
|
|
310
|
-
const posterResult = replaceAttribute(
|
|
332
|
+
const posterResult = replaceAttribute(
|
|
333
|
+
srcSetResult.html,
|
|
334
|
+
htmlFile,
|
|
335
|
+
"poster",
|
|
336
|
+
);
|
|
311
337
|
const iconHrefResult = replaceIconLinkHref(posterResult.html, htmlFile);
|
|
312
338
|
const fileChanged =
|
|
313
339
|
srcResult.changed ||
|
|
@@ -2,6 +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 { withBasePath } from "../lib/base-path";
|
|
5
6
|
|
|
6
7
|
interface Props {
|
|
7
8
|
askAiEnabled?: boolean;
|
|
@@ -66,7 +67,7 @@ const socialIcons: Record<string, string> = {
|
|
|
66
67
|
<div class="flex flex-wrap justify-center gap-x-8 gap-y-3">
|
|
67
68
|
{footer.links.map((link) => (
|
|
68
69
|
<a
|
|
69
|
-
href={link.href}
|
|
70
|
+
href={withBasePath(link.href)}
|
|
70
71
|
class="text-sm text-neutral-500 hover:text-neutral-900 dark:text-neutral-400 dark:hover:text-neutral-100 transition-colors duration-300"
|
|
71
72
|
>
|
|
72
73
|
{link.text}
|
|
@@ -4,6 +4,7 @@ import { getConfig } from "../lib/validation";
|
|
|
4
4
|
import Search from "./Search.astro";
|
|
5
5
|
import LogoLink from "./LogoLink.astro";
|
|
6
6
|
import sparkleIcon from "../assets/icons/sparkle.svg?url";
|
|
7
|
+
import { withBasePath } from "../lib/base-path";
|
|
7
8
|
|
|
8
9
|
interface Props {
|
|
9
10
|
showAskAiTrigger?: boolean;
|
|
@@ -58,14 +59,15 @@ const config = await getConfig();
|
|
|
58
59
|
showAskAiTrigger ? (
|
|
59
60
|
<button
|
|
60
61
|
type="button"
|
|
61
|
-
class="hidden md:inline-flex items-center gap-2 h-8 rounded-lg [corner-shape:superellipse(1.2)] bg-linear-to-b from-
|
|
62
|
+
class="hidden md:inline-flex items-center gap-2 h-8 rounded-lg [corner-shape:superellipse(1.2)] bg-linear-to-b from-[var(--color-theme-top)] to-[var(--color-theme-bottom)] px-3 text-[13px] font-[350] text-[var(--color-theme-foreground)] shadow-sm hover:opacity-95 cursor-pointer"
|
|
62
63
|
onclick="window.dispatchEvent(new CustomEvent('ask-ai:open'));"
|
|
63
64
|
>
|
|
64
65
|
<img
|
|
65
66
|
src={sparkleIcon}
|
|
66
67
|
alt=""
|
|
67
68
|
aria-hidden="true"
|
|
68
|
-
class="size-3 -ml-px
|
|
69
|
+
class="size-3 -ml-px"
|
|
70
|
+
style="filter: var(--color-theme-icon-filter);"
|
|
69
71
|
/>
|
|
70
72
|
Ask AI
|
|
71
73
|
</button>
|
|
@@ -92,7 +94,7 @@ const config = await getConfig();
|
|
|
92
94
|
? "hidden 2xl:flex"
|
|
93
95
|
: "flex",
|
|
94
96
|
]}
|
|
95
|
-
href={l.href}
|
|
97
|
+
href={withBasePath(l.href)}
|
|
96
98
|
>
|
|
97
99
|
{l.icon && (
|
|
98
100
|
<Icon
|
|
@@ -113,7 +115,7 @@ const config = await getConfig();
|
|
|
113
115
|
"h-[33px] items-center gap-1.5 px-[11px] text-[13px] bg-white/90 dark:bg-neutral-800/80 text-neutral-600/85 hover:text-neutral-600 dark:text-neutral-200/95 dark:hover:text-neutral-200 rounded-lg [corner-shape:superellipse(1.2)] border border-neutral-200 dark:border-neutral-700/40 shadow-xs transition-all whitespace-nowrap",
|
|
114
116
|
config.navbar.primary ? "hidden lg:flex" : "flex",
|
|
115
117
|
]}
|
|
116
|
-
href={config.navbar.secondary.href}
|
|
118
|
+
href={withBasePath(config.navbar.secondary.href)}
|
|
117
119
|
>
|
|
118
120
|
{config.navbar.secondary.icon && (
|
|
119
121
|
<Icon
|
|
@@ -129,9 +131,9 @@ const config = await getConfig();
|
|
|
129
131
|
{config.navbar.primary && (
|
|
130
132
|
<a
|
|
131
133
|
class:list={[
|
|
132
|
-
"font-[350]
|
|
134
|
+
"font-[350] h-8 flex items-center gap-2 px-3 text-[13px] rounded-lg [corner-shape:superellipse(1.2)] bg-linear-to-b from-[var(--color-theme-top)] to-[var(--color-theme-bottom)] text-[var(--color-theme-foreground)] duration-200 shadow-sm transition-all whitespace-nowrap hover:opacity-95",
|
|
133
135
|
]}
|
|
134
|
-
href={config.navbar.primary.href}
|
|
136
|
+
href={withBasePath(config.navbar.primary.href)}
|
|
135
137
|
>
|
|
136
138
|
{config.navbar.primary.icon && (
|
|
137
139
|
<Icon
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { getConfig, type LogoVariant } from "../lib/validation";
|
|
3
|
+
import { withBasePath } from "../lib/base-path";
|
|
3
4
|
import { resolveStaticAssetUrl } from "../lib/static-asset-url";
|
|
4
5
|
|
|
5
6
|
const config = await getConfig();
|
|
@@ -53,7 +54,7 @@ const lightLogoUrl = lightLogo.logoUrl;
|
|
|
53
54
|
const darkLogoUrl = darkLogo.logoUrl;
|
|
54
55
|
|
|
55
56
|
// Get the href for the logo link (defaults to "/")
|
|
56
|
-
const logoHref = config.logo?.href || "/";
|
|
57
|
+
const logoHref = withBasePath(config.logo?.href || "/");
|
|
57
58
|
const logoPillText =
|
|
58
59
|
config.logo?.pill === false ? null : (config.logo?.pill ?? "Docs");
|
|
59
60
|
|
|
@@ -14,14 +14,18 @@ import CodeBlock from "./user/CodeBlock.astro";
|
|
|
14
14
|
import CodeGroup from "./user/CodeGroup.astro";
|
|
15
15
|
import ComponentPreview from "./user/ComponentPreview.astro";
|
|
16
16
|
import ComponentPreviewBlock from "./user/ComponentPreviewBlock.astro";
|
|
17
|
-
import type { MdxRoute } from "../lib/routes";
|
|
17
|
+
import type { MdxRoute, Route } from "../lib/routes";
|
|
18
|
+
import PagePagination from "./PagePagination.astro";
|
|
18
19
|
|
|
19
20
|
interface Props {
|
|
20
21
|
entry: any;
|
|
21
22
|
route: MdxRoute;
|
|
23
|
+
previousRoute?: Route;
|
|
24
|
+
nextRoute?: Route;
|
|
25
|
+
homePath?: string;
|
|
22
26
|
}
|
|
23
27
|
|
|
24
|
-
const { entry, route } = Astro.props;
|
|
28
|
+
const { entry, route, previousRoute, nextRoute, homePath } = Astro.props;
|
|
25
29
|
|
|
26
30
|
const components = {
|
|
27
31
|
Accordion,
|
|
@@ -55,8 +59,15 @@ const tocHeadings = headings.filter(({ depth }) => depth === 2 || depth === 3);
|
|
|
55
59
|
<h1 class="text-4xl font-semibold tracking-tight">{title}</h1>
|
|
56
60
|
</header>
|
|
57
61
|
<div class="flex w-full min-w-0 justify-between gap-x-12">
|
|
58
|
-
<div class="
|
|
59
|
-
<
|
|
62
|
+
<div class="min-w-0 flex-1">
|
|
63
|
+
<div class="prose-rules">
|
|
64
|
+
<Content components={components} />
|
|
65
|
+
</div>
|
|
66
|
+
<PagePagination
|
|
67
|
+
previousRoute={previousRoute}
|
|
68
|
+
nextRoute={nextRoute}
|
|
69
|
+
homePath={homePath}
|
|
70
|
+
/>
|
|
60
71
|
</div>
|
|
61
72
|
<aside class="hidden xl:block w-56 shrink-0">
|
|
62
73
|
<TableOfContents headings={tocHeadings} />
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { Route } from "../lib/routes";
|
|
3
|
+
import { prependBasePath } from "../lib/base-path";
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
previousRoute?: Route;
|
|
7
|
+
nextRoute?: Route;
|
|
8
|
+
homePath?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const { previousRoute, nextRoute, homePath } = Astro.props;
|
|
12
|
+
|
|
13
|
+
function buildHref(route: Route): string {
|
|
14
|
+
if (route.type === "mdx" && homePath && route.filePath === homePath) {
|
|
15
|
+
return prependBasePath("/");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return prependBasePath(
|
|
19
|
+
route.slug.startsWith("/") ? route.slug : `/${route.slug}`,
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
{
|
|
25
|
+
(previousRoute || nextRoute) && (
|
|
26
|
+
<nav class="w-full max-w-2xl pt-16 dark:border-neutral-800" aria-label="Page pagination">
|
|
27
|
+
<div class="grid gap-3 sm:grid-cols-2">
|
|
28
|
+
{previousRoute && (
|
|
29
|
+
<a
|
|
30
|
+
href={buildHref(previousRoute)}
|
|
31
|
+
class="group flex flex-col rounded-lg border border-neutral-200/90 bg-white/70 p-4 transition-colors hover:border-neutral-300 dark:border-neutral-800 dark:bg-neutral-900/40 dark:hover:border-neutral-700 shadow-xs"
|
|
32
|
+
>
|
|
33
|
+
<span class="block text-[10px] font-medium uppercase tracking-wide text-neutral-400 dark:text-neutral-400">
|
|
34
|
+
Previous
|
|
35
|
+
</span>
|
|
36
|
+
<div class="font-medium text-neutral-900 dark:text-neutral-100">
|
|
37
|
+
{previousRoute.title}
|
|
38
|
+
</div>
|
|
39
|
+
</a>
|
|
40
|
+
)}
|
|
41
|
+
|
|
42
|
+
{nextRoute && (
|
|
43
|
+
<a
|
|
44
|
+
href={buildHref(nextRoute)}
|
|
45
|
+
class:list={[
|
|
46
|
+
"group flex flex-col rounded-lg border border-neutral-200/90 bg-white/70 p-4 transition-colors hover:border-neutral-300/80 dark:border-neutral-800 dark:bg-neutral-900/40 dark:hover:border-neutral-700 shadow-xs",
|
|
47
|
+
!previousRoute && "sm:col-start-2",
|
|
48
|
+
]}
|
|
49
|
+
>
|
|
50
|
+
<span class="block text-right text-[10px] font-medium uppercase tracking-wide text-neutral-400 dark:text-neutral-400">
|
|
51
|
+
Next
|
|
52
|
+
</span>
|
|
53
|
+
<div class="text-right font-medium text-neutral-900 dark:text-neutral-100">
|
|
54
|
+
{nextRoute.title}
|
|
55
|
+
</div>
|
|
56
|
+
</a>
|
|
57
|
+
)}
|
|
58
|
+
</div>
|
|
59
|
+
</nav>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
@@ -3,6 +3,7 @@ import Icon from "./ui/Icon.astro";
|
|
|
3
3
|
import { getConfig, type NavMenu } from "../lib/validation";
|
|
4
4
|
import SidebarMenu from "./SidebarMenu.astro";
|
|
5
5
|
import { slugify } from "../lib/utils";
|
|
6
|
+
import { prependBasePath, stripBasePath } from "../lib/base-path";
|
|
6
7
|
import { getAllRoutes } from "../lib/routes";
|
|
7
8
|
|
|
8
9
|
interface Props {
|
|
@@ -12,9 +13,9 @@ interface Props {
|
|
|
12
13
|
|
|
13
14
|
const { menu, parentSlug = "" } = Astro.props;
|
|
14
15
|
|
|
15
|
-
const pathname = Astro.url.pathname;
|
|
16
|
+
const pathname = stripBasePath(Astro.url.pathname);
|
|
16
17
|
const config = await getConfig();
|
|
17
|
-
const routes = await getAllRoutes();
|
|
18
|
+
const routes = (await getAllRoutes()).filter((route) => !route.hidden);
|
|
18
19
|
|
|
19
20
|
let currentMenuIndex = menu.items.findIndex(
|
|
20
21
|
(i) => slugify(i.label) === pathname.split("/")[1],
|
|
@@ -52,8 +53,8 @@ for (const route of routes) {
|
|
|
52
53
|
seen.add(topLevel);
|
|
53
54
|
const href =
|
|
54
55
|
route.type === "mdx" && config.home && route.filePath === config.home
|
|
55
|
-
? "/"
|
|
56
|
-
: `/${slug}
|
|
56
|
+
? prependBasePath("/")
|
|
57
|
+
: prependBasePath(`/${slug}`);
|
|
57
58
|
firstHrefOfMenuItems.push(href);
|
|
58
59
|
}
|
|
59
60
|
}
|
|
@@ -86,7 +87,10 @@ const currentPrefix = parentSlug
|
|
|
86
87
|
}
|
|
87
88
|
<div class="relative">
|
|
88
89
|
<button
|
|
89
|
-
class=
|
|
90
|
+
class:list={[
|
|
91
|
+
"flex items-center w-full text-sm text-neutral-700 dark:text-neutral-200 bg-white dark:bg-neutral-700/30 border-t border-x border-neutral-200/70 dark:border-neutral-700/40 dark:border-b rounded-lg shadow-xs px-3 py-2 cursor-pointer",
|
|
92
|
+
menu.label ? "" : "border-b",
|
|
93
|
+
]}
|
|
90
94
|
x-on:click="open = true"
|
|
91
95
|
aria-haspopup="menu"
|
|
92
96
|
aria-expanded
|
|
@@ -131,7 +135,7 @@ const currentPrefix = parentSlug
|
|
|
131
135
|
? "before:bg-neutral-200/50 dark:before:bg-neutral-700/50 text-neutral-900 dark:text-white"
|
|
132
136
|
: "hover:before:bg-neutral-100/70 dark:hover:before:bg-neutral-700/30",
|
|
133
137
|
]}
|
|
134
|
-
href={firstHrefOfMenuItems[index] ?? "/"}
|
|
138
|
+
href={firstHrefOfMenuItems[index] ?? prependBasePath("/")}
|
|
135
139
|
>
|
|
136
140
|
{menu.items[index].icon && (
|
|
137
141
|
<Icon
|
|
@@ -160,8 +164,8 @@ const currentPrefix = parentSlug
|
|
|
160
164
|
class:list={[
|
|
161
165
|
"relative -mt-2 pt-2 overflow-y-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
|
|
162
166
|
menu.label
|
|
163
|
-
? "h-[calc(100vh-4px-64px-12px-70px-
|
|
164
|
-
: "h-[calc(100vh-4px-64px-12px-38px-
|
|
167
|
+
? "h-[calc(100vh-4px-64px-12px-70px-51px+8px)]"
|
|
168
|
+
: "h-[calc(100vh-4px-64px-12px-38px-51px+8px)]",
|
|
165
169
|
]}
|
|
166
170
|
>
|
|
167
171
|
<SidebarMenu
|
|
@@ -18,7 +18,7 @@ const groupSlug = slugify(item.group);
|
|
|
18
18
|
const currentPrefix = parentSlug ? `${parentSlug}/${groupSlug}` : groupSlug;
|
|
19
19
|
---
|
|
20
20
|
|
|
21
|
-
<li>
|
|
21
|
+
<li class="my-8 first:my-0 last:my-0">
|
|
22
22
|
<div class:list={["text-sm font-semibold mb-2 flex items-center gap-2 px-2"]}>
|
|
23
23
|
{item.icon && <Icon name={item.icon} class="size-4 text-neutral-500" />}
|
|
24
24
|
{item.group}
|
|
@@ -22,7 +22,7 @@ let { navigation, parentSlug = "" } = Astro.props;
|
|
|
22
22
|
|
|
23
23
|
{
|
|
24
24
|
navigation.pages ? (
|
|
25
|
-
<ul class="px-2 pt-4 pb-
|
|
25
|
+
<ul class="px-2 pt-4 pb-4">
|
|
26
26
|
{navigation.pages.map((item) =>
|
|
27
27
|
typeof item === "string" ? (
|
|
28
28
|
<li>
|