radiant-docs 0.1.41 → 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.
Files changed (32) hide show
  1. package/package.json +1 -1
  2. package/template/astro.config.mjs +42 -40
  3. package/template/package-lock.json +7 -0
  4. package/template/package.json +1 -0
  5. package/template/src/components/Header.astro +150 -16
  6. package/template/src/components/MdxPage.astro +76 -22
  7. package/template/src/components/PagePagination.astro +44 -8
  8. package/template/src/components/Sidebar.astro +10 -1
  9. package/template/src/components/TableOfContents.astro +159 -53
  10. package/template/src/components/chat/AssistantDocsWidget.tsx +221 -8
  11. package/template/src/components/chat/AssistantEmbedPanel.tsx +1090 -104
  12. package/template/src/components/user/Accordion.astro +2 -2
  13. package/template/src/components/user/AccordionGroup.astro +1 -1
  14. package/template/src/components/user/Callout.astro +2 -2
  15. package/template/src/components/user/Card.astro +488 -0
  16. package/template/src/components/user/CardGradient.astro +964 -0
  17. package/template/src/components/user/CodeBlock.astro +1 -1
  18. package/template/src/components/user/CodeGroup.astro +1 -1
  19. package/template/src/components/user/Column.astro +25 -0
  20. package/template/src/components/user/Columns.astro +200 -0
  21. package/template/src/components/user/ComponentPreviewBlock.astro +1 -1
  22. package/template/src/components/user/Image.astro +1 -1
  23. package/template/src/components/user/Step.astro +1 -1
  24. package/template/src/components/user/Steps.astro +1 -1
  25. package/template/src/components/user/Tab.astro +1 -3
  26. package/template/src/components/user/Tabs.astro +2 -2
  27. package/template/src/layouts/Layout.astro +2 -4
  28. package/template/src/lib/assistant-chrome-defaults.ts +12 -0
  29. package/template/src/lib/assistant-embed-script.ts +209 -18
  30. package/template/src/lib/validation.ts +325 -75
  31. package/template/src/styles/global.css +81 -4
  32. package/template/src/components/chat/AskAiWidget.tsx +0 -2011
@@ -257,7 +257,7 @@ const renderedCodeLinesHtml = normalizedTokenLines
257
257
  <div
258
258
  class:list={[
259
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",
260
+ parsedInCodeGroup ? "my-0" : "rd-prose-block shadow-xs",
261
261
  ]}
262
262
  data-rd-code-block-root="true"
263
263
  data-rd-collapsed-lines={collapsedLinesValue}
