radiant-docs 0.1.38 → 0.1.40
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 +38 -7
- package/template/package-lock.json +19 -7
- package/template/package.json +1 -1
- package/template/scripts/generate-robots-txt.mjs +29 -1
- package/template/scripts/stamp-image-versions.mjs +59 -33
- package/template/src/components/Footer.astro +2 -1
- package/template/src/components/Header.astro +8 -6
- package/template/src/components/LogoLink.astro +2 -1
- package/template/src/components/MdxPage.astro +15 -4
- package/template/src/components/PagePagination.astro +61 -0
- package/template/src/components/SidebarDropdown.astro +12 -8
- package/template/src/components/SidebarGroup.astro +1 -1
- package/template/src/components/SidebarMenu.astro +1 -1
- package/template/src/components/SidebarSegmented.astro +6 -5
- package/template/src/components/TableOfContents.astro +4 -13
- package/template/src/components/chat/AskAiWidget.tsx +274 -39
- package/template/src/components/endpoint/PlaygroundForm.astro +2 -1
- package/template/src/components/user/CodeBlock.astro +8 -5
- package/template/src/components/user/CodeGroup.astro +262 -14
- package/template/src/components/user/ComponentPreviewBlock.astro +4 -3
- package/template/src/components/user/Image.astro +43 -53
- package/template/src/components/user/Tabs.astro +128 -23
- package/template/src/layouts/Layout.astro +217 -7
- package/template/src/lib/base-path.ts +98 -0
- package/template/src/lib/component-error.ts +49 -10
- package/template/src/lib/mdx/remark-resolve-internal-links.ts +128 -18
- package/template/src/lib/pagefind.ts +62 -14
- package/template/src/lib/routes.ts +49 -1
- package/template/src/lib/static-asset-url.ts +3 -1
- package/template/src/lib/utils.ts +12 -4
- package/template/src/lib/validation.ts +376 -36
- package/template/src/pages/404.astro +2 -1
- package/template/src/pages/[...slug].astro +68 -6
- package/template/src/styles/global.css +85 -1
|
@@ -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"
|
|
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
|
|
@@ -19,7 +19,7 @@ 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>
|
|
@@ -58,10 +58,13 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
58
58
|
</div>
|
|
59
59
|
</div>
|
|
60
60
|
|
|
61
|
-
<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
|
+
>
|
|
62
65
|
<slot />
|
|
63
66
|
</div>
|
|
64
|
-
<script is:inline>
|
|
67
|
+
<script is:inline data-astro-rerun>
|
|
65
68
|
(() => {
|
|
66
69
|
const script = document.currentScript;
|
|
67
70
|
if (!(script instanceof HTMLScriptElement)) return;
|
|
@@ -74,14 +77,27 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
74
77
|
const pillElement = root.querySelector("[data-rd-code-group-pill]");
|
|
75
78
|
const copyButton = root.querySelector("[data-rd-copy-trigger='true']");
|
|
76
79
|
|
|
77
|
-
if (
|
|
80
|
+
if (
|
|
81
|
+
!(contentElement instanceof HTMLElement) ||
|
|
82
|
+
!(tabsElement instanceof HTMLElement) ||
|
|
83
|
+
!(pillElement instanceof HTMLElement)
|
|
84
|
+
) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
78
87
|
|
|
79
88
|
const codeItems = Array.from(
|
|
80
89
|
contentElement.querySelectorAll("[data-rd-code-group-item='true']"),
|
|
81
|
-
);
|
|
90
|
+
).filter((item) => item instanceof HTMLElement);
|
|
82
91
|
if (codeItems.length === 0) return;
|
|
83
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
|
+
|
|
84
98
|
let activeIndex = 0;
|
|
99
|
+
let transitionTimeoutId = null;
|
|
100
|
+
let activeItemResizeObserver = null;
|
|
85
101
|
|
|
86
102
|
const setCopiedState = (button, copied) => {
|
|
87
103
|
const copyIcon = button.querySelector("[data-rd-copy-icon]");
|
|
@@ -146,14 +162,28 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
146
162
|
tabWrapper.appendChild(tabButton);
|
|
147
163
|
tabsElement.appendChild(tabWrapper);
|
|
148
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
|
+
|
|
149
175
|
return {
|
|
150
176
|
itemElement,
|
|
177
|
+
panelElement,
|
|
178
|
+
frameElement,
|
|
151
179
|
tabWrapper,
|
|
152
180
|
tabButton,
|
|
153
181
|
iconContainer,
|
|
154
182
|
};
|
|
155
183
|
});
|
|
156
184
|
|
|
185
|
+
contentElement.style.transitionDuration = `${TRANSITION_DURATION_MS}ms`;
|
|
186
|
+
|
|
157
187
|
const syncPill = () => {
|
|
158
188
|
const activeTab = tabs[activeIndex]?.tabWrapper;
|
|
159
189
|
if (!activeTab) {
|
|
@@ -172,10 +202,9 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
172
202
|
pillElement.classList.add("opacity-100");
|
|
173
203
|
};
|
|
174
204
|
|
|
175
|
-
const
|
|
176
|
-
tabs.forEach(({
|
|
205
|
+
const updateTabButtonStates = () => {
|
|
206
|
+
tabs.forEach(({ tabButton, iconContainer }, index) => {
|
|
177
207
|
const isActive = index === activeIndex;
|
|
178
|
-
itemElement.style.display = isActive ? "" : "none";
|
|
179
208
|
tabButton.classList.toggle("text-foreground", isActive);
|
|
180
209
|
tabButton.classList.toggle("text-muted-foreground", !isActive);
|
|
181
210
|
|
|
@@ -186,11 +215,163 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
186
215
|
syncPill();
|
|
187
216
|
};
|
|
188
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
|
+
|
|
189
372
|
tabs.forEach(({ tabButton }, index) => {
|
|
190
373
|
tabButton.addEventListener("click", () => {
|
|
191
|
-
|
|
192
|
-
activeIndex = index;
|
|
193
|
-
syncActiveTab();
|
|
374
|
+
transitionToIndex(index);
|
|
194
375
|
});
|
|
195
376
|
});
|
|
196
377
|
|
|
@@ -226,9 +407,76 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
226
407
|
}
|
|
227
408
|
|
|
228
409
|
tabsElement.addEventListener("scroll", syncPill, { passive: true });
|
|
229
|
-
window.addEventListener("resize",
|
|
230
|
-
|
|
410
|
+
window.addEventListener("resize", () => {
|
|
411
|
+
syncPill();
|
|
412
|
+
if (transitionTimeoutId === null) {
|
|
413
|
+
syncContentHeight();
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
updateTabButtonStates();
|
|
417
|
+
normalizeToCurrentState();
|
|
231
418
|
requestAnimationFrame(syncPill);
|
|
232
419
|
})();
|
|
233
420
|
</script>
|
|
234
421
|
</div>
|
|
422
|
+
|
|
423
|
+
<style>
|
|
424
|
+
[data-rd-code-group-content] > [data-rd-code-group-item="true"] {
|
|
425
|
+
position: relative;
|
|
426
|
+
z-index: 1;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
[data-rd-code-group-content]
|
|
430
|
+
> [data-rd-code-group-item="true"]:not(:first-child) {
|
|
431
|
+
position: absolute;
|
|
432
|
+
inset: 0;
|
|
433
|
+
opacity: 0;
|
|
434
|
+
visibility: hidden;
|
|
435
|
+
pointer-events: none;
|
|
436
|
+
z-index: 0;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
@keyframes rd-code-group-slide-in-from-right {
|
|
440
|
+
from {
|
|
441
|
+
transform: translateX(100%);
|
|
442
|
+
opacity: 0;
|
|
443
|
+
}
|
|
444
|
+
to {
|
|
445
|
+
transform: translateX(0);
|
|
446
|
+
opacity: 1;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
@keyframes rd-code-group-slide-in-from-left {
|
|
451
|
+
from {
|
|
452
|
+
transform: translateX(-100%);
|
|
453
|
+
opacity: 0;
|
|
454
|
+
}
|
|
455
|
+
to {
|
|
456
|
+
transform: translateX(0);
|
|
457
|
+
opacity: 1;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
@keyframes rd-code-group-slide-out-to-left {
|
|
462
|
+
from {
|
|
463
|
+
transform: translateX(0);
|
|
464
|
+
opacity: 1;
|
|
465
|
+
}
|
|
466
|
+
to {
|
|
467
|
+
transform: translateX(-100%);
|
|
468
|
+
opacity: 0;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
@keyframes rd-code-group-slide-out-to-right {
|
|
473
|
+
from {
|
|
474
|
+
transform: translateX(0);
|
|
475
|
+
opacity: 1;
|
|
476
|
+
}
|
|
477
|
+
to {
|
|
478
|
+
transform: translateX(100%);
|
|
479
|
+
opacity: 0;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
</style>
|
|
@@ -69,7 +69,7 @@ const isInitiallyExpanded = shouldShowAllCode || totalLineCount <= visibleLines;
|
|
|
69
69
|
<slot />
|
|
70
70
|
</div>
|
|
71
71
|
<div
|
|
72
|
-
class="rd-component-preview__code not-prose relative overflow-hidden rounded-b-xl bg-
|
|
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
|
>
|
|
@@ -142,7 +142,7 @@ const isInitiallyExpanded = shouldShowAllCode || totalLineCount <= visibleLines;
|
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
.rd-component-preview__code :global(.group\/prose-code > div) {
|
|
145
|
-
background-color:
|
|
145
|
+
background-color: var(--color-neutral-50) !important;
|
|
146
146
|
border-top-left-radius: 0 !important;
|
|
147
147
|
border-top-right-radius: 0 !important;
|
|
148
148
|
}
|
|
@@ -153,7 +153,7 @@ const isInitiallyExpanded = shouldShowAllCode || totalLineCount <= visibleLines;
|
|
|
153
153
|
|
|
154
154
|
.rd-component-preview__code :global(.group\/prose-code pre),
|
|
155
155
|
.rd-component-preview__code :global(.group\/prose-code code) {
|
|
156
|
-
background-color:
|
|
156
|
+
background-color: var(--color-neutral-50) !important;
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
:global(.dark) .rd-component-preview__code :global(.group\/prose-code pre),
|
|
@@ -199,6 +199,7 @@ const isInitiallyExpanded = shouldShowAllCode || totalLineCount <= visibleLines;
|
|
|
199
199
|
|
|
200
200
|
<script
|
|
201
201
|
is:inline
|
|
202
|
+
data-astro-rerun
|
|
202
203
|
define:vars={{
|
|
203
204
|
visibleLines,
|
|
204
205
|
totalLineCount,
|
|
@@ -1,28 +1,54 @@
|
|
|
1
1
|
---
|
|
2
|
-
import
|
|
3
|
-
import { validateProps } from "../../lib/component-error";
|
|
2
|
+
import { validateNoUnknownProps, validateProps } from "../../lib/component-error";
|
|
4
3
|
import { renderMarkdown } from "../../lib/utils";
|
|
5
4
|
import { resolveStaticAssetUrl } from "../../lib/static-asset-url";
|
|
6
5
|
|
|
7
|
-
interface Props
|
|
6
|
+
interface Props {
|
|
8
7
|
src: string;
|
|
8
|
+
alt?: string;
|
|
9
|
+
title?: string;
|
|
10
|
+
width?: number | string;
|
|
9
11
|
zoom?: boolean;
|
|
10
12
|
}
|
|
11
13
|
|
|
12
|
-
const
|
|
14
|
+
const imageProps = Astro.props as Record<string, unknown>;
|
|
15
|
+
|
|
16
|
+
validateNoUnknownProps(
|
|
17
|
+
"Image",
|
|
18
|
+
imageProps,
|
|
19
|
+
["src", "alt", "title", "width", "zoom"],
|
|
20
|
+
Astro.url.pathname,
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
validateProps(
|
|
24
|
+
"Image",
|
|
25
|
+
imageProps,
|
|
26
|
+
{
|
|
27
|
+
src: { required: true, type: "string" },
|
|
28
|
+
alt: { type: "string" },
|
|
29
|
+
title: { type: "string" },
|
|
30
|
+
width: { type: ["number", "string"] },
|
|
31
|
+
zoom: { type: "boolean" },
|
|
32
|
+
},
|
|
33
|
+
Astro.url.pathname,
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const { src, alt, title, width, zoom = true } = imageProps as Props;
|
|
13
37
|
const zoomEnabled = zoom !== false;
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
38
|
+
const resolvedSrc = resolveStaticAssetUrl(src);
|
|
39
|
+
const rawWidth = width;
|
|
40
|
+
const imageAttrs: Record<string, unknown> = { src: resolvedSrc };
|
|
41
|
+
if (typeof alt === "string") {
|
|
42
|
+
imageAttrs.alt = alt;
|
|
43
|
+
}
|
|
44
|
+
if (width !== undefined) {
|
|
45
|
+
imageAttrs.width = width;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const zoomAttrs: Record<string, unknown> = { src: resolvedSrc };
|
|
49
|
+
if (typeof alt === "string") {
|
|
50
|
+
zoomAttrs.alt = alt;
|
|
17
51
|
}
|
|
18
|
-
const rawStyle = attrsRecord.style;
|
|
19
|
-
const rawWidth = attrsRecord.width;
|
|
20
|
-
const zoomAttrs: Record<string, unknown> = { ...attrsRecord };
|
|
21
|
-
delete zoomAttrs.style;
|
|
22
|
-
delete zoomAttrs.width;
|
|
23
|
-
delete zoomAttrs.height;
|
|
24
|
-
delete zoomAttrs.class;
|
|
25
|
-
delete zoomAttrs.className;
|
|
26
52
|
|
|
27
53
|
function isConstrainedWidthValue(value: unknown): boolean {
|
|
28
54
|
if (typeof value === "number") {
|
|
@@ -55,48 +81,12 @@ function isConstrainedWidthValue(value: unknown): boolean {
|
|
|
55
81
|
return true;
|
|
56
82
|
}
|
|
57
83
|
|
|
58
|
-
|
|
59
|
-
if (typeof styleValue === "string") {
|
|
60
|
-
const widthMatch = styleValue.match(/(?:^|;)\s*width\s*:\s*([^;]+)/i);
|
|
61
|
-
const maxWidthMatch = styleValue.match(
|
|
62
|
-
/(?:^|;)\s*max-width\s*:\s*([^;]+)/i,
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
return (
|
|
66
|
-
isConstrainedWidthValue(widthMatch?.[1]) ||
|
|
67
|
-
isConstrainedWidthValue(maxWidthMatch?.[1])
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (!styleValue || typeof styleValue !== "object") return false;
|
|
72
|
-
const styleObject = styleValue as Record<string, unknown>;
|
|
73
|
-
|
|
74
|
-
return (
|
|
75
|
-
isConstrainedWidthValue(styleObject.width) ||
|
|
76
|
-
isConstrainedWidthValue(styleObject.maxWidth) ||
|
|
77
|
-
isConstrainedWidthValue(styleObject["max-width"])
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const hasCustomImageWidth =
|
|
82
|
-
isConstrainedWidthValue(rawWidth) || hasStyleWidthConstraint(rawStyle);
|
|
84
|
+
const hasCustomImageWidth = isConstrainedWidthValue(rawWidth);
|
|
83
85
|
|
|
84
86
|
const captionHtml =
|
|
85
87
|
typeof title === "string" && title.trim().length > 0
|
|
86
88
|
? (await renderMarkdown(title)).replace(/^<p>([\s\S]*)<\/p>\n?$/, "$1")
|
|
87
89
|
: "";
|
|
88
|
-
|
|
89
|
-
validateProps(
|
|
90
|
-
"Image",
|
|
91
|
-
Astro.props as Record<string, any>,
|
|
92
|
-
{
|
|
93
|
-
src: { required: true, type: "string" },
|
|
94
|
-
alt: { type: "string" },
|
|
95
|
-
title: { type: "string" },
|
|
96
|
-
zoom: { type: "boolean" },
|
|
97
|
-
},
|
|
98
|
-
Astro.url.pathname,
|
|
99
|
-
);
|
|
100
90
|
---
|
|
101
91
|
|
|
102
92
|
<figure
|
|
@@ -207,7 +197,7 @@ validateProps(
|
|
|
207
197
|
class="overflow-hidden rounded-xl border border-neutral-200 dark:border-neutral-800 bg-neutral-100 dark:bg-(--rd-code-surface)"
|
|
208
198
|
>
|
|
209
199
|
<img
|
|
210
|
-
{...
|
|
200
|
+
{...imageAttrs}
|
|
211
201
|
x-ref="img"
|
|
212
202
|
title={title}
|
|
213
203
|
class:list={[
|