radiant-docs 0.1.68 → 0.1.69
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/src/components/MdxPage.astro +49 -4
- package/template/src/components/OpenApiPage.astro +1 -1
- package/template/src/components/PageAiActions.astro +49 -43
- package/template/src/components/Sidebar.astro +27 -0
- package/template/src/components/TableOfContents.astro +14 -1
- package/template/src/components/chat/AssistantEmbedPanel.tsx +124 -2
- package/template/src/components/user/CodeBlock.astro +102 -72
- package/template/src/components/user/ComponentPreviewBlock.astro +73 -32
- package/template/src/layouts/Layout.astro +24 -1
- package/template/src/lib/assistant-embed-script.ts +33 -5
package/package.json
CHANGED
|
@@ -65,9 +65,54 @@ const tocHeadings = headings.filter(
|
|
|
65
65
|
);
|
|
66
66
|
---
|
|
67
67
|
|
|
68
|
-
<Layout pageTitle={title} pageDescription={description}>
|
|
69
|
-
<
|
|
70
|
-
|
|
68
|
+
<Layout pageTitle={title} pageDescription={description} hasMarkdownAlternate>
|
|
69
|
+
<style is:inline>
|
|
70
|
+
[data-rd-mdx-shell] {
|
|
71
|
+
display: grid;
|
|
72
|
+
grid-template-columns: minmax(0, 48rem);
|
|
73
|
+
width: 100%;
|
|
74
|
+
min-width: 0;
|
|
75
|
+
justify-content: center;
|
|
76
|
+
column-gap: 2.5rem;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
[data-rd-mdx-content] {
|
|
80
|
+
width: 100%;
|
|
81
|
+
max-width: none;
|
|
82
|
+
min-width: 0;
|
|
83
|
+
margin-inline: 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
[data-rd-toc-column] {
|
|
87
|
+
display: none;
|
|
88
|
+
width: 12rem;
|
|
89
|
+
flex: 0 0 12rem;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
@media (min-width: 80rem) {
|
|
93
|
+
[data-rd-mdx-shell] {
|
|
94
|
+
grid-template-columns: minmax(0, 1fr) minmax(0, 48rem) minmax(
|
|
95
|
+
0,
|
|
96
|
+
1fr
|
|
97
|
+
) 12rem;
|
|
98
|
+
justify-content: stretch;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
[data-rd-mdx-content] {
|
|
102
|
+
grid-column: 2;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
[data-rd-toc-column] {
|
|
106
|
+
display: block;
|
|
107
|
+
grid-column: 4;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
</style>
|
|
111
|
+
<div
|
|
112
|
+
class="flex w-full min-w-0 justify-between gap-x-10"
|
|
113
|
+
data-rd-mdx-shell
|
|
114
|
+
>
|
|
115
|
+
<div class="mx-auto max-w-3xl w-full" data-rd-mdx-content>
|
|
71
116
|
<header
|
|
72
117
|
class="mb-8 flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between"
|
|
73
118
|
>
|
|
@@ -91,7 +136,7 @@ const tocHeadings = headings.filter(
|
|
|
91
136
|
homePath={homePath}
|
|
92
137
|
/>
|
|
93
138
|
</div>
|
|
94
|
-
<aside class="hidden xl:block w-48 shrink-0">
|
|
139
|
+
<aside class="hidden xl:block w-48 shrink-0" data-rd-toc-column>
|
|
95
140
|
<TableOfContents headings={tocHeadings} />
|
|
96
141
|
</aside>
|
|
97
142
|
</div>
|
|
@@ -59,7 +59,7 @@ const snippetStickyClass = hasTopbarNavigationTabs
|
|
|
59
59
|
: "top-[92px] max-h-[calc(100vh-92px)]";
|
|
60
60
|
---
|
|
61
61
|
|
|
62
|
-
<Layout pageTitle={title}>
|
|
62
|
+
<Layout pageTitle={title} hasMarkdownAlternate>
|
|
63
63
|
<article class="mx-auto w-full max-w-7xl">
|
|
64
64
|
<header
|
|
65
65
|
class="mb-8 flex flex-col gap-4 sm:flex-row sm:items-end sm:justify-between"
|
|
@@ -431,24 +431,40 @@ const menuItems: MenuItem[] = [
|
|
|
431
431
|
}
|
|
432
432
|
</style>
|
|
433
433
|
|
|
434
|
-
<script
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
434
|
+
<script>
|
|
435
|
+
const pageActionsSelector = "[data-rd-page-actions]";
|
|
436
|
+
const pageActionsControlsKey = "__rdPageActionsControls";
|
|
437
|
+
|
|
438
|
+
function fallbackCopy(text) {
|
|
439
|
+
const textarea = document.createElement("textarea");
|
|
440
|
+
textarea.value = text;
|
|
441
|
+
textarea.setAttribute("readonly", "");
|
|
442
|
+
textarea.style.position = "fixed";
|
|
443
|
+
textarea.style.opacity = "0";
|
|
444
|
+
document.body.appendChild(textarea);
|
|
445
|
+
textarea.select();
|
|
446
|
+
const copied = document.execCommand("copy");
|
|
447
|
+
document.body.removeChild(textarea);
|
|
448
|
+
return copied;
|
|
449
|
+
}
|
|
445
450
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
+
async function copyToClipboard(text) {
|
|
452
|
+
try {
|
|
453
|
+
if (navigator.clipboard?.writeText) {
|
|
454
|
+
await navigator.clipboard.writeText(text);
|
|
455
|
+
return true;
|
|
456
|
+
}
|
|
457
|
+
} catch {
|
|
458
|
+
// Fallback below when clipboard API is unavailable or blocked.
|
|
451
459
|
}
|
|
460
|
+
|
|
461
|
+
return fallbackCopy(text);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
function initPageActions(root) {
|
|
465
|
+
if (!(root instanceof HTMLElement)) return;
|
|
466
|
+
if (root.dataset.pageActionsBound === "true") return;
|
|
467
|
+
|
|
452
468
|
root.dataset.pageActionsBound = "true";
|
|
453
469
|
|
|
454
470
|
const trigger = root.querySelector("[data-rd-page-actions-trigger]");
|
|
@@ -463,32 +479,6 @@ const menuItems: MenuItem[] = [
|
|
|
463
479
|
let mcpMetadataPromise;
|
|
464
480
|
const copyFeedbackTimeouts = new WeakMap();
|
|
465
481
|
|
|
466
|
-
function fallbackCopy(text) {
|
|
467
|
-
const textarea = document.createElement("textarea");
|
|
468
|
-
textarea.value = text;
|
|
469
|
-
textarea.setAttribute("readonly", "");
|
|
470
|
-
textarea.style.position = "fixed";
|
|
471
|
-
textarea.style.opacity = "0";
|
|
472
|
-
document.body.appendChild(textarea);
|
|
473
|
-
textarea.select();
|
|
474
|
-
const copied = document.execCommand("copy");
|
|
475
|
-
document.body.removeChild(textarea);
|
|
476
|
-
return copied;
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
async function copyToClipboard(text) {
|
|
480
|
-
try {
|
|
481
|
-
if (navigator.clipboard?.writeText) {
|
|
482
|
-
await navigator.clipboard.writeText(text);
|
|
483
|
-
return true;
|
|
484
|
-
}
|
|
485
|
-
} catch {
|
|
486
|
-
// Fallback below when clipboard API is unavailable or blocked.
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
return fallbackCopy(text);
|
|
490
|
-
}
|
|
491
|
-
|
|
492
482
|
function setExpanded(nextExpanded) {
|
|
493
483
|
if (!(trigger instanceof HTMLElement)) return;
|
|
494
484
|
trigger.setAttribute("aria-expanded", String(nextExpanded));
|
|
@@ -711,5 +701,21 @@ const menuItems: MenuItem[] = [
|
|
|
711
701
|
closeMenu();
|
|
712
702
|
});
|
|
713
703
|
});
|
|
714
|
-
}
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
function initAllPageActions() {
|
|
707
|
+
document.querySelectorAll(pageActionsSelector).forEach((root) => {
|
|
708
|
+
initPageActions(root);
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
window[pageActionsControlsKey] = window[pageActionsControlsKey] || {};
|
|
713
|
+
window[pageActionsControlsKey].init = initAllPageActions;
|
|
714
|
+
|
|
715
|
+
if (!window[pageActionsControlsKey].installed) {
|
|
716
|
+
window[pageActionsControlsKey].installed = true;
|
|
717
|
+
document.addEventListener("astro:page-load", initAllPageActions);
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
initAllPageActions();
|
|
715
721
|
</script>
|
|
@@ -19,6 +19,33 @@ const config: DocsConfig = await getConfig();
|
|
|
19
19
|
>
|
|
20
20
|
<SidebarMenu navigation={config.navigation} />
|
|
21
21
|
</nav>
|
|
22
|
+
<script is:inline>
|
|
23
|
+
(() => {
|
|
24
|
+
const script = document.currentScript;
|
|
25
|
+
const sidebar = script?.previousElementSibling;
|
|
26
|
+
|
|
27
|
+
if (
|
|
28
|
+
!(sidebar instanceof HTMLElement) ||
|
|
29
|
+
!sidebar.hasAttribute("data-rd-sidebar-scroll-container")
|
|
30
|
+
) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (document.readyState !== "loading") return;
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const value = Number(
|
|
38
|
+
sessionStorage.getItem("radiant-docs:sidebar-scroll-top"),
|
|
39
|
+
);
|
|
40
|
+
if (!Number.isFinite(value) || value <= 0) return;
|
|
41
|
+
|
|
42
|
+
sidebar.scrollTop = Math.max(0, Math.round(value));
|
|
43
|
+
sidebar.dataset.rdSidebarScrollRestored = "true";
|
|
44
|
+
} catch {
|
|
45
|
+
// Storage can be unavailable in private browsing or locked-down embeds.
|
|
46
|
+
}
|
|
47
|
+
})();
|
|
48
|
+
</script>
|
|
22
49
|
<div
|
|
23
50
|
class:list={[
|
|
24
51
|
"bg-background z-10 px-3 pt-3 pb-[calc(env(safe-area-inset-bottom)+0.75rem)] border-t border-t-border-light flex gap-1.5 items-center",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
import type { MarkdownHeading } from "astro";
|
|
3
3
|
import { Icon } from "astro-icon/components";
|
|
4
|
+
import { getConfig } from "../lib/validation";
|
|
4
5
|
|
|
5
6
|
interface Props {
|
|
6
7
|
headings: MarkdownHeading[];
|
|
@@ -11,6 +12,18 @@ interface GroupedHeading extends MarkdownHeading {
|
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
const { headings } = Astro.props;
|
|
15
|
+
type TabsPresentation = "topbar" | "sidebar";
|
|
16
|
+
const config = await getConfig();
|
|
17
|
+
const navigationTabs = config.navigation.tabs as
|
|
18
|
+
| (typeof config.navigation.tabs & { presentation?: TabsPresentation })
|
|
19
|
+
| undefined;
|
|
20
|
+
const hasTopbarNavigationTabs =
|
|
21
|
+
Array.isArray(navigationTabs?.items) &&
|
|
22
|
+
navigationTabs.items.length > 0 &&
|
|
23
|
+
(navigationTabs.presentation ?? "topbar") === "topbar";
|
|
24
|
+
const stickyTopClass = hasTopbarNavigationTabs
|
|
25
|
+
? "top-[calc(68px+44px+64px)]"
|
|
26
|
+
: "top-[calc(68px+64px)]";
|
|
14
27
|
|
|
15
28
|
// Group depth 3 headings under their preceding depth 2 heading
|
|
16
29
|
const groupedHeadings: GroupedHeading[] = [];
|
|
@@ -30,7 +43,7 @@ for (const heading of headings) {
|
|
|
30
43
|
---
|
|
31
44
|
|
|
32
45
|
<nav
|
|
33
|
-
class="sticky
|
|
46
|
+
class:list={["sticky text-[13px]/5", stickyTopClass]}
|
|
34
47
|
aria-label="Table of Contents"
|
|
35
48
|
data-slugs={JSON.stringify(headings.map((h) => h.slug))}
|
|
36
49
|
>
|
|
@@ -80,6 +80,7 @@ type ChatViewportWheelEvent = JSX.TargetedWheelEvent<HTMLDivElement>;
|
|
|
80
80
|
type ChatViewportScrollEvent = JSX.TargetedEvent<HTMLDivElement, Event>;
|
|
81
81
|
|
|
82
82
|
type PersistedPanelState = {
|
|
83
|
+
conversationId: string;
|
|
83
84
|
messages: ChatMessage[];
|
|
84
85
|
scrollTop: number;
|
|
85
86
|
inFlight: boolean;
|
|
@@ -104,6 +105,16 @@ type PendingAssistantHandoff = {
|
|
|
104
105
|
timeoutId: number;
|
|
105
106
|
};
|
|
106
107
|
|
|
108
|
+
type AssistantPageContext = {
|
|
109
|
+
hostname: string | null;
|
|
110
|
+
pagePath: string | null;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
type PendingPageContextRequest = {
|
|
114
|
+
resolve: (context: AssistantPageContext) => void;
|
|
115
|
+
timeoutId: number;
|
|
116
|
+
};
|
|
117
|
+
|
|
107
118
|
export const ASSISTANT_PANEL_STORAGE_KEY = "docs:assistant-embed-panel:v1";
|
|
108
119
|
const HANDOFF_QUERY_PARAM = "assistantHandoff";
|
|
109
120
|
const OPEN_QUERY_PARAM = "assistant";
|
|
@@ -413,6 +424,7 @@ function normalizePersistedMessages(rawMessages: unknown): ChatMessage[] {
|
|
|
413
424
|
|
|
414
425
|
function createEmptyPersistedPanelState(): PersistedPanelState {
|
|
415
426
|
return {
|
|
427
|
+
conversationId: createMessageId(),
|
|
416
428
|
messages: [],
|
|
417
429
|
scrollTop: 0,
|
|
418
430
|
inFlight: false,
|
|
@@ -426,6 +438,12 @@ function normalizePanelSize(value: unknown): AssistantPanelSize {
|
|
|
426
438
|
return value === "expanded" ? "expanded" : "default";
|
|
427
439
|
}
|
|
428
440
|
|
|
441
|
+
function normalizeConversationId(value: unknown): string {
|
|
442
|
+
return typeof value === "string" && value.trim()
|
|
443
|
+
? value.trim().slice(0, 128)
|
|
444
|
+
: createMessageId();
|
|
445
|
+
}
|
|
446
|
+
|
|
429
447
|
function getPanelFullscreenMediaQuery(
|
|
430
448
|
mobileBreakpoint: string,
|
|
431
449
|
panelFullscreenHeightBreakpoint: string,
|
|
@@ -439,6 +457,7 @@ function normalizePersistedPanelState(rawState: unknown): PersistedPanelState {
|
|
|
439
457
|
}
|
|
440
458
|
|
|
441
459
|
const state = rawState as {
|
|
460
|
+
conversationId?: unknown;
|
|
442
461
|
messages?: unknown;
|
|
443
462
|
scrollTop?: unknown;
|
|
444
463
|
inFlight?: unknown;
|
|
@@ -461,6 +480,7 @@ function normalizePersistedPanelState(rawState: unknown): PersistedPanelState {
|
|
|
461
480
|
: 0;
|
|
462
481
|
|
|
463
482
|
return {
|
|
483
|
+
conversationId: normalizeConversationId(state.conversationId),
|
|
464
484
|
messages: normalizePersistedMessages(state.messages),
|
|
465
485
|
scrollTop,
|
|
466
486
|
inFlight: isInFlightFresh,
|
|
@@ -515,6 +535,7 @@ function writePersistedPanelState(state: PersistedPanelState) {
|
|
|
515
535
|
ASSISTANT_PANEL_STORAGE_KEY,
|
|
516
536
|
JSON.stringify({
|
|
517
537
|
messages: state.messages,
|
|
538
|
+
conversationId: state.conversationId,
|
|
518
539
|
scrollTop:
|
|
519
540
|
Number.isFinite(state.scrollTop) && state.scrollTop > 0
|
|
520
541
|
? state.scrollTop
|
|
@@ -1013,7 +1034,7 @@ function AssistantSourcesBlock({
|
|
|
1013
1034
|
{visibleSources.map((source) => (
|
|
1014
1035
|
<li key={`${source.href}\0${source.label}`}>
|
|
1015
1036
|
<a
|
|
1016
|
-
href={source.href}
|
|
1037
|
+
href={withBasePath(source.href)}
|
|
1017
1038
|
target={linkTarget === "blank" ? "_blank" : undefined}
|
|
1018
1039
|
rel={linkTarget === "blank" ? "noopener noreferrer" : undefined}
|
|
1019
1040
|
>
|
|
@@ -1057,6 +1078,36 @@ function postParentMessage(
|
|
|
1057
1078
|
window.parent.postMessage({ type, ...payload }, "*");
|
|
1058
1079
|
}
|
|
1059
1080
|
|
|
1081
|
+
function getCurrentPageContext(): AssistantPageContext {
|
|
1082
|
+
if (typeof window === "undefined") {
|
|
1083
|
+
return { hostname: null, pagePath: null };
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
return {
|
|
1087
|
+
hostname: window.location.hostname || null,
|
|
1088
|
+
pagePath: window.location.pathname || "/",
|
|
1089
|
+
};
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
function normalizeParentPageContext(
|
|
1093
|
+
hostname: unknown,
|
|
1094
|
+
pagePath: unknown,
|
|
1095
|
+
): AssistantPageContext {
|
|
1096
|
+
const normalizedHostname =
|
|
1097
|
+
typeof hostname === "string" && hostname.trim().length > 0
|
|
1098
|
+
? hostname.trim().slice(0, 512)
|
|
1099
|
+
: null;
|
|
1100
|
+
const normalizedPagePath =
|
|
1101
|
+
typeof pagePath === "string" && pagePath.trim().startsWith("/")
|
|
1102
|
+
? pagePath.trim().slice(0, 2048)
|
|
1103
|
+
: null;
|
|
1104
|
+
|
|
1105
|
+
return {
|
|
1106
|
+
hostname: normalizedHostname,
|
|
1107
|
+
pagePath: normalizedPagePath,
|
|
1108
|
+
};
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1060
1111
|
function getApiPath(
|
|
1061
1112
|
apiPath: string,
|
|
1062
1113
|
allowApiPathQueryOverride: boolean,
|
|
@@ -1174,6 +1225,11 @@ export default function AssistantEmbedPanel({
|
|
|
1174
1225
|
const scrollPersistenceUnlockTimeoutRef = useRef<number | null>(null);
|
|
1175
1226
|
const isScrollPersistenceLockedRef = useRef(false);
|
|
1176
1227
|
const pendingHandoffsRef = useRef(new Map<string, PendingAssistantHandoff>());
|
|
1228
|
+
const pendingPageContextRequestsRef = useRef(
|
|
1229
|
+
new Map<string, PendingPageContextRequest>(),
|
|
1230
|
+
);
|
|
1231
|
+
const pageContextRef = useRef<AssistantPageContext>(getCurrentPageContext());
|
|
1232
|
+
const conversationIdRef = useRef(initialPanelState.conversationId);
|
|
1177
1233
|
const messagesRef = useRef(initialPanelState.messages);
|
|
1178
1234
|
const isBusyRef = useRef(initialPanelState.inFlight);
|
|
1179
1235
|
const isAwaitingFirstTokenRef = useRef(
|
|
@@ -1203,6 +1259,32 @@ export default function AssistantEmbedPanel({
|
|
|
1203
1259
|
launcherIconColors?.dark ?? launcherIconColor ?? "#ffffff";
|
|
1204
1260
|
const resolvedPanelSize = panelSize ?? localPanelSize;
|
|
1205
1261
|
|
|
1262
|
+
const requestPageContext = (): Promise<AssistantPageContext> => {
|
|
1263
|
+
const currentContext = getCurrentPageContext();
|
|
1264
|
+
if (
|
|
1265
|
+
panelSurface !== "iframe" ||
|
|
1266
|
+
typeof window === "undefined" ||
|
|
1267
|
+
window.parent === window
|
|
1268
|
+
) {
|
|
1269
|
+
pageContextRef.current = currentContext;
|
|
1270
|
+
return Promise.resolve(currentContext);
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
return new Promise((resolve) => {
|
|
1274
|
+
const requestId = createMessageId();
|
|
1275
|
+
const timeoutId = window.setTimeout(() => {
|
|
1276
|
+
pendingPageContextRequestsRef.current.delete(requestId);
|
|
1277
|
+
resolve(pageContextRef.current);
|
|
1278
|
+
}, 250);
|
|
1279
|
+
|
|
1280
|
+
pendingPageContextRequestsRef.current.set(requestId, {
|
|
1281
|
+
resolve,
|
|
1282
|
+
timeoutId,
|
|
1283
|
+
});
|
|
1284
|
+
postParentMessage("assistant-embed:get-page-context", { requestId });
|
|
1285
|
+
});
|
|
1286
|
+
};
|
|
1287
|
+
|
|
1206
1288
|
const persistPanelState = (
|
|
1207
1289
|
nextMessages = messagesRef.current,
|
|
1208
1290
|
scrollTop = savedScrollTopRef.current,
|
|
@@ -1227,6 +1309,7 @@ export default function AssistantEmbedPanel({
|
|
|
1227
1309
|
}
|
|
1228
1310
|
|
|
1229
1311
|
writePersistedPanelState({
|
|
1312
|
+
conversationId: conversationIdRef.current,
|
|
1230
1313
|
messages: nextMessages,
|
|
1231
1314
|
scrollTop,
|
|
1232
1315
|
inFlight: isBusyRef.current,
|
|
@@ -1388,6 +1471,7 @@ export default function AssistantEmbedPanel({
|
|
|
1388
1471
|
};
|
|
1389
1472
|
|
|
1390
1473
|
const applyPersistedPanelState = (nextState: PersistedPanelState) => {
|
|
1474
|
+
conversationIdRef.current = nextState.conversationId;
|
|
1391
1475
|
messagesRef.current = nextState.messages;
|
|
1392
1476
|
savedScrollTopRef.current = nextState.scrollTop;
|
|
1393
1477
|
isBusyRef.current = nextState.inFlight;
|
|
@@ -1445,6 +1529,7 @@ export default function AssistantEmbedPanel({
|
|
|
1445
1529
|
|
|
1446
1530
|
pendingHandoffsRef.current.set(handoffId, {
|
|
1447
1531
|
state: {
|
|
1532
|
+
conversationId: conversationIdRef.current,
|
|
1448
1533
|
messages: messagesRef.current,
|
|
1449
1534
|
scrollTop: savedScrollTopRef.current,
|
|
1450
1535
|
inFlight: isBusyRef.current,
|
|
@@ -1774,8 +1859,35 @@ export default function AssistantEmbedPanel({
|
|
|
1774
1859
|
type?: unknown;
|
|
1775
1860
|
size?: unknown;
|
|
1776
1861
|
isFullscreen?: unknown;
|
|
1862
|
+
hostname?: unknown;
|
|
1863
|
+
pagePath?: unknown;
|
|
1864
|
+
requestId?: unknown;
|
|
1777
1865
|
};
|
|
1778
1866
|
|
|
1867
|
+
if (data.type === "assistant-embed:set-page-context") {
|
|
1868
|
+
if (event.source !== window.parent) {
|
|
1869
|
+
return;
|
|
1870
|
+
}
|
|
1871
|
+
|
|
1872
|
+
const pageContext = normalizeParentPageContext(
|
|
1873
|
+
data.hostname,
|
|
1874
|
+
data.pagePath,
|
|
1875
|
+
);
|
|
1876
|
+
pageContextRef.current = pageContext;
|
|
1877
|
+
|
|
1878
|
+
if (typeof data.requestId === "string") {
|
|
1879
|
+
const pendingRequest = pendingPageContextRequestsRef.current.get(
|
|
1880
|
+
data.requestId,
|
|
1881
|
+
);
|
|
1882
|
+
if (pendingRequest) {
|
|
1883
|
+
window.clearTimeout(pendingRequest.timeoutId);
|
|
1884
|
+
pendingPageContextRequestsRef.current.delete(data.requestId);
|
|
1885
|
+
pendingRequest.resolve(pageContext);
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
return;
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1779
1891
|
if (data.type === "assistant-embed:panel-opened") {
|
|
1780
1892
|
setEmptyStateAnimationKey((previous) => previous + 1);
|
|
1781
1893
|
queueSavedScrollRestore();
|
|
@@ -1799,6 +1911,10 @@ export default function AssistantEmbedPanel({
|
|
|
1799
1911
|
window.addEventListener("message", handlePanelMessage);
|
|
1800
1912
|
return () => {
|
|
1801
1913
|
window.removeEventListener("message", handlePanelMessage);
|
|
1914
|
+
for (const pendingRequest of pendingPageContextRequestsRef.current.values()) {
|
|
1915
|
+
window.clearTimeout(pendingRequest.timeoutId);
|
|
1916
|
+
}
|
|
1917
|
+
pendingPageContextRequestsRef.current.clear();
|
|
1802
1918
|
};
|
|
1803
1919
|
}, []);
|
|
1804
1920
|
|
|
@@ -1810,6 +1926,7 @@ export default function AssistantEmbedPanel({
|
|
|
1810
1926
|
const handleStartNewChat = () => {
|
|
1811
1927
|
activeRequestAbortRef.current?.abort();
|
|
1812
1928
|
activeRequestAbortRef.current = null;
|
|
1929
|
+
conversationIdRef.current = createMessageId();
|
|
1813
1930
|
setSharedBusy(false);
|
|
1814
1931
|
setSharedAwaitingFirstToken(false);
|
|
1815
1932
|
resetThreadScrollPosition([]);
|
|
@@ -1837,6 +1954,7 @@ export default function AssistantEmbedPanel({
|
|
|
1837
1954
|
const handleUnavailableBack = () => {
|
|
1838
1955
|
activeRequestAbortRef.current?.abort();
|
|
1839
1956
|
activeRequestAbortRef.current = null;
|
|
1957
|
+
conversationIdRef.current = createMessageId();
|
|
1840
1958
|
setSharedBusy(false);
|
|
1841
1959
|
setSharedAwaitingFirstToken(false);
|
|
1842
1960
|
resetThreadScrollPosition([]);
|
|
@@ -1893,10 +2011,14 @@ export default function AssistantEmbedPanel({
|
|
|
1893
2011
|
requestHeaders["x-ask-ai-dev-token"] = devProxyToken;
|
|
1894
2012
|
}
|
|
1895
2013
|
|
|
2014
|
+
const pageContext = await requestPageContext();
|
|
1896
2015
|
const response = await fetch(resolvedApiPathRef.current, {
|
|
1897
2016
|
method: "POST",
|
|
1898
2017
|
headers: requestHeaders,
|
|
1899
2018
|
body: JSON.stringify({
|
|
2019
|
+
conversationId: conversationIdRef.current,
|
|
2020
|
+
pagePath: pageContext.pagePath,
|
|
2021
|
+
hostname: pageContext.hostname,
|
|
1900
2022
|
messages: nextConversation.map((message) => ({
|
|
1901
2023
|
role: message.role,
|
|
1902
2024
|
content: message.content,
|
|
@@ -2141,7 +2263,7 @@ export default function AssistantEmbedPanel({
|
|
|
2141
2263
|
linkTarget === "current" && onCurrentLinkNavigate
|
|
2142
2264
|
? getSameOriginNavigationRequest(event)
|
|
2143
2265
|
: null;
|
|
2144
|
-
if (!navigationRequest) {
|
|
2266
|
+
if (!navigationRequest || !onCurrentLinkNavigate) {
|
|
2145
2267
|
return;
|
|
2146
2268
|
}
|
|
2147
2269
|
|
|
@@ -397,90 +397,101 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
397
397
|
</div>
|
|
398
398
|
</div>
|
|
399
399
|
</div>
|
|
400
|
-
<script
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
400
|
+
<script>
|
|
401
|
+
const codeBlockRootSelector = "[data-rd-code-block-root='true']";
|
|
402
|
+
const codeBlockControlsKey = "__rdCodeBlockControls";
|
|
403
|
+
|
|
404
|
+
const getCodeBlockControls = () => {
|
|
405
|
+
window[codeBlockControlsKey] = window[codeBlockControlsKey] || {
|
|
406
|
+
copiedStateTimers: new WeakMap(),
|
|
407
|
+
installed: false,
|
|
408
|
+
};
|
|
404
409
|
|
|
405
|
-
|
|
406
|
-
|
|
410
|
+
return window[codeBlockControlsKey];
|
|
411
|
+
};
|
|
407
412
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
);
|
|
411
|
-
if (copyButtons.length === 0) return;
|
|
413
|
+
const setCopiedState = (button, copied) => {
|
|
414
|
+
const copyIcon = button.querySelector("[data-rd-copy-icon]");
|
|
415
|
+
const checkIcon = button.querySelector("[data-rd-copy-check]");
|
|
412
416
|
|
|
413
|
-
|
|
414
|
-
const copyIcon = button.querySelector("[data-rd-copy-icon]");
|
|
415
|
-
const checkIcon = button.querySelector("[data-rd-copy-check]");
|
|
417
|
+
if (!copyIcon || !checkIcon) return;
|
|
416
418
|
|
|
417
|
-
|
|
419
|
+
if (copied) {
|
|
420
|
+
copyIcon.classList.add("scale-50", "opacity-0", "-rotate-6");
|
|
421
|
+
copyIcon.classList.remove("scale-100", "opacity-100", "rotate-0");
|
|
418
422
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
checkIcon.classList.remove("scale-50", "opacity-0", "rotate-6");
|
|
424
|
-
checkIcon.classList.add("scale-110", "opacity-100", "rotate-0");
|
|
425
|
-
return;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
copyIcon.classList.remove("scale-50", "opacity-0", "-rotate-6");
|
|
429
|
-
copyIcon.classList.add("scale-100", "opacity-100", "rotate-0");
|
|
423
|
+
checkIcon.classList.remove("scale-50", "opacity-0", "rotate-6");
|
|
424
|
+
checkIcon.classList.add("scale-110", "opacity-100", "rotate-0");
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
430
427
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
428
|
+
copyIcon.classList.remove("scale-50", "opacity-0", "-rotate-6");
|
|
429
|
+
copyIcon.classList.add("scale-100", "opacity-100", "rotate-0");
|
|
430
|
+
|
|
431
|
+
checkIcon.classList.remove("scale-110", "opacity-100", "rotate-0");
|
|
432
|
+
checkIcon.classList.add("scale-50", "opacity-0", "rotate-6");
|
|
433
|
+
};
|
|
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);
|
|
434
451
|
|
|
435
|
-
const fallbackCopy = (text) => {
|
|
436
452
|
try {
|
|
437
|
-
|
|
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;
|
|
453
|
+
textarea.focus({ preventScroll: true });
|
|
463
454
|
} catch {
|
|
464
|
-
|
|
455
|
+
textarea.focus();
|
|
465
456
|
}
|
|
466
|
-
|
|
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
467
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
}
|
|
474
|
-
} catch {
|
|
475
|
-
// Fallback below when the async Clipboard API is unavailable or blocked.
|
|
468
|
+
const copyToClipboard = async (text) => {
|
|
469
|
+
try {
|
|
470
|
+
if (navigator.clipboard?.writeText) {
|
|
471
|
+
await navigator.clipboard.writeText(text);
|
|
472
|
+
return true;
|
|
476
473
|
}
|
|
474
|
+
} catch {
|
|
475
|
+
// Fallback below when the async Clipboard API is unavailable or blocked.
|
|
476
|
+
}
|
|
477
477
|
|
|
478
|
-
|
|
479
|
-
|
|
478
|
+
return fallbackCopy(text);
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
const initCodeBlock = (root) => {
|
|
482
|
+
if (!(root instanceof HTMLElement)) return;
|
|
483
|
+
if (root.dataset.rdCodeBlockInitialized === "true") return;
|
|
484
|
+
|
|
485
|
+
const copyButtons = root.querySelectorAll("[data-rd-copy-trigger='true']");
|
|
486
|
+
if (copyButtons.length === 0) return;
|
|
487
|
+
|
|
488
|
+
root.dataset.rdCodeBlockInitialized = "true";
|
|
480
489
|
|
|
481
490
|
copyButtons.forEach((button) => {
|
|
482
|
-
|
|
491
|
+
if (!(button instanceof HTMLElement)) return;
|
|
492
|
+
|
|
483
493
|
button.addEventListener("click", async () => {
|
|
494
|
+
const controls = getCodeBlockControls();
|
|
484
495
|
const encodedCopyValue =
|
|
485
496
|
button.getAttribute("data-rd-copy-content") ?? "";
|
|
486
497
|
const copyValue = decodeURIComponent(encodedCopyValue);
|
|
@@ -494,16 +505,35 @@ const renderedCodeLinesHtml = normalizedTokenLines
|
|
|
494
505
|
|
|
495
506
|
setCopiedState(button, true);
|
|
496
507
|
|
|
497
|
-
|
|
498
|
-
|
|
508
|
+
const existingTimeoutId = controls.copiedStateTimers.get(button);
|
|
509
|
+
if (existingTimeoutId) window.clearTimeout(existingTimeoutId);
|
|
510
|
+
|
|
511
|
+
const timeoutId = window.setTimeout(() => {
|
|
499
512
|
setCopiedState(button, false);
|
|
500
|
-
|
|
513
|
+
controls.copiedStateTimers.delete(button);
|
|
501
514
|
}, 1200);
|
|
515
|
+
controls.copiedStateTimers.set(button, timeoutId);
|
|
502
516
|
} catch {
|
|
503
517
|
setCopiedState(button, false);
|
|
504
518
|
}
|
|
505
519
|
});
|
|
506
520
|
});
|
|
507
|
-
}
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
const initCodeBlocks = () => {
|
|
524
|
+
document.querySelectorAll(codeBlockRootSelector).forEach((root) => {
|
|
525
|
+
initCodeBlock(root);
|
|
526
|
+
});
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
const controls = getCodeBlockControls();
|
|
530
|
+
controls.init = initCodeBlocks;
|
|
531
|
+
|
|
532
|
+
if (!controls.installed) {
|
|
533
|
+
controls.installed = true;
|
|
534
|
+
document.addEventListener("astro:page-load", initCodeBlocks);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
initCodeBlocks();
|
|
508
538
|
</script>
|
|
509
539
|
</div>
|
|
@@ -62,6 +62,9 @@ const isInitiallyExpanded = shouldShowAllCode || totalLineCount <= visibleLines;
|
|
|
62
62
|
<div
|
|
63
63
|
class="rd-prose-block rd-component-preview isolate flex w-full max-w-full min-w-0 flex-col"
|
|
64
64
|
data-rd-component-preview-root="true"
|
|
65
|
+
data-rd-preview-visible-lines={String(visibleLines)}
|
|
66
|
+
data-rd-preview-total-line-count={String(totalLineCount)}
|
|
67
|
+
data-rd-preview-show-all-code={shouldShowAllCode ? "true" : "false"}
|
|
65
68
|
>
|
|
66
69
|
<div
|
|
67
70
|
class="relative z-10 w-full max-w-full min-w-0 rounded-t-xl border-[0.5px] border-b-0 border-(--rd-code-tab-edge-border) bg-(--rd-code-surface) p-2"
|
|
@@ -215,27 +218,29 @@ const isInitiallyExpanded = shouldShowAllCode || totalLineCount <= visibleLines;
|
|
|
215
218
|
}
|
|
216
219
|
</style>
|
|
217
220
|
|
|
218
|
-
<script
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
(
|
|
228
|
-
const
|
|
229
|
-
if (!(
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
221
|
+
<script>
|
|
222
|
+
const previewRootSelector = '[data-rd-component-preview-root="true"]';
|
|
223
|
+
const previewControlsKey = "__rdComponentPreviewControls";
|
|
224
|
+
|
|
225
|
+
const parsePositiveInteger = (value, fallback) => {
|
|
226
|
+
const parsed = Number.parseInt(value ?? "", 10);
|
|
227
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
const syncExpandedHeight = (root) => {
|
|
231
|
+
const codeWrapper = root.querySelector(".rd-component-preview__code");
|
|
232
|
+
if (!(codeWrapper instanceof HTMLElement)) return;
|
|
233
|
+
|
|
234
|
+
const scrollArea = codeWrapper.querySelector("[data-rd-code-scroll-area]");
|
|
235
|
+
if (!(scrollArea instanceof HTMLElement)) return;
|
|
236
|
+
|
|
237
|
+
codeWrapper.style.setProperty(
|
|
238
|
+
"--rd-preview-expanded-height",
|
|
239
|
+
`${scrollArea.scrollHeight}px`,
|
|
240
|
+
);
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
const initComponentPreview = (root) => {
|
|
239
244
|
if (!(root instanceof HTMLElement)) return;
|
|
240
245
|
|
|
241
246
|
const codeWrapper = root.querySelector(".rd-component-preview__code");
|
|
@@ -252,30 +257,66 @@ const isInitiallyExpanded = shouldShowAllCode || totalLineCount <= visibleLines;
|
|
|
252
257
|
return;
|
|
253
258
|
}
|
|
254
259
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
);
|
|
260
|
-
};
|
|
260
|
+
syncExpandedHeight(root);
|
|
261
|
+
|
|
262
|
+
if (root.dataset.rdComponentPreviewInitialized === "true") return;
|
|
263
|
+
root.dataset.rdComponentPreviewInitialized = "true";
|
|
261
264
|
|
|
262
|
-
|
|
265
|
+
const visibleLines = parsePositiveInteger(
|
|
266
|
+
root.dataset.rdPreviewVisibleLines,
|
|
267
|
+
5,
|
|
268
|
+
);
|
|
269
|
+
const totalLineCount = parsePositiveInteger(
|
|
270
|
+
root.dataset.rdPreviewTotalLineCount,
|
|
271
|
+
visibleLines,
|
|
272
|
+
);
|
|
273
|
+
const shouldShowAllCode = root.dataset.rdPreviewShowAllCode === "true";
|
|
263
274
|
|
|
264
275
|
if (shouldShowAllCode || totalLineCount <= visibleLines) {
|
|
265
276
|
codeWrapper.dataset.rdPreviewExpanded = "true";
|
|
266
|
-
window.addEventListener("resize", syncExpandedHeight, { passive: true });
|
|
267
277
|
return;
|
|
268
278
|
}
|
|
269
279
|
|
|
270
280
|
const setExpanded = () => {
|
|
271
|
-
syncExpandedHeight();
|
|
281
|
+
syncExpandedHeight(root);
|
|
272
282
|
codeWrapper.dataset.rdPreviewExpanded = "true";
|
|
273
283
|
};
|
|
274
284
|
|
|
275
285
|
expandButton.addEventListener("click", () => {
|
|
276
286
|
setExpanded();
|
|
277
287
|
});
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
const initComponentPreviews = () => {
|
|
291
|
+
document.querySelectorAll(previewRootSelector).forEach((root) => {
|
|
292
|
+
initComponentPreview(root);
|
|
293
|
+
});
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
const schedulePreviewHeightSync = () => {
|
|
297
|
+
if (window[previewControlsKey]?.resizeFrameId) return;
|
|
298
|
+
|
|
299
|
+
window[previewControlsKey].resizeFrameId = window.requestAnimationFrame(
|
|
300
|
+
() => {
|
|
301
|
+
window[previewControlsKey].resizeFrameId = 0;
|
|
302
|
+
document.querySelectorAll(previewRootSelector).forEach((root) => {
|
|
303
|
+
if (root instanceof HTMLElement) syncExpandedHeight(root);
|
|
304
|
+
});
|
|
305
|
+
},
|
|
306
|
+
);
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
window[previewControlsKey] = window[previewControlsKey] || {};
|
|
310
|
+
window[previewControlsKey].init = initComponentPreviews;
|
|
311
|
+
|
|
312
|
+
if (!window[previewControlsKey].installed) {
|
|
313
|
+
window[previewControlsKey].installed = true;
|
|
314
|
+
window[previewControlsKey].resizeFrameId = 0;
|
|
315
|
+
window.addEventListener("resize", schedulePreviewHeightSync, {
|
|
316
|
+
passive: true,
|
|
317
|
+
});
|
|
318
|
+
document.addEventListener("astro:page-load", initComponentPreviews);
|
|
319
|
+
}
|
|
278
320
|
|
|
279
|
-
|
|
280
|
-
})();
|
|
321
|
+
initComponentPreviews();
|
|
281
322
|
</script>
|
|
@@ -17,6 +17,7 @@ import { resolvePageDescription } from "../lib/page-description";
|
|
|
17
17
|
interface Props {
|
|
18
18
|
pageTitle?: string;
|
|
19
19
|
pageDescription?: string;
|
|
20
|
+
hasMarkdownAlternate?: boolean;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
type TabsPresentation = "topbar" | "sidebar";
|
|
@@ -36,7 +37,13 @@ function routePathToOgImagePath(routePath: string): string {
|
|
|
36
37
|
return `/_og/images/${normalizedRoutePath.slice(1, -1)}.png`;
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
|
|
40
|
+
function routePathToMarkdownPath(routePath: string): string {
|
|
41
|
+
const normalizedRoutePath = routePath.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
42
|
+
return normalizedRoutePath ? `/${normalizedRoutePath}.md` : "/index.md";
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const { pageTitle, pageDescription, hasMarkdownAlternate = false } =
|
|
46
|
+
Astro.props as Props;
|
|
40
47
|
const config = await getConfig();
|
|
41
48
|
const favicon = getFaviconConfig();
|
|
42
49
|
const neutralPaletteCss = getDocsThemeCss(config.theme);
|
|
@@ -56,6 +63,12 @@ const canonicalUrl = new URL(
|
|
|
56
63
|
prependBasePath(routePathname),
|
|
57
64
|
Astro.site ?? Astro.url,
|
|
58
65
|
).toString();
|
|
66
|
+
const markdownUrl = hasMarkdownAlternate
|
|
67
|
+
? new URL(
|
|
68
|
+
prependBasePath(routePathToMarkdownPath(routePathname)),
|
|
69
|
+
Astro.site ?? Astro.url,
|
|
70
|
+
).toString()
|
|
71
|
+
: undefined;
|
|
59
72
|
const ogImageUrl = new URL(
|
|
60
73
|
resolveStaticAssetUrl(routePathToOgImagePath(routePathname)),
|
|
61
74
|
Astro.site ?? Astro.url,
|
|
@@ -288,6 +301,16 @@ const hasTopbarNavigationTabs =
|
|
|
288
301
|
/>
|
|
289
302
|
<meta name="generator" content={Astro.generator} />
|
|
290
303
|
<link rel="canonical" href={canonicalUrl} />
|
|
304
|
+
{
|
|
305
|
+
markdownUrl && (
|
|
306
|
+
<link
|
|
307
|
+
rel="alternate"
|
|
308
|
+
type="text/markdown"
|
|
309
|
+
href={markdownUrl}
|
|
310
|
+
title="Markdown version"
|
|
311
|
+
/>
|
|
312
|
+
)
|
|
313
|
+
}
|
|
291
314
|
<meta property="og:url" content={canonicalUrl} />
|
|
292
315
|
<meta property="og:type" content="website" />
|
|
293
316
|
<meta property="og:site_name" content={config.title} />
|
|
@@ -7,10 +7,7 @@ import {
|
|
|
7
7
|
} from "./assistant-chrome";
|
|
8
8
|
import { getDocsBasePath, withBasePath } from "./base-path";
|
|
9
9
|
import { getFaviconConfig } from "./favicon";
|
|
10
|
-
import {
|
|
11
|
-
getDocsBaseColorShade,
|
|
12
|
-
getThemeForegroundColor,
|
|
13
|
-
} from "./theme-css";
|
|
10
|
+
import { getDocsBaseColorShade, getThemeForegroundColor } from "./theme-css";
|
|
14
11
|
import { type DocsConfig, type ThemeColorByMode } from "./validation";
|
|
15
12
|
|
|
16
13
|
type AssistantColorByMode = {
|
|
@@ -141,7 +138,9 @@ function getAssistantButtonColor(
|
|
|
141
138
|
config.assistant?.button?.color,
|
|
142
139
|
mode,
|
|
143
140
|
);
|
|
144
|
-
return
|
|
141
|
+
return (
|
|
142
|
+
configuredAssistantColor ?? getDefaultAssistantButtonColor(config, mode)
|
|
143
|
+
);
|
|
145
144
|
}
|
|
146
145
|
|
|
147
146
|
export function getAssistantLauncherIconConfig(
|
|
@@ -905,6 +904,7 @@ export function renderAssistantEmbedScript(config: DocsConfig): string {
|
|
|
905
904
|
}
|
|
906
905
|
|
|
907
906
|
updatePanelLayout();
|
|
907
|
+
postPanelPageContextMessage();
|
|
908
908
|
|
|
909
909
|
try {
|
|
910
910
|
panelFrame.contentWindow.postMessage(
|
|
@@ -916,6 +916,28 @@ export function renderAssistantEmbedScript(config: DocsConfig): string {
|
|
|
916
916
|
}
|
|
917
917
|
}
|
|
918
918
|
|
|
919
|
+
function postPanelPageContextMessage(requestId) {
|
|
920
|
+
if (!panelFrame || !panelFrame.contentWindow) {
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
var message = {
|
|
925
|
+
type: "assistant-embed:set-page-context",
|
|
926
|
+
hostname: window.location.hostname || null,
|
|
927
|
+
pagePath: window.location.pathname || "/",
|
|
928
|
+
};
|
|
929
|
+
|
|
930
|
+
if (typeof requestId === "string" && requestId.length > 0) {
|
|
931
|
+
message.requestId = requestId;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
try {
|
|
935
|
+
panelFrame.contentWindow.postMessage(message, getPanelTargetOrigin());
|
|
936
|
+
} catch {
|
|
937
|
+
// Ignore cross-window messaging failures.
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
|
|
919
941
|
function getPanelTargetOrigin() {
|
|
920
942
|
if (!panelFrame || !panelFrame.src) {
|
|
921
943
|
return "*";
|
|
@@ -1154,6 +1176,7 @@ export function renderAssistantEmbedScript(config: DocsConfig): string {
|
|
|
1154
1176
|
frame.addEventListener("load", function () {
|
|
1155
1177
|
postPanelThemeMessage();
|
|
1156
1178
|
postPanelLayoutMessage();
|
|
1179
|
+
postPanelPageContextMessage();
|
|
1157
1180
|
if (isOpen) {
|
|
1158
1181
|
notifyPanelOpened();
|
|
1159
1182
|
}
|
|
@@ -1293,6 +1316,11 @@ export function renderAssistantEmbedScript(config: DocsConfig): string {
|
|
|
1293
1316
|
|
|
1294
1317
|
if (event.data.type === "assistant-embed:get-panel-layout") {
|
|
1295
1318
|
postPanelLayoutMessage();
|
|
1319
|
+
return;
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
if (event.data.type === "assistant-embed:get-page-context") {
|
|
1323
|
+
postPanelPageContextMessage(event.data.requestId);
|
|
1296
1324
|
}
|
|
1297
1325
|
});
|
|
1298
1326
|
|