radiant-docs 0.1.61 → 0.1.63
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 -27
- package/template/package-lock.json +2858 -1140
- package/template/package.json +18 -13
- package/template/scripts/generate-proxy-allowed-origins.mjs +10 -179
- package/template/scripts/publish-shiki-platform-assets.mjs +1177 -0
- package/template/src/components/Header.astro +6 -1
- package/template/src/components/NavigationTabList.astro +65 -0
- package/template/src/components/NavigationTabs.astro +109 -0
- package/template/src/components/OpenApiPage.astro +17 -1
- package/template/src/components/Sidebar.astro +2 -2
- package/template/src/components/SidebarDropdown.astro +105 -44
- package/template/src/components/SidebarMenu.astro +3 -0
- package/template/src/components/SidebarSegmented.astro +87 -52
- package/template/src/components/SidebarTabs.astro +86 -0
- package/template/src/components/chat/AssistantDocsWidget.tsx +127 -2
- package/template/src/components/chat/AssistantEmbedPanel.tsx +401 -283
- package/template/src/components/endpoint/PlaygroundForm.astro +69 -55
- package/template/src/components/endpoint/ResponseDisplay.astro +2 -2
- package/template/src/components/user/Accordion.astro +1 -1
- package/template/src/components/user/Callout.astro +2 -2
- package/template/src/components/user/CodeBlock.astro +58 -7
- package/template/src/components/user/CodeGroup.astro +52 -1
- package/template/src/components/user/Column.astro +1 -1
- package/template/src/components/user/Step.astro +1 -1
- package/template/src/components/user/Tabs.astro +1 -1
- package/template/src/generated/shiki-platform-assets.json +24 -0
- package/template/src/layouts/Layout.astro +111 -8
- package/template/src/lib/assistant-panel-config.ts +4 -0
- package/template/src/lib/assistant-shiki-client.ts +522 -0
- package/template/src/lib/client-shiki-config.ts +60 -0
- package/template/src/lib/dev-playground-proxy.mjs +597 -0
- package/template/src/lib/mdx/remark-resolve-internal-links.ts +334 -17
- package/template/src/lib/proxy-allowed-origins.mjs +189 -0
- package/template/src/lib/routes.ts +66 -24
- package/template/src/styles/global.css +16 -4
- package/template/src/components/ui/demo/CodeDemo.astro +0 -15
- package/template/src/components/ui/demo/Demo.astro +0 -3
- package/template/src/components/ui/demo/UiDisplay.astro +0 -13
|
@@ -4,6 +4,7 @@ import { withBasePath } from "../../lib/base-path";
|
|
|
4
4
|
import type { OpenApiRoute } from "../../lib/routes";
|
|
5
5
|
import { getConfig } from "../../lib/validation";
|
|
6
6
|
import { renderMarkdown } from "../../lib/utils";
|
|
7
|
+
import { getClientShikiRuntimeConfig } from "../../lib/client-shiki-config";
|
|
7
8
|
import {
|
|
8
9
|
OPENAPI_REQUEST_SECTION_LABELS,
|
|
9
10
|
type OpenApiRequestFields,
|
|
@@ -38,6 +39,7 @@ const {
|
|
|
38
39
|
} = Astro.props;
|
|
39
40
|
const headers: Record<string, string> = OPENAPI_REQUEST_SECTION_LABELS;
|
|
40
41
|
const config = await getConfig();
|
|
42
|
+
const shikiRuntimeConfig = getClientShikiRuntimeConfig(config);
|
|
41
43
|
const configuredProxyUrl =
|
|
42
44
|
typeof import.meta.env.PUBLIC_PROXY_URL === "string"
|
|
43
45
|
? import.meta.env.PUBLIC_PROXY_URL.trim()
|
|
@@ -77,6 +79,7 @@ const sectionVariantFieldNames = Object.fromEntries(
|
|
|
77
79
|
queryFieldMeta: ${JSON.stringify(queryFieldMeta)},
|
|
78
80
|
sectionVariantFieldNames: ${JSON.stringify(sectionVariantFieldNames)},
|
|
79
81
|
bodyDefaultKind: ${JSON.stringify(bodyDefaultKind ?? null)},
|
|
82
|
+
shiki: ${JSON.stringify(shikiRuntimeConfig ?? null)},
|
|
80
83
|
selectedSectionVariants: {},
|
|
81
84
|
inputs: {
|
|
82
85
|
header: {},
|
|
@@ -476,7 +479,7 @@ const sectionVariantFieldNames = Object.fromEntries(
|
|
|
476
479
|
}
|
|
477
480
|
};
|
|
478
481
|
}
|
|
479
|
-
|
|
482
|
+
|
|
480
483
|
// 6. Execute Request
|
|
481
484
|
const res = await fetch(finalUrl, finalOptions);
|
|
482
485
|
|
|
@@ -487,11 +490,12 @@ const sectionVariantFieldNames = Object.fromEntries(
|
|
|
487
490
|
responseHeaders[key] = value;
|
|
488
491
|
});
|
|
489
492
|
|
|
490
|
-
let
|
|
491
|
-
|
|
493
|
+
let responseDataText;
|
|
494
|
+
let responseDataLanguage = 'plaintext';
|
|
495
|
+
const highlightedHeaders = await window.RadiantPlaygroundHighlightCode(
|
|
492
496
|
JSON.stringify(responseHeaders, null, 2),
|
|
493
|
-
|
|
494
|
-
|
|
497
|
+
'json',
|
|
498
|
+
this.shiki,
|
|
495
499
|
);
|
|
496
500
|
const contentType = res.headers.get('content-type') || '';
|
|
497
501
|
const responseText = await res.text();
|
|
@@ -500,25 +504,19 @@ const sectionVariantFieldNames = Object.fromEntries(
|
|
|
500
504
|
try {
|
|
501
505
|
const parsed =
|
|
502
506
|
responseText.trim().length > 0 ? JSON.parse(responseText) : null;
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
Prism.languages.json,
|
|
506
|
-
'json'
|
|
507
|
-
);
|
|
507
|
+
responseDataText = JSON.stringify(parsed, null, 2);
|
|
508
|
+
responseDataLanguage = 'json';
|
|
508
509
|
} catch (parseError) {
|
|
509
|
-
|
|
510
|
-
responseText || '(empty response)',
|
|
511
|
-
Prism.languages.plaintext,
|
|
512
|
-
'plaintext'
|
|
513
|
-
);
|
|
510
|
+
responseDataText = responseText || '(empty response)';
|
|
514
511
|
}
|
|
515
512
|
} else {
|
|
516
|
-
|
|
517
|
-
responseText || '(empty response)',
|
|
518
|
-
Prism.languages.plaintext,
|
|
519
|
-
'plaintext'
|
|
520
|
-
);
|
|
513
|
+
responseDataText = responseText || '(empty response)';
|
|
521
514
|
}
|
|
515
|
+
const highlightedData = await window.RadiantPlaygroundHighlightCode(
|
|
516
|
+
responseDataText,
|
|
517
|
+
responseDataLanguage,
|
|
518
|
+
this.shiki,
|
|
519
|
+
);
|
|
522
520
|
|
|
523
521
|
this.response = {
|
|
524
522
|
status,
|
|
@@ -682,45 +680,61 @@ const sectionVariantFieldNames = Object.fromEntries(
|
|
|
682
680
|
</div>
|
|
683
681
|
|
|
684
682
|
<script>
|
|
685
|
-
import
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
683
|
+
import {
|
|
684
|
+
highlightAssistantCodeToHtml,
|
|
685
|
+
type AssistantShikiRuntimeConfig,
|
|
686
|
+
} from "../../lib/assistant-shiki-client";
|
|
687
|
+
|
|
688
|
+
type PlaygroundShikiConfig = AssistantShikiRuntimeConfig | null | undefined;
|
|
689
|
+
|
|
690
|
+
function escapeHtml(value: string): string {
|
|
691
|
+
return value
|
|
692
|
+
.replaceAll("&", "&")
|
|
693
|
+
.replaceAll("<", "<")
|
|
694
|
+
.replaceAll(">", ">")
|
|
695
|
+
.replaceAll('"', """)
|
|
696
|
+
.replaceAll("'", "'");
|
|
698
697
|
}
|
|
699
698
|
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
699
|
+
function renderPlainCodeToHtml(code: string): string {
|
|
700
|
+
const lines = code.split("\n");
|
|
701
|
+
const normalizedLines = lines.length > 0 ? lines : [""];
|
|
703
702
|
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
703
|
+
return normalizedLines
|
|
704
|
+
.map((line) => {
|
|
705
|
+
const lineHtml = line.length > 0 ? escapeHtml(line) : " ";
|
|
706
|
+
return `<span class="flex w-max min-w-full"><span class="flex-1 whitespace-pre pl-3 pr-3">${lineHtml}</span></span>`;
|
|
707
|
+
})
|
|
708
|
+
.join("");
|
|
709
709
|
}
|
|
710
710
|
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
:
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
711
|
+
async function highlightPlaygroundCodeToHtml(
|
|
712
|
+
code: unknown,
|
|
713
|
+
language: string,
|
|
714
|
+
config: PlaygroundShikiConfig,
|
|
715
|
+
): Promise<string> {
|
|
716
|
+
const normalizedCode = String(code ?? "");
|
|
717
|
+
if (!config) return renderPlainCodeToHtml(normalizedCode);
|
|
718
|
+
|
|
719
|
+
try {
|
|
720
|
+
const highlighted = await highlightAssistantCodeToHtml({
|
|
721
|
+
code: normalizedCode,
|
|
722
|
+
config,
|
|
723
|
+
language,
|
|
724
|
+
});
|
|
725
|
+
return highlighted.html;
|
|
726
|
+
} catch (error) {
|
|
727
|
+
console.error("Playground code highlighting failed", {
|
|
728
|
+
error,
|
|
729
|
+
language,
|
|
730
|
+
});
|
|
731
|
+
return renderPlainCodeToHtml(normalizedCode);
|
|
732
|
+
}
|
|
721
733
|
}
|
|
722
734
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
735
|
+
(
|
|
736
|
+
window as typeof window & {
|
|
737
|
+
RadiantPlaygroundHighlightCode?: typeof highlightPlaygroundCodeToHtml;
|
|
738
|
+
}
|
|
739
|
+
).RadiantPlaygroundHighlightCode = highlightPlaygroundCodeToHtml;
|
|
740
|
+
</script>
|
|
@@ -161,7 +161,7 @@ import { Icon } from "astro-icon/components";
|
|
|
161
161
|
</div>
|
|
162
162
|
<div x-show="response && response.highlightedData">
|
|
163
163
|
<pre
|
|
164
|
-
class="relative m-0 min-w-full p-0 text-[13px] leading-6"><code data-rd-code-theme class="block min-w-full
|
|
164
|
+
class="relative m-0 min-w-full 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" x-html="response?.highlightedData" /></pre>
|
|
165
165
|
</div>
|
|
166
166
|
</div>
|
|
167
167
|
|
|
@@ -185,7 +185,7 @@ import { Icon } from "astro-icon/components";
|
|
|
185
185
|
</div>
|
|
186
186
|
<div x-show="response && response.highlightedHeaders">
|
|
187
187
|
<pre
|
|
188
|
-
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
|
|
188
|
+
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" x-html="response?.highlightedHeaders" /></pre>
|
|
189
189
|
</div>
|
|
190
190
|
</div>
|
|
191
191
|
</div>
|
|
@@ -108,7 +108,7 @@ const hasTitle = typeof resolvedTitle === "string" && resolvedTitle.length > 0;
|
|
|
108
108
|
{resolvedTitle}
|
|
109
109
|
</div>
|
|
110
110
|
</div>
|
|
111
|
-
<div class="prose-rules
|
|
111
|
+
<div class="prose-rules max-w-none! text-sm! leading-6! text-neutral-700 dark:text-neutral-300">
|
|
112
112
|
<slot />
|
|
113
113
|
</div>
|
|
114
114
|
</>
|
|
@@ -129,7 +129,7 @@ const hasTitle = typeof resolvedTitle === "string" && resolvedTitle.length > 0;
|
|
|
129
129
|
class="mt-0.5 shrink-0 border border-white"
|
|
130
130
|
/>
|
|
131
131
|
) : null}
|
|
132
|
-
<div class="prose-rules
|
|
132
|
+
<div class="prose-rules max-w-none! min-w-0 flex-1 text-sm! leading-6! text-neutral-700 dark:text-neutral-300">
|
|
133
133
|
<slot />
|
|
134
134
|
</div>
|
|
135
135
|
</div>
|
|
@@ -258,7 +258,7 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
258
258
|
? ' data-rd-code-line-highlighted="true"'
|
|
259
259
|
: "";
|
|
260
260
|
|
|
261
|
-
return `<span class="flex min-w-full"${lineHighlightAttribute}>${lineNumberHtml}<span class="${lineContentClass}">${tokenHtml}</span></span>`;
|
|
261
|
+
return `<span class="flex w-max min-w-full"${lineHighlightAttribute}>${lineNumberHtml}<span class="${lineContentClass}">${tokenHtml}</span></span>`;
|
|
262
262
|
})
|
|
263
263
|
.join("");
|
|
264
264
|
---
|
|
@@ -339,7 +339,7 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
339
339
|
|
|
340
340
|
<div
|
|
341
341
|
class:list={[
|
|
342
|
-
"relative min-w-0 border-[0.5px] overflow-hidden border-(--rd-code-tab-edge-border)",
|
|
342
|
+
"relative min-w-0 border-[0.5px] overflow-hidden border-(--rd-code-tab-edge-border) bg-(--rd-code-surface)",
|
|
343
343
|
parsedFlushTop ? "rounded-b-xl" : "rounded-xl",
|
|
344
344
|
parsedFlushTop && "border-t-0",
|
|
345
345
|
parsedShowFilename && "border-t-0 rounded-t-none",
|
|
@@ -349,10 +349,10 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
349
349
|
>
|
|
350
350
|
{
|
|
351
351
|
!parsedInCodeGroup && !parsedShowFilename ? (
|
|
352
|
-
<div class="pointer-events-none absolute right-2 top-2 z-20">
|
|
352
|
+
<div class="pointer-events-none absolute right-2 top-2 z-20 [@media(pointer:coarse)]:pointer-events-auto">
|
|
353
353
|
<button
|
|
354
354
|
type="button"
|
|
355
|
-
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"
|
|
355
|
+
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 [@media(pointer:coarse)]: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"
|
|
356
356
|
data-rd-copy-trigger="true"
|
|
357
357
|
data-rd-copy-content={encodedRaw}
|
|
358
358
|
aria-label="Copy code"
|
|
@@ -390,10 +390,10 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
390
390
|
|
|
391
391
|
<div
|
|
392
392
|
data-rd-code-scroll-area
|
|
393
|
-
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"
|
|
393
|
+
class="relative overflow-x-auto overscroll-x-contain bg-(--rd-code-surface) [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"
|
|
394
394
|
>
|
|
395
395
|
<pre
|
|
396
|
-
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>
|
|
396
|
+
class="relative m-0 w-max min-w-full bg-(--rd-code-surface) p-0 text-[13px] leading-6"><code data-rd-code-theme class="block w-max min-w-full py-2.5 font-mono text-neutral-800 dark:text-neutral-200"><Fragment set:html={renderedCodeLinesHtml} /></code></pre>
|
|
397
397
|
</div>
|
|
398
398
|
</div>
|
|
399
399
|
</div>
|
|
@@ -432,6 +432,52 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
432
432
|
checkIcon.classList.add("scale-50", "opacity-0", "rotate-6");
|
|
433
433
|
};
|
|
434
434
|
|
|
435
|
+
const fallbackCopy = (text) => {
|
|
436
|
+
try {
|
|
437
|
+
const textarea = document.createElement("textarea");
|
|
438
|
+
textarea.value = text;
|
|
439
|
+
textarea.setAttribute("readonly", "");
|
|
440
|
+
textarea.style.position = "fixed";
|
|
441
|
+
textarea.style.top = "0";
|
|
442
|
+
textarea.style.left = "0";
|
|
443
|
+
textarea.style.width = "1px";
|
|
444
|
+
textarea.style.height = "1px";
|
|
445
|
+
textarea.style.padding = "0";
|
|
446
|
+
textarea.style.border = "0";
|
|
447
|
+
textarea.style.opacity = "0";
|
|
448
|
+
textarea.style.fontSize = "16px";
|
|
449
|
+
textarea.style.pointerEvents = "none";
|
|
450
|
+
document.body.appendChild(textarea);
|
|
451
|
+
|
|
452
|
+
try {
|
|
453
|
+
textarea.focus({ preventScroll: true });
|
|
454
|
+
} catch {
|
|
455
|
+
textarea.focus();
|
|
456
|
+
}
|
|
457
|
+
textarea.select();
|
|
458
|
+
textarea.setSelectionRange(0, textarea.value.length);
|
|
459
|
+
|
|
460
|
+
const copied = document.execCommand("copy");
|
|
461
|
+
document.body.removeChild(textarea);
|
|
462
|
+
return copied;
|
|
463
|
+
} catch {
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
|
|
468
|
+
const copyToClipboard = async (text) => {
|
|
469
|
+
try {
|
|
470
|
+
if (navigator.clipboard?.writeText) {
|
|
471
|
+
await navigator.clipboard.writeText(text);
|
|
472
|
+
return true;
|
|
473
|
+
}
|
|
474
|
+
} catch {
|
|
475
|
+
// Fallback below when the async Clipboard API is unavailable or blocked.
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
return fallbackCopy(text);
|
|
479
|
+
};
|
|
480
|
+
|
|
435
481
|
copyButtons.forEach((button) => {
|
|
436
482
|
let timeoutId = null;
|
|
437
483
|
button.addEventListener("click", async () => {
|
|
@@ -440,7 +486,12 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
440
486
|
const copyValue = decodeURIComponent(encodedCopyValue);
|
|
441
487
|
|
|
442
488
|
try {
|
|
443
|
-
await
|
|
489
|
+
const copied = await copyToClipboard(copyValue);
|
|
490
|
+
if (!copied) {
|
|
491
|
+
setCopiedState(button, false);
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
|
|
444
495
|
setCopiedState(button, true);
|
|
445
496
|
|
|
446
497
|
if (timeoutId) window.clearTimeout(timeoutId);
|
|
@@ -130,6 +130,52 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
130
130
|
checkIcon.classList.add("scale-50", "opacity-0", "rotate-6");
|
|
131
131
|
};
|
|
132
132
|
|
|
133
|
+
const fallbackCopy = (text) => {
|
|
134
|
+
try {
|
|
135
|
+
const textarea = document.createElement("textarea");
|
|
136
|
+
textarea.value = text;
|
|
137
|
+
textarea.setAttribute("readonly", "");
|
|
138
|
+
textarea.style.position = "fixed";
|
|
139
|
+
textarea.style.top = "0";
|
|
140
|
+
textarea.style.left = "0";
|
|
141
|
+
textarea.style.width = "1px";
|
|
142
|
+
textarea.style.height = "1px";
|
|
143
|
+
textarea.style.padding = "0";
|
|
144
|
+
textarea.style.border = "0";
|
|
145
|
+
textarea.style.opacity = "0";
|
|
146
|
+
textarea.style.fontSize = "16px";
|
|
147
|
+
textarea.style.pointerEvents = "none";
|
|
148
|
+
document.body.appendChild(textarea);
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
textarea.focus({ preventScroll: true });
|
|
152
|
+
} catch {
|
|
153
|
+
textarea.focus();
|
|
154
|
+
}
|
|
155
|
+
textarea.select();
|
|
156
|
+
textarea.setSelectionRange(0, textarea.value.length);
|
|
157
|
+
|
|
158
|
+
const copied = document.execCommand("copy");
|
|
159
|
+
document.body.removeChild(textarea);
|
|
160
|
+
return copied;
|
|
161
|
+
} catch {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const copyToClipboard = async (text) => {
|
|
167
|
+
try {
|
|
168
|
+
if (navigator.clipboard?.writeText) {
|
|
169
|
+
await navigator.clipboard.writeText(text);
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
} catch {
|
|
173
|
+
// Fallback below when the async Clipboard API is unavailable or blocked.
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return fallbackCopy(text);
|
|
177
|
+
};
|
|
178
|
+
|
|
133
179
|
const tabs = codeItems.map((itemElement, index) => {
|
|
134
180
|
const filename =
|
|
135
181
|
itemElement.getAttribute("data-rd-tab-filename") ??
|
|
@@ -411,7 +457,12 @@ import CodeTabEdge from "../ui/CodeTabEdge.astro";
|
|
|
411
457
|
const copyValue = decodeURIComponent(encodedCopyValue);
|
|
412
458
|
|
|
413
459
|
try {
|
|
414
|
-
await
|
|
460
|
+
const copied = await copyToClipboard(copyValue);
|
|
461
|
+
if (!copied) {
|
|
462
|
+
setCopiedState(copyButton, false);
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
|
|
415
466
|
setCopiedState(copyButton, true);
|
|
416
467
|
|
|
417
468
|
if (timeoutId) window.clearTimeout(timeoutId);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"assetVersion": "shiki-4.2.0-c0d7e21cea71",
|
|
3
|
+
"counts": {
|
|
4
|
+
"languages": 347,
|
|
5
|
+
"themes": 66
|
|
6
|
+
},
|
|
7
|
+
"manifest": {
|
|
8
|
+
"bytes": 172635,
|
|
9
|
+
"module": "manifest.json",
|
|
10
|
+
"sha256": "1840b6f21a79266d9bf3a74d5e6973d407fb06b96d71decd5542ca37eebf182d"
|
|
11
|
+
},
|
|
12
|
+
"packageVersions": {
|
|
13
|
+
"@shikijs/core": "4.2.0",
|
|
14
|
+
"@shikijs/engine-javascript": "4.2.0",
|
|
15
|
+
"@shikijs/langs": "4.2.0",
|
|
16
|
+
"@shikijs/themes": "4.2.0",
|
|
17
|
+
"shiki": "4.2.0"
|
|
18
|
+
},
|
|
19
|
+
"prefix": "_platform/shiki",
|
|
20
|
+
"runtime": {
|
|
21
|
+
"engine": "javascript-regexp",
|
|
22
|
+
"module": "runtime.mjs"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -4,6 +4,7 @@ import Sidebar from "../components/Sidebar.astro";
|
|
|
4
4
|
import { getConfig } from "../lib/validation";
|
|
5
5
|
import Header from "../components/Header.astro";
|
|
6
6
|
import Footer from "../components/Footer.astro";
|
|
7
|
+
import NavigationTabs from "../components/NavigationTabs.astro";
|
|
7
8
|
import AssistantDocsWidget from "../components/chat/AssistantDocsWidget.astro";
|
|
8
9
|
import { ClientRouter } from "astro:transitions";
|
|
9
10
|
import { prependBasePath, stripBasePath } from "../lib/base-path";
|
|
@@ -18,6 +19,8 @@ interface Props {
|
|
|
18
19
|
pageDescription?: string;
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
type TabsPresentation = "topbar" | "sidebar";
|
|
23
|
+
|
|
21
24
|
function normalizeRoutePath(routePath: string): string {
|
|
22
25
|
if (!routePath || routePath === "/") return "/";
|
|
23
26
|
if (!routePath.startsWith("/")) routePath = `/${routePath}`;
|
|
@@ -66,6 +69,12 @@ const orgTier =
|
|
|
66
69
|
Number.isFinite(parsedOrgTier) && parsedOrgTier > 0 ? parsedOrgTier : 1;
|
|
67
70
|
const isDev = import.meta.env.DEV;
|
|
68
71
|
const askAiEnabled = isDev || orgTier >= 3;
|
|
72
|
+
const navigationTabs = config.navigation.tabs as
|
|
73
|
+
| (typeof config.navigation.tabs & { presentation?: TabsPresentation })
|
|
74
|
+
| undefined;
|
|
75
|
+
const hasNavigationTabs =
|
|
76
|
+
Array.isArray(navigationTabs?.items) && navigationTabs.items.length > 0;
|
|
77
|
+
const tabsPresentation = navigationTabs?.presentation ?? "topbar";
|
|
69
78
|
---
|
|
70
79
|
|
|
71
80
|
<!doctype html>
|
|
@@ -73,7 +82,7 @@ const askAiEnabled = isDev || orgTier >= 3;
|
|
|
73
82
|
<head>
|
|
74
83
|
<style is:inline is:global set:html={neutralPaletteCss}></style>
|
|
75
84
|
<style is:inline is:global set:html={fontCss}></style>
|
|
76
|
-
<ClientRouter />
|
|
85
|
+
<ClientRouter fallback="swap" />
|
|
77
86
|
<script is:inline>
|
|
78
87
|
const applyTheme = () => {
|
|
79
88
|
const modeParam = new URLSearchParams(window.location.search).get(
|
|
@@ -192,6 +201,71 @@ const askAiEnabled = isDev || orgTier >= 3;
|
|
|
192
201
|
}
|
|
193
202
|
})();
|
|
194
203
|
</script>
|
|
204
|
+
<script is:inline>
|
|
205
|
+
(() => {
|
|
206
|
+
const root = document.documentElement;
|
|
207
|
+
let viewportFrameId = null;
|
|
208
|
+
|
|
209
|
+
const syncVisualViewport = () => {
|
|
210
|
+
viewportFrameId = null;
|
|
211
|
+
|
|
212
|
+
const viewport = window.visualViewport;
|
|
213
|
+
const width =
|
|
214
|
+
viewport && Number.isFinite(viewport.width)
|
|
215
|
+
? viewport.width
|
|
216
|
+
: window.innerWidth;
|
|
217
|
+
const height =
|
|
218
|
+
viewport && Number.isFinite(viewport.height)
|
|
219
|
+
? viewport.height
|
|
220
|
+
: window.innerHeight;
|
|
221
|
+
const offsetLeft =
|
|
222
|
+
viewport && Number.isFinite(viewport.offsetLeft)
|
|
223
|
+
? viewport.offsetLeft
|
|
224
|
+
: 0;
|
|
225
|
+
const offsetTop =
|
|
226
|
+
viewport && Number.isFinite(viewport.offsetTop)
|
|
227
|
+
? viewport.offsetTop
|
|
228
|
+
: 0;
|
|
229
|
+
|
|
230
|
+
root.style.setProperty(
|
|
231
|
+
"--rd-visual-viewport-left",
|
|
232
|
+
`${Math.max(0, offsetLeft)}px`,
|
|
233
|
+
);
|
|
234
|
+
root.style.setProperty(
|
|
235
|
+
"--rd-visual-viewport-top",
|
|
236
|
+
`${Math.max(0, offsetTop)}px`,
|
|
237
|
+
);
|
|
238
|
+
root.style.setProperty(
|
|
239
|
+
"--rd-visual-viewport-width",
|
|
240
|
+
`${Math.max(1, width)}px`,
|
|
241
|
+
);
|
|
242
|
+
root.style.setProperty(
|
|
243
|
+
"--rd-visual-viewport-height",
|
|
244
|
+
`${Math.max(1, height)}px`,
|
|
245
|
+
);
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
const scheduleVisualViewportSync = () => {
|
|
249
|
+
if (viewportFrameId !== null) return;
|
|
250
|
+
viewportFrameId = window.requestAnimationFrame(syncVisualViewport);
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
scheduleVisualViewportSync();
|
|
254
|
+
window.visualViewport?.addEventListener(
|
|
255
|
+
"resize",
|
|
256
|
+
scheduleVisualViewportSync,
|
|
257
|
+
);
|
|
258
|
+
window.visualViewport?.addEventListener(
|
|
259
|
+
"scroll",
|
|
260
|
+
scheduleVisualViewportSync,
|
|
261
|
+
);
|
|
262
|
+
window.addEventListener("resize", scheduleVisualViewportSync);
|
|
263
|
+
window.addEventListener(
|
|
264
|
+
"orientationchange",
|
|
265
|
+
scheduleVisualViewportSync,
|
|
266
|
+
);
|
|
267
|
+
})();
|
|
268
|
+
</script>
|
|
195
269
|
{
|
|
196
270
|
fontPreloads.map((font) => (
|
|
197
271
|
<link
|
|
@@ -233,12 +307,10 @@ const askAiEnabled = isDev || orgTier >= 3;
|
|
|
233
307
|
<body
|
|
234
308
|
class="bg-background text-neutral-900 dark:text-white"
|
|
235
309
|
x-data="{ open: false }"
|
|
236
|
-
x-bind:class="open ? 'overflow-hidden
|
|
310
|
+
x-bind:class="open ? 'overflow-hidden' : ''"
|
|
237
311
|
>
|
|
238
312
|
<!-- Edges -->
|
|
239
|
-
<div
|
|
240
|
-
class="fixed top-1 inset-x-1 h-16 -z-10 bg-background-dark"
|
|
241
|
-
>
|
|
313
|
+
<div class="fixed top-1 inset-x-1 h-16 -z-10 bg-background-dark">
|
|
242
314
|
<div class="bg-background w-full h-full rounded-t-2xl"></div>
|
|
243
315
|
</div>
|
|
244
316
|
<div
|
|
@@ -252,10 +324,21 @@ const askAiEnabled = isDev || orgTier >= 3;
|
|
|
252
324
|
|
|
253
325
|
<!-- Header -->
|
|
254
326
|
<Header showAskAiTrigger={askAiEnabled} />
|
|
327
|
+
{
|
|
328
|
+
hasNavigationTabs ? (
|
|
329
|
+
<NavigationTabs
|
|
330
|
+
tabs={navigationTabs!}
|
|
331
|
+
presentation={tabsPresentation}
|
|
332
|
+
/>
|
|
333
|
+
) : null
|
|
334
|
+
}
|
|
255
335
|
|
|
256
336
|
<!-- Desktop Sidebar -->
|
|
257
337
|
<div
|
|
258
|
-
class=
|
|
338
|
+
class:list={[
|
|
339
|
+
"bg-background w-[283px] ml-[5px] fixed inset-y-0 hidden lg:block border-r border-r-border-light",
|
|
340
|
+
hasNavigationTabs ? "mt-[112px]" : "mt-17",
|
|
341
|
+
]}
|
|
259
342
|
data-pagefind-ignore
|
|
260
343
|
>
|
|
261
344
|
<Sidebar />
|
|
@@ -265,7 +348,7 @@ const askAiEnabled = isDev || orgTier >= 3;
|
|
|
265
348
|
<div
|
|
266
349
|
x-show="open"
|
|
267
350
|
x-cloak
|
|
268
|
-
class="
|
|
351
|
+
class="rd-mobile-menu bg-background fixed lg:hidden z-50 overflow-y-auto overscroll-contain [scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
|
|
269
352
|
x-transition.opacity
|
|
270
353
|
>
|
|
271
354
|
<Sidebar askAiEnabled={askAiEnabled} />
|
|
@@ -275,11 +358,31 @@ const askAiEnabled = isDev || orgTier >= 3;
|
|
|
275
358
|
<div
|
|
276
359
|
class="mx-1 mt-1 px-4 sm:px-6 lg:pl-[calc(288px+32px)] pt-16 lg:pr-8 bg-background"
|
|
277
360
|
>
|
|
278
|
-
<main class="mx-auto pt-16 pb-
|
|
361
|
+
<main class="mx-auto pt-16 pb-20 min-h-[calc(100vh-64px)]">
|
|
279
362
|
<slot />
|
|
280
363
|
</main>
|
|
281
364
|
<Footer askAiEnabled={askAiEnabled} />
|
|
282
365
|
</div>
|
|
283
366
|
{askAiEnabled ? <AssistantDocsWidget /> : null}
|
|
367
|
+
<style is:global>
|
|
368
|
+
:root {
|
|
369
|
+
--rd-visual-viewport-left: 0px;
|
|
370
|
+
--rd-visual-viewport-top: 0px;
|
|
371
|
+
--rd-visual-viewport-width: 100vw;
|
|
372
|
+
--rd-visual-viewport-height: 100dvh;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
.rd-mobile-menu {
|
|
376
|
+
--rd-mobile-menu-top-offset: 68px;
|
|
377
|
+
left: calc(var(--rd-visual-viewport-left) + 5px);
|
|
378
|
+
top: calc(
|
|
379
|
+
var(--rd-visual-viewport-top) + var(--rd-mobile-menu-top-offset)
|
|
380
|
+
);
|
|
381
|
+
width: calc(var(--rd-visual-viewport-width) - 10px);
|
|
382
|
+
height: calc(
|
|
383
|
+
var(--rd-visual-viewport-height) - var(--rd-mobile-menu-top-offset)
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
</style>
|
|
284
387
|
</body>
|
|
285
388
|
</html>
|