@@ -4,7 +4,7 @@ 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 shadow-xs rounded-xl"
7
+ class="rd-prose-block group/prose-code-group not-prose relative 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
@@ -0,0 +1,25 @@
1
+ ---
2
+ const columnProps = Astro.props as Record<string, unknown>;
3
+
4
+ function getSourceFile(pathname: string): string {
5
+ const pagePath = pathname
6
+ .replace(/^\/documentation\//, "")
7
+ .replace(/\/$/, "");
8
+ return `${pagePath}.mdx`;
9
+ }
10
+
11
+ const unknownProps = Object.keys(columnProps);
12
+ if (unknownProps.length > 0) {
13
+ const propLabel = unknownProps.length === 1 ? "prop" : "props";
14
+ const unknownLabel = unknownProps.map((name) => `"${name}"`).join(", ");
15
+ throw new Error(
16
+ `[USER_ERROR]: <Column>: Unsupported ${propLabel}: ${unknownLabel}. <Column> does not accept props; render another <Columns> block for a new row. (in ${getSourceFile(Astro.url.pathname)})`,
17
+ );
18
+ }
19
+ ---
20
+
21
+ <div data-rd-column class="min-w-0">
22
+ <div class="prose-rules max-w-none! *:max-w-none!">
23
+ <slot />
24
+ </div>
25
+ </div>
@@ -0,0 +1,200 @@
1
+ ---
2
+ import {
3
+ validateNoUnknownProps,
4
+ validateProps,
5
+ } from "../../lib/component-error";
6
+
7
+ interface Props {
8
+ columns?: 2 | 3;
9
+ }
10
+
11
+ const columnsProps = Astro.props as Record<string, unknown>;
12
+
13
+ validateNoUnknownProps(
14
+ "Columns",
15
+ columnsProps,
16
+ ["columns"],
17
+ Astro.url.pathname,
18
+ );
19
+
20
+ validateProps(
21
+ "Columns",
22
+ columnsProps,
23
+ {
24
+ columns: { type: ["number", "string"] },
25
+ },
26
+ Astro.url.pathname,
27
+ );
28
+
29
+ function normalizeColumns(value: unknown): 2 | 3 {
30
+ if (value === undefined) return 2;
31
+
32
+ const normalizedValue =
33
+ typeof value === "number"
34
+ ? value
35
+ : typeof value === "string"
36
+ ? Number(value.trim())
37
+ : Number.NaN;
38
+
39
+ if (normalizedValue !== 2 && normalizedValue !== 3) {
40
+ throw new Error(
41
+ `[USER_ERROR]: <Columns>: Invalid prop "columns": expected 2 or 3 (in ${Astro.url.pathname})`,
42
+ );
43
+ }
44
+
45
+ return normalizedValue;
46
+ }
47
+
48
+ function getSourceFile(pathname: string): string {
49
+ const pagePath = pathname
50
+ .replace(/^\/documentation\//, "")
51
+ .replace(/\/$/, "");
52
+ return `${pagePath}.mdx`;
53
+ }
54
+
55
+ function createColumnsError(message: string): Error {
56
+ return new Error(
57
+ `[USER_ERROR]: <Columns>: ${message} (in ${getSourceFile(Astro.url.pathname)})`,
58
+ );
59
+ }
60
+
61
+ const VOID_ELEMENTS = new Set([
62
+ "area",
63
+ "base",
64
+ "br",
65
+ "col",
66
+ "embed",
67
+ "hr",
68
+ "img",
69
+ "input",
70
+ "link",
71
+ "meta",
72
+ "param",
73
+ "source",
74
+ "track",
75
+ "wbr",
76
+ ]);
77
+
78
+ function getTopLevelElements(html: string): Array<{
79
+ tagName: string;
80
+ attributes: string;
81
+ }> {
82
+ const elements: Array<{ tagName: string; attributes: string }> = [];
83
+ let depth = 0;
84
+ let index = 0;
85
+
86
+ while (index < html.length) {
87
+ const nextTagStart = html.indexOf("<", index);
88
+ if (nextTagStart === -1) break;
89
+
90
+ if (html.startsWith("<!--", nextTagStart)) {
91
+ const commentEnd = html.indexOf("-->", nextTagStart + 4);
92
+ index = commentEnd === -1 ? html.length : commentEnd + 3;
93
+ continue;
94
+ }
95
+
96
+ const tagEnd = html.indexOf(">", nextTagStart + 1);
97
+ if (tagEnd === -1) break;
98
+
99
+ const rawTag = html.slice(nextTagStart + 1, tagEnd).trim();
100
+ index = tagEnd + 1;
101
+
102
+ if (!rawTag || rawTag.startsWith("!") || rawTag.startsWith("?")) {
103
+ continue;
104
+ }
105
+
106
+ if (rawTag.startsWith("/")) {
107
+ depth = Math.max(0, depth - 1);
108
+ continue;
109
+ }
110
+
111
+ const tagMatch = rawTag.match(/^([A-Za-z][\w:-]*)([\s\S]*)$/);
112
+ if (!tagMatch) continue;
113
+
114
+ const tagName = tagMatch[1].toLowerCase();
115
+ const attributes = tagMatch[2] ?? "";
116
+ const isSelfClosing = /\/\s*$/.test(rawTag);
117
+
118
+ if (depth === 0) {
119
+ elements.push({ tagName, attributes });
120
+ }
121
+
122
+ if (!isSelfClosing && !VOID_ELEMENTS.has(tagName)) {
123
+ depth += 1;
124
+ }
125
+ }
126
+
127
+ return elements;
128
+ }
129
+
130
+ function isColumnElement(element: { tagName: string; attributes: string }) {
131
+ return (
132
+ element.tagName === "div" &&
133
+ /(?:^|\s)data-rd-column(?:\s|=|$)/.test(element.attributes)
134
+ );
135
+ }
136
+
137
+ function validateColumnChildren(html: string, expectedColumns: 2 | 3): void {
138
+ const topLevelElements = getTopLevelElements(html);
139
+ const columnElements = topLevelElements.filter(isColumnElement);
140
+
141
+ if (topLevelElements.length === 0) {
142
+ throw createColumnsError(
143
+ `Must contain exactly ${expectedColumns} <Column> children.`,
144
+ );
145
+ }
146
+
147
+ if (columnElements.length !== topLevelElements.length) {
148
+ throw createColumnsError(
149
+ "Only direct <Column> children are allowed. Wrap each column's content in <Column>.",
150
+ );
151
+ }
152
+
153
+ if (columnElements.length !== expectedColumns) {
154
+ throw createColumnsError(
155
+ `Expected exactly ${expectedColumns} <Column> children for columns={${expectedColumns}}, but found ${columnElements.length}. Render another <Columns> block for a new row.`,
156
+ );
157
+ }
158
+ }
159
+
160
+ const columns = normalizeColumns(columnsProps.columns);
161
+ const html = Astro.slots.has("default")
162
+ ? await Astro.slots.render("default")
163
+ : "";
164
+
165
+ validateColumnChildren(html, columns);
166
+ ---
167
+
168
+ <div class="rd-prose-block rd-columns-container w-full max-w-none!">
169
+ <div
170
+ class="rd-columns grid w-full max-w-none! gap-6"
171
+ data-rd-columns={columns}
172
+ set:html={html}
173
+ />
174
+ </div>
175
+
176
+ <style>
177
+ .rd-columns-container {
178
+ container: rd-columns / inline-size;
179
+ }
180
+
181
+ .rd-columns {
182
+ grid-template-columns: minmax(0, 1fr);
183
+ }
184
+
185
+ .rd-columns > :global(*) {
186
+ min-width: 0;
187
+ }
188
+
189
+ @container rd-columns (min-width: 36rem) {
190
+ .rd-columns[data-rd-columns="2"] {
191
+ grid-template-columns: repeat(2, minmax(0, 1fr));
192
+ }
193
+ }
194
+
195
+ @container rd-columns (min-width: 664px) {
196
+ .rd-columns[data-rd-columns="3"] {
197
+ grid-template-columns: repeat(3, minmax(0, 1fr));
198
+ }
199
+ }
200
+ </style>
@@ -60,7 +60,7 @@ const isInitiallyExpanded = shouldShowAllCode || totalLineCount <= visibleLines;
60
60
  ---
61
61
 
62
62
  <div
63
- class="rd-component-preview my-6 flex w-full max-w-full min-w-0 flex-col"
63
+ class="rd-prose-block rd-component-preview flex w-full max-w-full min-w-0 flex-col"
64
64
  data-rd-component-preview-root="true"
65
65
  >
66
66
  <div
@@ -91,7 +91,7 @@ const captionHtml =
91
91
 
92
92
  <figure
93
93
  class:list={[
94
- "p-1.5 pb-1 xs:pb-1.5 group border border-neutral-200 dark:border-neutral-800 shadow-xs bg-neutral-50 dark:bg-(--rd-code-surface) rounded-2xl",
94
+ "rd-prose-block p-1.5 pb-1 xs:pb-1.5 group border border-neutral-200 dark:border-neutral-800 shadow-xs bg-neutral-50 dark:bg-(--rd-code-surface) rounded-2xl",
95
95
  hasCustomImageWidth ? "w-fit max-w-full mx-auto" : "w-full",
96
96
  ]}
97
97
  x-data="{
@@ -35,7 +35,7 @@ validateProps(
35
35
  {title}
36
36
  </h3>
37
37
  </div>
38
- <div class="[&>p]:m-0 [&>p:not(:last-child)]:mb-2">
38
+ <div class="prose-rules max-w-none! *:max-w-none!">
39
39
  <slot />
40
40
  </div>
41
41
  </div>
@@ -2,6 +2,6 @@
2
2
  interface Props {}
3
3
  ---
4
4
 
5
- <div class="my-6 space-y-1.5">
5
+ <div class="rd-prose-block space-y-1.5">
6
6
  <slot />
7
7
  </div>
@@ -19,7 +19,5 @@ validateProps(
19
19
  ---
20
20
 
21
21
  <section data-label={label} data-icon={icon || ""}>
22
- <div class="*:first:mt-0! *:last:mb-0!">
23
- <slot />
24
- </div>
22
+ <slot />
25
23
  </section>
@@ -131,7 +131,7 @@ if (labels.length === 0) {
131
131
  });
132
132
  }
133
133
  }"
134
- class="my-5">
134
+ class="rd-prose-block">
135
135
  <ul
136
136
  class="relative isolate not-prose flex w-full max-w-full min-w-0 rounded-lg border border-neutral-100 bg-neutral-100/80 p-[3px] dark:border-none dark:bg-neutral-800/50"
137
137
  >
@@ -174,7 +174,7 @@ class="my-5">
174
174
  <div
175
175
  {...(index !== 0 ? { "x-cloak": true } : {})}
176
176
  x-ref={`content-${index}`}
177
- class="w-full"
177
+ class="prose-rules w-full max-w-none! *:max-w-none!"
178
178
  :style={`getPanelStyle(${index})`}
179
179
  style={index === 0 ? 'position: relative;' : ''}
180
180
  set:html={content}
@@ -292,7 +292,7 @@ const askAiEnabled = isDev || orgTier >= 3;
292
292
  class="bg-background mx-[5px] min-h-[calc(100vh-68px)] mt-17 fixed inset-0 lg:hidden z-50 overflow-y-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
293
293
  x-transition.opacity
294
294
  >
295
- <Sidebar />
295
+ <Sidebar askAiEnabled={askAiEnabled} />
296
296
  </div>
297
297
 
298
298
  <!-- Main Content -->
@@ -300,9 +300,7 @@ const askAiEnabled = isDev || orgTier >= 3;
300
300
  class="mx-1 mt-1 px-4 sm:px-6 lg:pl-[calc(288px+32px)] pt-16 lg:pr-8 bg-background"
301
301
  data-vaul-scale-chrome
302
302
  >
303
- <main
304
- class="max-w-2xl xl:max-w-5xl mx-auto pt-16 pb-16 min-h-[calc(100vh-64px)]"
305
- >
303
+ <main class="mx-auto pt-16 pb-16 min-h-[calc(100vh-64px)]">
306
304
  <slot />
307
305
  </main>
308
306
  <Footer askAiEnabled={askAiEnabled} />
@@ -10,6 +10,9 @@ export type AssistantChromeConfig = {
10
10
  launcherShadow: string;
11
11
  panelWidth: string;
12
12
  panelHeight: string;
13
+ panelExpandedWidth: string;
14
+ panelExpandedHeight: string;
15
+ panelViewportMargin: string;
13
16
  panelGap: string;
14
17
  panelRadius: string;
15
18
  panelBorder: string;
@@ -22,9 +25,12 @@ export type AssistantChromeConfig = {
22
25
  panelOpenScale: string;
23
26
  panelOpenDuration: string;
24
27
  panelOpenTiming: string;
28
+ panelSizeDuration: string;
29
+ panelSizeTiming: string;
25
30
  panelCloseDuration: string;
26
31
  panelCloseTiming: string;
27
32
  mobileBreakpoint: string;
33
+ panelFullscreenHeightBreakpoint: string;
28
34
  };
29
35
 
30
36
  const ASSISTANT_PANEL_DARK_NEUTRAL_800_MIX = "20%";
@@ -53,6 +59,9 @@ export const DEFAULT_ASSISTANT_CHROME_CONFIG: AssistantChromeConfig = {
53
59
  launcherShadow: "0 16px 32px -8px rgb(0 0 0 / 24%)",
54
60
  panelWidth: "420px",
55
61
  panelHeight: "640px",
62
+ panelExpandedWidth: "640px",
63
+ panelExpandedHeight: "760px",
64
+ panelViewportMargin: "16px",
56
65
  panelGap: "12px",
57
66
  panelRadius: "16px",
58
67
  panelBorder: "1px solid rgb(9 14 21 / 8%)",
@@ -68,7 +77,10 @@ export const DEFAULT_ASSISTANT_CHROME_CONFIG: AssistantChromeConfig = {
68
77
  panelOpenScale: ".9",
69
78
  panelOpenDuration: ".5s",
70
79
  panelOpenTiming: "cubic-bezier(.34, 1.56, .64, 1)",
80
+ panelSizeDuration: ".46s",
81
+ panelSizeTiming: "cubic-bezier(.22, 1.26, .36, 1)",
71
82
  panelCloseDuration: ".2s",
72
83
  panelCloseTiming: "cubic-bezier(.25, 1, .5, 1)",
73
84
  mobileBreakpoint: "640px",
85
+ panelFullscreenHeightBreakpoint: "560px",
74
86
  };