radiant-docs 0.1.46 → 0.1.48
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/package-lock.json +10 -0
- package/template/package.json +1 -0
- package/template/src/components/OpenApiPage.astro +121 -64
- package/template/src/components/PagePagination.astro +1 -1
- package/template/src/components/SidebarSubgroup.astro +1 -1
- package/template/src/components/endpoint/RequestSnippets.astro +175 -16
- package/template/src/components/endpoint/ResponseDisplay.astro +21 -16
- package/template/src/components/endpoint/ResponseSnippets.astro +175 -16
- package/template/src/components/ui/CodeTabEdge.astro +11 -60
- package/template/src/components/user/Callout.astro +117 -62
- package/template/src/components/user/CodeBlock.astro +31 -20
- package/template/src/components/user/CodeGroup.astro +46 -36
- package/template/src/lib/code/code-block.ts +89 -10
- package/template/src/lib/code/shiki-theme-config.ts +16 -0
- package/template/src/lib/validation.ts +137 -0
- package/template/src/styles/global.css +75 -12
- package/template/src/assets/icons/check.svg +0 -33
- package/template/src/assets/icons/danger.svg +0 -37
- package/template/src/assets/icons/info.svg +0 -36
- package/template/src/assets/icons/lightbulb.svg +0 -74
- package/template/src/assets/icons/sparkle.svg +0 -22
- package/template/src/assets/icons/warning.svg +0 -37
|
@@ -1,112 +1,167 @@
|
|
|
1
1
|
---
|
|
2
2
|
import Icon from "../ui/Icon.astro";
|
|
3
|
-
import warningIcon from "../../assets/icons/warning.svg?url";
|
|
4
|
-
import infoIcon from "../../assets/icons/info.svg?url";
|
|
5
|
-
import lightbulbIcon from "../../assets/icons/lightbulb.svg?url";
|
|
6
|
-
import dangerIcon from "../../assets/icons/danger.svg?url";
|
|
7
|
-
import successIcon from "../../assets/icons/check.svg?url";
|
|
8
3
|
import { validateProps } from "../../lib/component-error";
|
|
9
4
|
|
|
10
5
|
type CalloutType = "warning" | "info" | "tip" | "danger" | "success";
|
|
11
6
|
|
|
12
7
|
interface Props {
|
|
13
8
|
type?: CalloutType;
|
|
14
|
-
title?: string;
|
|
15
|
-
icon?: string;
|
|
9
|
+
title?: string | false;
|
|
10
|
+
icon?: string | false;
|
|
11
|
+
accent?: boolean;
|
|
16
12
|
color?: string;
|
|
17
13
|
}
|
|
18
14
|
|
|
19
15
|
const typeDefaults: Record<
|
|
20
16
|
CalloutType,
|
|
21
|
-
{ icon: string; color: string;
|
|
17
|
+
{ icon: string; color: string; title: string }
|
|
22
18
|
> = {
|
|
23
19
|
warning: {
|
|
24
|
-
icon:
|
|
25
|
-
color: "
|
|
26
|
-
iconColor: "text-amber-500 dark:text-amber-400",
|
|
20
|
+
icon: "fluent:warning-16-filled",
|
|
21
|
+
color: "#FF990A",
|
|
27
22
|
title: "Warning",
|
|
28
23
|
},
|
|
29
24
|
info: {
|
|
30
|
-
icon:
|
|
31
|
-
color: "
|
|
32
|
-
iconColor: "text-sky-600/80 dark:text-sky-400",
|
|
25
|
+
icon: "fluent:info-16-filled",
|
|
26
|
+
color: "#5589C5",
|
|
33
27
|
title: "Info",
|
|
34
28
|
},
|
|
35
29
|
tip: {
|
|
36
|
-
icon:
|
|
37
|
-
color: "
|
|
38
|
-
iconColor: "text-yellow-500 dark:text-yellow-400",
|
|
30
|
+
icon: "fluent:lightbulb-filament-24-filled",
|
|
31
|
+
color: "#FFB400",
|
|
39
32
|
title: "Tip",
|
|
40
33
|
},
|
|
41
34
|
danger: {
|
|
42
|
-
icon:
|
|
43
|
-
color: "
|
|
44
|
-
iconColor: "text-red-600 dark:text-red-400",
|
|
35
|
+
icon: "fluent:diamond-dismiss-24-filled",
|
|
36
|
+
color: "#E5484D",
|
|
45
37
|
title: "Danger",
|
|
46
38
|
},
|
|
47
39
|
success: {
|
|
48
|
-
icon:
|
|
49
|
-
color: "
|
|
50
|
-
iconColor: "text-green-600 dark:text-green-400",
|
|
40
|
+
icon: "fluent:checkmark-starburst-24-filled",
|
|
41
|
+
color: "#46A758",
|
|
51
42
|
title: "Success",
|
|
52
43
|
},
|
|
53
44
|
};
|
|
54
45
|
|
|
55
|
-
const
|
|
46
|
+
const rawProps = Astro.props as { icon?: unknown; title?: unknown };
|
|
47
|
+
const rawIcon = rawProps.icon;
|
|
48
|
+
const rawTitle = rawProps.title;
|
|
49
|
+
const { type = "info", title, icon, accent = true, color } = Astro.props;
|
|
56
50
|
|
|
57
51
|
validateProps(
|
|
58
52
|
"Callout",
|
|
59
|
-
{ type, title, icon, color },
|
|
53
|
+
{ type, title, icon, accent, color },
|
|
60
54
|
{
|
|
61
55
|
type: { enum: ["warning", "info", "tip", "danger", "success"] },
|
|
62
|
-
title: { type: "string" },
|
|
63
|
-
icon: { type: "string" },
|
|
56
|
+
title: { type: ["string", "boolean"] },
|
|
57
|
+
icon: { type: ["string", "boolean"] },
|
|
58
|
+
accent: { type: "boolean" },
|
|
64
59
|
color: { type: "string" },
|
|
65
60
|
},
|
|
66
61
|
Astro.url.pathname,
|
|
67
62
|
);
|
|
68
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
|
+
|
|
69
76
|
const defaults = typeDefaults[type];
|
|
70
|
-
const resolvedTitle = title ?? defaults.title;
|
|
77
|
+
const resolvedTitle = title === false ? null : (title ?? defaults.title);
|
|
78
|
+
const resolvedIcon = icon === false ? null : (icon ?? defaults.icon);
|
|
79
|
+
const resolvedColor = color ?? defaults.color;
|
|
80
|
+
const isIconifyName = (value: string) => {
|
|
81
|
+
const parts = value.split(":");
|
|
82
|
+
return (
|
|
83
|
+
parts.length === 2 &&
|
|
84
|
+
/^[a-z0-9-]+$/i.test(parts[0]) &&
|
|
85
|
+
/^[a-z0-9-]+$/i.test(parts[1])
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
const shouldUseIconComponent =
|
|
89
|
+
typeof resolvedIcon === "string" && isIconifyName(resolvedIcon);
|
|
90
|
+
const hasTitle = typeof resolvedTitle === "string" && resolvedTitle.length > 0;
|
|
71
91
|
---
|
|
72
92
|
|
|
73
93
|
<aside
|
|
74
94
|
class:list={[
|
|
75
|
-
"rd-prose-block relative space-y-1 rounded-xl border-[0.5px]
|
|
95
|
+
"rd-prose-block relative space-y-1 rounded-xl border-[0.5px] bg-neutral-50/70 border-neutral-900/8 dark:border-white/6 px-4 py-3.5 dark:bg-(--rd-code-surface) shadow-[0_.5px_1px_rgba(0,0,0,0.15),0_5px_12px_-6px_rgba(0,0,0,0.08)] dark:shadow-[0_-.5px_1px_rgba(255,255,255,0.15),0_5px_12px_-6px_rgba(0,0,0,0.2)]",
|
|
96
|
+
accent ? "pl-6" : "pl-4",
|
|
76
97
|
]}
|
|
77
98
|
role="note"
|
|
78
99
|
>
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
<
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
100
|
+
{
|
|
101
|
+
accent && (
|
|
102
|
+
<div
|
|
103
|
+
class="absolute left-2.5 inset-y-2.5 w-[2px] rounded-full mb-0"
|
|
104
|
+
style={{ backgroundColor: resolvedColor }}
|
|
105
|
+
/>
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
{
|
|
109
|
+
hasTitle ? (
|
|
110
|
+
<>
|
|
111
|
+
<div
|
|
112
|
+
class:list={[
|
|
113
|
+
"flex items-start gap-2 not-prose",
|
|
114
|
+
resolvedIcon && shouldUseIconComponent ? "mb-2" : "mb-1",
|
|
115
|
+
]}
|
|
116
|
+
>
|
|
117
|
+
{resolvedIcon && shouldUseIconComponent ? (
|
|
118
|
+
<Icon
|
|
119
|
+
name={resolvedIcon}
|
|
120
|
+
class="size-5 shrink-0"
|
|
121
|
+
style={{ color: resolvedColor }}
|
|
122
|
+
/>
|
|
123
|
+
) : resolvedIcon ? (
|
|
124
|
+
<img
|
|
125
|
+
src={resolvedIcon}
|
|
126
|
+
alt=""
|
|
127
|
+
width="16"
|
|
128
|
+
height="16"
|
|
129
|
+
class="shrink-0 border border-white"
|
|
130
|
+
/>
|
|
131
|
+
) : null}
|
|
132
|
+
<h6
|
|
133
|
+
class:list={[
|
|
134
|
+
"font-semibold text-sm text-neutral-900 dark:text-neutral-100",
|
|
135
|
+
]}
|
|
136
|
+
>
|
|
137
|
+
{resolvedTitle}
|
|
138
|
+
</h6>
|
|
139
|
+
</div>
|
|
140
|
+
<div class="prose-rules prose-sm! max-w-none! *:max-w-none! text-neutral-700 dark:text-neutral-300">
|
|
141
|
+
<slot />
|
|
142
|
+
</div>
|
|
143
|
+
</>
|
|
144
|
+
) : (
|
|
145
|
+
<div class="flex items-start gap-2">
|
|
146
|
+
{resolvedIcon && shouldUseIconComponent ? (
|
|
147
|
+
<Icon
|
|
148
|
+
name={resolvedIcon}
|
|
149
|
+
class="mt-0.5 size-5 shrink-0"
|
|
150
|
+
style={{ color: resolvedColor }}
|
|
151
|
+
/>
|
|
152
|
+
) : resolvedIcon ? (
|
|
153
|
+
<img
|
|
154
|
+
src={resolvedIcon}
|
|
155
|
+
alt=""
|
|
156
|
+
width="16"
|
|
157
|
+
height="16"
|
|
158
|
+
class="mt-0.5 shrink-0 border border-white"
|
|
159
|
+
/>
|
|
160
|
+
) : null}
|
|
161
|
+
<div class="prose-rules prose-sm! max-w-none! min-w-0 flex-1 *:max-w-none! text-neutral-700 dark:text-neutral-300">
|
|
162
|
+
<slot />
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
)
|
|
166
|
+
}
|
|
112
167
|
</aside>
|
|
@@ -199,10 +199,14 @@ const displayFilename =
|
|
|
199
199
|
? trimmedFilename
|
|
200
200
|
: buildDefaultCodeFileName(normalizedLanguage);
|
|
201
201
|
|
|
202
|
-
const { lines: tokenLines } = await getCodeLineTokens({
|
|
202
|
+
const { lines: tokenLines, themeColors } = await getCodeLineTokens({
|
|
203
203
|
code: raw,
|
|
204
204
|
language: normalizedLanguage,
|
|
205
205
|
});
|
|
206
|
+
const codeThemeStyle = [
|
|
207
|
+
`--rd-code-line-highlight-theme-bg-light:${themeColors.lineHighlightBackground.light}`,
|
|
208
|
+
`--rd-code-line-highlight-theme-bg-dark:${themeColors.lineHighlightBackground.dark}`,
|
|
209
|
+
].join(";");
|
|
206
210
|
|
|
207
211
|
const rawLines = raw.split("\n");
|
|
208
212
|
const normalizedRawLines = rawLines.length > 0 ? rawLines : [""];
|
|
@@ -244,12 +248,14 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
244
248
|
|
|
245
249
|
const lineContentClass = parsedShowLineNumbers
|
|
246
250
|
? "flex-1 whitespace-pre pr-4"
|
|
247
|
-
:
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
+
: !parsedInCodeGroup && !parsedShowFilename
|
|
252
|
+
? "flex-1 whitespace-pre pl-4 pr-8.5"
|
|
253
|
+
: "flex-1 whitespace-pre pl-4 pr-4";
|
|
254
|
+
const lineHighlightAttribute = isHighlighted
|
|
255
|
+
? ' data-rd-code-line-highlighted="true"'
|
|
256
|
+
: "";
|
|
251
257
|
|
|
252
|
-
return `<span class="${
|
|
258
|
+
return `<span class="flex min-w-full"${lineHighlightAttribute}>${lineNumberHtml}<span class="${lineContentClass}">${tokenHtml}</span></span>`;
|
|
253
259
|
})
|
|
254
260
|
.join("");
|
|
255
261
|
---
|
|
@@ -257,7 +263,7 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
257
263
|
<div
|
|
258
264
|
class:list={[
|
|
259
265
|
"group/prose-code not-prose relative w-full max-w-full min-w-0 rounded-xl",
|
|
260
|
-
parsedInCodeGroup ? "my-0" : "rd-prose-block
|
|
266
|
+
parsedInCodeGroup ? "my-0" : "rd-prose-block",
|
|
261
267
|
]}
|
|
262
268
|
data-rd-code-block-root="true"
|
|
263
269
|
data-rd-collapsed-lines={collapsedLinesValue}
|
|
@@ -268,21 +274,22 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
268
274
|
data-rd-tab-hide-icon={parsedInCodeGroup && parsedHideLanguageIcon
|
|
269
275
|
? "true"
|
|
270
276
|
: undefined}
|
|
277
|
+
style={codeThemeStyle}
|
|
271
278
|
>
|
|
272
279
|
<div
|
|
273
280
|
class:list={[
|
|
274
|
-
"w-full max-w-full min-w-0
|
|
275
|
-
parsedInCodeGroup ? "rounded-
|
|
281
|
+
"w-full max-w-full min-w-0 bg-(--rd-code-surface)",
|
|
282
|
+
parsedInCodeGroup ? "rounded-tr-none rounded-xl" : "rounded-xl",
|
|
276
283
|
]}
|
|
277
284
|
>
|
|
278
285
|
{
|
|
279
286
|
!parsedInCodeGroup && parsedShowFilename ? (
|
|
280
|
-
<div class="flex items-center justify-between gap-2 border-b border-
|
|
287
|
+
<div class="flex items-center justify-between gap-2 border-b-[0.5px] border-(--rd-code-tab-edge-border) bg-(--rd-code-header-surface)">
|
|
281
288
|
<div class="min-w-0 flex-1">
|
|
282
|
-
<div class="relative h-9 w-fit max-w-full rounded-tl-xl bg-
|
|
283
|
-
<div class="absolute inset-x-0 -bottom-px h-px bg-
|
|
284
|
-
<CodeTabEdge className="pointer-events-none absolute -top-
|
|
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">
|
|
289
|
+
<div class="relative h-9 w-fit max-w-full rounded-tl-xl bg-(--rd-code-surface)">
|
|
290
|
+
<div class="absolute inset-x-0 -bottom-px h-px bg-(--rd-code-surface)" />
|
|
291
|
+
<CodeTabEdge className="pointer-events-none absolute -top-[0.5px] left-full z-10 h-[calc(100%+1.5px)]" />
|
|
292
|
+
<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 rounded-tl-xl border-t-[0.5px] border-l-[0.5px] border-(--rd-code-tab-edge-border)">
|
|
286
293
|
{shouldRenderLanguageIcon ? (
|
|
287
294
|
<CodeLanguageIcon
|
|
288
295
|
language={normalizedLanguage}
|
|
@@ -294,8 +301,8 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
294
301
|
</div>
|
|
295
302
|
</div>
|
|
296
303
|
</div>
|
|
297
|
-
<div class="relative h-9 w-5 shrink-0 rounded-tr-xl bg-
|
|
298
|
-
<div class="absolute inset-x-0 -bottom-px h-px bg-
|
|
304
|
+
<div class="relative h-9 w-5 shrink-0 rounded-tr-xl bg-(--rd-code-surface) border-t-[0.5px] border-r-[0.5px] border-(--rd-code-tab-edge-border)">
|
|
305
|
+
<div class="absolute inset-x-0 -bottom-px h-px bg-(--rd-code-surface)" />
|
|
299
306
|
<CodeTabEdge className="pointer-events-none absolute -top-px right-full z-10 h-[calc(100%+2px)] rotate-y-180" />
|
|
300
307
|
<button
|
|
301
308
|
type="button"
|
|
@@ -323,7 +330,11 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
323
330
|
}
|
|
324
331
|
|
|
325
332
|
<div
|
|
326
|
-
class=
|
|
333
|
+
class:list={[
|
|
334
|
+
"relative min-w-0 border-[0.5px] rounded-xl overflow-hidden border-(--rd-code-tab-edge-border)",
|
|
335
|
+
parsedShowFilename && "border-t-0 rounded-t-none",
|
|
336
|
+
parsedInCodeGroup && "rounded-tl-xl border-0!",
|
|
337
|
+
]}
|
|
327
338
|
data-rd-code-group-panel={parsedInCodeGroup ? "true" : undefined}
|
|
328
339
|
>
|
|
329
340
|
{
|
|
@@ -331,7 +342,7 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
331
342
|
<div class="pointer-events-none absolute right-2 top-2 z-20">
|
|
332
343
|
<button
|
|
333
344
|
type="button"
|
|
334
|
-
class="pointer-events-
|
|
345
|
+
class="pointer-events-none inline-flex size-7 appearance-none items-center justify-center rounded-md bg-(--rd-code-surface)/40 backdrop-blur-sm text-neutral-500/80 outline-none ring-0 transition-colors duration-150 hover:text-neutral-700 focus:outline-none focus-visible:outline-none focus:ring-0 focus-visible:ring-0 cursor-pointer group-hover/prose-code:pointer-events-auto group-focus-within/prose-code:pointer-events-auto dark:text-neutral-400 dark:hover:text-neutral-200 relative before:absolute before:inset-1 hover:before:inset-0 before:rounded-md hover:before:bg-neutral-900/4 dark:hover:before:bg-white/4 before:duration-150"
|
|
335
346
|
data-rd-copy-trigger="true"
|
|
336
347
|
data-rd-copy-content={encodedRaw}
|
|
337
348
|
aria-label="Copy code"
|
|
@@ -344,7 +355,7 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
344
355
|
/>
|
|
345
356
|
<Icon
|
|
346
357
|
name="lucide:check"
|
|
347
|
-
class="absolute size-3.5 stroke-3 origin-center scale-25 rotate-6 opacity-0 text-green-
|
|
358
|
+
class="absolute size-3.5 stroke-3 origin-center scale-25 rotate-6 opacity-0 text-green-800/70 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"
|
|
348
359
|
data-rd-copy-check
|
|
349
360
|
aria-hidden="true"
|
|
350
361
|
/>
|
|
@@ -372,7 +383,7 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
372
383
|
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"
|
|
373
384
|
>
|
|
374
385
|
<pre
|
|
375
|
-
class="relative m-0 min-w-full bg-
|
|
386
|
+
class="relative m-0 min-w-full bg-(--rd-code-surface) p-0 text-[13px] leading-6"><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>
|
|
376
387
|
</div>
|
|
377
388
|
</div>
|
|
378
389
|
</div>
|
|
@@ -4,11 +4,11 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
<div
|
|
7
|
-
class="rd-prose-block group/prose-code-group not-prose relative w-full max-w-full min-w-0
|
|
7
|
+
class="rd-prose-block group/prose-code-group not-prose relative w-full max-w-full min-w-0 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
|
|
11
|
+
class="relative z-10 overflow-visible rounded-t-xl bg-(--rd-code-header-surface)"
|
|
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,18 +19,16 @@ 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-
|
|
22
|
+
class="pointer-events-none absolute top-1/2 z-0 h-[28px] -translate-y-1/2 rounded-[9px] border-[0.5px] border-(--rd-code-tab-edge-border) bg-(--rd-code-surface) opacity-0 transition-[left,width,opacity] duration-200 ease-out"
|
|
23
23
|
>
|
|
24
24
|
</div>
|
|
25
25
|
</div>
|
|
26
26
|
</div>
|
|
27
27
|
|
|
28
28
|
<div
|
|
29
|
-
class="relative h-9 w-5 shrink-0 rounded-tr-xl bg-
|
|
29
|
+
class="relative h-9 w-5 shrink-0 rounded-tr-xl bg-(--rd-code-surface) border-t-[0.5px] border-r-[0.5px] border-(--rd-code-tab-edge-border)"
|
|
30
30
|
>
|
|
31
|
-
<div
|
|
32
|
-
class="absolute inset-x-0 -bottom-px h-px bg-white dark:bg-(--rd-code-surface)"
|
|
33
|
-
>
|
|
31
|
+
<div class="absolute inset-x-0 -bottom-px h-px bg-(--rd-code-surface)">
|
|
34
32
|
</div>
|
|
35
33
|
<CodeTabEdge
|
|
36
34
|
className="pointer-events-none absolute -top-px right-full z-10 h-[calc(100%+2px)] rotate-y-180"
|
|
@@ -49,7 +47,7 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
49
47
|
/>
|
|
50
48
|
<Icon
|
|
51
49
|
name="lucide:check"
|
|
52
|
-
class="absolute size-3.5 stroke-3 origin-center scale-25 rotate-6 opacity-0 text-green-
|
|
50
|
+
class="absolute size-3.5 stroke-3 origin-center scale-25 rotate-6 opacity-0 text-green-800/70 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"
|
|
53
51
|
data-rd-copy-check
|
|
54
52
|
aria-hidden="true"
|
|
55
53
|
/>
|
|
@@ -60,7 +58,7 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
60
58
|
|
|
61
59
|
<div
|
|
62
60
|
data-rd-code-group-content
|
|
63
|
-
class="relative min-w-0 overflow-hidden transition-[height] duration-
|
|
61
|
+
class="relative min-w-0 overflow-hidden transition-[height] duration-[360ms] ease-[cubic-bezier(0.22,1,0.36,1)] bg-(--rd-code-surface) rounded-xl rounded-tr-none border-[0.5px] border-(--rd-code-tab-edge-border)"
|
|
64
62
|
>
|
|
65
63
|
<slot />
|
|
66
64
|
</div>
|
|
@@ -93,7 +91,8 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
93
91
|
const prefersReducedMotion =
|
|
94
92
|
typeof window.matchMedia === "function" &&
|
|
95
93
|
window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
96
|
-
const TRANSITION_DURATION_MS = prefersReducedMotion ? 0 :
|
|
94
|
+
const TRANSITION_DURATION_MS = prefersReducedMotion ? 0 : 360;
|
|
95
|
+
const TRANSITION_EASING = "cubic-bezier(0.22, 1, 0.36, 1)";
|
|
97
96
|
|
|
98
97
|
let activeIndex = 0;
|
|
99
98
|
let transitionTimeoutId = null;
|
|
@@ -139,7 +138,7 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
139
138
|
|
|
140
139
|
const tabButton = document.createElement("button");
|
|
141
140
|
tabButton.type = "button";
|
|
142
|
-
tabButton.className = `relative inline-flex h-9 items-center border-0 bg-transparent px-3 py-1.5 text-xs font-medium
|
|
141
|
+
tabButton.className = `relative inline-flex h-9 items-center border-0 bg-transparent px-3 py-1.5 text-xs font-medium transition-colors duration-150 focus:outline-none focus-visible:outline-none cursor-pointer ${hasTabIcon ? "gap-2" : ""}`;
|
|
143
142
|
tabButton.setAttribute("aria-label", filename);
|
|
144
143
|
tabButton.setAttribute("data-rd-code-group-tab", String(index));
|
|
145
144
|
|
|
@@ -205,12 +204,11 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
205
204
|
const updateTabButtonStates = () => {
|
|
206
205
|
tabs.forEach(({ tabButton, iconContainer }, index) => {
|
|
207
206
|
const isActive = index === activeIndex;
|
|
208
|
-
tabButton.classList.toggle("text-
|
|
209
|
-
tabButton.classList.toggle("text-
|
|
210
|
-
|
|
207
|
+
tabButton.classList.toggle("text-neutral-500/80", !isActive);
|
|
208
|
+
tabButton.classList.toggle("dark:text-neutral-400/80", !isActive);
|
|
211
209
|
if (!iconContainer) return;
|
|
212
|
-
iconContainer.classList.toggle("opacity-100", isActive);
|
|
213
210
|
iconContainer.classList.toggle("opacity-80", !isActive);
|
|
211
|
+
iconContainer.classList.toggle("grayscale-100", !isActive);
|
|
214
212
|
});
|
|
215
213
|
syncPill();
|
|
216
214
|
};
|
|
@@ -269,15 +267,31 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
269
267
|
activeItemResizeObserver.observe(activeItem);
|
|
270
268
|
};
|
|
271
269
|
|
|
270
|
+
const setItemToTransitionPosition = (itemElement) => {
|
|
271
|
+
itemElement.style.position = "absolute";
|
|
272
|
+
itemElement.style.inset = "";
|
|
273
|
+
itemElement.style.top = "0";
|
|
274
|
+
itemElement.style.right = "0";
|
|
275
|
+
itemElement.style.bottom = "";
|
|
276
|
+
itemElement.style.left = "0";
|
|
277
|
+
};
|
|
278
|
+
|
|
272
279
|
const setPanelsToRestState = () => {
|
|
273
280
|
tabs.forEach(({ itemElement, panelElement, frameElement }, index) => {
|
|
274
281
|
const isActive = index === activeIndex;
|
|
275
282
|
itemElement.style.position = isActive ? "relative" : "absolute";
|
|
276
|
-
itemElement.style.inset =
|
|
283
|
+
itemElement.style.inset = "";
|
|
284
|
+
itemElement.style.top = isActive ? "" : "0";
|
|
285
|
+
itemElement.style.right = isActive ? "" : "0";
|
|
286
|
+
itemElement.style.bottom = isActive ? "" : "0";
|
|
287
|
+
itemElement.style.left = isActive ? "" : "0";
|
|
277
288
|
itemElement.style.opacity = isActive ? "1" : "0";
|
|
278
289
|
itemElement.style.visibility = isActive ? "visible" : "hidden";
|
|
279
290
|
itemElement.style.pointerEvents = isActive ? "auto" : "none";
|
|
280
291
|
itemElement.style.zIndex = isActive ? "1" : "0";
|
|
292
|
+
itemElement.style.transform = "translateX(0)";
|
|
293
|
+
itemElement.style.animation = "none";
|
|
294
|
+
itemElement.style.willChange = "auto";
|
|
281
295
|
panelElement.style.transform = "translateX(0)";
|
|
282
296
|
panelElement.style.animation = "none";
|
|
283
297
|
panelElement.style.willChange = "auto";
|
|
@@ -313,8 +327,6 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
313
327
|
const nextItem = nextTab?.itemElement;
|
|
314
328
|
const previousPanel = previousTab?.panelElement;
|
|
315
329
|
const nextPanel = nextTab?.panelElement;
|
|
316
|
-
const previousFrame = previousTab?.frameElement;
|
|
317
|
-
const nextFrame = nextTab?.frameElement;
|
|
318
330
|
if (!previousItem || !nextItem || !previousPanel || !nextPanel) {
|
|
319
331
|
normalizeToCurrentState();
|
|
320
332
|
return;
|
|
@@ -331,37 +343,35 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
331
343
|
});
|
|
332
344
|
}
|
|
333
345
|
|
|
334
|
-
previousItem
|
|
335
|
-
previousItem.style.inset = "0";
|
|
346
|
+
setItemToTransitionPosition(previousItem);
|
|
336
347
|
previousItem.style.opacity = "1";
|
|
337
348
|
previousItem.style.visibility = "visible";
|
|
338
349
|
previousItem.style.pointerEvents = "none";
|
|
339
350
|
previousItem.style.zIndex = "1";
|
|
351
|
+
previousItem.style.transform = "translateX(0)";
|
|
352
|
+
previousItem.style.willChange = "transform, opacity";
|
|
340
353
|
previousPanel.style.transform = "translateX(0)";
|
|
341
|
-
previousPanel.style.
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
}
|
|
345
|
-
previousPanel.style.animation =
|
|
354
|
+
previousPanel.style.animation = "none";
|
|
355
|
+
previousPanel.style.willChange = "auto";
|
|
356
|
+
previousItem.style.animation =
|
|
346
357
|
direction === 1
|
|
347
|
-
? `rd-code-group-slide-out-to-left ${TRANSITION_DURATION_MS}ms
|
|
348
|
-
: `rd-code-group-slide-out-to-right ${TRANSITION_DURATION_MS}ms
|
|
358
|
+
? `rd-code-group-slide-out-to-left ${TRANSITION_DURATION_MS}ms ${TRANSITION_EASING} both`
|
|
359
|
+
: `rd-code-group-slide-out-to-right ${TRANSITION_DURATION_MS}ms ${TRANSITION_EASING} both`;
|
|
349
360
|
|
|
350
|
-
nextItem
|
|
351
|
-
nextItem.style.inset = "0";
|
|
361
|
+
setItemToTransitionPosition(nextItem);
|
|
352
362
|
nextItem.style.opacity = "1";
|
|
353
363
|
nextItem.style.visibility = "visible";
|
|
354
364
|
nextItem.style.pointerEvents = "auto";
|
|
355
365
|
nextItem.style.zIndex = "2";
|
|
366
|
+
nextItem.style.transform = "translateX(0)";
|
|
367
|
+
nextItem.style.willChange = "transform, opacity";
|
|
356
368
|
nextPanel.style.transform = "translateX(0)";
|
|
357
|
-
nextPanel.style.
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
}
|
|
361
|
-
nextPanel.style.animation =
|
|
369
|
+
nextPanel.style.animation = "none";
|
|
370
|
+
nextPanel.style.willChange = "auto";
|
|
371
|
+
nextItem.style.animation =
|
|
362
372
|
direction === 1
|
|
363
|
-
? `rd-code-group-slide-in-from-right ${TRANSITION_DURATION_MS}ms
|
|
364
|
-
: `rd-code-group-slide-in-from-left ${TRANSITION_DURATION_MS}ms
|
|
373
|
+
? `rd-code-group-slide-in-from-right ${TRANSITION_DURATION_MS}ms ${TRANSITION_EASING} both`
|
|
374
|
+
: `rd-code-group-slide-in-from-left ${TRANSITION_DURATION_MS}ms ${TRANSITION_EASING} both`;
|
|
365
375
|
|
|
366
376
|
transitionTimeoutId = window.setTimeout(() => {
|
|
367
377
|
transitionTimeoutId = null;
|