radiant-docs 0.1.7 → 0.1.9

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 (78) hide show
  1. package/dist/index.js +28 -5
  2. package/package.json +5 -4
  3. package/template/astro.config.mjs +76 -3
  4. package/template/package-lock.json +924 -737
  5. package/template/package.json +7 -5
  6. package/template/scripts/generate-og-images.mjs +335 -0
  7. package/template/scripts/generate-og-metadata.mjs +173 -0
  8. package/template/scripts/rewrite-static-asset-host.mjs +408 -0
  9. package/template/scripts/stamp-image-versions.mjs +277 -0
  10. package/template/scripts/stamp-og-image-versions.mjs +199 -0
  11. package/template/scripts/stamp-pagefind-runtime-version.mjs +140 -0
  12. package/template/src/assets/fonts/geist-mono/cyrillic.woff2 +0 -0
  13. package/template/src/assets/fonts/geist-mono/latin-ext.woff2 +0 -0
  14. package/template/src/assets/fonts/geist-mono/latin.woff2 +0 -0
  15. package/template/src/assets/fonts/google-sans-flex/canadian-aboriginal.woff2 +0 -0
  16. package/template/src/assets/fonts/google-sans-flex/cherokee.woff2 +0 -0
  17. package/template/src/assets/fonts/google-sans-flex/latin-ext.woff2 +0 -0
  18. package/template/src/assets/fonts/google-sans-flex/latin.woff2 +0 -0
  19. package/template/src/assets/fonts/google-sans-flex/math.woff2 +0 -0
  20. package/template/src/assets/fonts/google-sans-flex/nushu.woff2 +0 -0
  21. package/template/src/assets/fonts/google-sans-flex/symbols.woff2 +0 -0
  22. package/template/src/assets/fonts/google-sans-flex/syriac.woff2 +0 -0
  23. package/template/src/assets/fonts/google-sans-flex/tifinagh.woff2 +0 -0
  24. package/template/src/assets/fonts/google-sans-flex/vietnamese.woff2 +0 -0
  25. package/template/src/components/Footer.astro +94 -0
  26. package/template/src/components/Header.astro +11 -66
  27. package/template/src/components/LogoLink.astro +103 -0
  28. package/template/src/components/MdxPage.astro +126 -11
  29. package/template/src/components/OpenApiPage.astro +1036 -69
  30. package/template/src/components/Search.astro +0 -2
  31. package/template/src/components/SidebarDropdown.astro +34 -14
  32. package/template/src/components/SidebarGroup.astro +3 -6
  33. package/template/src/components/SidebarLink.astro +22 -12
  34. package/template/src/components/SidebarMenu.astro +19 -16
  35. package/template/src/components/SidebarSegmented.astro +99 -0
  36. package/template/src/components/SidebarSubgroup.astro +12 -12
  37. package/template/src/components/ThemeSwitcher.astro +30 -7
  38. package/template/src/components/endpoint/PlaygroundBar.astro +32 -36
  39. package/template/src/components/endpoint/PlaygroundButton.astro +40 -4
  40. package/template/src/components/endpoint/PlaygroundField.astro +1068 -22
  41. package/template/src/components/endpoint/PlaygroundForm.astro +559 -61
  42. package/template/src/components/endpoint/RequestSnippets.astro +342 -193
  43. package/template/src/components/endpoint/ResponseDisplay.astro +161 -147
  44. package/template/src/components/endpoint/ResponseFieldTree.astro +134 -0
  45. package/template/src/components/endpoint/ResponseFields.astro +711 -68
  46. package/template/src/components/endpoint/ResponseSnippets.astro +299 -173
  47. package/template/src/components/sidebar/SidebarEndpointLink.astro +1 -1
  48. package/template/src/components/ui/CodeLanguageIcon.astro +19 -0
  49. package/template/src/components/ui/CodeTabEdge.astro +79 -0
  50. package/template/src/components/ui/Field.astro +103 -20
  51. package/template/src/components/ui/Icon.astro +32 -0
  52. package/template/src/components/ui/ListChevronsToggle.astro +31 -0
  53. package/template/src/components/ui/Tag.astro +1 -1
  54. package/template/src/components/user/{Accordian.astro → Accordion.astro} +6 -6
  55. package/template/src/components/user/Callout.astro +5 -9
  56. package/template/src/components/user/CodeBlock.astro +400 -0
  57. package/template/src/components/user/CodeGroup.astro +225 -0
  58. package/template/src/components/user/ComponentPreview.astro +1 -0
  59. package/template/src/components/user/ComponentPreviewBlock.astro +181 -0
  60. package/template/src/components/user/Image.astro +132 -0
  61. package/template/src/components/user/Steps.astro +1 -3
  62. package/template/src/components/user/Tabs.astro +2 -2
  63. package/template/src/content.config.ts +1 -0
  64. package/template/src/layouts/Layout.astro +109 -8
  65. package/template/src/lib/code/code-block.ts +546 -0
  66. package/template/src/lib/frontmatter-schema.ts +8 -7
  67. package/template/src/lib/mdx/remark-code-block-component.ts +342 -0
  68. package/template/src/lib/mdx/remark-demote-h1.ts +16 -0
  69. package/template/src/lib/pagefind.ts +19 -5
  70. package/template/src/lib/routes.ts +49 -31
  71. package/template/src/lib/utils.ts +20 -0
  72. package/template/src/lib/validation.ts +638 -200
  73. package/template/src/pages/[...slug].astro +18 -5
  74. package/template/src/styles/geist-mono.css +33 -0
  75. package/template/src/styles/global.css +89 -84
  76. package/template/src/styles/google-sans-flex.css +143 -0
  77. package/template/ec.config.mjs +0 -51
  78. /package/template/src/components/user/{AccordianGroup.astro → AccordionGroup.astro} +0 -0
