radiant-docs 0.1.34 → 0.1.38

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 (56) hide show
  1. package/package.json +1 -1
  2. package/template/astro.config.mjs +27 -0
  3. package/template/package-lock.json +1027 -513
  4. package/template/package.json +3 -2
  5. package/template/scripts/generate-proxy-allowed-origins.mjs +217 -0
  6. package/template/scripts/generate-robots-txt.mjs +19 -0
  7. package/template/scripts/stamp-image-versions.mjs +63 -11
  8. package/template/src/components/Footer.astro +1 -1
  9. package/template/src/components/Header.astro +9 -9
  10. package/template/src/components/LogoLink.astro +2 -1
  11. package/template/src/components/OpenApiPage.astro +18 -18
  12. package/template/src/components/Search.astro +18 -18
  13. package/template/src/components/Sidebar.astro +4 -2
  14. package/template/src/components/SidebarDropdown.astro +82 -79
  15. package/template/src/components/SidebarGroup.astro +3 -0
  16. package/template/src/components/SidebarMenu.astro +14 -1
  17. package/template/src/components/SidebarSegmented.astro +5 -5
  18. package/template/src/components/SidebarSubgroup.astro +35 -12
  19. package/template/src/components/TableOfContents.astro +24 -15
  20. package/template/src/components/ThemeSwitcher.astro +15 -8
  21. package/template/src/components/chat/AskAiWidget.tsx +10 -5
  22. package/template/src/components/endpoint/PlaygroundBar.astro +3 -3
  23. package/template/src/components/endpoint/PlaygroundButton.astro +3 -3
  24. package/template/src/components/endpoint/PlaygroundField.astro +53 -53
  25. package/template/src/components/endpoint/PlaygroundForm.astro +51 -37
  26. package/template/src/components/endpoint/RequestSnippets.astro +54 -21
  27. package/template/src/components/endpoint/ResponseDisplay.astro +24 -24
  28. package/template/src/components/endpoint/ResponseFieldTree.astro +12 -12
  29. package/template/src/components/endpoint/ResponseFields.astro +19 -19
  30. package/template/src/components/endpoint/ResponseSnippets.astro +66 -29
  31. package/template/src/components/sidebar/SidebarEndpointLink.astro +18 -15
  32. package/template/src/components/sidebar/SidebarOpenApiPageLink.astro +56 -0
  33. package/template/src/components/ui/CodeTabEdge.astro +6 -4
  34. package/template/src/components/ui/Field.astro +7 -7
  35. package/template/src/components/ui/Icon.astro +2 -1
  36. package/template/src/components/ui/demo/Demo.astro +1 -1
  37. package/template/src/components/user/Accordion.astro +3 -3
  38. package/template/src/components/user/Callout.astro +8 -8
  39. package/template/src/components/user/CodeBlock.astro +57 -22
  40. package/template/src/components/user/CodeGroup.astro +14 -10
  41. package/template/src/components/user/ComponentPreviewBlock.astro +38 -12
  42. package/template/src/components/user/Image.astro +6 -2
  43. package/template/src/components/user/Step.astro +4 -4
  44. package/template/src/components/user/Tab.astro +1 -1
  45. package/template/src/components/user/Tabs.astro +15 -20
  46. package/template/src/layouts/Layout.astro +9 -4
  47. package/template/src/lib/code/code-block.ts +150 -15
  48. package/template/src/lib/mdx/remark-resolve-internal-links.ts +639 -0
  49. package/template/src/lib/pagefind.ts +2 -1
  50. package/template/src/lib/routes.ts +134 -58
  51. package/template/src/lib/static-asset-url.ts +62 -0
  52. package/template/src/lib/utils.ts +48 -0
  53. package/template/src/lib/validation.ts +115 -27
  54. package/template/src/pages/404.astro +44 -0
  55. package/template/src/styles/global.css +28 -19
  56. package/template/scripts/rewrite-static-asset-host.mjs +0 -408
@@ -55,6 +55,9 @@
55
55
  --border-light: var(--color-neutral-100);
56
56
  --input: oklch(0.922 0 0);
57
57
  --ring: oklch(0.708 0 0);
58
+ --rd-code-surface: #ffffff;
59
+ --rd-code-tab-edge-bg: var(--rd-code-surface);
60
+ --rd-code-tab-edge-border: var(--color-neutral-200);
58
61
  }
59
62
 
60
63
  /* 3. Dark Mode */
@@ -77,6 +80,13 @@
77
80
  --border-light: color-mix(in srgb, var(--color-neutral-800) 50%, transparent);
