radiant-docs 0.1.64 → 0.1.65
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 +4 -3
- package/template/package-lock.json +1991 -4096
- package/template/package.json +7 -19
- package/template/src/components/OpenApiPage.astro +107 -18
- package/template/src/components/Sidebar.astro +1 -0
- package/template/src/components/endpoint/PlaygroundBar.astro +1 -1
- package/template/src/components/endpoint/PlaygroundField.astro +433 -71
- package/template/src/components/endpoint/PlaygroundForm.astro +470 -87
- package/template/src/components/endpoint/RequestSnippets.astro +6 -1
- package/template/src/components/endpoint/ResponseDisplay.astro +109 -2
- package/template/src/components/endpoint/ResponseFieldTree.astro +1 -1
- package/template/src/components/endpoint/ResponseFields.astro +97 -28
- package/template/src/components/endpoint/ResponseSnippets.astro +19 -7
- package/template/src/layouts/Layout.astro +94 -0
- package/template/src/lib/openapi/operation-doc.ts +308 -70
- package/template/src/lib/openapi/response-content.ts +133 -0
- package/template/src/lib/openapi/schema-variant-labels.ts +213 -0
- package/template/.vscode/extensions.json +0 -4
- package/template/.vscode/launch.json +0 -11
- package/template/scripts/generate-og-images.mjs +0 -667
- package/template/scripts/generate-og-metadata.mjs +0 -206
- package/template/scripts/generate-proxy-allowed-origins.mjs +0 -48
- package/template/scripts/generate-robots-txt.mjs +0 -47
- package/template/scripts/publish-shiki-platform-assets.mjs +0 -1177
- package/template/scripts/remove-assistant-for-non-pro.mjs +0 -28
- package/template/scripts/stamp-image-versions.mjs +0 -355
- package/template/scripts/stamp-og-image-versions.mjs +0 -199
- package/template/scripts/stamp-pagefind-runtime-version.mjs +0 -140
|
@@ -507,7 +507,11 @@ const hasMultipleRequests = requestSnippetItems.length > 1;
|
|
|
507
507
|
class="flex h-full min-h-0 w-full max-w-full min-w-0 flex-col rounded-xl"
|
|
508
508
|
>
|
|
509
509
|
<div
|
|
510
|
-
class=
|
|
510
|
+
class:list={[
|
|
511
|
+
"flex items-center justify-between gap-2",
|
|
512
|
+
!hasMultipleRequests &&
|
|
513
|
+
"border-b-[0.5px] border-(--rd-code-tab-edge-border)",
|
|
514
|
+
]}
|
|
511
515
|
>
|
|
512
516
|
{
|
|
513
517
|
hasMultipleRequests ? (
|
|
@@ -597,6 +601,7 @@ const hasMultipleRequests = requestSnippetItems.length > 1;
|
|
|
597
601
|
class:list={[
|
|
598
602
|
"relative min-h-0 min-w-0 flex-1 overflow-hidden rounded-b-xl border-[0.5px] border-(--rd-code-tab-edge-border) bg-(--rd-code-surface)",
|
|
599
603
|
hasMultipleRequests && "rounded-tl-xl",
|
|
604
|
+
!hasMultipleRequests && "border-t-0",
|
|
600
605
|
]}
|
|
601
606
|
>
|
|
602
607
|
<div
|
|
@@ -74,7 +74,7 @@ import { Icon } from "astro-icon/components";
|
|
|
74
74
|
<div
|
|
75
75
|
class="flex h-full min-h-0 w-full max-w-full min-w-0 flex-col rounded-xl"
|
|
76
76
|
>
|
|
77
|
-
<div class="flex items-center justify-between gap-2">
|
|
77
|
+
<div class="relative z-10 flex items-center justify-between gap-2">
|
|
78
78
|
<div class="min-w-0 flex-1 overflow-hidden rounded-t-xl">
|
|
79
79
|
<div
|
|
80
80
|
x-ref="tabList"
|
|
@@ -143,7 +143,7 @@ import { Icon } from "astro-icon/components";
|
|
|
143
143
|
>
|
|
144
144
|
<div x-show="selected === 'body'" class="h-full">
|
|
145
145
|
<div
|
|
146
|
-
x-show="!response || !response.highlightedData"
|
|
146
|
+
x-show="!response || (!response.highlightedData && !response.bodyObjectUrl)"
|
|
147
147
|
class="text-sm px-4 py-4 xs:py-8 flex flex-col items-center justify-center h-full text-foreground"
|
|
148
148
|
>
|
|
149
149
|
<div class="p-2 rounded-xl mb-1">
|
|
@@ -163,6 +163,113 @@ import { Icon } from "astro-icon/components";
|
|
|
163
163
|
<pre
|
|
164
164
|
class="relative m-0 min-w-full p-0 text-[13px] leading-6"><code data-rd-code-theme class="block min-w-full py-2.5 font-mono text-neutral-800 dark:text-neutral-200" x-html="response?.highlightedData" /></pre>
|
|
165
165
|
</div>
|
|
166
|
+
<div
|
|
167
|
+
x-show="response?.bodyKind === 'media'"
|
|
168
|
+
x-cloak
|
|
169
|
+
class="min-h-full p-4"
|
|
170
|
+
>
|
|
171
|
+
<div class="mb-4 flex flex-wrap items-center justify-between gap-3">
|
|
172
|
+
<div class="min-w-0">
|
|
173
|
+
<div
|
|
174
|
+
class="truncate text-sm font-medium text-neutral-900 dark:text-neutral-100"
|
|
175
|
+
x-text="response?.bodyFilename || 'Response media'"
|
|
176
|
+
>
|
|
177
|
+
</div>
|
|
178
|
+
<div class="mt-0.5 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-neutral-500 dark:text-neutral-400">
|
|
179
|
+
<span x-text="response?.bodyContentType || 'Binary response'">
|
|
180
|
+
</span>
|
|
181
|
+
<span x-show="response?.bodySizeLabel" aria-hidden="true">
|
|
182
|
+
/
|
|
183
|
+
</span>
|
|
184
|
+
<span x-text="response?.bodySizeLabel"></span>
|
|
185
|
+
</div>
|
|
186
|
+
</div>
|
|
187
|
+
<a
|
|
188
|
+
x-bind:href="response?.bodyObjectUrl"
|
|
189
|
+
x-bind:download="response?.bodyFilename || 'response'"
|
|
190
|
+
class="inline-flex h-8 shrink-0 items-center gap-1.5 rounded-lg border border-neutral-200 bg-white px-2.5 text-xs font-medium text-neutral-700 shadow-xs transition-colors hover:bg-neutral-50 dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-300 dark:hover:bg-neutral-900"
|
|
191
|
+
>
|
|
192
|
+
<Icon class="size-3.5" name="lucide:download" />
|
|
193
|
+
Download
|
|
194
|
+
</a>
|
|
195
|
+
</div>
|
|
196
|
+
|
|
197
|
+
<div
|
|
198
|
+
x-show="response?.mediaKind === 'audio'"
|
|
199
|
+
x-cloak
|
|
200
|
+
class="flex min-h-28 items-center"
|
|
201
|
+
>
|
|
202
|
+
<audio
|
|
203
|
+
class="w-full"
|
|
204
|
+
controls
|
|
205
|
+
preload="metadata"
|
|
206
|
+
x-bind:src="response?.bodyObjectUrl"
|
|
207
|
+
>
|
|
208
|
+
</audio>
|
|
209
|
+
</div>
|
|
210
|
+
|
|
211
|
+
<div
|
|
212
|
+
x-show="response?.mediaKind === 'image'"
|
|
213
|
+
x-cloak
|
|
214
|
+
class="flex min-h-48 items-start justify-center"
|
|
215
|
+
>
|
|
216
|
+
<img
|
|
217
|
+
class="max-h-[min(60dvh,32rem)] max-w-full rounded-lg object-contain"
|
|
218
|
+
x-bind:src="response?.bodyObjectUrl"
|
|
219
|
+
x-bind:alt="response?.bodyFilename || 'Response image'"
|
|
220
|
+
/>
|
|
221
|
+
</div>
|
|
222
|
+
|
|
223
|
+
<div
|
|
224
|
+
x-show="response?.mediaKind === 'video'"
|
|
225
|
+
x-cloak
|
|
226
|
+
class="flex min-h-48 items-start justify-center"
|
|
227
|
+
>
|
|
228
|
+
<video
|
|
229
|
+
class="max-h-[min(60dvh,32rem)] max-w-full rounded-lg"
|
|
230
|
+
controls
|
|
231
|
+
preload="metadata"
|
|
232
|
+
x-bind:src="response?.bodyObjectUrl"
|
|
233
|
+
>
|
|
234
|
+
</video>
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
|
|
238
|
+
<div
|
|
239
|
+
x-show="response?.bodyKind === 'binary'"
|
|
240
|
+
x-cloak
|
|
241
|
+
class="flex min-h-full items-center justify-center p-4"
|
|
242
|
+
>
|
|
243
|
+
<div class="flex w-full max-w-md flex-col items-center text-center">
|
|
244
|
+
<div class="mb-3 rounded-xl bg-neutral-100 p-3 dark:bg-neutral-900">
|
|
245
|
+
<Icon
|
|
246
|
+
class="size-6 text-neutral-500 dark:text-neutral-400"
|
|
247
|
+
name="lucide:file-down"
|
|
248
|
+
/>
|
|
249
|
+
</div>
|
|
250
|
+
<div
|
|
251
|
+
class="max-w-full truncate text-sm font-medium text-neutral-900 dark:text-neutral-100"
|
|
252
|
+
x-text="response?.bodyFilename || 'Binary response'"
|
|
253
|
+
>
|
|
254
|
+
</div>
|
|
255
|
+
<div class="mt-1 flex max-w-full flex-wrap justify-center gap-x-2 gap-y-1 text-xs text-neutral-500 dark:text-neutral-400">
|
|
256
|
+
<span x-text="response?.bodyContentType || 'application/octet-stream'">
|
|
257
|
+
</span>
|
|
258
|
+
<span x-show="response?.bodySizeLabel" aria-hidden="true">
|
|
259
|
+
/
|
|
260
|
+
</span>
|
|
261
|
+
<span x-text="response?.bodySizeLabel"></span>
|
|
262
|
+
</div>
|
|
263
|
+
<a
|
|
264
|
+
x-bind:href="response?.bodyObjectUrl"
|
|
265
|
+
x-bind:download="response?.bodyFilename || 'response'"
|
|
266
|
+
class="mt-4 inline-flex h-8 items-center gap-1.5 rounded-lg border border-neutral-200 bg-white px-2.5 text-xs font-medium text-neutral-700 shadow-xs transition-colors hover:bg-neutral-50 dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-300 dark:hover:bg-neutral-900"
|
|
267
|
+
>
|
|
268
|
+
<Icon class="size-3.5" name="lucide:download" />
|
|
269
|
+
Download
|
|
270
|
+
</a>
|
|
271
|
+
</div>
|
|
272
|
+
</div>
|
|
166
273
|
</div>
|
|
167
274
|
|
|
168
275
|
<div x-show="selected === 'header'" x-cloak class="h-full">
|
|
@@ -71,7 +71,7 @@ function countImmediateChildren(field: ResponseField): number {
|
|
|
71
71
|
exclusiveMaximum={field.exclusiveMaximum}
|
|
72
72
|
/>
|
|
73
73
|
{hasExpandableContent && (
|
|
74
|
-
<div class="mt-2.5 w-full overflow-hidden rounded-lg border-[0.5px] border-neutral-900/8 bg-
|
|
74
|
+
<div class="mt-2.5 w-full overflow-hidden rounded-lg border-[0.5px] border-neutral-900/8 bg-neutral-50/50 shadow-[0_.5px_1px_rgba(0,0,0,0.15),0_5px_12px_-6px_rgba(0,0,0,0.08)] transition-colors duration-200 dark:border-white/6 dark:bg-(--rd-code-surface) dark:shadow-[0_-.5px_1px_rgba(255,255,255,0.15),0_5px_12px_-6px_rgba(0,0,0,0.2)]">
|
|
75
75
|
<button
|
|
76
76
|
type="button"
|
|
77
77
|
x-on:click="expanded = !expanded"
|
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
import type { OpenAPIV3, OpenAPIV3_1 } from "openapi-types";
|
|
3
3
|
import ListChevronsToggle from "../ui/ListChevronsToggle.astro";
|
|
4
4
|
import ResponseFieldTree from "./ResponseFieldTree.astro";
|
|
5
|
+
import { getSchemaVariantLabel } from "../../lib/openapi/schema-variant-labels";
|
|
6
|
+
import {
|
|
7
|
+
getBinaryResponseSummary,
|
|
8
|
+
type OpenApiBinaryResponseSummary,
|
|
9
|
+
} from "../../lib/openapi/response-content";
|
|
5
10
|
|
|
6
11
|
interface Props {
|
|
7
12
|
responses: OpenAPIV3.ResponsesObject | OpenAPIV3_1.ResponsesObject;
|
|
@@ -39,6 +44,7 @@ interface ResponseData {
|
|
|
39
44
|
fields: ResponseField[];
|
|
40
45
|
variants?: ResponseVariant[];
|
|
41
46
|
variantType?: "oneOf" | "anyOf";
|
|
47
|
+
binarySummary?: OpenApiBinaryResponseSummary;
|
|
42
48
|
}
|
|
43
49
|
|
|
44
50
|
function getStatusCodeDotClass(statusCode: string): string {
|
|
@@ -82,7 +88,9 @@ function getSchemaEnumValues(schema: any): (string | number)[] | undefined {
|
|
|
82
88
|
}
|
|
83
89
|
|
|
84
90
|
function parseFiniteNumber(value: unknown): number | undefined {
|
|
85
|
-
return typeof value === "number" && Number.isFinite(value)
|
|
91
|
+
return typeof value === "number" && Number.isFinite(value)
|
|
92
|
+
? value
|
|
93
|
+
: undefined;
|
|
86
94
|
}
|
|
87
95
|
|
|
88
96
|
function parseNonNegativeInteger(value: unknown): number | undefined {
|
|
@@ -182,7 +190,10 @@ function mergeConjunctiveNumericConstraints(
|
|
|
182
190
|
if (!second) return first;
|
|
183
191
|
if (first.value > second.value) return first;
|
|
184
192
|
if (second.value > first.value) return second;
|
|
185
|
-
return {
|
|
193
|
+
return {
|
|
194
|
+
value: first.value,
|
|
195
|
+
exclusive: first.exclusive || second.exclusive,
|
|
196
|
+
};
|
|
186
197
|
};
|
|
187
198
|
const pickStricterUpper = (
|
|
188
199
|
first?: { value: number; exclusive: boolean },
|
|
@@ -192,7 +203,10 @@ function mergeConjunctiveNumericConstraints(
|
|
|
192
203
|
if (!second) return first;
|
|
193
204
|
if (first.value < second.value) return first;
|
|
194
205
|
if (second.value < first.value) return second;
|
|
195
|
-
return {
|
|
206
|
+
return {
|
|
207
|
+
value: first.value,
|
|
208
|
+
exclusive: first.exclusive || second.exclusive,
|
|
209
|
+
};
|
|
196
210
|
};
|
|
197
211
|
|
|
198
212
|
const lower = pickStricterLower(toLowerBound(base), toLowerBound(next));
|
|
@@ -438,6 +452,23 @@ function getAdditionalPropertiesSchema(schema: any): any {
|
|
|
438
452
|
return additionalProperties;
|
|
439
453
|
}
|
|
440
454
|
|
|
455
|
+
function getSchemaObjectProperties(schema: any): Record<string, any> {
|
|
456
|
+
if (!schema || typeof schema !== "object") return {};
|
|
457
|
+
|
|
458
|
+
let properties: Record<string, any> = {};
|
|
459
|
+
if (schema.properties && typeof schema.properties === "object") {
|
|
460
|
+
properties = { ...properties, ...schema.properties };
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
if (Array.isArray(schema.allOf)) {
|
|
464
|
+
schema.allOf.forEach((part: any) => {
|
|
465
|
+
properties = { ...properties, ...getSchemaObjectProperties(part) };
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
return properties;
|
|
470
|
+
}
|
|
471
|
+
|
|
441
472
|
function extractVariantData(
|
|
442
473
|
schema: any,
|
|
443
474
|
parentName: string,
|
|
@@ -458,7 +489,12 @@ function extractVariantData(
|
|
|
458
489
|
|
|
459
490
|
const variants = variantSchemas
|
|
460
491
|
.map((variantSchema: any, index: number) => ({
|
|
461
|
-
label:
|
|
492
|
+
label: getSchemaVariantLabel(variantSchema, index, {
|
|
493
|
+
parentSchema: schema,
|
|
494
|
+
siblings: variantSchemas,
|
|
495
|
+
getObjectProperties: getSchemaObjectProperties,
|
|
496
|
+
getTypeLabel: getSchemaTypeLabel,
|
|
497
|
+
}),
|
|
462
498
|
fields: extractFieldsFromSchema(
|
|
463
499
|
variantSchema,
|
|
464
500
|
parentName,
|
|
@@ -568,7 +604,9 @@ function extractFieldsFromSchema(
|
|
|
568
604
|
const nestedFields = extractFieldsFromSchema(
|
|
569
605
|
basePropSchema,
|
|
570
606
|
fullName,
|
|
571
|
-
Array.isArray(basePropSchema.required)
|
|
607
|
+
Array.isArray(basePropSchema.required)
|
|
608
|
+
? basePropSchema.required
|
|
609
|
+
: [],
|
|
572
610
|
);
|
|
573
611
|
fields.push({
|
|
574
612
|
name: fullName,
|
|
@@ -591,7 +629,9 @@ function extractFieldsFromSchema(
|
|
|
591
629
|
const itemFields = extractFieldsFromSchema(
|
|
592
630
|
baseItemSchema,
|
|
593
631
|
`${fullName}[]`,
|
|
594
|
-
Array.isArray(baseItemSchema.required)
|
|
632
|
+
Array.isArray(baseItemSchema.required)
|
|
633
|
+
? baseItemSchema.required
|
|
634
|
+
: [],
|
|
595
635
|
);
|
|
596
636
|
const itemVariantData = extractVariantData(
|
|
597
637
|
itemSchema,
|
|
@@ -643,14 +683,18 @@ function extractFieldsFromSchema(
|
|
|
643
683
|
? extractFieldsFromSchema(
|
|
644
684
|
additionalSchema,
|
|
645
685
|
mapFieldName,
|
|
646
|
-
Array.isArray(additionalSchema?.required)
|
|
686
|
+
Array.isArray(additionalSchema?.required)
|
|
687
|
+
? additionalSchema.required
|
|
688
|
+
: [],
|
|
647
689
|
)
|
|
648
690
|
: [];
|
|
649
691
|
const additionalVariantData = additionalSchema
|
|
650
692
|
? extractVariantData(
|
|
651
693
|
additionalSchema,
|
|
652
694
|
mapFieldName,
|
|
653
|
-
Array.isArray(additionalSchema?.required)
|
|
695
|
+
Array.isArray(additionalSchema?.required)
|
|
696
|
+
? additionalSchema.required
|
|
697
|
+
: [],
|
|
654
698
|
)
|
|
655
699
|
: {};
|
|
656
700
|
|
|
@@ -664,7 +708,9 @@ function extractFieldsFromSchema(
|
|
|
664
708
|
nested: additionalContent.length > 0 ? additionalContent : undefined,
|
|
665
709
|
variants: additionalVariantData.variants,
|
|
666
710
|
variantType: additionalVariantData.variantType,
|
|
667
|
-
enum: additionalSchema
|
|
711
|
+
enum: additionalSchema
|
|
712
|
+
? getSchemaEnumValues(additionalSchema)
|
|
713
|
+
: undefined,
|
|
668
714
|
});
|
|
669
715
|
}
|
|
670
716
|
|
|
@@ -688,10 +734,13 @@ Object.entries(responses)
|
|
|
688
734
|
return numA - numB;
|
|
689
735
|
})
|
|
690
736
|
.forEach(([statusCode, response]: [string, any]) => {
|
|
737
|
+
const binarySummary = getBinaryResponseSummary(response);
|
|
691
738
|
// Try to get application/json content first
|
|
692
|
-
const contentType =
|
|
693
|
-
|
|
694
|
-
|
|
739
|
+
const contentType =
|
|
740
|
+
binarySummary?.contentTypes[0] ||
|
|
741
|
+
(response.content?.["application/json"]
|
|
742
|
+
? "application/json"
|
|
743
|
+
: Object.keys(response.content || {})[0]);
|
|
695
744
|
|
|
696
745
|
const mediaType = contentType ? response.content?.[contentType] : null;
|
|
697
746
|
const schema = mediaType?.schema;
|
|
@@ -700,7 +749,7 @@ Object.entries(responses)
|
|
|
700
749
|
let variants: ResponseVariant[] | undefined;
|
|
701
750
|
let variantType: "oneOf" | "anyOf" | undefined;
|
|
702
751
|
|
|
703
|
-
if (schema) {
|
|
752
|
+
if (schema && !binarySummary) {
|
|
704
753
|
const hasOneOf = Array.isArray(schema.oneOf) && schema.oneOf.length > 0;
|
|
705
754
|
const hasAnyOf = Array.isArray(schema.anyOf) && schema.anyOf.length > 0;
|
|
706
755
|
|
|
@@ -720,7 +769,12 @@ Object.entries(responses)
|
|
|
720
769
|
|
|
721
770
|
variants = variantSchemas
|
|
722
771
|
.map((variantSchema, index) => ({
|
|
723
|
-
label:
|
|
772
|
+
label: getSchemaVariantLabel(variantSchema, index, {
|
|
773
|
+
parentSchema: schema,
|
|
774
|
+
siblings: variantSchemas,
|
|
775
|
+
getObjectProperties: getSchemaObjectProperties,
|
|
776
|
+
getTypeLabel: getSchemaTypeLabel,
|
|
777
|
+
}),
|
|
724
778
|
fields: extractFieldsFromSchema(
|
|
725
779
|
variantSchema,
|
|
726
780
|
"",
|
|
@@ -739,6 +793,7 @@ Object.entries(responses)
|
|
|
739
793
|
fields,
|
|
740
794
|
variants,
|
|
741
795
|
variantType,
|
|
796
|
+
binarySummary,
|
|
742
797
|
});
|
|
743
798
|
});
|
|
744
799
|
---
|
|
@@ -769,12 +824,12 @@ Object.entries(responses)
|
|
|
769
824
|
{response.fields.length > 0 && (
|
|
770
825
|
<>
|
|
771
826
|
{response.variants && response.variants.length > 0 && (
|
|
772
|
-
<p class="mb-2 text-xs text-neutral-500 dark:text-neutral-400">
|
|
827
|
+
<p class="mb-2 text-xs text-neutral-500 dark:text-neutral-400">
|
|
828
|
+
Common fields
|
|
829
|
+
</p>
|
|
773
830
|
)}
|
|
774
831
|
<div x-data="{ expanded: true }">
|
|
775
|
-
<div
|
|
776
|
-
class="w-full overflow-hidden rounded-xl border-[0.5px] border-neutral-900/8 bg-white shadow-[0_.5px_1px_rgba(0,0,0,0.15),0_5px_12px_-6px_rgba(0,0,0,0.08)] transition-colors duration-200 dark:border-white/6 dark:bg-(--rd-code-surface) dark:shadow-[0_-.5px_1px_rgba(255,255,255,0.15),0_5px_12px_-6px_rgba(0,0,0,0.2)]"
|
|
777
|
-
>
|
|
832
|
+
<div class="w-full overflow-hidden rounded-xl border-[0.5px] border-neutral-900/12 bg-neutral-50/50 shadow-[0_.5px_1px_rgba(0,0,0,0.15),0_5px_12px_-6px_rgba(0,0,0,0.08)] transition-colors duration-200 dark:border-white/6 dark:bg-(--rd-code-surface) dark:shadow-[0_-.5px_1px_rgba(255,255,255,0.15),0_5px_12px_-6px_rgba(0,0,0,0.2)]">
|
|
778
833
|
<button
|
|
779
834
|
type="button"
|
|
780
835
|
x-on:click="expanded = !expanded"
|
|
@@ -785,9 +840,7 @@ Object.entries(responses)
|
|
|
785
840
|
<ListChevronsToggle class="size-4 shrink-0 text-neutral-500 group-hover:text-neutral-600 transition duration-200 dark:text-neutral-500 dark:group-hover:text-neutral-300" />
|
|
786
841
|
<span>
|
|
787
842
|
{response.fields.length}{" "}
|
|
788
|
-
{response.fields.length === 1
|
|
789
|
-
? "field"
|
|
790
|
-
: "fields"}
|
|
843
|
+
{response.fields.length === 1 ? "field" : "fields"}
|
|
791
844
|
</span>
|
|
792
845
|
</span>
|
|
793
846
|
</button>
|
|
@@ -814,9 +867,7 @@ Object.entries(responses)
|
|
|
814
867
|
{variant.label}
|
|
815
868
|
</div>
|
|
816
869
|
<div x-data="{ expanded: true }">
|
|
817
|
-
<div
|
|
818
|
-
class="w-full overflow-hidden rounded-lg border-[0.5px] border-neutral-900/8 bg-white shadow-[0_.5px_1px_rgba(0,0,0,0.15),0_5px_12px_-6px_rgba(0,0,0,0.08)] transition-colors duration-200 dark:border-white/6 dark:bg-(--rd-code-surface) dark:shadow-[0_-.5px_1px_rgba(255,255,255,0.15),0_5px_12px_-6px_rgba(0,0,0,0.2)]"
|
|
819
|
-
>
|
|
870
|
+
<div class="w-full overflow-hidden rounded-lg border-[0.5px] border-neutral-900/8 bg-white shadow-[0_.5px_1px_rgba(0,0,0,0.15),0_5px_12px_-6px_rgba(0,0,0,0.08)] transition-colors duration-200 dark:border-white/6 dark:bg-(--rd-code-surface) dark:shadow-[0_-.5px_1px_rgba(255,255,255,0.15),0_5px_12px_-6px_rgba(0,0,0,0.2)]">
|
|
820
871
|
<button
|
|
821
872
|
type="button"
|
|
822
873
|
x-on:click="expanded = !expanded"
|
|
@@ -827,9 +878,7 @@ Object.entries(responses)
|
|
|
827
878
|
<ListChevronsToggle class="size-4 shrink-0 text-neutral-400 group-hover:text-neutral-600 transition duration-200 dark:text-neutral-500 dark:group-hover:text-neutral-300" />
|
|
828
879
|
<span>
|
|
829
880
|
{variant.fields.length}{" "}
|
|
830
|
-
{variant.fields.length === 1
|
|
831
|
-
? "field"
|
|
832
|
-
: "fields"}
|
|
881
|
+
{variant.fields.length === 1 ? "field" : "fields"}
|
|
833
882
|
</span>
|
|
834
883
|
</span>
|
|
835
884
|
</button>
|
|
@@ -857,7 +906,27 @@ Object.entries(responses)
|
|
|
857
906
|
)}
|
|
858
907
|
{response.fields.length === 0 &&
|
|
859
908
|
(!response.variants || response.variants.length === 0) ? (
|
|
860
|
-
|
|
909
|
+
response.binarySummary ? (
|
|
910
|
+
<div class="ml-2 space-y-2 text-sm">
|
|
911
|
+
<div class="font-medium text-neutral-800 dark:text-neutral-200">
|
|
912
|
+
{response.binarySummary.title}
|
|
913
|
+
</div>
|
|
914
|
+
<p class="text-neutral-500 dark:text-neutral-400">
|
|
915
|
+
{response.binarySummary.description}
|
|
916
|
+
</p>
|
|
917
|
+
<div class="flex flex-wrap gap-1.5">
|
|
918
|
+
{response.binarySummary.contentTypes.map((contentType) => (
|
|
919
|
+
<code class="rounded-sm border border-neutral-900/4 bg-neutral-100/80 px-[5px] py-[2px] font-mono text-[11px] leading-none text-neutral-700/90 dark:border-white/3 dark:bg-neutral-800/90 dark:text-neutral-200/90">
|
|
920
|
+
{contentType}
|
|
921
|
+
</code>
|
|
922
|
+
))}
|
|
923
|
+
</div>
|
|
924
|
+
</div>
|
|
925
|
+
) : (
|
|
926
|
+
<p class="text-sm text-neutral-500 ml-2 dark:text-neutral-400">
|
|
927
|
+
No structured response body fields
|
|
928
|
+
</p>
|
|
929
|
+
)
|
|
861
930
|
) : null}
|
|
862
931
|
</div>
|
|
863
932
|
))
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
getCodeLineTokens,
|
|
9
9
|
normalizeCodeLanguageValue,
|
|
10
10
|
} from "../../lib/code/code-block";
|
|
11
|
+
import { getBinaryResponseSummary } from "../../lib/openapi/response-content";
|
|
11
12
|
|
|
12
13
|
interface Props {
|
|
13
14
|
responses: OpenAPIV3.ResponsesObject | OpenAPIV3_1.ResponsesObject;
|
|
@@ -20,19 +21,23 @@ const sampledResponses: Array<{
|
|
|
20
21
|
description: string;
|
|
21
22
|
example?: unknown;
|
|
22
23
|
contentType?: string;
|
|
24
|
+
binarySummaryText?: string;
|
|
23
25
|
}> = [];
|
|
24
26
|
|
|
25
27
|
Object.entries(responses).forEach(([statusCode, response]: [string, any]) => {
|
|
28
|
+
const binarySummary = getBinaryResponseSummary(response);
|
|
26
29
|
const contentTypes = Object.keys(response.content || {});
|
|
27
|
-
const contentType =
|
|
28
|
-
|
|
29
|
-
: contentTypes[0];
|
|
30
|
+
const contentType =
|
|
31
|
+
binarySummary?.contentTypes[0] ||
|
|
32
|
+
(response.content?.["application/json"] ? "application/json" : contentTypes[0]);
|
|
30
33
|
|
|
31
34
|
const mediaType = contentType ? response.content?.[contentType] : null;
|
|
32
35
|
const schema = mediaType?.schema;
|
|
33
36
|
|
|
34
37
|
let example: unknown = undefined;
|
|
35
|
-
if (
|
|
38
|
+
if (binarySummary) {
|
|
39
|
+
example = binarySummary.snippetText;
|
|
40
|
+
} else if (schema) {
|
|
36
41
|
try {
|
|
37
42
|
example = Sampler.sample(schema as JSONSchema7, {
|
|
38
43
|
skipReadOnly: false,
|
|
@@ -47,6 +52,7 @@ Object.entries(responses).forEach(([statusCode, response]: [string, any]) => {
|
|
|
47
52
|
description: response.description ?? "",
|
|
48
53
|
example,
|
|
49
54
|
contentType,
|
|
55
|
+
binarySummaryText: binarySummary?.snippetText,
|
|
50
56
|
});
|
|
51
57
|
});
|
|
52
58
|
|
|
@@ -194,11 +200,12 @@ const responseSnippetItems = await Promise.all(
|
|
|
194
200
|
? "json"
|
|
195
201
|
: "plaintext";
|
|
196
202
|
const code =
|
|
197
|
-
response.
|
|
203
|
+
response.binarySummaryText ??
|
|
204
|
+
(response.example === undefined
|
|
198
205
|
? "This response has no body data."
|
|
199
206
|
: typeof response.example === "string"
|
|
200
207
|
? response.example
|
|
201
|
-
: JSON.stringify(response.example, null, 2);
|
|
208
|
+
: JSON.stringify(response.example, null, 2));
|
|
202
209
|
|
|
203
210
|
return {
|
|
204
211
|
statusCode: response.statusCode,
|
|
@@ -430,7 +437,11 @@ const hasMultipleResponses = responseSnippetItems.length > 1;
|
|
|
430
437
|
class="flex h-full min-h-0 w-full max-w-full min-w-0 flex-col rounded-xl"
|
|
431
438
|
>
|
|
432
439
|
<div
|
|
433
|
-
class=
|
|
440
|
+
class:list={[
|
|
441
|
+
"flex items-center justify-between gap-2",
|
|
442
|
+
!hasMultipleResponses &&
|
|
443
|
+
"border-b-[0.5px] border-(--rd-code-tab-edge-border)",
|
|
444
|
+
]}
|
|
434
445
|
>
|
|
435
446
|
{
|
|
436
447
|
hasMultipleResponses ? (
|
|
@@ -517,6 +528,7 @@ const hasMultipleResponses = responseSnippetItems.length > 1;
|
|
|
517
528
|
class:list={[
|
|
518
529
|
"relative min-h-0 min-w-0 flex-1 overflow-hidden rounded-b-xl border-[0.5px] border-(--rd-code-tab-edge-border) bg-(--rd-code-surface)",
|
|
519
530
|
hasMultipleResponses && "rounded-tl-xl",
|
|
531
|
+
!hasMultipleResponses && "border-t-0",
|
|
520
532
|
]}
|
|
521
533
|
>
|
|
522
534
|
<div
|
|
@@ -384,5 +384,99 @@ const tabsPresentation = navigationTabs?.presentation ?? "topbar";
|
|
|
384
384
|
);
|
|
385
385
|
}
|
|
386
386
|
</style>
|
|
387
|
+
<script is:inline>
|
|
388
|
+
(() => {
|
|
389
|
+
const initializedKey = "__radiantDocsSidebarScrollPersistence";
|
|
390
|
+
const storageKey = "radiant-docs:sidebar-scroll-top";
|
|
391
|
+
const selector = "[data-rd-sidebar-scroll-container]";
|
|
392
|
+
|
|
393
|
+
const getVisibleSidebar = () => {
|
|
394
|
+
const sidebars = document.querySelectorAll(selector);
|
|
395
|
+
|
|
396
|
+
for (const sidebar of sidebars) {
|
|
397
|
+
if (!(sidebar instanceof HTMLElement)) continue;
|
|
398
|
+
|
|
399
|
+
const rect = sidebar.getBoundingClientRect();
|
|
400
|
+
if (rect.width > 0 && rect.height > 0) return sidebar;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return null;
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
const getSavedScrollTop = () => {
|
|
407
|
+
try {
|
|
408
|
+
const value = Number(sessionStorage.getItem(storageKey));
|
|
409
|
+
return Number.isFinite(value) && value > 0 ? value : 0;
|
|
410
|
+
} catch {
|
|
411
|
+
return 0;
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
const saveSidebarScroll = () => {
|
|
416
|
+
const sidebar = getVisibleSidebar();
|
|
417
|
+
if (!sidebar) return;
|
|
418
|
+
|
|
419
|
+
try {
|
|
420
|
+
sessionStorage.setItem(
|
|
421
|
+
storageKey,
|
|
422
|
+
String(Math.max(0, Math.round(sidebar.scrollTop))),
|
|
423
|
+
);
|
|
424
|
+
} catch {
|
|
425
|
+
// Storage can be unavailable in private browsing or locked-down embeds.
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
const restoreSidebarScroll = () => {
|
|
430
|
+
const sidebar = getVisibleSidebar();
|
|
431
|
+
if (!sidebar) return;
|
|
432
|
+
|
|
433
|
+
const savedScrollTop = getSavedScrollTop();
|
|
434
|
+
if (savedScrollTop <= 0) return;
|
|
435
|
+
|
|
436
|
+
sidebar.scrollTop = Math.min(
|
|
437
|
+
savedScrollTop,
|
|
438
|
+
Math.max(0, sidebar.scrollHeight - sidebar.clientHeight),
|
|
439
|
+
);
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
const scheduleSidebarScrollRestore = () => {
|
|
443
|
+
window.requestAnimationFrame(() => {
|
|
444
|
+
restoreSidebarScroll();
|
|
445
|
+
window.setTimeout(restoreSidebarScroll, 0);
|
|
446
|
+
});
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
if (window[initializedKey]) {
|
|
450
|
+
scheduleSidebarScrollRestore();
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
window[initializedKey] = true;
|
|
455
|
+
document.addEventListener(
|
|
456
|
+
"astro:before-preparation",
|
|
457
|
+
saveSidebarScroll,
|
|
458
|
+
);
|
|
459
|
+
document.addEventListener("astro:before-swap", saveSidebarScroll);
|
|
460
|
+
document.addEventListener(
|
|
461
|
+
"astro:after-swap",
|
|
462
|
+
scheduleSidebarScrollRestore,
|
|
463
|
+
);
|
|
464
|
+
document.addEventListener(
|
|
465
|
+
"astro:page-load",
|
|
466
|
+
scheduleSidebarScrollRestore,
|
|
467
|
+
);
|
|
468
|
+
window.addEventListener("pagehide", saveSidebarScroll);
|
|
469
|
+
|
|
470
|
+
if (document.readyState === "loading") {
|
|
471
|
+
document.addEventListener(
|
|
472
|
+
"DOMContentLoaded",
|
|
473
|
+
scheduleSidebarScrollRestore,
|
|
474
|
+
{ once: true },
|
|
475
|
+
);
|
|
476
|
+
} else {
|
|
477
|
+
scheduleSidebarScrollRestore();
|
|
478
|
+
}
|
|
479
|
+
})();
|
|
480
|
+
</script>
|
|
387
481
|
</body>
|
|
388
482
|
</html>
|