@@ -0,0 +1,103 @@
1
+ ---
2
+ import { getConfig, type LogoVariant } from "../lib/validation";
3
+
4
+ const config = await getConfig();
5
+
6
+ function getLogoUrl(logoPath: string | undefined): string | null {
7
+ if (!logoPath) return null;
8
+
9
+ // Normalize path: remove leading slash if present
10
+ const normalizedPath = logoPath.startsWith("/")
11
+ ? logoPath.slice(1)
12
+ : logoPath;
13
+
14
+ // Return public URL - Vite plugin ensures file exists in public
15
+ return `/${normalizedPath}`;
16
+ }
17
+
18
+ function resolveLogoVariant(
19
+ variant: LogoVariant | undefined,
20
+ defaults: { top: number; bottom: number },
21
+ ): { logoUrl: string | null; paddingTop: number; paddingBottom: number } {
22
+ if (!variant) {
23
+ return {
24
+ logoUrl: null,
25
+ paddingTop: defaults.top,
26
+ paddingBottom: defaults.bottom,
27
+ };
28
+ }
29
+
30
+ if (typeof variant === "string") {
31
+ return {
32
+ logoUrl: getLogoUrl(variant),
33
+ paddingTop: defaults.top,
34
+ paddingBottom: defaults.bottom,
35
+ };
36
+ }
37
+
38
+ return {
39
+ logoUrl: getLogoUrl(variant.image),
40
+ paddingTop: variant.padding?.top ?? defaults.top,
41
+ paddingBottom: variant.padding?.bottom ?? defaults.bottom,
42
+ };
43
+ }
44
+
45
+ // Load light and dark logos
46
+ const lightLogo = resolveLogoVariant(config.logo?.light, {
47
+ top: 10,
48
+ bottom: 10,
49
+ });
50
+ const darkLogo = resolveLogoVariant(config.logo?.dark, { top: 10, bottom: 10 });
51
+ const lightLogoUrl = lightLogo.logoUrl;
52
+ const darkLogoUrl = darkLogo.logoUrl;
53
+
54
+ // Get the href for the logo link (defaults to "/")
55
+ const logoHref = config.logo?.href || "/";
56
+ const logoPillText =
57
+ config.logo?.pill === false ? null : (config.logo?.pill ?? "Docs");
58
+
59
+ const lightLogoContainerStyle = `padding-top: ${lightLogo.paddingTop}px; padding-bottom: ${lightLogo.paddingBottom}px;`;
60
+ const darkLogoContainerStyle = `padding-top: ${darkLogo.paddingTop}px; padding-bottom: ${darkLogo.paddingBottom}px;`;
61
+ ---
62
+
63
+ <a
64
+ href={logoHref}
65
+ class="h-full flex items-center justify-center gap-2 lg:gap-3 text-xl font-bold text-neutral-800 dark:text-neutral-100 overflow-hidden"
66
+ >
67
+ {
68
+ lightLogoUrl || darkLogoUrl ? (
69
+ <>
70
+ {/* Light mode: show light logo if available, otherwise show title */}
71
+ {lightLogoUrl ? (
72
+ <div class="h-full dark:hidden" style={lightLogoContainerStyle}>
73
+ <img src={lightLogoUrl} class="h-full object-contain" alt="Logo" />
74
+ </div>
75
+ ) : (
76
+ <span class="dark:hidden">{config.title}</span>
77
+ )}
78
+
79
+ {/* Dark mode: show dark logo if available, otherwise show title */}
80
+ {darkLogoUrl ? (
81
+ <div class="h-full hidden dark:block" style={darkLogoContainerStyle}>
82
+ <img src={darkLogoUrl} class="h-full object-contain" alt="Logo" />
83
+ </div>
84
+ ) : (
85
+ <span class="hidden dark:block">{config.title}</span>
86
+ )}
87
+ </>
88
+ ) : (
89
+ config.title
90
+ )
91
+ }
92
+ {
93
+ logoPillText && (
94
+ <span
95
+ class:list={[
96
+ "text-[10px] text-neutral-500 font-semibold bg-neutral-100 dark:bg-neutral-800 px-2 py-px rounded-full border border-neutral-200 dark:border-neutral-700/70 shadow-xs",
97
+ ]}
98
+ >
99
+ {logoPillText}
100
+ </span>
101
+ )
102
+ }
103
+ </a>
@@ -6,39 +6,56 @@ import Tabs from "./user/Tabs.astro";
6
6
  import Tab from "./user/Tab.astro";