78
81
  --input: oklch(1 0 0 / 15%);
79
82
  --ring: oklch(0.556 0 0);
83
+ --rd-code-surface: color-mix(
84
+ in srgb,
85
+ var(--color-neutral-800) 55%,
86
+ var(--color-neutral-900) 45%
87
+ );
88
+ --rd-code-tab-edge-bg: var(--rd-code-surface);
89
+ --rd-code-tab-edge-border: var(--color-neutral-800);
80
90
  }
81
91
 
82
92
  @variant dark (&:where(.dark, .dark *));
@@ -143,7 +153,17 @@
143
153
 
144
154
  /* Code single-line styling */
145
155
  :is(.prose, .prose-rules) :not(pre) > code {
146
- @apply px-1 py-px bg-neutral-100/90 text-neutral-600 rounded-md font-mono font-medium border border-neutral-200/80 after:hidden before:hidden;
156
+ @apply px-1 py-px bg-neutral-100/90 text-neutral-600 rounded-md font-mono font-medium border border-neutral-200/80 after:hidden before:hidden dark:bg-neutral-800/80 dark:text-neutral-200 dark:border-neutral-700/80;
157
+ }
158
+
159
+ [data-rd-code-theme] [data-rd-token] {
160
+ color: var(--rd-token-color, currentColor);
161
+ background-color: var(--rd-token-bg, transparent);
162
+ }
163
+
164
+ .dark [data-rd-code-theme] [data-rd-token] {
165
+ color: var(--rd-token-color-dark, var(--rd-token-color, currentColor));
166
+ background-color: var(--rd-token-bg-dark, var(--rd-token-bg, transparent));
147
167
  }
148
168
 
149
169
  /* Keep nested blockquote content flush with the quote container edges */
@@ -203,22 +223,11 @@
203
223
  );
204
224
  }
205
225
 
