radiant-docs 0.1.40 → 0.1.42
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 +42 -40
- package/template/package-lock.json +7 -0
- package/template/package.json +3 -2
- package/template/public/favicon.svg +16 -8
- package/template/scripts/remove-assistant-for-non-pro.mjs +28 -0
- package/template/src/components/Header.astro +151 -17
- package/template/src/components/MdxPage.astro +76 -22
- package/template/src/components/PagePagination.astro +44 -8
- package/template/src/components/Sidebar.astro +10 -1
- package/template/src/components/TableOfContents.astro +159 -53
- package/template/src/components/chat/AssistantDocsWidget.astro +16 -0
- package/template/src/components/chat/AssistantDocsWidget.tsx +615 -0
- package/template/src/components/chat/AssistantEmbedPanel.tsx +2679 -0
- package/template/src/components/chat/AssistantEmbedPanelPage.astro +95 -0
- package/template/src/components/user/Accordion.astro +2 -2
- package/template/src/components/user/AccordionGroup.astro +1 -1
- package/template/src/components/user/Callout.astro +10 -4
- package/template/src/components/user/Card.astro +488 -0
- package/template/src/components/user/CardGradient.astro +964 -0
- package/template/src/components/user/CodeBlock.astro +1 -1
- package/template/src/components/user/CodeGroup.astro +1 -1
- package/template/src/components/user/Column.astro +25 -0
- package/template/src/components/user/Columns.astro +200 -0
- package/template/src/components/user/ComponentPreviewBlock.astro +1 -1
- package/template/src/components/user/Image.astro +1 -1
- package/template/src/components/user/Step.astro +1 -1
- package/template/src/components/user/Steps.astro +1 -1
- package/template/src/components/user/Tab.astro +1 -3
- package/template/src/components/user/Tabs.astro +2 -2
- package/template/src/layouts/Layout.astro +13 -156
- package/template/src/lib/assistant-chrome-defaults.ts +86 -0
- package/template/src/lib/assistant-chrome.ts +39 -0
- package/template/src/lib/assistant-embed-script.ts +1088 -0
- package/template/src/lib/assistant-panel-config.ts +80 -0
- package/template/src/lib/favicon.ts +31 -0
- package/template/src/lib/theme-css.ts +176 -0
- package/template/src/lib/validation.ts +668 -41
- package/template/src/pages/-/assistant/embed.js.ts +15 -0
- package/template/src/pages/-/assistant/panel.astro +5 -0
- package/template/src/pages/404.astro +4 -4
- package/template/src/styles/global.css +81 -4
- package/template/src/components/chat/AskAiWidget.tsx +0 -2011
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
import "../../styles/global.css";
|
|
3
|
+
import "../../styles/google-sans-flex.css";
|
|
4
|
+
import "../../styles/geist-mono.css";
|
|
5
|
+
import AssistantEmbedPanel from "./AssistantEmbedPanel";
|
|
6
|
+
import { getAssistantPanelRuntimeConfig } from "../../lib/assistant-panel-config";
|
|
7
|
+
import { getDocsThemeCss } from "../../lib/theme-css";
|
|
8
|
+
import { getConfig } from "../../lib/validation";
|
|
9
|
+
|
|
10
|
+
const config = await getConfig();
|
|
11
|
+
const themeCss = getDocsThemeCss(config.theme);
|
|
12
|
+
const assistantConfig = getAssistantPanelRuntimeConfig(config);
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
<!doctype html>
|
|
16
|
+
<html lang="en">
|
|
17
|
+
<head>
|
|
18
|
+
<meta charset="utf-8" />
|
|
19
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
20
|
+
<meta name="robots" content="noindex" />
|
|
21
|
+
<style is:inline is:global set:html={themeCss}></style>
|
|
22
|
+
<script is:inline>
|
|
23
|
+
(() => {
|
|
24
|
+
const applyTheme = (theme) => {
|
|
25
|
+
if (theme !== "light" && theme !== "dark") {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
document.documentElement.dataset.theme = theme;
|
|
30
|
+
document.documentElement.classList.toggle("dark", theme === "dark");
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const params = new URLSearchParams(window.location.search);
|
|
34
|
+
const forcedTheme = params.get("mode");
|
|
35
|
+
const localStorageTheme = localStorage.getItem("theme");
|
|
36
|
+
const prefersDark = window.matchMedia(
|
|
37
|
+
"(prefers-color-scheme: dark)",
|
|
38
|
+
).matches;
|
|
39
|
+
const theme =
|
|
40
|
+
forcedTheme === "light" || forcedTheme === "dark"
|
|
41
|
+
? forcedTheme
|
|
42
|
+
: localStorageTheme === "light" || localStorageTheme === "dark"
|
|
43
|
+
? localStorageTheme
|
|
44
|
+
: prefersDark
|
|
45
|
+
? "dark"
|
|
46
|
+
: "light";
|
|
47
|
+
|
|
48
|
+
applyTheme(theme);
|
|
49
|
+
|
|
50
|
+
window.addEventListener("message", (event) => {
|
|
51
|
+
if (
|
|
52
|
+
!event.data ||
|
|
53
|
+
typeof event.data !== "object" ||
|
|
54
|
+
event.data.type !== "assistant-embed:set-theme"
|
|
55
|
+
) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
applyTheme(event.data.theme);
|
|
60
|
+
});
|
|
61
|
+
})();
|
|
62
|
+
</script>
|
|
63
|
+
<style is:inline>
|
|
64
|
+
html,
|
|
65
|
+
body {
|
|
66
|
+
width: 100%;
|
|
67
|
+
height: 100%;
|
|
68
|
+
margin: 0;
|
|
69
|
+
overflow: hidden;
|
|
70
|
+
background: transparent;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
body {
|
|
74
|
+
color-scheme: inherit;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@media (max-width: 640px) {
|
|
78
|
+
.assistant-panel-shell > div {
|
|
79
|
+
border-radius: 0;
|
|
80
|
+
border-left: 0;
|
|
81
|
+
border-right: 0;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
</style>
|
|
85
|
+
</head>
|
|
86
|
+
<body data-pagefind-ignore>
|
|
87
|
+
<div class="assistant-panel-shell h-full">
|
|
88
|
+
<AssistantEmbedPanel
|
|
89
|
+
client:only="preact"
|
|
90
|
+
{...assistantConfig}
|
|
91
|
+
linkTarget="blank"
|
|
92
|
+
/>
|
|
93
|
+
</div>
|
|
94
|
+
</body>
|
|
95
|
+
</html>
|
|
@@ -50,7 +50,7 @@ validateProps(
|
|
|
50
50
|
}`
|
|
51
51
|
x-init="id = (typeof register === 'function') ? register() : Math.random()"
|
|
52
52
|
role="region"
|
|
53
|
-
class="block border-b border-neutral-800/10 dark:border-neutral-700/50 last:border-b-0. [&:first-child>h4>button]:pt-0 [&:last-child>div>div]:pb-0"
|
|
53
|
+
class="rd-accordion block border-b border-neutral-800/10 dark:border-neutral-700/50 last:border-b-0. [&:first-child>h4>button]:pt-0 [&:last-child>div>div]:pb-0"
|
|
54
54
|
>
|
|
55
55
|
<h4 class="not-prose">
|
|
56
56
|
<button
|
|
@@ -71,7 +71,7 @@ validateProps(
|
|
|
71
71
|
</button>
|
|
72
72
|
</h4>
|
|
73
73
|
<div x-show="expanded" x-collapse>
|
|
74
|
-
<div class="
|
|
74
|
+
<div class="prose-rules max-w-none! *:max-w-none! pb-4!">
|
|
75
75
|
<slot />
|
|
76
76
|
</div>
|
|
77
77
|
</div>
|
|
@@ -72,13 +72,13 @@ const resolvedTitle = title ?? defaults.title;
|
|
|
72
72
|
|
|
73
73
|
<aside
|
|
74
74
|
class:list={[
|
|
75
|
-
"
|
|
75
|
+
"rd-prose-block relative space-y-1 rounded-xl border-[0.5px]. border-neutral-900/8 bg-white px-4 py-3.5 pl-6 dark:border-neutral-800 dark:bg-(--rd-code-surface) shadow-[0px_1px_3px_0px_rgba(0,0,0,0.04),0px_0px_0px_0.8px_rgba(0,0,0,0.06)_inset,0px_-1px_0px_0px_rgba(0,0,0,0.06)_inset]",
|
|
76
76
|
]}
|
|
77
77
|
role="note"
|
|
78
78
|
>
|
|
79
79
|
<div
|
|
80
80
|
class:list={[
|
|
81
|
-
"absolute left-2 inset-y-2 w-[
|
|
81
|
+
"absolute left-2.5 inset-y-2.5 w-[2px] rounded-full mb-0",
|
|
82
82
|
defaults.color,
|
|
83
83
|
]}
|
|
84
84
|
style={color && { backgroundColor: color }}
|
|
@@ -96,11 +96,17 @@ const resolvedTitle = title ?? defaults.title;
|
|
|
96
96
|
<img src={defaults.icon} alt="" width="16" height="16" class="" />
|
|
97
97
|
)
|
|
98
98
|
}
|
|
99
|
-
<h6
|
|
99
|
+
<h6
|
|
100
|
+
class:list={[
|
|
101
|
+
"font-semibold text-sm text-neutral-900 dark:text-neutral-100",
|
|
102
|
+
]}
|
|
103
|
+
>
|
|
100
104
|
{resolvedTitle}
|
|
101
105
|
</h6>
|
|
102
106
|
</div>
|
|
103
|
-
<div
|
|
107
|
+
<div
|
|
108
|
+
class="prose-rules prose-sm! max-w-none! *:max-w-none! text-neutral-700 dark:text-neutral-300"
|
|
109
|
+
>
|
|
104
110
|
<slot />
|
|
105
111
|
</div>
|
|
106
112
|
</aside>
|
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { withBasePath } from "../../lib/base-path";
|
|
3
|
+
import { getConfig, type ThemeColorByMode } from "../../lib/validation";
|
|
4
|
+
import Icon from "../ui/Icon.astro";
|
|
5
|
+
import {
|
|
6
|
+
validateNoUnknownProps,
|
|
7
|
+
validateProps,
|
|
8
|
+
} from "../../lib/component-error";
|
|
9
|
+
import {
|
|
10
|
+
getDocsBaseColorShade,
|
|
11
|
+
getThemeForegroundColor,
|
|
12
|
+
} from "../../lib/theme-css";
|
|
13
|
+
|
|
14
|
+
interface Cover {
|
|
15
|
+
icon?: string;
|
|
16
|
+
text?: string;
|
|
17
|
+
glass?: boolean;
|
|
18
|
+
colors?: string[];
|
|
19
|
+
patternSeed?: string;
|
|
20
|
+
colorSeed?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface CardButton {
|
|
24
|
+
text: string;
|
|
25
|
+
href: string;
|
|
26
|
+
color?: string | ThemeColorByMode;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface Props {
|
|
30
|
+
title: string;
|
|
31
|
+
href?: string;
|
|
32
|
+
icon?: string;
|
|
33
|
+
cover?: Cover;
|
|
34
|
+
button?: CardButton;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const cardProps = Astro.props as Record<string, unknown>;
|
|
38
|
+
|
|
39
|
+
validateNoUnknownProps(
|
|
40
|
+
"Card",
|
|
41
|
+
cardProps,
|
|
42
|
+
["title", "href", "icon", "cover", "button"],
|
|
43
|
+
Astro.url.pathname,
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
validateProps(
|
|
47
|
+
"Card",
|
|
48
|
+
cardProps,
|
|
49
|
+
{
|
|
50
|
+
title: { required: true, type: "string" },
|
|
51
|
+
href: { type: "string" },
|
|
52
|
+
icon: { type: "string" },
|
|
53
|
+
cover: { type: "object" },
|
|
54
|
+
button: { type: "object" },
|
|
55
|
+
},
|
|
56
|
+
Astro.url.pathname,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const rawCover = cardProps.cover;
|
|
60
|
+
const rawButton = cardProps.button;
|
|
61
|
+
if (rawCover !== undefined && (rawCover === null || Array.isArray(rawCover))) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`[USER_ERROR]: <Card>: Invalid prop "cover": expected object (in ${Astro.url.pathname})`,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
if (
|
|
67
|
+
rawButton !== undefined &&
|
|
68
|
+
(rawButton === null || Array.isArray(rawButton))
|
|
69
|
+
) {
|
|
70
|
+
throw new Error(
|
|
71
|
+
`[USER_ERROR]: <Card>: Invalid prop "button": expected object (in ${Astro.url.pathname})`,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const coverProps =
|
|
76
|
+
rawCover && typeof rawCover === "object"
|
|
77
|
+
? (rawCover as Record<string, unknown>)
|
|
78
|
+
: undefined;
|
|
79
|
+
const buttonProps =
|
|
80
|
+
rawButton && typeof rawButton === "object"
|
|
81
|
+
? (rawButton as Record<string, unknown>)
|
|
82
|
+
: undefined;
|
|
83
|
+
|
|
84
|
+
if (coverProps) {
|
|
85
|
+
validateNoUnknownProps(
|
|
86
|
+
"Card.cover",
|
|
87
|
+
coverProps,
|
|
88
|
+
["icon", "text", "glass", "colors", "patternSeed", "colorSeed"],
|
|
89
|
+
Astro.url.pathname,
|
|
90
|
+
);
|
|
91
|
+
validateProps(
|
|
92
|
+
"Card.cover",
|
|
93
|
+
coverProps,
|
|
94
|
+
{
|
|
95
|
+
icon: { type: "string" },
|
|
96
|
+
text: { type: "string" },
|
|
97
|
+
glass: { type: "boolean" },
|
|
98
|
+
colors: { type: "array" },
|
|
99
|
+
patternSeed: { type: "string" },
|
|
100
|
+
colorSeed: { type: "string" },
|
|
101
|
+
},
|
|
102
|
+
Astro.url.pathname,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (buttonProps) {
|
|
107
|
+
validateNoUnknownProps(
|
|
108
|
+
"Card.button",
|
|
109
|
+
buttonProps,
|
|
110
|
+
["text", "href", "color"],
|
|
111
|
+
Astro.url.pathname,
|
|
112
|
+
);
|
|
113
|
+
validateProps(
|
|
114
|
+
"Card.button",
|
|
115
|
+
buttonProps,
|
|
116
|
+
{
|
|
117
|
+
text: { required: true, type: "string" },
|
|
118
|
+
href: { required: true, type: "string" },
|
|
119
|
+
color: { type: ["string", "object"] },
|
|
120
|
+
},
|
|
121
|
+
Astro.url.pathname,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function normalizeHexColor(value: unknown, propPath: string): string {
|
|
126
|
+
if (typeof value !== "string") {
|
|
127
|
+
throw new Error(
|
|
128
|
+
`[USER_ERROR]: <Card>: Invalid prop "${propPath}": expected string (in ${Astro.url.pathname})`,
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const trimmedValue = value.trim();
|
|
133
|
+
const normalizedValue = trimmedValue.startsWith("#")
|
|
134
|
+
? trimmedValue
|
|
135
|
+
: `#${trimmedValue}`;
|
|
136
|
+
if (
|
|
137
|
+
!/^#(?:[A-Fa-f0-9]{3}|[A-Fa-f0-9]{4}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})$/.test(
|
|
138
|
+
normalizedValue,
|
|
139
|
+
)
|
|
140
|
+
) {
|
|
141
|
+
throw new Error(
|
|
142
|
+
`[USER_ERROR]: <Card>: Invalid prop "${propPath}": expected a hex color like "#3b82f6" (in ${Astro.url.pathname})`,
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return normalizedValue.toLowerCase();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function normalizeColorArray(
|
|
150
|
+
value: unknown,
|
|
151
|
+
propPath: string,
|
|
152
|
+
): string[] | undefined {
|
|
153
|
+
if (value === undefined) return undefined;
|
|
154
|
+
if (!Array.isArray(value)) {
|
|
155
|
+
throw new Error(
|
|
156
|
+
`[USER_ERROR]: <Card>: Invalid prop "${propPath}": expected array (in ${Astro.url.pathname})`,
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
if (value.length < 1 || value.length > 4) {
|
|
160
|
+
throw new Error(
|
|
161
|
+
`[USER_ERROR]: <Card>: Invalid prop "${propPath}": expected 1 to 4 colors (in ${Astro.url.pathname})`,
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return value.map((color, index) =>
|
|
166
|
+
normalizeHexColor(color, `${propPath}.${index}`),
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function normalizeSeed(value: unknown, propPath: string): string | undefined {
|
|
171
|
+
if (value === undefined) return undefined;
|
|
172
|
+
if (typeof value !== "string") {
|
|
173
|
+
throw new Error(
|
|
174
|
+
`[USER_ERROR]: <Card>: Invalid prop "${propPath}": expected string (in ${Astro.url.pathname})`,
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const trimmedValue = value.trim();
|
|
179
|
+
if (trimmedValue.length === 0) {
|
|
180
|
+
throw new Error(
|
|
181
|
+
`[USER_ERROR]: <Card>: Invalid prop "${propPath}": expected a non-empty string (in ${Astro.url.pathname})`,
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return trimmedValue;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function normalizeThemeColorConfig(
|
|
189
|
+
value: unknown,
|
|
190
|
+
propPath: string,
|
|
191
|
+
): string | ThemeColorByMode | undefined {
|
|
192
|
+
if (value === undefined) return undefined;
|
|
193
|
+
if (typeof value === "string") {
|
|
194
|
+
return normalizeHexColor(value, propPath);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
198
|
+
throw new Error(
|
|
199
|
+
`[USER_ERROR]: <Card>: Invalid prop "${propPath}": expected a hex color string or an object with light/dark values (in ${Astro.url.pathname})`,
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const colorByMode = value as Record<string, unknown>;
|
|
204
|
+
for (const key of Object.keys(colorByMode)) {
|
|
205
|
+
if (key !== "light" && key !== "dark") {
|
|
206
|
+
throw new Error(
|
|
207
|
+
`[USER_ERROR]: <Card>: Invalid prop "${propPath}.${key}": only "light" and "dark" are supported (in ${Astro.url.pathname})`,
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const light =
|
|
213
|
+
colorByMode.light !== undefined
|
|
214
|
+
? normalizeHexColor(colorByMode.light, `${propPath}.light`)
|
|
215
|
+
: undefined;
|
|
216
|
+
const dark =
|
|
217
|
+
colorByMode.dark !== undefined
|
|
218
|
+
? normalizeHexColor(colorByMode.dark, `${propPath}.dark`)
|
|
219
|
+
: undefined;
|
|
220
|
+
|
|
221
|
+
if (light === undefined && dark === undefined) {
|
|
222
|
+
throw new Error(
|
|
223
|
+
`[USER_ERROR]: <Card>: Invalid prop "${propPath}": expected at least one of "light" or "dark" (in ${Astro.url.pathname})`,
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return {
|
|
228
|
+
...(light !== undefined ? { light } : {}),
|
|
229
|
+
...(dark !== undefined ? { dark } : {}),
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function normalizeRequiredString(value: unknown, propPath: string): string {
|
|
234
|
+
if (typeof value !== "string") {
|
|
235
|
+
throw new Error(
|
|
236
|
+
`[USER_ERROR]: <Card>: Invalid prop "${propPath}": expected string (in ${Astro.url.pathname})`,
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const trimmedValue = value.trim();
|
|
241
|
+
if (trimmedValue.length === 0) {
|
|
242
|
+
throw new Error(
|
|
243
|
+
`[USER_ERROR]: <Card>: Invalid prop "${propPath}": expected a non-empty string (in ${Astro.url.pathname})`,
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return trimmedValue;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function getConfiguredColorForMode(
|
|
251
|
+
value: string | ThemeColorByMode | undefined,
|
|
252
|
+
mode: "light" | "dark",
|
|
253
|
+
): string | undefined {
|
|
254
|
+
if (typeof value === "string") return value;
|
|
255
|
+
return value?.[mode];
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const { title, href, icon, cover } = cardProps as Props;
|
|
259
|
+
const resolvedTitle = title.trim();
|
|
260
|
+
const resolvedHref =
|
|
261
|
+
typeof href === "string" && href.trim().length > 0
|
|
262
|
+
? withBasePath(href)
|
|
263
|
+
: undefined;
|
|
264
|
+
const contentIcon = icon?.trim();
|
|
265
|
+
const coverIcon = cover?.icon?.trim();
|
|
266
|
+
const coverText = cover?.text?.trim();
|
|
267
|
+
const hasCover = Boolean(coverIcon || coverText);
|
|
268
|
+
const cardButton = buttonProps
|
|
269
|
+
? {
|
|
270
|
+
text: normalizeRequiredString(buttonProps.text, "button.text"),
|
|
271
|
+
href: withBasePath(
|
|
272
|
+
normalizeRequiredString(buttonProps.href, "button.href"),
|
|
273
|
+
),
|
|
274
|
+
color: normalizeThemeColorConfig(buttonProps.color, "button.color"),
|
|
275
|
+
}
|
|
276
|
+
: undefined;
|
|
277
|
+
const explicitCoverColors = normalizeColorArray(
|
|
278
|
+
coverProps?.colors,
|
|
279
|
+
"cover.colors",
|
|
280
|
+
);
|
|
281
|
+
const explicitPatternSeed = normalizeSeed(
|
|
282
|
+
coverProps?.patternSeed,
|
|
283
|
+
"cover.patternSeed",
|
|
284
|
+
);
|
|
285
|
+
const explicitColorSeed = normalizeSeed(
|
|
286
|
+
coverProps?.colorSeed,
|
|
287
|
+
"cover.colorSeed",
|
|
288
|
+
);
|
|
289
|
+
const config =
|
|
290
|
+
cardButton || (hasCover && (!explicitCoverColors || !explicitColorSeed))
|
|
291
|
+
? await getConfig()
|
|
292
|
+
: undefined;
|
|
293
|
+
const themeColorCoverColors =
|
|
294
|
+
typeof config?.theme?.themeColor === "string"
|
|
295
|
+
? [config.theme.themeColor]
|
|
296
|
+
: undefined;
|
|
297
|
+
const coverColors =
|
|
298
|
+
explicitCoverColors ??
|
|
299
|
+
config?.theme?.card?.cover?.colors ??
|
|
300
|
+
themeColorCoverColors;
|
|
301
|
+
const coverColorSeed =
|
|
302
|
+
explicitColorSeed ?? config?.theme?.card?.cover?.colorSeed;
|
|
303
|
+
const useThemeColorForCover =
|
|
304
|
+
coverColors === undefined && config?.theme?.themeColor !== undefined;
|
|
305
|
+
function getDefaultButtonColor(mode: "light" | "dark"): string {
|
|
306
|
+
return getDocsBaseColorShade(
|
|
307
|
+
config?.theme,
|
|
308
|
+
mode,
|
|
309
|
+
mode === "light" ? "900" : "100",
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function getButtonForegroundColor(
|
|
314
|
+
mode: "light" | "dark",
|
|
315
|
+
color: string,
|
|
316
|
+
): string {
|
|
317
|
+
return getThemeForegroundColor(
|
|
318
|
+
color,
|
|
319
|
+
getDocsBaseColorShade(config?.theme, mode, "900"),
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function getNavbarPrimaryThemeColor(mode: "light" | "dark"): string {
|
|
324
|
+
return (
|
|
325
|
+
getConfiguredColorForMode(config?.navbar?.primary?.color, mode) ??
|
|
326
|
+
getDefaultButtonColor(mode)
|
|
327
|
+
);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function getCardButtonThemeColor(mode: "light" | "dark"): string {
|
|
331
|
+
return (
|
|
332
|
+
getConfiguredColorForMode(cardButton?.color, mode) ??
|
|
333
|
+
getConfiguredColorForMode(config?.theme?.card?.button?.color, mode) ??
|
|
334
|
+
getNavbarPrimaryThemeColor(mode)
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const cardButtonThemeColors = cardButton
|
|
339
|
+
? {
|
|
340
|
+
light: getCardButtonThemeColor("light"),
|
|
341
|
+
dark: getCardButtonThemeColor("dark"),
|
|
342
|
+
}
|
|
343
|
+
: null;
|
|
344
|
+
const cardButtonStyle = cardButtonThemeColors
|
|
345
|
+
? [
|
|
346
|
+
`--rd-card-button-theme-light: ${cardButtonThemeColors.light}`,
|
|
347
|
+
`--rd-card-button-theme-dark: ${cardButtonThemeColors.dark}`,
|
|
348
|
+
`--rd-card-button-foreground-light: ${getButtonForegroundColor(
|
|
349
|
+
"light",
|
|
350
|
+
cardButtonThemeColors.light,
|
|
351
|
+
)}`,
|
|
352
|
+
`--rd-card-button-foreground-dark: ${getButtonForegroundColor(
|
|
353
|
+
"dark",
|
|
354
|
+
cardButtonThemeColors.dark,
|
|
355
|
+
)}`,
|
|
356
|
+
].join("; ")
|
|
357
|
+
: "";
|
|
358
|
+
const descriptionHtml = Astro.slots.has("default")
|
|
359
|
+
? (await Astro.slots.render("default")).trim()
|
|
360
|
+
: "";
|
|
361
|
+
const rootIsLink = Boolean(resolvedHref && !cardButton);
|
|
362
|
+
const Element = rootIsLink ? "a" : "article";
|
|
363
|
+
const rootAttrs = rootIsLink ? { href: resolvedHref } : {};
|
|
364
|
+
const CardGradient = hasCover
|
|
365
|
+
? (await import("./CardGradient.astro")).default
|
|
366
|
+
: undefined;
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
<div class="rd-prose-block">
|
|
370
|
+
<Element
|
|
371
|
+
{...rootAttrs}
|
|
372
|
+
data-rd-card-root
|
|
373
|
+
data-rd-card-link={resolvedHref ? "true" : undefined}
|
|
374
|
+
class:list={[
|
|
375
|
+
"not-prose group/rd-card block text-left no-underline transition duration-200 relative z-10 before:absolute before:-z-10 before:rounded-b-xl before:inset-0 before:duration-200",
|
|
376
|
+
resolvedHref &&
|
|
377
|
+
"hover:before:-inset-2.5 hover:before:bg-neutral-50 dark:hover:before:bg-(--rd-code-surface)",
|
|
378
|
+
rootIsLink &&
|
|
379
|
+
"cursor-pointer outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
|
380
|
+
hasCover
|
|
381
|
+
? "before:rounded-t-2xl"
|
|
382
|
+
: "before:rounded-t-xl dark:before:bg-(--rd-code-surface)",
|
|
383
|
+
]}
|
|
384
|
+
>
|
|
385
|
+
{
|
|
386
|
+
CardGradient && (
|
|
387
|
+
<CardGradient
|
|
388
|
+
title={resolvedTitle}
|
|
389
|
+
icon={coverIcon}
|
|
390
|
+
text={coverText}
|
|
391
|
+
interactive={Boolean(resolvedHref)}
|
|
392
|
+
glass={cover?.glass}
|
|
393
|
+
colors={coverColors}
|
|
394
|
+
patternSeed={explicitPatternSeed}
|
|
395
|
+
colorSeed={coverColorSeed}
|
|
396
|
+
useThemeColor={useThemeColorForCover}
|
|
397
|
+
/>
|
|
398
|
+
)
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
<div
|
|
402
|
+
class:list={[
|
|
403
|
+
"flex min-w-0 gap-3",
|
|
404
|
+
cardButton
|
|
405
|
+
? "flex-col xs:flex-row xs:items-center xs:justify-between"
|
|
406
|
+
: "items-start",
|
|
407
|
+
hasCover && "pt-3 px-0.5",
|
|
408
|
+
]}
|
|
409
|
+
>
|
|
410
|
+
<div class="flex min-w-0 flex-1 gap-2">
|
|
411
|
+
{
|
|
412
|
+
contentIcon && (
|
|
413
|
+
<span class="self-start flex size-12 shrink-0 items-center justify-center rounded-lg border-[0.5px] border-neutral-900/10 bg-linear-to-br from-white/80 to-neutral-100/60 dark:from-white/7 dark:to-white/2 text-neutral-600 dark:border-white/8 dark:text-neutral-300/90 shadow-[0_.5px_1px_rgba(0,0,0,0.15),0_5px_12px_-4px_rgba(0,0,0,0.08)]">
|
|
414
|
+
<Icon name={contentIcon} class="size-5" />
|
|
415
|
+
</span>
|
|
416
|
+
)
|
|
417
|
+
}
|
|
418
|
+
<div class="ml-1 self-center min-w-0 flex-1">
|
|
419
|
+
<h4
|
|
420
|
+
class="not-prose m-0 flex min-w-0 items-center text-base font-semibold text-neutral-900 dark:text-neutral-100"
|
|
421
|
+
>
|
|
422
|
+
{
|
|
423
|
+
resolvedHref && cardButton ? (
|
|
424
|
+
<a
|
|
425
|
+
href={resolvedHref}
|
|
426
|
+
class="group/rd-card-title inline-flex min-w-0 items-center rounded-sm text-inherit no-underline outline-none focus-visible:ring-ring/50 focus-visible:ring-[3px]"
|
|
427
|
+
>
|
|
428
|
+
<span class="min-w-0 leading-6">{resolvedTitle}</span>
|
|
429
|
+
<Icon
|
|
430
|
+
name="lucide:chevron-right"
|
|
431
|
+
class="ml-px mt-px size-4 shrink-0 -translate-x-1 opacity-0 transition duration-200 ease-out group-hover/rd-card:translate-x-0 group-hover/rd-card:opacity-90 group-focus-visible/rd-card-title:translate-x-0 group-focus-visible/rd-card-title:opacity-100"
|
|
432
|
+
/>
|
|
433
|
+
</a>
|
|
434
|
+
) : (
|
|
435
|
+
<>
|
|
436
|
+
<span class="min-w-0 leading-6">{resolvedTitle}</span>
|
|
437
|
+
{resolvedHref && (
|
|
438
|
+
<Icon
|
|
439
|
+
name="lucide:chevron-right"
|
|
440
|
+
class="ml-px mt-px size-4 shrink-0 -translate-x-1 opacity-0 transition duration-200 ease-out group-hover/rd-card:translate-x-0 group-hover/rd-card:opacity-90 group-focus-visible/rd-card:translate-x-0 group-focus-visible/rd-card:opacity-100"
|
|
441
|
+
/>
|
|
442
|
+
)}
|
|
443
|
+
</>
|
|
444
|
+
)
|
|
445
|
+
}
|
|
446
|
+
</h4>
|
|
447
|
+
{
|
|
448
|
+
descriptionHtml && (
|
|
449
|
+
<div
|
|
450
|
+
class="prose-rules prose-sm! leading-6 text-sm! text-neutral-500 **:text-neutral-500 dark:text-neutral-300 dark:**:text-neutral-300/75"
|
|
451
|
+
set:html={descriptionHtml}
|
|
452
|
+
/>
|
|
453
|
+
)
|
|
454
|
+
}
|
|
455
|
+
</div>
|
|
456
|
+
</div>
|
|
457
|
+
{
|
|
458
|
+
cardButton && (
|
|
459
|
+
<a
|
|
460
|
+
href={cardButton.href}
|
|
461
|
+
class="rd-card-button relative z-10 inline-flex h-8 shrink-0 items-center justify-center self-center rounded-xl [corner-shape:superellipse(1.2)] px-3 text-[13px] font-[350] no-underline transition-opacity duration-200 hover:opacity-95 focus-visible:outline-none focus-visible:ring-ring/50 focus-visible:ring-[3px] dark:font-[450]"
|
|
462
|
+
style={cardButtonStyle}
|
|
463
|
+
>
|
|
464
|
+
{cardButton.text}
|
|
465
|
+
</a>
|
|
466
|
+
)
|
|
467
|
+
}
|
|
468
|
+
</div>
|
|
469
|
+
</Element>
|
|
470
|
+
</div>
|
|
471
|
+
|
|
472
|
+
<style>
|
|
473
|
+
.rd-card-button {
|
|
474
|
+
--rd-card-button-theme: var(--rd-card-button-theme-light);
|
|
475
|
+
--rd-card-button-foreground: var(--rd-card-button-foreground-light);
|
|
476
|
+
background: linear-gradient(
|
|
477
|
+
to bottom,
|
|
478
|
+
color-mix(in oklab, var(--rd-card-button-theme) 88%, white),
|
|
479
|
+
color-mix(in oklab, var(--rd-card-button-theme) 90%, black)
|
|
480
|
+
);
|
|
481
|
+
color: var(--rd-card-button-foreground);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
:global(.dark) .rd-card-button {
|
|
485
|
+
--rd-card-button-theme: var(--rd-card-button-theme-dark);
|
|
486
|
+
--rd-card-button-foreground: var(--rd-card-button-foreground-dark);
|
|
487
|
+
}
|
|
488
|
+
</style>
|