7
7
  import Steps from "./user/Steps.astro";
8
8
  import Step from "./user/Step.astro";
9
- import Accordian from "./user/Accordian.astro";
10
- import AccordianGroup from "./user/AccordianGroup.astro";
9
+ import Accordion from "./user/Accordion.astro";
10
+ import AccordionGroup from "./user/AccordionGroup.astro";
11
11
  import TableOfContents from "./TableOfContents.astro";
12
- import { deriveTitleFromEntryId } from "../lib/utils";
12
+ import Image from "./user/Image.astro";
13
+ import CodeBlock from "./user/CodeBlock.astro";
14
+ import CodeGroup from "./user/CodeGroup.astro";
15
+ import ComponentPreview from "./user/ComponentPreview.astro";
16
+ import ComponentPreviewBlock from "./user/ComponentPreviewBlock.astro";
17
+ import type { MdxRoute } from "../lib/routes";
18
+
13
19
  interface Props {
14
20
  entry: any;
21
+ route: MdxRoute;
15
22
  }
16
23
 
17
- const { entry } = Astro.props;
24
+ const { entry, route } = Astro.props;
18
25
 
19
26
  const components = {
20
- Accordian,
21
- AccordianGroup,
27
+ Accordion,
28
+ AccordionGroup,
22
29
  Callout,
23
30
  Tabs,
24
31
  Tab,
25
32
  Steps,
26
33
  Step,
34
+ img: Image,
35
+ Image,
36
+ CodeBlockInternal: CodeBlock,
37
+ CodeGroup,
38
+ ComponentPreview,
39
+ ComponentPreviewBlock,
27
40
  };
28
41
 
29
42
  const { Content, headings } = await render(entry);
30
- const title = entry.data.title || deriveTitleFromEntryId(entry.filePath);
43
+ const title = route.title;
44
+ const description =
45
+ typeof entry?.data?.description === "string"
46
+ ? entry.data.description.trim()
47
+ : undefined;
31
48
 
32
49
  const tocHeadings = headings.filter(({ depth }) => depth === 2 || depth === 3);
33
50
  ---
34
51
 
35
- <Layout>
52
+ <Layout pageTitle={title} pageDescription={description}>
36
53
  <article>
37
54
  <header class="mb-6">