206
- :root {
207
- --theme-transition: 0ms; /* Default is instant */
208
- }
209
-
210
- /* When the switching class is active, force ALL transitions
211
- to use our synchronized duration */
212
- .is-switching-theme * {
213
- --theme-transition: 200ms; /* Set your desired sync speed */
214
-
215
- transition-duration: var(--theme-transition) !important;
216
- transition-property:
217
- background-color, border-color, color, fill, stroke !important;
218
- }
219
- /* Ensure the pill slider is NOT affected by the forced color duration
220
- so its movement remains independent */
221
- .is-switching-theme .anchor-pill {
222
- transition-duration: 200ms !important;
223
- transition-property: left, width, background-color !important;
226
+ /* While toggling the root theme class, disable transitions for one frame
227
+ so all dark/light styles flip atomically. */
228
+ .is-switching-theme *,
229
+ .is-switching-theme *::before,
230
+ .is-switching-theme *::after {
231
+ transition-duration: 0ms !important;
232
+ transition-delay: 0ms !important;
224
233
  }
@@ -1,408 +0,0 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
-
4
- const CWD = process.cwd();
5
- const DIST_DIR = path.join(CWD, "dist");
6
- const LOCAL_ORIGIN = "https://radiant.invalid";
7
-
8
- const STATIC_EXTENSIONS = new Set([
9
- ".avif",
10
- ".css",
11
- ".eot",
12
- ".gif",
13
- ".ico",
14
- ".jpeg",
15
- ".jpg",
16
- ".js",
17
- ".json",
18
- ".mjs",
19
- ".mp4",
20
- ".otf",
21
- ".pdf",
22
- ".png",
23
- ".svg",
24
- ".ttf",
25
- ".txt",
26
- ".wasm",
27
- ".webmanifest",
28
- ".webp",
29
- ".woff",
30
- ".woff2",
31
- ".xml",
32
- ]);
33
-
34
- const STATIC_PATH_PREFIXES = ["/_astro/", "/_og/", "/pagefind/"];
35
-
36
- function normalizeHostUrl(input) {
37
- const withScheme = /^https?:\/\//i.test(input) ? input : `https://${input}`;
38
- return new URL(withScheme);
39
- }
40
-
41
- function normalizePrefix(input) {
42
- return input.replace(/^\/+/, "").replace(/\/+$/, "");
43
- }
44
-
45
- function findFilesByExtension(dir, extension, files = []) {
46
- if (!fs.existsSync(dir)) return files;
47
-
48
- const entries = fs.readdirSync(dir, { withFileTypes: true });
49
- for (const entry of entries) {
50
- const fullPath = path.join(dir, entry.name);
51
-
52
- if (entry.isDirectory()) {
53
- findFilesByExtension(fullPath, extension, files);
54
- continue;
55
- }
56
-
57
- if (entry.isFile() && entry.name.endsWith(extension)) {
58
- files.push(fullPath);
59
- }
60
- }
61
-
62
- return files;
63
- }
64
-
65
- function htmlBasePathname(filePath) {
66
- const relative = path.relative(DIST_DIR, filePath).replace(/\\/g, "/");
67
- if (relative === "index.html") return "/";
68
-
69
- if (relative.endsWith("/index.html")) {
70
- return `/${relative.slice(0, -"index.html".length)}`;
71
- }
72
-
73
- const slashIndex = relative.lastIndexOf("/");
74
- if (slashIndex === -1) return "/";
75
- return `/${relative.slice(0, slashIndex + 1)}`;
76
- }
77
-
78
- function decodeValue(value) {
79
- return value.trim().replace(/&/g, "&");
80
- }
81
-
82
- function isSkippableUrl(value) {
83
- return (
84
- !value ||
85
- value.startsWith("data:") ||
86
- value.startsWith("blob:") ||
87
- value.startsWith("mailto:") ||
88
- value.startsWith("tel:") ||
89
- value.startsWith("javascript:") ||
90
- value.startsWith("//")
91
- );
92
- }
93
-
94
- function isStaticAssetPath(pathname) {
95
- const normalizedPath = pathname.toLowerCase();
96
- if (STATIC_PATH_PREFIXES.some((prefix) => normalizedPath.startsWith(prefix))) {
97
- return true;
98
- }
99
-
100
- const extension = path.extname(normalizedPath);
101
- return STATIC_EXTENSIONS.has(extension);
102
- }
103
-
104
- function withPrefix(pathname, prefix) {
105
- const normalizedPathname = pathname.startsWith("/") ? pathname : `/${pathname}`;
106
- if (
107
- normalizedPathname === `/${prefix}` ||
108
- normalizedPathname.startsWith(`/${prefix}/`)
109
- ) {
110
- return normalizedPathname;
111
- }
112
-
113
- return `/${prefix}${normalizedPathname}`.replace(/\/+/g, "/");
114
- }
115
-
116
- function rewriteSingleUrl(value, filePath, hostUrl, prefix) {
117
- const decoded = decodeValue(value);
118
- if (isSkippableUrl(decoded)) {
119
- return { value, changed: false };
120
- }
121
-
122
- let parsed;
123
- try {
124
- parsed = new URL(decoded, `${LOCAL_ORIGIN}${htmlBasePathname(filePath)}`);
125
- } catch {
126
- return { value, changed: false };
127
- }
128
-
129
- if (parsed.origin === hostUrl.origin) {
130
- const prefixedPathname = withPrefix(parsed.pathname, prefix);
131
- if (prefixedPathname === parsed.pathname) {
132
- return { value, changed: false };
133
- }
134
-
135
- const updated = `${hostUrl.origin}${prefixedPathname}${parsed.search}${parsed.hash}`;
136
- return {
137
- value: updated.replace(/&/g, "&"),
138
- changed: true,
139
- };
140
- }
141
-
142
- if (parsed.origin !== LOCAL_ORIGIN) {
143
- return { value, changed: false };
144
- }
145
-
146
- if (!isStaticAssetPath(parsed.pathname)) {
147
- return { value, changed: false };
148
- }
149
-
150
- const prefixedPathname = withPrefix(parsed.pathname, prefix);
151
- const updated = `${hostUrl.origin}${prefixedPathname}${parsed.search}${parsed.hash}`;
152
-
153
- return {
154
- value: updated.replace(/&/g, "&"),
155
- changed: updated !== decoded,
156
- };
157
- }
158
-
159
- function rewriteSrcset(value, filePath, hostUrl, prefix) {
160
- const candidates = value.split(",");
161
- let changed = false;
162
-
163
- const rewritten = candidates.map((candidate) => {
164
- const trimmed = candidate.trim();
165
- if (!trimmed) return candidate;
166
-
167
- const whitespaceIndex = trimmed.search(/\s/);
168
- const urlPart =
169
- whitespaceIndex === -1 ? trimmed : trimmed.slice(0, whitespaceIndex);
170
- const descriptor = whitespaceIndex === -1 ? "" : trimmed.slice(whitespaceIndex);
171
-
172
- const rewrittenCandidate = rewriteSingleUrl(urlPart, filePath, hostUrl, prefix);
173
- if (rewrittenCandidate.changed) changed = true;
174
-
175
- return `${rewrittenCandidate.value}${descriptor}`;
176
- });
177
-
178
- return {
179
- value: changed ? rewritten.join(", ") : value,
180
- changed,
181
- };
182
- }
183
-
184
- function rewriteAttribute(html, filePath, tagName, attribute, hostUrl, prefix) {
185
- const pattern = new RegExp(
186
- `(<${tagName}\\b[^>]*\\b${attribute}\\s*=\\s*["'])([^"']*)(["'][^>]*>)`,
187
- "gi",
188
- );
189
-
190
- let changed = false;
191
-
192
- const rewritten = html.replace(pattern, (full, before, value, after) => {
193
- const result =
194
- attribute === "srcset"
195
- ? rewriteSrcset(value, filePath, hostUrl, prefix)
196
- : rewriteSingleUrl(value, filePath, hostUrl, prefix);
197
-
198
- if (!result.changed) return full;
199
- changed = true;
200
- return `${before}${result.value}${after}`;
201
- });
202
-
203
- return { html: rewritten, changed };
204
- }
205
-
206
- function rewriteMetaImageContent(html, propertyName, hostUrl, prefix) {
207
- const patterns = [
208
- new RegExp(
209
- `(<meta\\s+[^>]*property\\s*=\\s*["']${propertyName}["'][^>]*\\bcontent\\s*=\\s*["'])([^"']*)(["'][^>]*>)`,
210
- "gi",
211
- ),
212
- new RegExp(
213
- `(<meta\\s+[^>]*\\bcontent\\s*=\\s*["'])([^"']*)(["'][^>]*property\\s*=\\s*["']${propertyName}["'][^>]*>)`,
214
- "gi",
215
- ),
216
- ];
217
-
218
- let changed = false;
219
- let nextHtml = html;
220
-
221
- for (const pattern of patterns) {
222
- nextHtml = nextHtml.replace(pattern, (full, before, value, after) => {
223
- const result = rewriteSingleUrl(value, DIST_DIR, hostUrl, prefix);
224
- if (!result.changed) return full;
225
- changed = true;
226
- return `${before}${result.value}${after}`;
227
- });
228
- }
229
-
230
- return { html: nextHtml, changed };
231
- }
232
-
233
- function rewriteMetaNameContent(html, name, hostUrl, prefix) {
234
- const patterns = [
235
- new RegExp(
236
- `(<meta\\s+[^>]*name\\s*=\\s*["']${name}["'][^>]*\\bcontent\\s*=\\s*["'])([^"']*)(["'][^>]*>)`,
237
- "gi",
238
- ),
239
- new RegExp(
240
- `(<meta\\s+[^>]*\\bcontent\\s*=\\s*["'])([^"']*)(["'][^>]*name\\s*=\\s*["']${name}["'][^>]*>)`,
241
- "gi",
242
- ),
243
- ];
244
-
245
- let changed = false;
246
- let nextHtml = html;
247
-
248
- for (const pattern of patterns) {
249
- nextHtml = nextHtml.replace(pattern, (full, before, value, after) => {
250
- const result = rewriteSingleUrl(value, DIST_DIR, hostUrl, prefix);
251
- if (!result.changed) return full;
252
- changed = true;
253
- return `${before}${result.value}${after}`;
254
- });
255
- }
256
-
257
- return { html: nextHtml, changed };
258
- }
259
-
260
- function rewriteInlinePagefindRuntimeImports(html, filePath, hostUrl, prefix) {
261
- const pattern =
262
- /(["'])(https?:\/\/[^"'`)]*\/pagefind\/pagefind\.js(?:\?[^"'`)]*)?|\/pagefind\/pagefind\.js(?:\?[^"'`)]*)?)\1/g;
263
- let changed = false;
264
-
265
- const rewritten = html.replace(pattern, (full, quote, urlValue) => {
266
- const result = rewriteSingleUrl(urlValue, filePath, hostUrl, prefix);
267
- if (!result.changed) return full;
268
-
269
- changed = true;
270
- return `${quote}${result.value}${quote}`;
271
- });
272
-
273
- return { html: rewritten, changed };
274
- }
275
-
276
- function rewriteCssUrls(css, filePath, hostUrl, prefix) {
277
- const pattern = /url\(\s*(['"]?)([^"')]+)\1\s*\)/gi;
278
- let changed = false;
279
-
280
- const rewritten = css.replace(pattern, (full, quote, value) => {
281
- const result = rewriteSingleUrl(value, filePath, hostUrl, prefix);
282
- if (!result.changed) return full;
283
-
284
- changed = true;
285
- return `url(${quote}${result.value}${quote})`;
286
- });
287
-
288
- return { css: rewritten, changed };
289
- }
290
-
291
- function main() {
292
- const staticAssetHostInput = process.env.STATIC_ASSET_HOST?.trim();
293
- const staticAssetPrefixInput =
294
- process.env.R2_BUCKET_PREFIX?.trim() ??
295
- process.env.STATIC_ASSET_PREFIX?.trim();
296
-
297
- if (!staticAssetHostInput) {
298
- console.log(
299
- "Skipping static asset host rewrite: STATIC_ASSET_HOST is not configured.",
300
- );
301
- return;
302
- }
303
-
304
- if (!staticAssetPrefixInput) {
305
- console.log(
306
- "Skipping static asset host rewrite: R2_BUCKET_PREFIX or STATIC_ASSET_PREFIX is not configured.",
307
- );
308
- return;
309
- }
310
-
311
- if (!fs.existsSync(DIST_DIR)) {
312
- console.warn("Skipping static asset host rewrite: dist directory not found.");
313
- return;
314
- }
315
-
316
- const hostUrl = normalizeHostUrl(staticAssetHostInput);
317
- const prefix = normalizePrefix(staticAssetPrefixInput);
318
- const htmlFiles = findFilesByExtension(DIST_DIR, ".html").sort();
319
-
320
- if (htmlFiles.length === 0) {
321
- console.warn("Skipping static asset host rewrite: no HTML files found in dist.");
322
- return;
323
- }
324
-
325
- let updatedHtmlCount = 0;
326
- let updatedCssCount = 0;
327
-
328
- for (const htmlFile of htmlFiles) {
329
- const sourceHtml = fs.readFileSync(htmlFile, "utf8");
330
- let nextHtml = sourceHtml;
331
- let fileChanged = false;
332
-
333
- const rewrites = [
334
- ["link", "href"],
335
- ["script", "src"],
336
- ["img", "src"],
337
- ["img", "srcset"],
338
- ["source", "src"],
339
- ["source", "srcset"],
340
- ["video", "src"],
341
- ["video", "poster"],
342
- ["audio", "src"],
343
- ];
344
-
345
- for (const [tagName, attribute] of rewrites) {
346
- const result = rewriteAttribute(
347
- nextHtml,
348
- htmlFile,
349
- tagName,
350
- attribute,
351
- hostUrl,
352
- prefix,
353
- );
354
- nextHtml = result.html;
355
- fileChanged = fileChanged || result.changed;
356
- }
357
-
358
- const ogResult = rewriteMetaImageContent(
359
- nextHtml,
360
- "og:image",
361
- hostUrl,
362
- prefix,
363
- );
364
- nextHtml = ogResult.html;
365
- fileChanged = fileChanged || ogResult.changed;
366
-
367
- const twitterResult = rewriteMetaNameContent(
368
- nextHtml,
369
- "twitter:image",
370
- hostUrl,
371
- prefix,
372
- );
373
- nextHtml = twitterResult.html;
374
- fileChanged = fileChanged || twitterResult.changed;
375
-
376
- const pagefindImportResult = rewriteInlinePagefindRuntimeImports(
377
- nextHtml,
378
- htmlFile,
379
- hostUrl,
380
- prefix,
381
- );
382
- nextHtml = pagefindImportResult.html;
383
- fileChanged = fileChanged || pagefindImportResult.changed;
384
-
385
- if (fileChanged) {
386
- fs.writeFileSync(htmlFile, nextHtml, "utf8");
387
- updatedHtmlCount += 1;
388
- }
389
- }
390
-
391
- const cssFiles = findFilesByExtension(DIST_DIR, ".css").sort();
392
-
393
- for (const cssFile of cssFiles) {
394
- const sourceCss = fs.readFileSync(cssFile, "utf8");
395
- const result = rewriteCssUrls(sourceCss, cssFile, hostUrl, prefix);
396
-
397
- if (!result.changed) continue;
398
-
399
- fs.writeFileSync(cssFile, result.css, "utf8");
400
- updatedCssCount += 1;
401
- }
402
-
403
- console.log(
404
- `✅ Static asset host rewrite complete. Updated HTML ${updatedHtmlCount}/${htmlFiles.length}, CSS ${updatedCssCount}/${cssFiles.length}.`,
405
- );
406
- }
407
-
408
- main();