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
@@ -11,7 +11,7 @@ import {
11
11
  getDocsBaseColorShade,
12
12
  getThemeForegroundColor,
13
13
  } from "./theme-css";
14
- import { type DocsConfig } from "./validation";
14
+ import { type DocsConfig, type ThemeColorByMode } from "./validation";
15
15
 
16
16
  type AssistantColorByMode = {
17
17
  light: string;
@@ -115,35 +115,33 @@ function resolveLauncherIcon(
115
115
  }
116
116
 
117
117
  function getConfiguredColorForMode(
118
- value: DocsConfig["theme"]["themeColor"] | undefined,
118
+ value: string | ThemeColorByMode | undefined,
119
119
  mode: "light" | "dark",
120
120
  ): string | undefined {
121
121
  if (typeof value === "string") return value;
122
122
  return value?.[mode];
123
123
  }
124
124
 
125
- function getDefaultAssistantThemeColor(
125
+ function getDefaultAssistantButtonColor(
126
126
  config: DocsConfig,
127
127
  mode: "light" | "dark",
128
128
  ): string {
129
- const configuredThemeColor = getConfiguredColorForMode(
130
- config.theme?.themeColor,
129
+ return getDocsBaseColorShade(
130
+ config.theme,
131
131
  mode,
132
+ mode === "light" ? "900" : "100",
132
133
  );
133
- if (configuredThemeColor) return configuredThemeColor;
134
-
135
- return getDocsBaseColorShade(config.theme, mode, mode === "light" ? "900" : "100");
136
134
  }
137
135
 
138
- function getAssistantThemeColor(
136
+ function getAssistantButtonColor(
139
137
  config: DocsConfig,
140
138
  mode: "light" | "dark",
141
139
  ): string {
142
140
  const configuredAssistantColor = getConfiguredColorForMode(
143
- config.assistant?.themeColor,
141
+ config.assistant?.button?.color,
144
142
  mode,
145
143
  );
146
- return configuredAssistantColor ?? getDefaultAssistantThemeColor(config, mode);
144
+ return configuredAssistantColor ?? getDefaultAssistantButtonColor(config, mode);
147
145
  }
148
146
 
149
147
  export function getAssistantLauncherIconConfig(
@@ -151,8 +149,8 @@ export function getAssistantLauncherIconConfig(
151
149
  ): ResolvedAssistantLauncherIcon {
152
150
  const assistantConfig = config.assistant;
153
151
  const themeColors = {
154
- light: getAssistantThemeColor(config, "light"),
155
- dark: getAssistantThemeColor(config, "dark"),
152
+ light: getAssistantButtonColor(config, "light"),
153
+ dark: getAssistantButtonColor(config, "dark"),
156
154
  };
157
155
  const iconColors = {
158
156
  light:
@@ -318,6 +316,9 @@ export function renderAssistantEmbedScript(config: DocsConfig): string {
318
316
  var mobileOffsetY = chrome.mobileOffsetY || "16px";
319
317
  var panelWidth = scriptDataset.panelWidth || chrome.panelWidth || "420px";
320
318
  var panelHeight = scriptDataset.panelHeight || chrome.panelHeight || "640px";
319
+ var panelExpandedWidth = chrome.panelExpandedWidth || "640px";
320
+ var panelExpandedHeight = chrome.panelExpandedHeight || "760px";
321
+ var panelViewportMargin = chrome.panelViewportMargin || "16px";
321
322
  var panelGap = chrome.panelGap || "12px";
322
323
  var panelRadius = chrome.panelRadius || "16px";
323
324
  var panelBorder = chrome.panelBorder || "1px solid rgb(9 14 21 / 8%)";
@@ -334,9 +335,13 @@ export function renderAssistantEmbedScript(config: DocsConfig): string {
334
335
  var panelOpenScale = chrome.panelOpenScale || ".9";
335
336
  var panelOpenDuration = chrome.panelOpenDuration || ".5s";
336
337
  var panelOpenTiming = chrome.panelOpenTiming || "cubic-bezier(.34,1.56,.64,1)";
338
+ var panelSizeDuration = chrome.panelSizeDuration || ".42s";
339
+ var panelSizeTiming = chrome.panelSizeTiming || "cubic-bezier(.22,1.18,.36,1)";
337
340
  var panelCloseDuration = chrome.panelCloseDuration || ".2s";
338
341
  var panelCloseTiming = chrome.panelCloseTiming || "cubic-bezier(.25,1,.5,1)";
339
342
  var mobileBreakpoint = chrome.mobileBreakpoint || "640px";
343
+ var panelFullscreenHeightBreakpoint =
344
+ chrome.panelFullscreenHeightBreakpoint || "560px";
340
345
  var launcherSize = scriptDataset.launcherSize || chrome.launcherSize || "48px";
341
346
  var launcherIconSize = chrome.launcherIconSize || "20px";
342
347
  var launcherShadow =
@@ -354,10 +359,14 @@ export function renderAssistantEmbedScript(config: DocsConfig): string {
354
359
  var themeColor = "";
355
360
  var iconColor = "";
356
361
  var styleId = "assistant-embed-style";
362
+ var panelSizeStorageKey = "docs:assistant-embed-panel-size:v1";
357
363
  var launcherButton;
358
364
  var panelShell;
359
365
  var panelFrame;
360
366
  var isOpen = false;
367
+ var panelSize = readPanelSize();
368
+ var panelSizeTransitionTimeout;
369
+ var isPanelFullscreen = false;
361
370
  var systemThemeMediaQuery =
362
371
  typeof window.matchMedia === "function"
363
372
  ? window.matchMedia("(prefers-color-scheme: dark)")
@@ -376,6 +385,26 @@ export function renderAssistantEmbedScript(config: DocsConfig): string {
376
385
  return "";
377
386
  }
378
387
 
388
+ function normalizePanelSize(value) {
389
+ return value === "expanded" ? "expanded" : "default";
390
+ }
391
+
392
+ function readPanelSize() {
393
+ try {
394
+ return normalizePanelSize(window.localStorage.getItem(panelSizeStorageKey));
395
+ } catch {
396
+ return "default";
397
+ }
398
+ }
399
+
400
+ function writePanelSize() {
401
+ try {
402
+ window.localStorage.setItem(panelSizeStorageKey, panelSize);
403
+ } catch {
404
+ // Ignore storage failures in constrained embeds.
405
+ }
406
+ }
407
+
379
408
  function getSystemTheme() {
380
409
  if (systemThemeMediaQuery && systemThemeMediaQuery.matches) {
381
410
  return "dark";
@@ -507,11 +536,19 @@ export function renderAssistantEmbedScript(config: DocsConfig): string {
507
536
  ".assistant-embed-launcher-chevron{opacity:0;transform:scale(.55);}",
508
537
  ".assistant-embed-launcher[data-open='true'] .assistant-embed-launcher-mark{opacity:0;transform:scale(.55);}",
509
538
  ".assistant-embed-launcher[data-open='true'] .assistant-embed-launcher-chevron{opacity:1;transform:scale(1);}",
510
- ".assistant-embed-panel-shell{position:fixed;width:min(" +
539
+ ".assistant-embed-panel-shell{--assistant-embed-panel-available-height:calc(100dvh - " +
540
+ offsetY +
541
+ " - " +
542
+ launcherSize +
543
+ " - " +
544
+ panelGap +
545
+ " - " +
546
+ panelViewportMargin +
547
+ ");position:fixed;width:min(" +
511
548
  panelWidth +
512
549
  ",calc(100vw - 32px));height:min(" +
513
550
  panelHeight +
514
- ",calc(100dvh - 32px));bottom:calc(" +
551
+ ",var(--assistant-embed-panel-available-height));bottom:calc(" +
515
552
  offsetY +
516
553
  " + " +
517
554
  launcherSize +
@@ -537,11 +574,32 @@ export function renderAssistantEmbedScript(config: DocsConfig): string {
537
574
  panelBackdropBlur +
538
575
  ");overflow:hidden;opacity:1;pointer-events:auto;transform:scale(1);transform-origin:bottom " +
539
576
  side +
540
- ";transition-property:transform,opacity,display;transition-duration:" +
577
+ ";transition-property:width,height,transform,opacity,display;transition-duration:" +
578
+ panelSizeDuration +
579
+ "," +
580
+ panelSizeDuration +
581
+ "," +
582
+ panelOpenDuration +
583
+ "," +
584
+ panelOpenDuration +
585
+ "," +
541
586
  panelOpenDuration +
542
587
  ";transition-timing-function:" +
588
+ panelSizeTiming +
589
+ "," +
590
+ panelSizeTiming +
591
+ "," +
592
+ panelOpenTiming +
593
+ "," +
594
+ panelOpenTiming +
595
+ "," +
543
596
  panelOpenTiming +
544
597
  ";transition-behavior:allow-discrete;}",
598
+ ".assistant-embed-panel-shell[data-size='expanded']{width:min(" +
599
+ panelExpandedWidth +
600
+ ",calc(100vw - 32px));height:min(" +
601
+ panelExpandedHeight +
602
+ ",var(--assistant-embed-panel-available-height));}",
545
603
  ".assistant-embed-panel-shell[data-theme='dark']{border:" +
546
604
  panelDarkBorder +
547
605
  ";background:" +
@@ -554,13 +612,15 @@ export function renderAssistantEmbedScript(config: DocsConfig): string {
554
612
  ");}}",
555
613
  ".assistant-embed-panel-shell[data-state='closed']{display:none;opacity:0;pointer-events:none;transform:scale(" +
556
614
  panelOpenScale +
557
- ");transition-property:transform,opacity,display;transition-duration:" +
615
+ ");transition-property:width,height,transform,opacity,display;transition-duration:" +
558
616
  panelCloseDuration +
559
617
  ";transition-timing-function:" +
560
618
  panelCloseTiming +
561
619
  ";transition-behavior:allow-discrete;}",
562
620
  "@media (max-width:" +
563
621
  mobileBreakpoint +
622
+ "),(max-height:" +
623
+ panelFullscreenHeightBreakpoint +
564
624
  "){.assistant-embed-panel-shell{inset:0!important;width:100vw!important;height:100dvh!important;border:0!important;border-radius:0!important;z-index:" +
565
625
  (numericZIndex + 2) +
566
626
  "!important;}}",
@@ -573,7 +633,7 @@ export function renderAssistantEmbedScript(config: DocsConfig): string {
573
633
  ":" +
574
634
  mobileOffsetX +
575
635
  "!important;}}",
576
- "@media (prefers-reduced-motion:reduce){.assistant-embed-launcher{animation:none!important;}.assistant-embed-launcher,.assistant-embed-launcher-icon,.assistant-embed-panel-shell{transition:none!important;}}",
636
+ "@media (prefers-reduced-motion:reduce){.assistant-embed-launcher,.assistant-embed-panel-shell{animation:none!important;}.assistant-embed-launcher,.assistant-embed-launcher-icon,.assistant-embed-panel-shell{transition:none!important;}}",
577
637
  ].join("");
578
638
  document.head.appendChild(style);
579
639
  }
@@ -603,6 +663,8 @@ export function renderAssistantEmbedScript(config: DocsConfig): string {
603
663
  return;
604
664
  }
605
665
 
666
+ updatePanelLayout();
667
+
606
668
  try {
607
669
  panelFrame.contentWindow.postMessage(
608
670
  { type: "assistant-embed:panel-opened" },
@@ -643,6 +705,103 @@ export function renderAssistantEmbedScript(config: DocsConfig): string {
643
705
  }
644
706
  }
645
707
 
708
+ function postPanelSizeMessage() {
709
+ if (!panelFrame || !panelFrame.contentWindow) {
710
+ return;
711
+ }
712
+
713
+ try {
714
+ panelFrame.contentWindow.postMessage(
715
+ {
716
+ type: "assistant-embed:set-panel-size",
717
+ size: panelSize,
718
+ },
719
+ getPanelTargetOrigin(),
720
+ );
721
+ } catch {
722
+ // Ignore cross-window messaging failures.
723
+ }
724
+ }
725
+
726
+ function postPanelLayoutMessage() {
727
+ if (!panelFrame || !panelFrame.contentWindow) {
728
+ return;
729
+ }
730
+
731
+ try {
732
+ panelFrame.contentWindow.postMessage(
733
+ {
734
+ type: "assistant-embed:set-panel-layout",
735
+ isFullscreen: isPanelFullscreen,
736
+ },
737
+ getPanelTargetOrigin(),
738
+ );
739
+ } catch {
740
+ // Ignore cross-window messaging failures.
741
+ }
742
+ }
743
+
744
+ function startPanelSizeTransition(nextPanelSize) {
745
+ if (
746
+ !panelShell ||
747
+ panelShell.dataset.state === "closed" ||
748
+ isPanelFullscreen
749
+ ) {
750
+ return;
751
+ }
752
+
753
+ if (panelSizeTransitionTimeout) {
754
+ window.clearTimeout(panelSizeTransitionTimeout);
755
+ }
756
+
757
+ panelShell.dataset.sizeTransition =
758
+ nextPanelSize === "expanded" ? "expand" : "collapse";
759
+ panelSizeTransitionTimeout = window.setTimeout(function () {
760
+ if (panelShell) {
761
+ delete panelShell.dataset.sizeTransition;
762
+ }
763
+ panelSizeTransitionTimeout = undefined;
764
+ }, 480);
765
+ }
766
+
767
+ function updatePanelLayout() {
768
+ var nextIsPanelFullscreen =
769
+ window.innerWidth <= Number.parseFloat(mobileBreakpoint) ||
770
+ window.innerHeight <= Number.parseFloat(panelFullscreenHeightBreakpoint);
771
+
772
+ if (nextIsPanelFullscreen === isPanelFullscreen) {
773
+ return;
774
+ }
775
+
776
+ isPanelFullscreen = nextIsPanelFullscreen;
777
+ if (panelShell) {
778
+ panelShell.dataset.fullscreen = String(isPanelFullscreen);
779
+ }
780
+ postPanelLayoutMessage();
781
+ }
782
+
783
+ function setPanelSize(nextPanelSize, shouldNotifyPanel) {
784
+ var normalizedPanelSize = normalizePanelSize(nextPanelSize);
785
+ var didChange = normalizedPanelSize !== panelSize;
786
+ if (didChange) {
787
+ startPanelSizeTransition(normalizedPanelSize);
788
+ }
789
+
790
+ panelSize = normalizedPanelSize;
791
+ if (panelShell) {
792
+ panelShell.dataset.size = panelSize;
793
+ }
794
+ writePanelSize();
795
+
796
+ if (shouldNotifyPanel) {
797
+ postPanelSizeMessage();
798
+ }
799
+ }
800
+
801
+ function togglePanelSize() {
802
+ setPanelSize(panelSize === "expanded" ? "default" : "expanded", true);
803
+ }
804
+
646
805
  function applyResolvedTheme(shouldNotifyPanel) {
647
806
  if (panelShell) {
648
807
  panelShell.dataset.theme = resolvedTheme;
@@ -749,6 +908,7 @@ export function renderAssistantEmbedScript(config: DocsConfig): string {
749
908
  frame.setAttribute("data-assistant-embed-frame", "true");
750
909
  frame.addEventListener("load", function () {
751
910
  postPanelThemeMessage();
911
+ postPanelLayoutMessage();
752
912
  if (isOpen) {
753
913
  notifyPanelOpened();
754
914
  }
@@ -761,6 +921,8 @@ export function renderAssistantEmbedScript(config: DocsConfig): string {
761
921
  shell.className = "assistant-embed-panel-shell";
762
922
  shell.dataset.state = "closed";
763
923
  shell.dataset.theme = resolvedTheme;
924
+ shell.dataset.size = panelSize;
925
+ shell.dataset.fullscreen = String(isPanelFullscreen);
764
926
  shell.setAttribute("data-assistant-embed-panel", "true");
765
927
  shell.appendChild(frame);
766
928
  return shell;
@@ -811,6 +973,7 @@ export function renderAssistantEmbedScript(config: DocsConfig): string {
811
973
  }
812
974
 
813
975
  ensureStyle();
976
+ updatePanelLayout();
814
977
 
815
978
  panelFrame = createFrame(
816
979
  "assistant-embed-panel-frame",
@@ -824,6 +987,8 @@ export function renderAssistantEmbedScript(config: DocsConfig): string {
824
987
  document.body.appendChild(launcherButton);
825
988
  }
826
989
 
990
+ window.addEventListener("resize", updatePanelLayout);
991
+
827
992
  window.addEventListener("message", function (event) {
828
993
  if (
829
994
  !event.data ||
@@ -849,6 +1014,21 @@ export function renderAssistantEmbedScript(config: DocsConfig): string {
849
1014
 
850
1015
  if (event.data.type === "assistant-embed:toggle") {
851
1016
  setOpen(!isOpen);
1017
+ return;
1018
+ }
1019
+
1020
+ if (event.data.type === "assistant-embed:toggle-panel-size") {
1021
+ togglePanelSize();
1022
+ return;
1023
+ }
1024
+
1025
+ if (event.data.type === "assistant-embed:set-panel-size") {
1026
+ setPanelSize(event.data.size, false);
1027
+ return;
1028
+ }
1029
+
1030
+ if (event.data.type === "assistant-embed:get-panel-layout") {
1031
+ postPanelLayoutMessage();
852
1032
  }
853
1033
  });
854
1034
 
@@ -867,6 +1047,13 @@ export function renderAssistantEmbedScript(config: DocsConfig): string {
867
1047
  toggle: function () {
868
1048
  setOpen(!isOpen);
869
1049
  },
1050
+ setPanelSize: function (nextPanelSize) {
1051
+ setPanelSize(nextPanelSize, true);
1052
+ },
1053
+ getPanelSize: function () {
1054
+ return panelSize;
1055
+ },
1056
+ togglePanelSize: togglePanelSize,
870
1057
  setTheme: setTheme,
871
1058
  getTheme: function () {
872
1059
  return {
@@ -876,6 +1063,10 @@ export function renderAssistantEmbedScript(config: DocsConfig): string {
876
1063
  },
877
1064
  destroy: function () {
878
1065
  setSystemThemeListener(false);
1066
+ window.removeEventListener("resize", updatePanelLayout);
1067
+ if (panelSizeTransitionTimeout) {
1068
+ window.clearTimeout(panelSizeTransitionTimeout);
1069
+ }
879
1070
  if (launcherButton) {
880
1071
  launcherButton.remove();
881
1072
  }