38
- <h1 class="text-3xl font-semibold">{title}</h1>
55
+ <h1 class="text-4xl font-semibold tracking-tight">{title}</h1>
39
56
  </header>
40
- <div class="flex justify-between w-full">
41
- <div class="prose-rules">
57
+ <div class="flex w-full min-w-0 justify-between gap-x-12">
58
+ <div class="prose-rules min-w-0 flex-1">
42
59
  <Content components={components} />
43
60
  </div>
44
61
  <aside class="hidden xl:block w-56 shrink-0">
@@ -46,4 +63,102 @@ const tocHeadings = headings.filter(({ depth }) => depth === 2 || depth === 3);
46
63
  </aside>
47
64
  </div>
48
65
  </article>
66
+ <script is:inline>
67
+ function fallbackCopy(text) {
68
+ const textarea = document.createElement("textarea");
69
+ textarea.value = text;
70
+ textarea.setAttribute("readonly", "");
71
+ textarea.style.position = "fixed";
72
+ textarea.style.opacity = "0";
73
+ document.body.appendChild(textarea);
74
+ textarea.select();
75
+ const copied = document.execCommand("copy");
76
+ document.body.removeChild(textarea);
77
+ return copied;
78
+ }
79
+
80
+ async function copyToClipboard(text) {
81
+ try {
82
+ if (navigator.clipboard?.writeText) {
83
+ await navigator.clipboard.writeText(text);
84
+ return true;
85
+ }
86
+ } catch {
87
+ // Fallback below when clipboard API is unavailable or blocked.
88
+ }
89
+
90
+ return fallbackCopy(text);
91
+ }
92
+
93
+ async function copyHeadingUrlFromHash(hash) {
94
+ const url = `${window.location.origin}${window.location.pathname}${hash}`;
95
+ const copied = await copyToClipboard(url);
96
+ if (!copied) return false;
97
+
98
+ if (window.history?.replaceState) {
99
+ window.history.replaceState(null, "", hash);
100
+ } else {
101
+ window.location.hash = hash;
102
+ }
103
+
104
+ return true;
105
+ }
106
+
107
+ function initHeadingLinkCopy() {
108
+ const anchors = document.querySelectorAll(
109
+ ".prose-rules a.heading-anchor[href^='#']",
110
+ );
111
+
112
+ anchors.forEach((anchor) => {
113
+ if (anchor.dataset.copyBound === "true") return;
114
+ anchor.dataset.copyBound = "true";
115
+
116
+ anchor.addEventListener("click", async (event) => {
117
+ event.preventDefault();
118
+ const isPointerClick = event.detail > 0;
119
+
120
+ const hash = anchor.getAttribute("href");
121
+ if (!hash) {
122
+ if (isPointerClick) anchor.blur();
123
+ return;
124
+ }
125
+
126
+ const copied = await copyHeadingUrlFromHash(hash);
127
+ if (!copied) {
128
+ if (isPointerClick) anchor.blur();
129
+ return;
130
+ }
131
+
132
+ if (isPointerClick) anchor.blur();
133
+ });
134
+ });
135
+
136
+ const headings = document.querySelectorAll(
137
+ ".prose-rules :is(h2, h3, h4, h5, h6)[id]",
138
+ );
139
+
140
+ headings.forEach((heading) => {
141
+ if (heading.dataset.copyBound === "true") return;
142
+ heading.dataset.copyBound = "true";
143
+
144
+ heading.addEventListener("click", async (event) => {
145
+ if (!(event.target instanceof Element)) return;
146
+ if (event.target.closest("a.heading-anchor")) return;
147
+ if (event.target.closest("a")) return;
148
+
149
+ const id = heading.getAttribute("id");
150
+ if (!id) return;
151
+
152
+ await copyHeadingUrlFromHash(`#${id}`);
153
+ });
154
+ });
155
+ }
156
+
157
+ initHeadingLinkCopy();
158
+
159
+ if (!window.__mdxHeadingCopyListenerBound) {
160
+ document.addEventListener("astro:after-swap", initHeadingLinkCopy);
161
+ window.__mdxHeadingCopyListenerBound = true;
162
+ }
163
+ </script>
49
164
  </Layout>