radiant-docs 0.1.37 → 0.1.39
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 +2 -0
- package/template/src/components/Footer.astro +1 -1
- package/template/src/components/Header.astro +8 -8
- package/template/src/components/OpenApiPage.astro +18 -18
- package/template/src/components/Search.astro +18 -18
- package/template/src/components/Sidebar.astro +4 -2
- package/template/src/components/SidebarDropdown.astro +82 -79
- package/template/src/components/SidebarSegmented.astro +5 -5
- package/template/src/components/TableOfContents.astro +24 -15
- package/template/src/components/ThemeSwitcher.astro +15 -8
- package/template/src/components/chat/AskAiWidget.tsx +4 -3
- package/template/src/components/endpoint/PlaygroundBar.astro +3 -3
- package/template/src/components/endpoint/PlaygroundButton.astro +2 -2
- package/template/src/components/endpoint/PlaygroundField.astro +53 -53
- package/template/src/components/endpoint/PlaygroundForm.astro +38 -22
- package/template/src/components/endpoint/RequestSnippets.astro +54 -21
- package/template/src/components/endpoint/ResponseDisplay.astro +24 -24
- package/template/src/components/endpoint/ResponseFieldTree.astro +12 -12
- package/template/src/components/endpoint/ResponseFields.astro +19 -19
- package/template/src/components/endpoint/ResponseSnippets.astro +66 -29
- package/template/src/components/ui/CodeTabEdge.astro +6 -4
- package/template/src/components/ui/Field.astro +7 -7
- package/template/src/components/ui/demo/Demo.astro +1 -1
- package/template/src/components/user/Accordion.astro +3 -3
- package/template/src/components/user/Callout.astro +8 -8
- package/template/src/components/user/CodeBlock.astro +63 -25
- package/template/src/components/user/CodeGroup.astro +259 -22
- package/template/src/components/user/ComponentPreviewBlock.astro +36 -10
- package/template/src/components/user/Image.astro +2 -2
- package/template/src/components/user/Step.astro +4 -4
- package/template/src/components/user/Tab.astro +1 -1
- package/template/src/components/user/Tabs.astro +142 -42
- package/template/src/layouts/Layout.astro +1 -1
- package/template/src/lib/code/code-block.ts +150 -15
- package/template/src/lib/mdx/remark-resolve-internal-links.ts +639 -0
- package/template/src/pages/404.astro +44 -0
- package/template/src/styles/global.css +51 -19
|
@@ -116,25 +116,58 @@ function parseHighlightedLineNumbers(
|
|
|
116
116
|
|
|
117
117
|
function buildTokenStyle(token: {
|
|
118
118
|
color?: string;
|
|
119
|
+
darkColor?: string;
|
|
119
120
|
bgColor?: string;
|
|
121
|
+
darkBgColor?: string;
|
|
120
122
|
fontStyle?: number;
|
|
121
123
|
htmlStyle?: Record<string, string>;
|
|
124
|
+
darkHtmlStyle?: Record<string, string>;
|
|
122
125
|
}): string | undefined {
|
|
123
126
|
const styleSegments: string[] = [];
|
|
124
127
|
|
|
125
|
-
|
|
126
|
-
|
|
128
|
+
const pushStyleVariable = (property: string, value?: string) => {
|
|
129
|
+
if (value) styleSegments.push(`${property}:${value}`);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
pushStyleVariable("--rd-token-color", token.color);
|
|
133
|
+
pushStyleVariable("--rd-token-color-dark", token.darkColor);
|
|
134
|
+
pushStyleVariable("--rd-token-bg", token.bgColor);
|
|
135
|
+
pushStyleVariable("--rd-token-bg-dark", token.darkBgColor);
|
|
127
136
|
|
|
128
137
|
const fontStyle = typeof token.fontStyle === "number" ? token.fontStyle : 0;
|
|
129
138
|
if ((fontStyle & 1) === 1) styleSegments.push("font-style:italic");
|
|
130
139
|
if ((fontStyle & 2) === 2) styleSegments.push("font-weight:600");
|
|
131
140
|
if ((fontStyle & 4) === 4) styleSegments.push("text-decoration:underline");
|
|
132
141
|
|
|
133
|
-
|
|
134
|
-
|
|
142
|
+
const pushHtmlStyle = (
|
|
143
|
+
styleObject: Record<string, string> | undefined,
|
|
144
|
+
isDarkStyle: boolean,
|
|
145
|
+
) => {
|
|
146
|
+
if (!styleObject || typeof styleObject !== "object") return;
|
|
147
|
+
|
|
148
|
+
for (const [property, value] of Object.entries(styleObject)) {
|
|
149
|
+
const normalizedProperty = property.trim().toLowerCase();
|
|
150
|
+
if (normalizedProperty === "color") {
|
|
151
|
+
pushStyleVariable(
|
|
152
|
+
isDarkStyle ? "--rd-token-color-dark" : "--rd-token-color",
|
|
153
|
+
value,
|
|
154
|
+
);
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
if (normalizedProperty === "background-color") {
|
|
158
|
+
pushStyleVariable(
|
|
159
|
+
isDarkStyle ? "--rd-token-bg-dark" : "--rd-token-bg",
|
|
160
|
+
value,
|
|
161
|
+
);
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
|
|
135
165
|
styleSegments.push(`${property}:${value}`);
|
|
136
166
|
}
|
|
137
|
-
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
pushHtmlStyle(token.htmlStyle, false);
|
|
170
|
+
pushHtmlStyle(token.darkHtmlStyle, true);
|
|
138
171
|
|
|
139
172
|
if (!styleSegments.length) return undefined;
|
|
140
173
|
return styleSegments.join(";");
|
|
@@ -198,7 +231,7 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
198
231
|
const tokenStyleAttribute = tokenStyle
|
|
199
232
|
? ` style="${escapeAttribute(tokenStyle)}"`
|
|
200
233
|
: "";
|
|
201
|
-
return `<span${tokenStyleAttribute}>${escapeHtml(token.content)}</span>`;
|
|
234
|
+
return `<span data-rd-token${tokenStyleAttribute}>${escapeHtml(token.content)}</span>`;
|
|
202
235
|
})
|
|
203
236
|
.join("")
|
|
204
237
|
: fallbackLineContent.length > 0
|
|
@@ -206,14 +239,14 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
206
239
|
: " ";
|
|
207
240
|
|
|
208
241
|
const lineNumberHtml = parsedShowLineNumbers
|
|
209
|
-
? `<span class="w-10 shrink-0 select-none pl-4 pr-3 text-right tabular-nums text-neutral-400">${lineNumber}</span>`
|
|
242
|
+
? `<span class="w-10 shrink-0 select-none pl-4 pr-3 text-right tabular-nums text-neutral-400 dark:text-neutral-500">${lineNumber}</span>`
|
|
210
243
|
: "";
|
|
211
244
|
|
|
212
245
|
const lineContentClass = parsedShowLineNumbers
|
|
213
246
|
? "flex-1 whitespace-pre pr-4"
|
|
214
247
|
: "flex-1 whitespace-pre pr-4 pl-4";
|
|
215
248
|
const lineClass = isHighlighted
|
|
216
|
-
? "flex min-w-full bg-neutral-100/80"
|
|
249
|
+
? "flex min-w-full bg-neutral-100/80 dark:bg-neutral-800/70"
|
|
217
250
|
: "flex min-w-full";
|
|
218
251
|
|
|
219
252
|
return `<span class="${lineClass}">${lineNumberHtml}<span class="${lineContentClass}">${tokenHtml}</span></span>`;
|
|
@@ -223,8 +256,8 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
223
256
|
|
|
224
257
|
<div
|
|
225
258
|
class:list={[
|
|
226
|
-
"group/prose-code not-prose relative w-full max-w-full min-w-0",
|
|
227
|
-
parsedInCodeGroup ? "my-0" : "my-6",
|
|
259
|
+
"group/prose-code not-prose relative w-full max-w-full min-w-0 rounded-xl",
|
|
260
|
+
parsedInCodeGroup ? "my-0" : "my-6 shadow-xs",
|
|
228
261
|
]}
|
|
229
262
|
data-rd-code-block-root="true"
|
|
230
263
|
data-rd-collapsed-lines={collapsedLinesValue}
|
|
@@ -238,18 +271,18 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
238
271
|
>
|
|
239
272
|
<div
|
|
240
273
|
class:list={[
|
|
241
|
-
"w-full max-w-full min-w-0 overflow-hidden border border-neutral-200 bg-white
|
|
274
|
+
"w-full max-w-full min-w-0 overflow-hidden border border-neutral-200 bg-white dark:border-neutral-800 dark:bg-(--rd-code-surface)",
|
|
242
275
|
parsedInCodeGroup ? "rounded-t-none rounded-b-xl" : "rounded-xl",
|
|
243
276
|
]}
|
|
244
277
|
>
|
|
245
278
|
{
|
|
246
279
|
!parsedInCodeGroup && parsedShowFilename ? (
|
|
247
|
-
<div class="flex items-center justify-between gap-2 border-b border-neutral-200 bg-neutral-50 inset-shadow-sm inset-shadow-neutral-100/80">
|
|
280
|
+
<div class="flex items-center justify-between gap-2 border-b border-neutral-200 bg-neutral-50 inset-shadow-sm inset-shadow-neutral-100/80 dark:border-neutral-800 dark:bg-neutral-900/60 dark:inset-shadow-neutral-900/80">
|
|
248
281
|
<div class="min-w-0 flex-1">
|
|
249
|
-
<div class="relative h-9 w-fit max-w-full rounded-tl-xl bg-white">
|
|
250
|
-
<div class="absolute inset-x-0 -bottom-px h-px bg-white" />
|
|
282
|
+
<div class="relative h-9 w-fit max-w-full rounded-tl-xl bg-white dark:bg-(--rd-code-surface)">
|
|
283
|
+
<div class="absolute inset-x-0 -bottom-px h-px bg-white dark:bg-(--rd-code-surface)" />
|
|
251
284
|
<CodeTabEdge className="pointer-events-none absolute -top-px left-full z-10 h-[calc(100%+2px)]" />
|
|
252
|
-
<div class="relative z-20 inline-flex h-9 max-w-full items-center gap-2 pl-5 py-1.5 text-xs font-medium text-neutral-700">
|
|
285
|
+
<div class="relative z-20 inline-flex h-9 max-w-full items-center gap-2 pl-5 py-1.5 text-xs font-medium text-neutral-700 dark:text-neutral-300">
|
|
253
286
|
{shouldRenderLanguageIcon ? (
|
|
254
287
|
<CodeLanguageIcon
|
|
255
288
|
language={normalizedLanguage}
|
|
@@ -261,12 +294,12 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
261
294
|
</div>
|
|
262
295
|
</div>
|
|
263
296
|
</div>
|
|
264
|
-
<div class="relative h-9 w-5 shrink-0 rounded-tr-xl bg-white">
|
|
265
|
-
<div class="absolute inset-x-0 -bottom-px h-px bg-white" />
|
|
297
|
+
<div class="relative h-9 w-5 shrink-0 rounded-tr-xl bg-white dark:bg-(--rd-code-surface)">
|
|
298
|
+
<div class="absolute inset-x-0 -bottom-px h-px bg-white dark:bg-(--rd-code-surface)" />
|
|
266
299
|
<CodeTabEdge className="pointer-events-none absolute -top-px right-full z-10 h-[calc(100%+2px)] rotate-y-180" />
|
|
267
300
|
<button
|
|
268
301
|
type="button"
|
|
269
|
-
class="absolute right-2 top-1/2 z-20 inline-flex size-7 -translate-y-1/2 appearance-none items-center justify-center rounded-md border-0 bg-transparent text-neutral-500/80 shadow-none outline-none ring-0 transition-colors duration-150 hover:bg-neutral-50 hover:text-neutral-600 focus:outline-none focus-visible:outline-none focus:ring-0 focus-visible:ring-0 cursor-pointer"
|
|
302
|
+
class="absolute right-2 top-1/2 z-20 inline-flex size-7 -translate-y-1/2 appearance-none items-center justify-center rounded-md border-0 bg-transparent text-neutral-500/80 shadow-none outline-none ring-0 transition-colors duration-150 hover:bg-neutral-50 hover:text-neutral-600 focus:outline-none focus-visible:outline-none focus:ring-0 focus-visible:ring-0 cursor-pointer dark:text-neutral-400 dark:hover:bg-neutral-800 dark:hover:text-neutral-200"
|
|
270
303
|
data-rd-copy-trigger="true"
|
|
271
304
|
data-rd-copy-content={encodedRaw}
|
|
272
305
|
aria-label="Copy code"
|
|
@@ -279,7 +312,7 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
279
312
|
/>
|
|
280
313
|
<Icon
|
|
281
314
|
name="lucide:check"
|
|
282
|
-
class="absolute size-3.5 stroke-3 origin-center scale-25 rotate-6 opacity-0 text-green-700/80 transition-all duration-250 ease-[cubic-bezier(0.22,1,0.36,1)] will-change-transform motion-reduce:transition-none"
|
|
315
|
+
class="absolute size-3.5 stroke-3 origin-center scale-25 rotate-6 opacity-0 text-green-700/80 transition-all duration-250 ease-[cubic-bezier(0.22,1,0.36,1)] will-change-transform motion-reduce:transition-none dark:text-green-400/90"
|
|
283
316
|
data-rd-copy-check
|
|
284
317
|
aria-hidden="true"
|
|
285
318
|
/>
|
|
@@ -289,13 +322,16 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
289
322
|
) : null
|
|
290
323
|
}
|
|
291
324
|
|
|
292
|
-
<div
|
|
325
|
+
<div
|
|
326
|
+
class="relative min-w-0"
|
|
327
|
+
data-rd-code-group-panel={parsedInCodeGroup ? "true" : undefined}
|
|
328
|
+
>
|
|
293
329
|
{
|
|
294
330
|
!parsedInCodeGroup && !parsedShowFilename ? (
|
|
295
331
|
<div class="pointer-events-none absolute right-2 top-2 z-20">
|
|
296
332
|
<button
|
|
297
333
|
type="button"
|
|
298
|
-
class="pointer-events-auto inline-flex size-7 appearance-none items-center justify-center rounded-md border border-neutral-200/80 text-neutral-500/80 bg-white/80 backdrop-blur-xs outline-none ring-0 transition-colors duration-150 hover:bg-neutral-50 hover:text-neutral-600 focus:outline-none focus-visible:outline-none focus:ring-0 focus-visible:ring-0 cursor-pointer"
|
|
334
|
+
class="pointer-events-auto inline-flex size-7 appearance-none items-center justify-center rounded-md border border-neutral-200/80 text-neutral-500/80 bg-white/80 backdrop-blur-xs outline-none ring-0 transition-colors duration-150 hover:bg-neutral-50 hover:text-neutral-600 focus:outline-none focus-visible:outline-none focus:ring-0 focus-visible:ring-0 cursor-pointer dark:border-neutral-700/50 dark:bg-(--rd-code-surface) dark:text-neutral-400 dark:hover:bg-neutral-800 dark:hover:text-neutral-200"
|
|
299
335
|
data-rd-copy-trigger="true"
|
|
300
336
|
data-rd-copy-content={encodedRaw}
|
|
301
337
|
aria-label="Copy code"
|
|
@@ -308,7 +344,7 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
308
344
|
/>
|
|
309
345
|
<Icon
|
|
310
346
|
name="lucide:check"
|
|
311
|
-
class="absolute size-3.5 stroke-3 origin-center scale-25 rotate-6 opacity-0 text-green-700/80 transition-all duration-250 ease-[cubic-bezier(0.22,1,0.36,1)] will-change-transform motion-reduce:transition-none"
|
|
347
|
+
class="absolute size-3.5 stroke-3 origin-center scale-25 rotate-6 opacity-0 text-green-700/80 transition-all duration-250 ease-[cubic-bezier(0.22,1,0.36,1)] will-change-transform motion-reduce:transition-none dark:text-green-400/90"
|
|
312
348
|
data-rd-copy-check
|
|
313
349
|
aria-hidden="true"
|
|
314
350
|
/>
|
|
@@ -333,10 +369,10 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
333
369
|
|
|
334
370
|
<div
|
|
335
371
|
data-rd-code-scroll-area
|
|
336
|
-
class="relative overflow-x-auto [scrollbar-width:thin] [scrollbar-color:var(--color-neutral-300)_transparent] [&::-webkit-scrollbar]:h-1.5 [&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-neutral-300/70 hover:[&::-webkit-scrollbar-thumb]:bg-neutral-300/90"
|
|
372
|
+
class="relative overflow-x-auto [scrollbar-width:thin] [scrollbar-color:var(--color-neutral-300)_transparent] [&::-webkit-scrollbar]:h-1.5 [&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar-track]:bg-transparent [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-neutral-300/70 hover:[&::-webkit-scrollbar-thumb]:bg-neutral-300/90 dark:[scrollbar-color:var(--color-neutral-700)_transparent] dark:[&::-webkit-scrollbar-thumb]:bg-neutral-700/70 dark:hover:[&::-webkit-scrollbar-thumb]:bg-neutral-700/90"
|
|
337
373
|
>
|
|
338
374
|
<pre
|
|
339
|
-
class="relative m-0 min-w-full bg-white p-0 text-[13px] leading-6"><code class="block min-w-full py-2.5 font-mono text-neutral-800"><Fragment set:html={renderedCodeLinesHtml} /></code></pre>
|
|
375
|
+
class="relative m-0 min-w-full bg-white p-0 text-[13px] leading-6 dark:bg-(--rd-code-surface)"><code data-rd-code-theme class="block min-w-full py-2.5 font-mono text-neutral-800 dark:text-neutral-200"><Fragment set:html={renderedCodeLinesHtml} /></code></pre>
|
|
340
376
|
</div>
|
|
341
377
|
</div>
|
|
342
378
|
</div>
|
|
@@ -348,7 +384,9 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
348
384
|
const root = script.closest("[data-rd-code-block-root='true']");
|
|
349
385
|
if (!(root instanceof HTMLElement)) return;
|
|
350
386
|
|
|
351
|
-
const copyButtons = root.querySelectorAll(
|
|
387
|
+
const copyButtons = root.querySelectorAll(
|
|
388
|
+
"[data-rd-copy-trigger='true']",
|
|
389
|
+
);
|
|
352
390
|
if (copyButtons.length === 0) return;
|
|
353
391
|
|
|
354
392
|
const setCopiedState = (button, copied) => {
|
|
@@ -4,11 +4,11 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
<div
|
|
7
|
-
class="group/prose-code-group not-prose relative my-6 w-full max-w-full min-w-0"
|
|
7
|
+
class="group/prose-code-group not-prose relative my-6 w-full max-w-full min-w-0 shadow-xs rounded-xl"
|
|
8
8
|
data-rd-code-group-root="true"
|
|
9
9
|
>
|
|
10
10
|
<div
|
|
11
|
-
class="relative z-10 overflow-visible rounded-t-xl border border-b-0 border-neutral-200 bg-neutral-50 inset-shadow-sm inset-shadow-neutral-100/80"
|
|
11
|
+
class="relative z-10 overflow-visible rounded-t-xl border border-b-0 border-neutral-200 bg-neutral-50 inset-shadow-sm inset-shadow-neutral-100/80 dark:border-neutral-800 dark:bg-neutral-900/60 dark:inset-shadow-neutral-900/80"
|
|
12
12
|
>
|
|
13
13
|
<div class="flex min-w-0 items-end justify-between gap-2">
|
|
14
14
|
<div class="min-w-0 flex-1 overflow-hidden rounded-t-xl">
|
|
@@ -19,20 +19,25 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
19
19
|
<div
|
|
20
20
|
data-rd-code-group-pill
|
|
21
21
|
aria-hidden="true"
|
|
22
|
-
class="pointer-events-none absolute top-1/2 z-0 h-[28px] -translate-y-1/2 rounded-[9px] border-[0.5px] border-neutral-200 bg-white
|
|
22
|
+
class="pointer-events-none absolute top-1/2 z-0 h-[28px] -translate-y-1/2 rounded-[9px] border-[0.5px] border-neutral-200 bg-white opacity-0 transition-[left,width,opacity] duration-200 ease-out dark:border-neutral-700/70 dark:bg-(--rd-code-surface)"
|
|
23
23
|
>
|
|
24
24
|
</div>
|
|
25
25
|
</div>
|
|
26
26
|
</div>
|
|
27
27
|
|
|
28
|
-
<div
|
|
29
|
-
|
|
28
|
+
<div
|
|
29
|
+
class="relative h-9 w-5 shrink-0 rounded-tr-xl bg-white dark:bg-(--rd-code-surface)"
|
|
30
|
+
>
|
|
31
|
+
<div
|
|
32
|
+
class="absolute inset-x-0 -bottom-px h-px bg-white dark:bg-(--rd-code-surface)"
|
|
33
|
+
>
|
|
34
|
+
</div>
|
|
30
35
|
<CodeTabEdge
|
|
31
36
|
className="pointer-events-none absolute -top-px right-full z-10 h-[calc(100%+2px)] rotate-y-180"
|
|
32
37
|
/>
|
|
33
38
|
<button
|
|
34
39
|
type="button"
|
|
35
|
-
class="absolute right-2 top-1/2 z-20 inline-flex size-7 -translate-y-1/2 appearance-none items-center justify-center rounded-md border-0 bg-transparent text-neutral-500/80 shadow-none outline-none ring-0 transition-colors duration-150 hover:bg-neutral-50 hover:text-neutral-600 focus:outline-none focus-visible:outline-none focus:ring-0 focus-visible:ring-0 cursor-pointer"
|
|
40
|
+
class="absolute right-2 top-1/2 z-20 inline-flex size-7 -translate-y-1/2 appearance-none items-center justify-center rounded-md border-0 bg-transparent text-neutral-500/80 shadow-none outline-none ring-0 transition-colors duration-150 hover:bg-neutral-50 hover:text-neutral-600 focus:outline-none focus-visible:outline-none focus:ring-0 focus-visible:ring-0 cursor-pointer dark:text-neutral-400 dark:hover:bg-neutral-800 dark:hover:text-neutral-200"
|
|
36
41
|
data-rd-copy-trigger="true"
|
|
37
42
|
aria-label="Copy code"
|
|
38
43
|
>
|
|
@@ -44,7 +49,7 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
44
49
|
/>
|
|
45
50
|
<Icon
|
|
46
51
|
name="lucide:check"
|
|
47
|
-
class="absolute size-3.5 stroke-3 origin-center scale-25 rotate-6 opacity-0 text-green-700/80 transition-all duration-250 ease-[cubic-bezier(0.22,1,0.36,1)] will-change-transform motion-reduce:transition-none"
|
|
52
|
+
class="absolute size-3.5 stroke-3 origin-center scale-25 rotate-6 opacity-0 text-green-700/80 transition-all duration-250 ease-[cubic-bezier(0.22,1,0.36,1)] will-change-transform motion-reduce:transition-none dark:text-green-400/90"
|
|
48
53
|
data-rd-copy-check
|
|
49
54
|
aria-hidden="true"
|
|
50
55
|
/>
|
|
@@ -53,7 +58,10 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
53
58
|
</div>
|
|
54
59
|
</div>
|
|
55
60
|
|
|
56
|
-
<div
|
|
61
|
+
<div
|
|
62
|
+
data-rd-code-group-content
|
|
63
|
+
class="relative min-w-0 overflow-hidden transition-[height] duration-300 ease-in-out"
|
|
64
|
+
>
|
|
57
65
|
<slot />
|
|
58
66
|
</div>
|
|
59
67
|
<script is:inline>
|
|
@@ -69,14 +77,27 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
69
77
|
const pillElement = root.querySelector("[data-rd-code-group-pill]");
|
|
70
78
|
const copyButton = root.querySelector("[data-rd-copy-trigger='true']");
|
|
71
79
|
|
|
72
|
-
if (
|
|
80
|
+
if (
|
|
81
|
+
!(contentElement instanceof HTMLElement) ||
|
|
82
|
+
!(tabsElement instanceof HTMLElement) ||
|
|
83
|
+
!(pillElement instanceof HTMLElement)
|
|
84
|
+
) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
73
87
|
|
|
74
88
|
const codeItems = Array.from(
|
|
75
89
|
contentElement.querySelectorAll("[data-rd-code-group-item='true']"),
|
|
76
|
-
);
|
|
90
|
+
).filter((item) => item instanceof HTMLElement);
|
|
77
91
|
if (codeItems.length === 0) return;
|
|
78
92
|
|
|
93
|
+
const prefersReducedMotion =
|
|
94
|
+
typeof window.matchMedia === "function" &&
|
|
95
|
+
window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
96
|
+
const TRANSITION_DURATION_MS = prefersReducedMotion ? 0 : 300;
|
|
97
|
+
|
|
79
98
|
let activeIndex = 0;
|
|
99
|
+
let transitionTimeoutId = null;
|
|
100
|
+
let activeItemResizeObserver = null;
|
|
80
101
|
|
|
81
102
|
const setCopiedState = (button, copied) => {
|
|
82
103
|
const copyIcon = button.querySelector("[data-rd-copy-icon]");
|
|
@@ -118,8 +139,7 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
118
139
|
|
|
119
140
|
const tabButton = document.createElement("button");
|
|
120
141
|
tabButton.type = "button";
|
|
121
|
-
tabButton.className =
|
|
122
|
-
`relative inline-flex h-9 items-center border-0 bg-transparent px-3 py-1.5 text-xs font-medium text-neutral-600 transition-colors duration-150 focus:outline-none focus-visible:outline-none cursor-pointer ${hasTabIcon ? "gap-2" : ""}`;
|
|
142
|
+
tabButton.className = `relative inline-flex h-9 items-center border-0 bg-transparent px-3 py-1.5 text-xs font-medium text-muted-foreground transition-colors duration-150 focus:outline-none focus-visible:outline-none cursor-pointer ${hasTabIcon ? "gap-2" : ""}`;
|
|
123
143
|
tabButton.setAttribute("aria-label", filename);
|
|
124
144
|
tabButton.setAttribute("data-rd-code-group-tab", String(index));
|
|
125
145
|
|
|
@@ -142,14 +162,28 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
142
162
|
tabWrapper.appendChild(tabButton);
|
|
143
163
|
tabsElement.appendChild(tabWrapper);
|
|
144
164
|
|
|
165
|
+
const panelCandidate = itemElement.querySelector(
|
|
166
|
+
"[data-rd-code-group-panel='true']",
|
|
167
|
+
);
|
|
168
|
+
const panelElement =
|
|
169
|
+
panelCandidate instanceof HTMLElement ? panelCandidate : itemElement;
|
|
170
|
+
const frameElement =
|
|
171
|
+
itemElement.firstElementChild instanceof HTMLElement
|
|
172
|
+
? itemElement.firstElementChild
|
|
173
|
+
: null;
|
|
174
|
+
|
|
145
175
|
return {
|
|
146
176
|
itemElement,
|
|
177
|
+
panelElement,
|
|
178
|
+
frameElement,
|
|
147
179
|
tabWrapper,
|
|
148
180
|
tabButton,
|
|
149
181
|
iconContainer,
|
|
150
182
|
};
|
|
151
183
|
});
|
|
152
184
|
|
|
185
|
+
contentElement.style.transitionDuration = `${TRANSITION_DURATION_MS}ms`;
|
|
186
|
+
|
|
153
187
|
const syncPill = () => {
|
|
154
188
|
const activeTab = tabs[activeIndex]?.tabWrapper;
|
|
155
189
|
if (!activeTab) {
|
|
@@ -168,12 +202,11 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
168
202
|
pillElement.classList.add("opacity-100");
|
|
169
203
|
};
|
|
170
204
|
|
|
171
|
-
const
|
|
172
|
-
tabs.forEach(({
|
|
205
|
+
const updateTabButtonStates = () => {
|
|
206
|
+
tabs.forEach(({ tabButton, iconContainer }, index) => {
|
|
173
207
|
const isActive = index === activeIndex;
|
|
174
|
-
|
|
175
|
-
tabButton.classList.toggle("text-
|
|
176
|
-
tabButton.classList.toggle("text-neutral-600", !isActive);
|
|
208
|
+
tabButton.classList.toggle("text-foreground", isActive);
|
|
209
|
+
tabButton.classList.toggle("text-muted-foreground", !isActive);
|
|
177
210
|
|
|
178
211
|
if (!iconContainer) return;
|
|
179
212
|
iconContainer.classList.toggle("opacity-100", isActive);
|
|
@@ -182,11 +215,163 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
182
215
|
syncPill();
|
|
183
216
|
};
|
|
184
217
|
|
|
218
|
+
const getItemOuterHeight = (itemElement) => {
|
|
219
|
+
const frameElement =
|
|
220
|
+
itemElement.firstElementChild instanceof HTMLElement
|
|
221
|
+
? itemElement.firstElementChild
|
|
222
|
+
: null;
|
|
223
|
+
if (frameElement) {
|
|
224
|
+
const frameRectHeight = frameElement.getBoundingClientRect().height;
|
|
225
|
+
if (Number.isFinite(frameRectHeight) && frameRectHeight > 0) {
|
|
226
|
+
return Math.ceil(frameRectHeight);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const frameOffsetHeight = frameElement.offsetHeight;
|
|
230
|
+
if (Number.isFinite(frameOffsetHeight) && frameOffsetHeight > 0) {
|
|
231
|
+
return frameOffsetHeight;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
const rectHeight = itemElement.getBoundingClientRect().height;
|
|
236
|
+
if (Number.isFinite(rectHeight) && rectHeight > 0) {
|
|
237
|
+
return Math.ceil(rectHeight);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const offsetHeight = itemElement.offsetHeight;
|
|
241
|
+
if (Number.isFinite(offsetHeight) && offsetHeight > 0) {
|
|
242
|
+
return offsetHeight;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return itemElement.scrollHeight;
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
const syncContentHeight = () => {
|
|
249
|
+
const activeItem = tabs[activeIndex]?.itemElement;
|
|
250
|
+
if (!activeItem) return;
|
|
251
|
+
contentElement.style.height = `${getItemOuterHeight(activeItem)}px`;
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
const observeActiveItemHeight = () => {
|
|
255
|
+
if (activeItemResizeObserver) {
|
|
256
|
+
activeItemResizeObserver.disconnect();
|
|
257
|
+
activeItemResizeObserver = null;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
261
|
+
|
|
262
|
+
const activeItem = tabs[activeIndex]?.itemElement;
|
|
263
|
+
if (!activeItem) return;
|
|
264
|
+
|
|
265
|
+
activeItemResizeObserver = new ResizeObserver(() => {
|
|
266
|
+
if (transitionTimeoutId !== null) return;
|
|
267
|
+
syncContentHeight();
|
|
268
|
+
});
|
|
269
|
+
activeItemResizeObserver.observe(activeItem);
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
const setPanelsToRestState = () => {
|
|
273
|
+
tabs.forEach(({ itemElement, panelElement, frameElement }, index) => {
|
|
274
|
+
const isActive = index === activeIndex;
|
|
275
|
+
itemElement.style.position = isActive ? "relative" : "absolute";
|
|
276
|
+
itemElement.style.inset = isActive ? "" : "0";
|
|
277
|
+
itemElement.style.opacity = isActive ? "1" : "0";
|
|
278
|
+
itemElement.style.visibility = isActive ? "visible" : "hidden";
|
|
279
|
+
itemElement.style.pointerEvents = isActive ? "auto" : "none";
|
|
280
|
+
itemElement.style.zIndex = isActive ? "1" : "0";
|
|
281
|
+
panelElement.style.transform = "translateX(0)";
|
|
282
|
+
panelElement.style.animation = "none";
|
|
283
|
+
panelElement.style.willChange = "auto";
|
|
284
|
+
if (frameElement) {
|
|
285
|
+
frameElement.style.height = "";
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
const normalizeToCurrentState = () => {
|
|
291
|
+
setPanelsToRestState();
|
|
292
|
+
syncContentHeight();
|
|
293
|
+
observeActiveItemHeight();
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
const transitionToIndex = (nextIndex) => {
|
|
297
|
+
if (nextIndex === activeIndex) return;
|
|
298
|
+
|
|
299
|
+
if (transitionTimeoutId !== null) {
|
|
300
|
+
window.clearTimeout(transitionTimeoutId);
|
|
301
|
+
transitionTimeoutId = null;
|
|
302
|
+
normalizeToCurrentState();
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const previousIndex = activeIndex;
|
|
306
|
+
const direction = nextIndex > previousIndex ? 1 : -1;
|
|
307
|
+
activeIndex = nextIndex;
|
|
308
|
+
updateTabButtonStates();
|
|
309
|
+
|
|
310
|
+
const previousTab = tabs[previousIndex];
|
|
311
|
+
const nextTab = tabs[nextIndex];
|
|
312
|
+
const previousItem = previousTab?.itemElement;
|
|
313
|
+
const nextItem = nextTab?.itemElement;
|
|
314
|
+
const previousPanel = previousTab?.panelElement;
|
|
315
|
+
const nextPanel = nextTab?.panelElement;
|
|
316
|
+
const previousFrame = previousTab?.frameElement;
|
|
317
|
+
const nextFrame = nextTab?.frameElement;
|
|
318
|
+
if (!previousItem || !nextItem || !previousPanel || !nextPanel) {
|
|
319
|
+
normalizeToCurrentState();
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const previousHeight = getItemOuterHeight(previousItem);
|
|
324
|
+
const nextHeight = getItemOuterHeight(nextItem);
|
|
325
|
+
contentElement.style.height = `${previousHeight}px`;
|
|
326
|
+
if (TRANSITION_DURATION_MS === 0) {
|
|
327
|
+
contentElement.style.height = `${nextHeight}px`;
|
|
328
|
+
} else {
|
|
329
|
+
requestAnimationFrame(() => {
|
|
330
|
+
contentElement.style.height = `${nextHeight}px`;
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
previousItem.style.position = "absolute";
|
|
335
|
+
previousItem.style.inset = "0";
|
|
336
|
+
previousItem.style.opacity = "1";
|
|
337
|
+
previousItem.style.visibility = "visible";
|
|
338
|
+
previousItem.style.pointerEvents = "none";
|
|
339
|
+
previousItem.style.zIndex = "1";
|
|
340
|
+
previousPanel.style.transform = "translateX(0)";
|
|
341
|
+
previousPanel.style.willChange = "transform";
|
|
342
|
+
if (previousFrame) {
|
|
343
|
+
previousFrame.style.height = "100%";
|
|
344
|
+
}
|
|
345
|
+
previousPanel.style.animation =
|
|
346
|
+
direction === 1
|
|
347
|
+
? `rd-code-group-slide-out-to-left ${TRANSITION_DURATION_MS}ms ease-in-out both`
|
|
348
|
+
: `rd-code-group-slide-out-to-right ${TRANSITION_DURATION_MS}ms ease-in-out both`;
|
|
349
|
+
|
|
350
|
+
nextItem.style.position = "absolute";
|
|
351
|
+
nextItem.style.inset = "0";
|
|
352
|
+
nextItem.style.opacity = "1";
|
|
353
|
+
nextItem.style.visibility = "visible";
|
|
354
|
+
nextItem.style.pointerEvents = "auto";
|
|
355
|
+
nextItem.style.zIndex = "2";
|
|
356
|
+
nextPanel.style.transform = "translateX(0)";
|
|
357
|
+
nextPanel.style.willChange = "transform";
|
|
358
|
+
if (nextFrame) {
|
|
359
|
+
nextFrame.style.height = "100%";
|
|
360
|
+
}
|
|
361
|
+
nextPanel.style.animation =
|
|
362
|
+
direction === 1
|
|
363
|
+
? `rd-code-group-slide-in-from-right ${TRANSITION_DURATION_MS}ms ease-in-out both`
|
|
364
|
+
: `rd-code-group-slide-in-from-left ${TRANSITION_DURATION_MS}ms ease-in-out both`;
|
|
365
|
+
|
|
366
|
+
transitionTimeoutId = window.setTimeout(() => {
|
|
367
|
+
transitionTimeoutId = null;
|
|
368
|
+
normalizeToCurrentState();
|
|
369
|
+
}, TRANSITION_DURATION_MS);
|
|
370
|
+
};
|
|
371
|
+
|
|
185
372
|
tabs.forEach(({ tabButton }, index) => {
|
|
186
373
|
tabButton.addEventListener("click", () => {
|
|
187
|
-
|
|
188
|
-
activeIndex = index;
|
|
189
|
-
syncActiveTab();
|
|
374
|
+
transitionToIndex(index);
|
|
190
375
|
});
|
|
191
376
|
});
|
|
192
377
|
|
|
@@ -222,9 +407,61 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
222
407
|
}
|
|
223
408
|
|
|
224
409
|
tabsElement.addEventListener("scroll", syncPill, { passive: true });
|
|
225
|
-
window.addEventListener("resize",
|
|
226
|
-
|
|
410
|
+
window.addEventListener("resize", () => {
|
|
411
|
+
syncPill();
|
|
412
|
+
if (transitionTimeoutId === null) {
|
|
413
|
+
syncContentHeight();
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
updateTabButtonStates();
|
|
417
|
+
normalizeToCurrentState();
|
|
227
418
|
requestAnimationFrame(syncPill);
|
|
228
419
|
})();
|
|
229
420
|
</script>
|
|
230
421
|
</div>
|
|
422
|
+
|
|
423
|
+
<style>
|
|
424
|
+
@keyframes rd-code-group-slide-in-from-right {
|
|
425
|
+
from {
|
|
426
|
+
transform: translateX(100%);
|
|
427
|
+
opacity: 0;
|
|
428
|
+
}
|
|
429
|
+
to {
|
|
430
|
+
transform: translateX(0);
|
|
431
|
+
opacity: 1;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
@keyframes rd-code-group-slide-in-from-left {
|
|
436
|
+
from {
|
|
437
|
+
transform: translateX(-100%);
|
|
438
|
+
opacity: 0;
|
|
439
|
+
}
|
|
440
|
+
to {
|
|
441
|
+
transform: translateX(0);
|
|
442
|
+
opacity: 1;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
@keyframes rd-code-group-slide-out-to-left {
|
|
447
|
+
from {
|
|
448
|
+
transform: translateX(0);
|
|
449
|
+
opacity: 1;
|
|
450
|
+
}
|
|
451
|
+
to {
|
|
452
|
+
transform: translateX(-100%);
|
|
453
|
+
opacity: 0;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
@keyframes rd-code-group-slide-out-to-right {
|
|
458
|
+
from {
|
|
459
|
+
transform: translateX(0);
|
|
460
|
+
opacity: 1;
|
|
461
|
+
}
|
|
462
|
+
to {
|
|
463
|
+
transform: translateX(100%);
|
|
464
|
+
opacity: 0;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
</style>
|
|
@@ -64,12 +64,12 @@ const isInitiallyExpanded = shouldShowAllCode || totalLineCount <= visibleLines;
|
|
|
64
64
|
data-rd-component-preview-root="true"
|
|
65
65
|
>
|
|
66
66
|
<div
|
|
67
|
-
class="w-full max-w-full min-w-0 overflow-x-auto rounded-t-xl border border-b-0
|
|
67
|
+
class="w-full max-w-full min-w-0 overflow-x-auto rounded-t-xl border border-b-0 bg-white dark:bg-neutral-800/15 p-4 xs:p-6 sm:p-12 shadow-xs [&>:first-child]:mt-0! [&>:last-child]:mb-0!"
|
|
68
68
|
>
|
|
69
69
|
<slot />
|
|
70
70
|
</div>
|
|
71
71
|
<div
|
|
72
|
-
class="rd-component-preview__code not-prose relative"
|
|
72
|
+
class="rd-component-preview__code not-prose relative overflow-hidden rounded-b-xl bg-neutral-50 dark:bg-(--rd-code-surface)"
|
|
73
73
|
data-rd-preview-expanded={isInitiallyExpanded ? "true" : "false"}
|
|
74
74
|
style={{ "--rd-preview-visible-lines": String(visibleLines) }}
|
|
75
75
|
>
|
|
@@ -84,17 +84,19 @@ const isInitiallyExpanded = shouldShowAllCode || totalLineCount <= visibleLines;
|
|
|
84
84
|
collapsedLines={collapsedLines}
|
|
85
85
|
/>
|
|
86
86
|
<div
|
|
87
|
-
class="rd-component-preview__overlay pointer-events-none absolute inset-x-px inset-y-px hidden items-end justify-center rounded-b-xl
|
|
87
|
+
class="rd-component-preview__overlay pointer-events-none absolute inset-x-px inset-y-px hidden items-end justify-center rounded-b-xl pb-4"
|
|
88
88
|
data-rd-preview-overlay
|
|
89
89
|
aria-hidden="true"
|
|
90
90
|
>
|
|
91
|
-
<
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
91
|
+
<div class="bg-white dark:bg-neutral-800">
|
|
92
|
+
<button
|
|
93
|
+
type="button"
|
|
94
|
+
class="pointer-events-auto inline-flex h-8 items-center justify-center rounded-md border border-neutral-200 bg-white px-3 text-sm font-medium text-neutral-700 shadow-xl transition-colors duration-150 hover:bg-neutral-50 cursor-pointer dark:border-neutral-700 dark:bg-neutral-700/30 dark:text-neutral-200 dark:hover:bg-neutral-700/50"
|
|
95
|
+
data-rd-preview-expand
|
|
96
|
+
>
|
|
97
|
+
View code
|
|
98
|
+
</button>
|
|
99
|
+
</div>
|
|
98
100
|
</div>
|
|
99
101
|
</div>
|
|
100
102
|
</div>
|
|
@@ -145,14 +147,38 @@ const isInitiallyExpanded = shouldShowAllCode || totalLineCount <= visibleLines;
|
|
|
145
147
|
border-top-right-radius: 0 !important;
|
|
146
148
|
}
|
|
147
149
|
|
|
150
|
+
:global(.dark) .rd-component-preview__code :global(.group\/prose-code > div) {
|
|
151
|
+
background-color: var(--rd-code-surface) !important;
|
|
152
|
+
}
|
|
153
|
+
|
|
148
154
|
.rd-component-preview__code :global(.group\/prose-code pre),
|
|
149
155
|
.rd-component-preview__code :global(.group\/prose-code code) {
|
|
150
156
|
background-color: var(--color-neutral-50) !important;
|
|
151
157
|
}
|
|
152
158
|
|
|
159
|
+
:global(.dark) .rd-component-preview__code :global(.group\/prose-code pre),
|
|
160
|
+
:global(.dark) .rd-component-preview__code :global(.group\/prose-code code) {
|
|
161
|
+
background-color: var(--rd-code-surface) !important;
|
|
162
|
+
}
|
|
163
|
+
|
|
153
164
|
.rd-component-preview__code[data-rd-preview-expanded="false"]
|
|
154
165
|
.rd-component-preview__overlay {
|
|
155
166
|
display: flex;
|
|
167
|
+
background: linear-gradient(
|
|
168
|
+
to top,
|
|
169
|
+
rgb(250 250 250 / 90%),
|
|
170
|
+
rgb(250 250 250 / 30%)
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
:global(.dark)
|
|
175
|
+
.rd-component-preview__code[data-rd-preview-expanded="false"]
|
|
176
|
+
.rd-component-preview__overlay {
|
|
177
|
+
background: linear-gradient(
|
|
178
|
+
to top,
|
|
179
|
+
color-mix(in srgb, var(--rd-code-surface) 90%, transparent),
|
|
180
|
+
color-mix(in srgb, var(--rd-code-surface) 35%, transparent)
|
|
181
|
+
);
|
|
156
182
|
}
|
|
157
183
|
|
|
158
184
|
.rd-component-preview__code :global([data-rd-code-scroll-area]) {
|