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.
- package/dist/index.js +28 -5
- package/package.json +5 -4
- package/template/astro.config.mjs +76 -3
- package/template/package-lock.json +924 -737
- package/template/package.json +7 -5
- package/template/scripts/generate-og-images.mjs +335 -0
- package/template/scripts/generate-og-metadata.mjs +173 -0
- package/template/scripts/rewrite-static-asset-host.mjs +408 -0
- package/template/scripts/stamp-image-versions.mjs +277 -0
- package/template/scripts/stamp-og-image-versions.mjs +199 -0
- package/template/scripts/stamp-pagefind-runtime-version.mjs +140 -0
- package/template/src/assets/fonts/geist-mono/cyrillic.woff2 +0 -0
- package/template/src/assets/fonts/geist-mono/latin-ext.woff2 +0 -0
- package/template/src/assets/fonts/geist-mono/latin.woff2 +0 -0
- package/template/src/assets/fonts/google-sans-flex/canadian-aboriginal.woff2 +0 -0
- package/template/src/assets/fonts/google-sans-flex/cherokee.woff2 +0 -0
- package/template/src/assets/fonts/google-sans-flex/latin-ext.woff2 +0 -0
- package/template/src/assets/fonts/google-sans-flex/latin.woff2 +0 -0
- package/template/src/assets/fonts/google-sans-flex/math.woff2 +0 -0
- package/template/src/assets/fonts/google-sans-flex/nushu.woff2 +0 -0
- package/template/src/assets/fonts/google-sans-flex/symbols.woff2 +0 -0
- package/template/src/assets/fonts/google-sans-flex/syriac.woff2 +0 -0
- package/template/src/assets/fonts/google-sans-flex/tifinagh.woff2 +0 -0
- package/template/src/assets/fonts/google-sans-flex/vietnamese.woff2 +0 -0
- package/template/src/components/Footer.astro +94 -0
- package/template/src/components/Header.astro +11 -66
- package/template/src/components/LogoLink.astro +103 -0
- package/template/src/components/MdxPage.astro +126 -11
- package/template/src/components/OpenApiPage.astro +1036 -69
- package/template/src/components/Search.astro +0 -2
- package/template/src/components/SidebarDropdown.astro +34 -14
- package/template/src/components/SidebarGroup.astro +3 -6
- package/template/src/components/SidebarLink.astro +22 -12
- package/template/src/components/SidebarMenu.astro +19 -16
- package/template/src/components/SidebarSegmented.astro +99 -0
- package/template/src/components/SidebarSubgroup.astro +12 -12
- package/template/src/components/ThemeSwitcher.astro +30 -7
- package/template/src/components/endpoint/PlaygroundBar.astro +32 -36
- package/template/src/components/endpoint/PlaygroundButton.astro +40 -4
- package/template/src/components/endpoint/PlaygroundField.astro +1068 -22
- package/template/src/components/endpoint/PlaygroundForm.astro +559 -61
- package/template/src/components/endpoint/RequestSnippets.astro +342 -193
- package/template/src/components/endpoint/ResponseDisplay.astro +161 -147
- package/template/src/components/endpoint/ResponseFieldTree.astro +134 -0
- package/template/src/components/endpoint/ResponseFields.astro +711 -68
- package/template/src/components/endpoint/ResponseSnippets.astro +299 -173
- package/template/src/components/sidebar/SidebarEndpointLink.astro +1 -1
- package/template/src/components/ui/CodeLanguageIcon.astro +19 -0
- package/template/src/components/ui/CodeTabEdge.astro +79 -0
- package/template/src/components/ui/Field.astro +103 -20
- package/template/src/components/ui/Icon.astro +32 -0
- package/template/src/components/ui/ListChevronsToggle.astro +31 -0
- package/template/src/components/ui/Tag.astro +1 -1
- package/template/src/components/user/{Accordian.astro → Accordion.astro} +6 -6
- package/template/src/components/user/Callout.astro +5 -9
- package/template/src/components/user/CodeBlock.astro +400 -0
- package/template/src/components/user/CodeGroup.astro +225 -0
- package/template/src/components/user/ComponentPreview.astro +1 -0
- package/template/src/components/user/ComponentPreviewBlock.astro +181 -0
- package/template/src/components/user/Image.astro +132 -0
- package/template/src/components/user/Steps.astro +1 -3
- package/template/src/components/user/Tabs.astro +2 -2
- package/template/src/content.config.ts +1 -0
- package/template/src/layouts/Layout.astro +109 -8
- package/template/src/lib/code/code-block.ts +546 -0
- package/template/src/lib/frontmatter-schema.ts +8 -7
- package/template/src/lib/mdx/remark-code-block-component.ts +342 -0
- package/template/src/lib/mdx/remark-demote-h1.ts +16 -0
- package/template/src/lib/pagefind.ts +19 -5
- package/template/src/lib/routes.ts +49 -31
- package/template/src/lib/utils.ts +20 -0
- package/template/src/lib/validation.ts +638 -200
- package/template/src/pages/[...slug].astro +18 -5
- package/template/src/styles/geist-mono.css +33 -0
- package/template/src/styles/global.css +89 -84
- package/template/src/styles/google-sans-flex.css +143 -0
- package/template/ec.config.mjs +0 -51
- /package/template/src/components/user/{AccordianGroup.astro → AccordionGroup.astro} +0 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
---
|
|
2
|
+
import CodeBlock from "./CodeBlock.astro";
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
language?: string;
|
|
6
|
+
raw?: string;
|
|
7
|
+
filename?: string;
|
|
8
|
+
showFilename?: boolean | string;
|
|
9
|
+
showLineNumbers?: boolean | string;
|
|
10
|
+
hideLanguageIcon?: boolean | string;
|
|
11
|
+
highlightedLines?: string;
|
|
12
|
+
collapsedLines?: string;
|
|
13
|
+
previewVisibleLines?: number | string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const {
|
|
17
|
+
language = "jsx",
|
|
18
|
+
raw = "",
|
|
19
|
+
filename = "",
|
|
20
|
+
showFilename = false,
|
|
21
|
+
showLineNumbers = false,
|
|
22
|
+
hideLanguageIcon = false,
|
|
23
|
+
highlightedLines = "",
|
|
24
|
+
collapsedLines = "",
|
|
25
|
+
previewVisibleLines = 5,
|
|
26
|
+
} = Astro.props as Props;
|
|
27
|
+
|
|
28
|
+
function parsePositiveInteger(
|
|
29
|
+
value: number | string | undefined,
|
|
30
|
+
fallback: number,
|
|
31
|
+
): number {
|
|
32
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0) {
|
|
33
|
+
return Math.floor(value);
|
|
34
|
+
}
|
|
35
|
+
if (typeof value === "string") {
|
|
36
|
+
const parsed = Number.parseInt(value, 10);
|
|
37
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
38
|
+
return parsed;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return fallback;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const visibleLines = parsePositiveInteger(previewVisibleLines, 5);
|
|
45
|
+
const totalLineCount = Math.max(1, raw.split("\n").length);
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
<div
|
|
49
|
+
class="rd-component-preview my-6 flex w-full max-w-full min-w-0 flex-col"
|
|
50
|
+
data-rd-component-preview-root="true"
|
|
51
|
+
>
|
|
52
|
+
<div
|
|
53
|
+
class="w-full max-w-full min-w-0 overflow-x-auto rounded-t-xl border border-b-0 border-neutral-200 bg-white p-4 xs:p-6 sm:p-12 shadow-xs [&>:first-child]:mt-0! [&>:last-child]:mb-0!"
|
|
54
|
+
>
|
|
55
|
+
<slot />
|
|
56
|
+
</div>
|
|
57
|
+
<div
|
|
58
|
+
class="rd-component-preview__code not-prose relative"
|
|
59
|
+
data-rd-preview-expanded="false"
|
|
60
|
+
style={{ "--rd-preview-visible-lines": String(visibleLines) }}
|
|
61
|
+
>
|
|
62
|
+
<CodeBlock
|
|
63
|
+
language={language}
|
|
64
|
+
raw={raw}
|
|
65
|
+
filename={filename}
|
|
66
|
+
showFilename={showFilename}
|
|
67
|
+
showLineNumbers={showLineNumbers}
|
|
68
|
+
hideLanguageIcon={hideLanguageIcon}
|
|
69
|
+
highlightedLines={highlightedLines}
|
|
70
|
+
collapsedLines={collapsedLines}
|
|
71
|
+
/>
|
|
72
|
+
<div
|
|
73
|
+
class="rd-component-preview__overlay pointer-events-none absolute inset-x-px inset-y-px hidden items-end justify-center rounded-b-xl bg-linear-to-t from-neutral-50/90 to-neutral-50/30 pb-4"
|
|
74
|
+
data-rd-preview-overlay
|
|
75
|
+
aria-hidden="true"
|
|
76
|
+
>
|
|
77
|
+
<button
|
|
78
|
+
type="button"
|
|
79
|
+
class="pointer-events-auto inline-flex h-8 items-center justify-center rounded-md border border-neutral-200 bg-white px-3 text-sm font-medium text-neutral-700 shadow-md shadow-neutral-200 transition-colors duration-150 hover:bg-neutral-50 cursor-pointer"
|
|
80
|
+
data-rd-preview-expand
|
|
81
|
+
>
|
|
82
|
+
View code
|
|
83
|
+
</button>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
|
|
88
|
+
<style>
|
|
89
|
+
.rd-component-preview :global(.group\/prose-code) {
|
|
90
|
+
margin-top: 0 !important;
|
|
91
|
+
margin-bottom: 0 !important;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.rd-component-preview :global(.group\/prose-code > div) {
|
|
95
|
+
background-color: var(--color-neutral-50) !important;
|
|
96
|
+
border-top-left-radius: 0 !important;
|
|
97
|
+
border-top-right-radius: 0 !important;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.rd-component-preview :global(.group\/prose-code pre),
|
|
101
|
+
.rd-component-preview :global(.group\/prose-code code) {
|
|
102
|
+
background-color: var(--color-neutral-50) !important;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.rd-component-preview__code[data-rd-preview-expanded="false"]
|
|
106
|
+
.rd-component-preview__overlay {
|
|
107
|
+
display: flex;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.rd-component-preview__code :global([data-rd-code-scroll-area]) {
|
|
111
|
+
overflow-y: hidden;
|
|
112
|
+
transition: max-height 280ms cubic-bezier(0.22, 1, 0.36, 1);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.rd-component-preview__code[data-rd-preview-expanded="false"]
|
|
116
|
+
:global([data-rd-code-scroll-area]) {
|
|
117
|
+
max-height: calc(var(--rd-preview-visible-lines, 5) * 1.5rem + 1.25rem);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.rd-component-preview__code[data-rd-preview-expanded="true"]
|
|
121
|
+
:global([data-rd-code-scroll-area]) {
|
|
122
|
+
max-height: var(--rd-preview-expanded-height, 200rem);
|
|
123
|
+
}
|
|
124
|
+
</style>
|
|
125
|
+
|
|
126
|
+
<script is:inline define:vars={{ visibleLines, totalLineCount }}>
|
|
127
|
+
(() => {
|
|
128
|
+
const script = document.currentScript;
|
|
129
|
+
if (!(script instanceof HTMLScriptElement)) return;
|
|
130
|
+
|
|
131
|
+
let root = script.previousElementSibling;
|
|
132
|
+
while (
|
|
133
|
+
root &&
|
|
134
|
+
(!(root instanceof HTMLElement) ||
|
|
135
|
+
!root.hasAttribute("data-rd-component-preview-root"))
|
|
136
|
+
) {
|
|
137
|
+
root = root.previousElementSibling;
|
|
138
|
+
}
|
|
139
|
+
if (!(root instanceof HTMLElement)) return;
|
|
140
|
+
|
|
141
|
+
const codeWrapper = root.querySelector(".rd-component-preview__code");
|
|
142
|
+
if (!(codeWrapper instanceof HTMLElement)) return;
|
|
143
|
+
|
|
144
|
+
const overlay = codeWrapper.querySelector("[data-rd-preview-overlay]");
|
|
145
|
+
const expandButton = codeWrapper.querySelector("[data-rd-preview-expand]");
|
|
146
|
+
const scrollArea = codeWrapper.querySelector("[data-rd-code-scroll-area]");
|
|
147
|
+
if (
|
|
148
|
+
!(overlay instanceof HTMLElement) ||
|
|
149
|
+
!(expandButton instanceof HTMLButtonElement) ||
|
|
150
|
+
!(scrollArea instanceof HTMLElement)
|
|
151
|
+
) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const syncExpandedHeight = () => {
|
|
156
|
+
codeWrapper.style.setProperty(
|
|
157
|
+
"--rd-preview-expanded-height",
|
|
158
|
+
`${scrollArea.scrollHeight}px`,
|
|
159
|
+
);
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
syncExpandedHeight();
|
|
163
|
+
|
|
164
|
+
if (totalLineCount <= visibleLines) {
|
|
165
|
+
codeWrapper.dataset.rdPreviewExpanded = "true";
|
|
166
|
+
window.addEventListener("resize", syncExpandedHeight, { passive: true });
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const setExpanded = () => {
|
|
171
|
+
syncExpandedHeight();
|
|
172
|
+
codeWrapper.dataset.rdPreviewExpanded = "true";
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
expandButton.addEventListener("click", () => {
|
|
176
|
+
setExpanded();
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
window.addEventListener("resize", syncExpandedHeight, { passive: true });
|
|
180
|
+
})();
|
|
181
|
+
</script>
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { HTMLAttributes } from "astro/types";
|
|
3
|
+
import { validateProps } from "../../lib/component-error";
|
|
4
|
+
|
|
5
|
+
interface Props extends HTMLAttributes<"img"> {
|
|
6
|
+
src: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const { title, ...attrs } = Astro.props;
|
|
10
|
+
|
|
11
|
+
validateProps(
|
|
12
|
+
"Image",
|
|
13
|
+
Astro.props as Record<string, any>,
|
|
14
|
+
{
|
|
15
|
+
src: { required: true, type: "string" },
|
|
16
|
+
alt: { type: "string" },
|
|
17
|
+
title: { type: "string" },
|
|
18
|
+
},
|
|
19
|
+
Astro.url.pathname,
|
|
20
|
+
);
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
<figure
|
|
24
|
+
class="p-1.5 pb-2 my-8 group border border-neutral-200/80 dark:border-neutral-800 shadow-xs bg-neutral-50 dark:bg-neutral-900 rounded-2xl"
|
|
25
|
+
x-data="{
|
|
26
|
+
open: false,
|
|
27
|
+
showZoomed: false,
|
|
28
|
+
style: 'visibility: hidden;',
|
|
29
|
+
fullShadow: '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
|
|
30
|
+
noShadow: '0 0 0 rgba(0, 0, 0, 0)',
|
|
31
|
+
async zoom() {
|
|
32
|
+
// 1. Lock scroll and measure
|
|
33
|
+
document.body.style.overflow = 'hidden';
|
|
34
|
+
const rect = this.$refs.img.getBoundingClientRect();
|
|
35
|
+
|
|
36
|
+
// 2. Prepare the zoomed image (hidden but in DOM)
|
|
37
|
+
this.style = 'opacity: 0; transition: none;';
|
|
38
|
+
this.open = true;
|
|
39
|
+
this.showZoomed = false;
|
|
40
|
+
|
|
41
|
+
await this.$nextTick();
|
|
42
|
+
const zoomed = this.$refs.zoomedImg;
|
|
43
|
+
const zRect = zoomed.getBoundingClientRect();
|
|
44
|
+
|
|
45
|
+
// 3. Calculate positioning
|
|
46
|
+
const scale = rect.width / zRect.width;
|
|
47
|
+
const tx = (rect.left + rect.width/2) - (zRect.left + zRect.width/2);
|
|
48
|
+
const ty = (rect.top + rect.height/2) - (zRect.top + zRect.height/2);
|
|
49
|
+
|
|
50
|
+
// 4. Snap to initial position (still invisible)
|
|
51
|
+
this.style = `transform: translate(${tx}px, ${ty}px) scale(${scale}); box-shadow: ${this.noShadow}; opacity: 0; transition: none;`;
|
|
52
|
+
|
|
53
|
+
// 5. Triple-frame buffer to ensure paint completion
|
|
54
|
+
requestAnimationFrame(() => {
|
|
55
|
+
// Reveal zoomed image exactly over the thumbnail
|
|
56
|
+
this.style = `transform: translate(${tx}px, ${ty}px) scale(${scale}); box-shadow: ${this.noShadow}; opacity: 1; transition: none;`;
|
|
57
|
+
|
|
58
|
+
requestAnimationFrame(() => {
|
|
59
|
+
// Now start the animation and hide the thumbnail simultaneously
|
|
60
|
+
this.showZoomed = true;
|
|
61
|
+
this.style = `transform: translate(0,0) scale(1); box-shadow: ${this.fullShadow}; opacity: 1; transition: transform 450ms cubic-bezier(0.4, 0, 0.2, 1), box-shadow 450ms cubic-bezier(0.4, 0, 0.2, 1);`;
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
close() {
|
|
66
|
+
document.body.style.overflow = 'auto';
|
|
67
|
+
const rect = this.$refs.img.getBoundingClientRect();
|
|
68
|
+
const zRect = this.$refs.zoomedImg.getBoundingClientRect();
|
|
69
|
+
|
|
70
|
+
const scale = rect.width / zRect.width;
|
|
71
|
+
const tx = (rect.left + rect.width/2) - (zRect.left + zRect.width/2);
|
|
72
|
+
const ty = (rect.top + rect.height/2) - (zRect.top + zRect.height/2);
|
|
73
|
+
|
|
74
|
+
this.style = `transform: translate(${tx}px, ${ty}px) scale(${scale}); box-shadow: ${this.noShadow}; opacity: 1; transition: transform 400ms cubic-bezier(0.4, 0, 0.2, 1), box-shadow 400ms cubic-bezier(0.4, 0, 0.2, 1);`;
|
|
75
|
+
this.showZoomed = false;
|
|
76
|
+
|
|
77
|
+
setTimeout(() => {
|
|
78
|
+
this.open = false;
|
|
79
|
+
this.style = 'opacity: 0;';
|
|
80
|
+
}, 400);
|
|
81
|
+
}
|
|
82
|
+
}"
|
|
83
|
+
>
|
|
84
|
+
<div
|
|
85
|
+
class="overflow-hidden rounded-xl border border-neutral-200/50 dark:border-neutral-800/50 bg-neutral-100 dark:bg-black/20"
|
|
86
|
+
>
|
|
87
|
+
<img
|
|
88
|
+
{...attrs}
|
|
89
|
+
x-ref="img"
|
|
90
|
+
title={title}
|
|
91
|
+
class="w-full h-auto my-0! block cursor-zoom-in transition-opacity"
|
|
92
|
+
:class="showZoomed ? 'opacity-0 duration-0' : 'opacity-100 duration-300'"
|
|
93
|
+
@click="zoom()"
|
|
94
|
+
/>
|
|
95
|
+
</div>
|
|
96
|
+
{
|
|
97
|
+
title && (
|
|
98
|
+
<figcaption class="mt-2 text-center text-sm text-neutral-500 dark:text-neutral-400 font-medium whitespace-pre-line leading-relaxed px-2">
|
|
99
|
+
{title}
|
|
100
|
+
</figcaption>
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
<template x-teleport="body">
|
|
105
|
+
<div
|
|
106
|
+
x-show="open"
|
|
107
|
+
class="fixed bottom-0 top-1 inset-x-1 rounded-t-2xl z-20 flex items-center justify-center pt-20 pb-4 px-4 md:pt-28 md:pb-12 md:px-12 overflow-hidden"
|
|
108
|
+
@keydown.escape.window="close()"
|
|
109
|
+
style="display: none;"
|
|
110
|
+
>
|
|
111
|
+
<div
|
|
112
|
+
x-show="showZoomed"
|
|
113
|
+
x-transition:enter="transition ease-out duration-300"
|
|
114
|
+
x-transition:enter-start="opacity-0"
|
|
115
|
+
x-transition:enter-end="opacity-100"
|
|
116
|
+
x-transition:leave="transition ease-in duration-400"
|
|
117
|
+
x-transition:leave-start="opacity-100"
|
|
118
|
+
x-transition:leave-end="opacity-0"
|
|
119
|
+
class="absolute inset-0 bg-white/90 dark:bg-black/90 backdrop-blur-xl cursor-zoom-out"
|
|
120
|
+
@click="close()"
|
|
121
|
+
>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<img
|
|
125
|
+
{...attrs}
|
|
126
|
+
x-ref="zoomedImg"
|
|
127
|
+
class="relative z-10 max-w-full max-h-full object-contain rounded-2xl shadow-none will-change-transform pointer-events-none"
|
|
128
|
+
:style="style"
|
|
129
|
+
/>
|
|
130
|
+
</div>
|
|
131
|
+
</template>
|
|
132
|
+
</figure>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
import
|
|
2
|
+
import Icon from '../ui/Icon.astro';
|
|
3
3
|
|
|
4
4
|
const html = await Astro.slots.render("default");
|
|
5
5
|
|
|
@@ -92,7 +92,7 @@ class="my-5">
|
|
|
92
92
|
'text-neutral-500 hover:text-neutral-600': activeTab !== ${index}
|
|
93
93
|
}`}
|
|
94
94
|
>
|
|
95
|
-
{icons[index] && <Icon name={
|
|
95
|
+
{icons[index] && <Icon name={icons[index]} class="size-4 shrink-0" />}
|
|
96
96
|
{label}
|
|
97
97
|
</button>
|
|
98
98
|
</li>
|
|
@@ -6,6 +6,7 @@ const docs = defineCollection({
|
|
|
6
6
|
// Load Markdown and MDX files from src/content/docs
|
|
7
7
|
// This pattern excludes non-content files like docs.json and images
|
|
8
8
|
loader: glob({ pattern: "**/*.{md,mdx}", base: "./src/content/docs" }),
|
|
9
|
+
schema: docsSchema,
|
|
9
10
|
});
|
|
10
11
|
|
|
11
12
|
export const collections = { docs };
|
|
@@ -1,10 +1,56 @@
|
|
|
1
1
|
---
|
|
2
2
|
import "../styles/global.css";
|
|
3
|
+
import "../styles/google-sans-flex.css";
|
|
4
|
+
import "../styles/geist-mono.css";
|
|
5
|
+
import googleSansLatinWoff2 from "../assets/fonts/google-sans-flex/latin.woff2?url";
|
|
6
|
+
import googleSansLatinExtWoff2 from "../assets/fonts/google-sans-flex/latin-ext.woff2?url";
|
|
7
|
+
import geistMonoLatinWoff2 from "../assets/fonts/geist-mono/latin.woff2?url";
|
|
8
|
+
import geistMonoLatinExtWoff2 from "../assets/fonts/geist-mono/latin-ext.woff2?url";
|
|
3
9
|
import Sidebar from "../components/Sidebar.astro";
|
|
4
10
|
import { getConfig } from "../lib/validation";
|
|
5
11
|
import Header from "../components/Header.astro";
|
|
12
|
+
import Footer from "../components/Footer.astro";
|
|
6
13
|
|
|
14
|
+
interface Props {
|
|
15
|
+
pageTitle?: string;
|
|
16
|
+
pageDescription?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function normalizeRoutePath(routePath: string): string {
|
|
20
|
+
if (!routePath || routePath === "/") return "/";
|
|
21
|
+
if (!routePath.startsWith("/")) routePath = `/${routePath}`;
|
|
22
|
+
return routePath.endsWith("/") ? routePath : `${routePath}/`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function routePathToOgImagePath(routePath: string): string {
|
|
26
|
+
const normalizedRoutePath = normalizeRoutePath(routePath);
|
|
27
|
+
if (normalizedRoutePath === "/") {
|
|
28
|
+
return "/_og/images/index.png";
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return `/_og/images/${normalizedRoutePath.slice(1, -1)}.png`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const { pageTitle, pageDescription } = Astro.props as Props;
|
|
7
35
|
const config = await getConfig();
|
|
36
|
+
const resolvedPageTitle = pageTitle?.trim();
|
|
37
|
+
const resolvedPageDescription =
|
|
38
|
+
typeof pageDescription === "string" && pageDescription.trim().length > 0
|
|
39
|
+
? pageDescription.trim()
|
|
40
|
+
: undefined;
|
|
41
|
+
const fallbackDescription = resolvedPageTitle
|
|
42
|
+
? `Learn about ${resolvedPageTitle} in the ${config.title} documentation.`
|
|
43
|
+
: `${config.title} documentation.`;
|
|
44
|
+
const resolvedMetaDescription = resolvedPageDescription ?? fallbackDescription;
|
|
45
|
+
const documentTitle = resolvedPageTitle
|
|
46
|
+
? `${resolvedPageTitle} | ${config.title}`
|
|
47
|
+
: `${config.title} Docs`;
|
|
48
|
+
const canonicalUrl = new URL(Astro.url.pathname, Astro.site ?? Astro.url).toString();
|
|
49
|
+
const ogImageUrl = new URL(
|
|
50
|
+
routePathToOgImagePath(Astro.url.pathname),
|
|
51
|
+
Astro.site ?? Astro.url,
|
|
52
|
+
);
|
|
53
|
+
const ogImageHref = ogImageUrl.toString();
|
|
8
54
|
---
|
|
9
55
|
|
|
10
56
|
<!doctype html>
|
|
@@ -12,30 +58,82 @@ const config = await getConfig();
|
|
|
12
58
|
<head>
|
|
13
59
|
<script is:inline>
|
|
14
60
|
const applyTheme = () => {
|
|
61
|
+
const modeParam = new URLSearchParams(window.location.search).get(
|
|
62
|
+
"mode",
|
|
63
|
+
);
|
|
64
|
+
const forcedTheme =
|
|
65
|
+
modeParam === "light" || modeParam === "dark" ? modeParam : null;
|
|
15
66
|
const localStorageTheme = localStorage.getItem("theme");
|
|
16
67
|
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
|
|
17
68
|
.matches
|
|
18
69
|
? "dark"
|
|
19
70
|
: "light";
|
|
20
|
-
const resolvedTheme =
|
|
21
|
-
|
|
71
|
+
const resolvedTheme = forcedTheme
|
|
72
|
+
? forcedTheme
|
|
73
|
+
: localStorageTheme === "system" || !localStorageTheme
|
|
22
74
|
? systemTheme
|
|
23
75
|
: localStorageTheme;
|
|
24
76
|
|
|
25
77
|
document.documentElement.classList.toggle(
|
|
26
78
|
"dark",
|
|
27
|
-
resolvedTheme === "dark"
|
|
79
|
+
resolvedTheme === "dark",
|
|
28
80
|
);
|
|
81
|
+
document.documentElement.dataset.theme = resolvedTheme;
|
|
29
82
|
};
|
|
30
83
|
|
|
31
84
|
// Run on initial load
|
|
32
85
|
applyTheme();
|
|
33
86
|
</script>
|
|
87
|
+
<link
|
|
88
|
+
rel="preload"
|
|
89
|
+
href={googleSansLatinWoff2}
|
|
90
|
+
as="font"
|
|
91
|
+
type="font/woff2"
|
|
92
|
+
crossorigin
|
|
93
|
+
/>
|
|
94
|
+
<link
|
|
95
|
+
rel="preload"
|
|
96
|
+
href={googleSansLatinExtWoff2}
|
|
97
|
+
as="font"
|
|
98
|
+
type="font/woff2"
|
|
99
|
+
crossorigin
|
|
100
|
+
/>
|
|
101
|
+
<link
|
|
102
|
+
rel="preload"
|
|
103
|
+
href={geistMonoLatinWoff2}
|
|
104
|
+
as="font"
|
|
105
|
+
type="font/woff2"
|
|
106
|
+
crossorigin
|
|
107
|
+
/>
|
|
108
|
+
<link
|
|
109
|
+
rel="preload"
|
|
110
|
+
href={geistMonoLatinExtWoff2}
|
|
111
|
+
as="font"
|
|
112
|
+
type="font/woff2"
|
|
113
|
+
crossorigin
|
|
114
|
+
/>
|
|
34
115
|
<meta charset="UTF-8" />
|
|
35
116
|
<meta name="viewport" content="width=device-width" />
|
|
36
117
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
37
118
|
<meta name="generator" content={Astro.generator} />
|
|
38
|
-
<
|
|
119
|
+
<link rel="canonical" href={canonicalUrl} />
|
|
120
|
+
<meta property="og:url" content={canonicalUrl} />
|
|
121
|
+
<meta property="og:type" content="website" />
|
|
122
|
+
<meta property="og:site_name" content={config.title} />
|
|
123
|
+
<title>{documentTitle}</title>
|
|
124
|
+
<meta property="og:title" content={documentTitle} />
|
|
125
|
+
<meta property="og:image" content={ogImageHref} />
|
|
126
|
+
<meta property="og:image:type" content="image/png" />
|
|
127
|
+
<meta property="og:image:width" content="1200" />
|
|
128
|
+
<meta property="og:image:height" content="630" />
|
|
129
|
+
<meta property="og:image:alt" content={documentTitle} />
|
|
130
|
+
<meta name="twitter:title" content={documentTitle} />
|
|
131
|
+
<meta name="twitter:card" content="summary_large_image" />
|
|
132
|
+
<meta name="twitter:image" content={ogImageHref} />
|
|
133
|
+
<meta name="twitter:image:alt" content={documentTitle} />
|
|
134
|
+
<meta name="description" content={resolvedMetaDescription} />
|
|
135
|
+
<meta property="og:description" content={resolvedMetaDescription} />
|
|
136
|
+
<meta name="twitter:description" content={resolvedMetaDescription} />
|
|
39
137
|
</head>
|
|
40
138
|
<body
|
|
41
139
|
class="bg-background text-neutral-900 dark:text-white"
|
|
@@ -50,11 +148,11 @@ const config = await getConfig();
|
|
|
50
148
|
</div>
|
|
51
149
|
<div class="fixed top-0 inset-x-0 h-1 bg-background-dark z-50"></div>
|
|
52
150
|
<div
|
|
53
|
-
class="fixed top-[63px]
|
|
151
|
+
class="fixed top-[63px] z-30 w-[5px] right-0 bottom-0 bg-background-dark border-l border-l-border"
|
|
54
152
|
>
|
|
55
153
|
</div>
|
|
56
154
|
<div
|
|
57
|
-
class="fixed top-[63px]
|
|
155
|
+
class="fixed top-[63px] z-30 w-[5px] left-0 bottom-0 bg-background-dark border-r border-r-border"
|
|
58
156
|
>
|
|
59
157
|
</div>
|
|
60
158
|
<div
|
|
@@ -83,10 +181,13 @@ const config = await getConfig();
|
|
|
83
181
|
</div>
|
|
84
182
|
|
|
85
183
|
<!-- Main Content -->
|
|
86
|
-
<div class="px-5 sm:px-7 lg:pl-[calc(288px+
|
|
87
|
-
<main
|
|
184
|
+
<div class="px-5 sm:px-7 lg:pl-[calc(288px+36px)] pt-17 lg:pr-9">
|
|
185
|
+
<main
|
|
186
|
+
class="max-w-2xl xl:max-w-5xl mx-auto pt-16 pb-16 min-h-[calc(100vh-64px)]"
|
|
187
|
+
>
|
|
88
188
|
<slot />
|
|
89
189
|
</main>
|
|
190
|
+
<Footer />
|
|
90
191
|
</div>
|
|
91
192
|
</body>
|
|
92
193
|
</html>
|