mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-17 08:05:19 +00:00
Restyle openapi blocks (#3169)
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
"@gitbook/react-openapi": minor
|
||||||
|
"gitbook": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Design tweaks to code blocks and OpenAPI pages
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.highlight-line-number {
|
.highlight-line-number {
|
||||||
@apply text-sm text-right pr-3.5 rounded-l pl-2 sticky left-[-3px] bg-gradient-to-r from-80% from-tint to-transparent;
|
@apply text-sm text-right pr-3.5 rounded-l pl-2 sticky left-[-3px] bg-gradient-to-r from-80% from-tint-subtle contrast-more:from-tint-base theme-muted:from-tint-base [html.theme-bold.sidebar-filled_&]:from-tint-base to-transparent;
|
||||||
@apply before:text-tint before:content-[counter(line)];
|
@apply before:text-tint before:content-[counter(line)];
|
||||||
|
|
||||||
.highlight-line.highlighted > & {
|
.highlight-line.highlighted > & {
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export const CodeBlockRenderer = forwardRef(function CodeBlockRenderer(
|
|||||||
>
|
>
|
||||||
<div className="flex items-center justify-start gap-2 text-sm [grid-area:1/1]">
|
<div className="flex items-center justify-start gap-2 text-sm [grid-area:1/1]">
|
||||||
{title ? (
|
{title ? (
|
||||||
<div className="inline-flex items-center justify-center rounded-t straight-corners:rounded-t-s bg-tint px-3 py-2 text-tint text-xs leading-none tracking-wide">
|
<div className="relative top-px z-20 inline-flex items-center justify-center rounded-t straight-corners:rounded-t-s border border-tint-subtle border-b-0 bg-tint-subtle theme-muted:bg-tint-base px-3 py-2 text-tint text-xs leading-none tracking-wide contrast-more:border-tint contrast-more:bg-tint-base [html.theme-bold.sidebar-filled_&]:bg-tint-base">
|
||||||
{title}
|
{title}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
@@ -50,8 +50,8 @@ export const CodeBlockRenderer = forwardRef(function CodeBlockRenderer(
|
|||||||
/>
|
/>
|
||||||
<pre
|
<pre
|
||||||
className={tcls(
|
className={tcls(
|
||||||
'hide-scroll relative overflow-auto bg-tint theme-gradient:bg-tint-12/1 ring-tint-subtle [grid-area:2/1]',
|
'hide-scroll relative overflow-auto border border-tint-subtle bg-tint-subtle theme-muted:bg-tint-base [grid-area:2/1] contrast-more:border-tint contrast-more:bg-tint-base [html.theme-bold.sidebar-filled_&]:bg-tint-base',
|
||||||
'rounded-md straight-corners:rounded-sm',
|
'rounded-md straight-corners:rounded-sm shadow-sm',
|
||||||
title && 'rounded-ss-none'
|
title && 'rounded-ss-none'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,31 +1,67 @@
|
|||||||
:root {
|
:root {
|
||||||
--shiki-color-text: theme("colors.tint.11");
|
--shiki-color-text: theme("colors.tint.11");
|
||||||
--shiki-token-constant: #0a6355;
|
--shiki-token-punctuation: theme("colors.tint.11");
|
||||||
--shiki-token-string: #8b6d32;
|
--shiki-token-comment: theme("colors.neutral.9/.7");
|
||||||
--shiki-token-comment: theme("colors.teal.700/.64");
|
--shiki-token-link: theme("colors.primary.10");
|
||||||
--shiki-token-keyword: theme("colors.pomegranate.600");
|
|
||||||
--shiki-token-parameter: #0a3069;
|
--shiki-token-constant: theme("colors.warning.10");
|
||||||
--shiki-token-function: #8250df;
|
--shiki-token-string: theme("colors.success.10");
|
||||||
--shiki-token-string-expression: #6a4906;
|
--shiki-token-string-expression: theme("colors.success.10");
|
||||||
--shiki-token-punctuation: theme("colors.pomegranate.700/.92");
|
--shiki-token-keyword: theme("colors.danger.10");
|
||||||
--shiki-token-link: theme("colors.tint.12");
|
--shiki-token-parameter: theme("colors.warning.10");
|
||||||
--shiki-token-inserted: #22863a;
|
--shiki-token-function: theme("colors.primary.10");
|
||||||
--shiki-token-deleted: #b31d28;
|
|
||||||
--shiki-token-changed: #8250df;
|
--shiki-token-inserted: theme("colors.success.10");
|
||||||
|
--shiki-token-deleted: theme("colors.danger.10");
|
||||||
|
--shiki-token-changed: theme("colors.tint.12");
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-contrast: more) {
|
||||||
|
:root {
|
||||||
|
--shiki-color-text: theme("colors.tint.12");
|
||||||
|
--shiki-token-punctuation: theme("colors.tint.12");
|
||||||
|
--shiki-token-comment: theme("colors.neutral.11");
|
||||||
|
--shiki-token-link: theme("colors.primary.11");
|
||||||
|
|
||||||
|
--shiki-token-constant: theme("colors.warning.11");
|
||||||
|
--shiki-token-string: theme("colors.success.11");
|
||||||
|
--shiki-token-string-expression: theme("colors.success.11");
|
||||||
|
--shiki-token-keyword: theme("colors.danger.11");
|
||||||
|
--shiki-token-parameter: theme("colors.warning.11");
|
||||||
|
--shiki-token-function: theme("colors.primary.11");
|
||||||
|
|
||||||
|
--shiki-token-inserted: theme("colors.success.11");
|
||||||
|
--shiki-token-deleted: theme("colors.danger.11");
|
||||||
|
--shiki-token-changed: theme("colors.tint.12");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
html.dark {
|
html.dark {
|
||||||
--shiki-color-text: theme("colors.tint.11");
|
/* Override select colors to have more contrast */
|
||||||
--shiki-token-constant: #d19a66;
|
--shiki-token-comment: theme("colors.neutral.9");
|
||||||
--shiki-token-string: theme("colors.pomegranate.300");
|
|
||||||
--shiki-token-comment: theme("colors.teal.300/.64");
|
--shiki-token-constant: theme("colors.warning.11");
|
||||||
--shiki-token-keyword: theme("colors.pomegranate.400");
|
--shiki-token-string: theme("colors.success.11");
|
||||||
--shiki-token-parameter: theme("colors.yellow.500");
|
--shiki-token-string-expression: theme("colors.success.11");
|
||||||
--shiki-token-function: #56b6c2;
|
--shiki-token-keyword: theme("colors.danger.11");
|
||||||
--shiki-token-string-expression: theme("colors.tint.11");
|
--shiki-token-parameter: theme("colors.warning.11");
|
||||||
--shiki-token-punctuation: #acc6ee;
|
--shiki-token-function: theme("colors.primary.11");
|
||||||
--shiki-token-link: theme("colors.pomegranate.400");
|
}
|
||||||
--shiki-token-inserted: #85e89d;
|
|
||||||
--shiki-token-deleted: #fdaeb7;
|
.code-monochrome {
|
||||||
--shiki-token-changed: #56b6c2;
|
--shiki-token-constant: theme("colors.tint.11");
|
||||||
|
--shiki-token-string: theme("colors.tint.12");
|
||||||
|
--shiki-token-string-expression: theme("colors.tint.12");
|
||||||
|
--shiki-token-keyword: theme("colors.primary.10");
|
||||||
|
--shiki-token-parameter: theme("colors.tint.9");
|
||||||
|
--shiki-token-function: theme("colors.primary.9");
|
||||||
|
}
|
||||||
|
|
||||||
|
html.dark.code-monochrome {
|
||||||
|
--shiki-token-constant: theme("colors.tint.11");
|
||||||
|
--shiki-token-string: theme("colors.tint.12");
|
||||||
|
--shiki-token-string-expression: theme("colors.tint.12");
|
||||||
|
--shiki-token-keyword: theme("colors.primary.11");
|
||||||
|
--shiki-token-parameter: theme("colors.tint.10");
|
||||||
|
--shiki-token-function: theme("colors.primary.10");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,41 +169,18 @@
|
|||||||
@apply flex flex-col;
|
@apply flex flex-col;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-schema {
|
.openapi-schema,
|
||||||
|
.openapi-disclosure {
|
||||||
@apply py-2.5 flex flex-col gap-2;
|
@apply py-2.5 flex flex-col gap-2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-section-body .openapi-schema-properties {
|
|
||||||
@apply divide-y divide-tint-subtle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openapi-disclosure-group-panel > .openapi-schema-properties > *:first-child > .openapi-schema {
|
|
||||||
@apply pt-0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openapi-responsebody > .openapi-schema-properties > .openapi-schema:last-child {
|
|
||||||
@apply pb-0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openapi-responsebody > .openapi-schema-properties > .openapi-schema:only-child {
|
|
||||||
@apply py-0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openapi-schema-properties .openapi-schema:last-child {
|
.openapi-schema-properties .openapi-schema:last-child {
|
||||||
@apply border-b-0;
|
@apply border-b-0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-schema-properties .openapi-schema-opened {
|
|
||||||
@apply pb-3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openapi-schema > .openapi-schema-properties {
|
|
||||||
@apply mt-3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Schema Presentation */
|
/* Schema Presentation */
|
||||||
.openapi-schema-presentation {
|
.openapi-schema-presentation {
|
||||||
@apply flex flex-col gap-1.5 font-normal;
|
@apply flex flex-col gap-1 font-normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-schema-properties:last-child {
|
.openapi-schema-properties:last-child {
|
||||||
@@ -221,7 +198,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-schema-propertyname {
|
.openapi-schema-propertyname {
|
||||||
@apply select-all font-mono font-normal text-tint-strong;
|
@apply select-all font-mono font-semibold text-tint-strong;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-schema-propertyname[data-deprecated="true"] {
|
.openapi-schema-propertyname[data-deprecated="true"] {
|
||||||
@@ -244,6 +221,10 @@
|
|||||||
@apply text-success dark:text-success-subtle/9 text-[0.813rem] lowercase;
|
@apply text-success dark:text-success-subtle/9 text-[0.813rem] lowercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.openapi-schema-types {
|
||||||
|
@apply flex items-baseline flex-wrap gap-1;
|
||||||
|
}
|
||||||
|
|
||||||
.openapi-schema-type {
|
.openapi-schema-type {
|
||||||
@apply text-tint select-text text-[0.813rem] font-mono [word-spacing:-0.25rem];
|
@apply text-tint select-text text-[0.813rem] font-mono [word-spacing:-0.25rem];
|
||||||
}
|
}
|
||||||
@@ -321,7 +302,7 @@
|
|||||||
.openapi-schema-pattern code,
|
.openapi-schema-pattern code,
|
||||||
.openapi-schema-enum-value code,
|
.openapi-schema-enum-value code,
|
||||||
.openapi-schema-default code {
|
.openapi-schema-default code {
|
||||||
@apply py-px px-1 min-w-[1.625rem] text-tint-strong font-normal w-fit justify-center items-center ring-1 ring-inset ring-tint bg-tint rounded text-xs leading-[calc(max(1.20em,1.25rem))] before:!content-none after:!content-none;
|
@apply py-px px-1 min-w-[1.625rem] text-tint-strong font-normal w-fit justify-center items-center ring-1 ring-inset ring-tint-subtle bg-tint rounded text-xs leading-[calc(max(1.20em,1.25rem))] before:!content-none after:!content-none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Authentication */
|
/* Authentication */
|
||||||
@@ -373,28 +354,25 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-response-tab-content {
|
.openapi-response-tab-content {
|
||||||
@apply overflow-hidden max-w-full flex items-baseline;
|
@apply flex items-baseline truncate grow shrink max-w-max basis-[60%] mr-auto;
|
||||||
@apply text-left text-pretty relative leading-[1.125rem] text-tint !font-normal truncate select-text;
|
@apply text-left text-pretty relative leading-tight text-tint select-text;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-response-description.openapi-markdown {
|
.openapi-response-description.openapi-markdown {
|
||||||
@apply text-left prose-sm text-[0.813rem] text-pretty h-auto relative leading-[1.125rem] text-tint !font-normal truncate select-text prose-strong:font-semibold prose-strong:text-inherit;
|
@apply text-left truncate prose-sm text-sm leading-tight text-tint select-text prose-strong:font-semibold prose-strong:text-inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-response-description.openapi-markdown::-webkit-scrollbar {
|
.openapi-disclosure-group-trigger[aria-expanded="true"] .openapi-response-tab-content {
|
||||||
display: none;
|
@apply basis-full;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-response-description p {
|
.openapi-disclosure-group-trigger[aria-expanded="true"]
|
||||||
@apply truncate max-w-full inline pr-1;
|
.openapi-response-description.openapi-markdown {
|
||||||
}
|
@apply whitespace-normal;
|
||||||
|
|
||||||
.openapi-response-content-type {
|
|
||||||
@apply text-xs text-tint-8 ml-auto shrink-0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-response-body {
|
.openapi-response-body {
|
||||||
@apply flex flex-col gap-3;
|
@apply flex flex-col;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Response Body and Headers */
|
/* Response Body and Headers */
|
||||||
@@ -411,16 +389,7 @@
|
|||||||
@apply px-3 py-1;
|
@apply px-3 py-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-responsebody-header-content,
|
|
||||||
.openapi-responseheaders-header-content {
|
|
||||||
/* unstyled */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Code Sample */
|
/* Code Sample */
|
||||||
.openapi-codesample {
|
|
||||||
@apply border rounded-md straight-corners:rounded-none bg-tint border-tint-subtle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openapi-codesample-header {
|
.openapi-codesample-header {
|
||||||
@apply flex flex-row items-center;
|
@apply flex flex-row items-center;
|
||||||
}
|
}
|
||||||
@@ -429,6 +398,12 @@
|
|||||||
@apply flex flex-row items-center gap-2.5;
|
@apply flex flex-row items-center gap-2.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.openapi-panel-heading,
|
||||||
|
.openapi-codesample-header,
|
||||||
|
.openapi-response-examples-header {
|
||||||
|
@apply border-b border-tint-subtle;
|
||||||
|
}
|
||||||
|
|
||||||
.openapi-response-examples-header .openapi-select > button {
|
.openapi-response-examples-header .openapi-select > button {
|
||||||
@apply max-w-full overflow-hidden shrink pl-0.5 py-0.5;
|
@apply max-w-full overflow-hidden shrink pl-0.5 py-0.5;
|
||||||
}
|
}
|
||||||
@@ -503,8 +478,16 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Panel */
|
/* Panel */
|
||||||
.openapi-panel {
|
.openapi-panel,
|
||||||
@apply border rounded-md straight-corners:rounded-none bg-tint border-tint-subtle;
|
.openapi-codesample,
|
||||||
|
.openapi-response-examples {
|
||||||
|
@apply border rounded-md straight-corners:rounded-none bg-tint-subtle border-tint-subtle shadow-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-panel pre,
|
||||||
|
.openapi-codesample pre,
|
||||||
|
.openapi-response-examples pre {
|
||||||
|
@apply bg-transparent border-none rounded-none shadow-none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-panel-heading {
|
.openapi-panel-heading {
|
||||||
@@ -513,12 +496,11 @@
|
|||||||
|
|
||||||
.openapi-panel-body {
|
.openapi-panel-body {
|
||||||
@apply relative;
|
@apply relative;
|
||||||
@apply before:w-full before:h-px before:absolute before:bg-tint-6 before:-top-px before:z-10;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-panel-footer,
|
.openapi-panel-footer,
|
||||||
.openapi-codesample-footer {
|
.openapi-codesample-footer {
|
||||||
@apply px-3 py-2 pt-2.5 border-t border-tint-subtle text-[0.813rem] text-tint;
|
@apply px-3 py-2 pt-2.5 border-t border-tint-subtle text-[0.813rem] text-tint empty:hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-panel-footer .openapi-markdown {
|
.openapi-panel-footer .openapi-markdown {
|
||||||
@@ -526,10 +508,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Example */
|
/* Example */
|
||||||
.openapi-response-examples {
|
|
||||||
@apply border rounded-md straight-corners:rounded-none bg-tint border-tint-subtle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openapi-response-examples-header {
|
.openapi-response-examples-header {
|
||||||
@apply flex flex-row items-center p-2.5;
|
@apply flex flex-row items-center p-2.5;
|
||||||
}
|
}
|
||||||
@@ -551,7 +529,6 @@
|
|||||||
.openapi-response-examples-panel,
|
.openapi-response-examples-panel,
|
||||||
.openapi-codesample-panel {
|
.openapi-codesample-panel {
|
||||||
@apply flex-1 text-sm relative focus-visible:outline-none;
|
@apply flex-1 text-sm relative focus-visible:outline-none;
|
||||||
@apply before:w-full before:h-px before:absolute before:bg-tint-6 before:-top-px before:z-10;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-example-empty {
|
.openapi-example-empty {
|
||||||
@@ -703,15 +680,19 @@ body:has(.openapi-select-popover) {
|
|||||||
|
|
||||||
/* Disclosure group */
|
/* Disclosure group */
|
||||||
.openapi-disclosure-group {
|
.openapi-disclosure-group {
|
||||||
@apply border-tint-subtle border-b border-x overflow-auto last:rounded-b-md straight-corners:last:rounded-none first:rounded-t-md straight-corners:first:rounded-none first:border-t relative;
|
@apply border-tint-subtle transition-all border-b border-x overflow-auto last:rounded-b-md straight-corners:last:rounded-none first:rounded-t-md straight-corners:first:rounded-none first:border-t relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-group-header {
|
.openapi-disclosure-group:has(.openapi-disclosure-group-trigger:hover) {
|
||||||
@apply flex flex-row items-baseline justify-between gap-3 relative;
|
@apply bg-tint-subtle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-group-trigger {
|
.openapi-disclosure-group-trigger {
|
||||||
@apply flex items-baseline transition-all hover:bg-tint-subtle relative flex-1 gap-2.5 p-3 truncate -outline-offset-1;
|
@apply flex w-full items-baseline gap-3 transition-all relative flex-1 p-3 -outline-offset-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-disclosure-group-label {
|
||||||
|
@apply flex flex-wrap items-baseline gap-x-3 gap-y-1 flex-1 truncate;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-group-trigger:disabled {
|
.openapi-disclosure-group-trigger:disabled {
|
||||||
@@ -722,10 +703,6 @@ body:has(.openapi-select-popover) {
|
|||||||
@apply invisible;
|
@apply invisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-group-trigger[aria-expanded="true"] .openapi-response-description {
|
|
||||||
@apply whitespace-normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openapi-disclosure-group-icon > svg {
|
.openapi-disclosure-group-icon > svg {
|
||||||
@apply size-3 text-tint-subtle transition-all duration-300;
|
@apply size-3 text-tint-subtle transition-all duration-300;
|
||||||
}
|
}
|
||||||
@@ -735,29 +712,20 @@ body:has(.openapi-select-popover) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-group-panel {
|
.openapi-disclosure-group-panel {
|
||||||
@apply p-3 pt-1 transition-all;
|
@apply px-3 transition-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-group-trigger[aria-expanded="true"] > .openapi-disclosure-group-icon > svg {
|
.openapi-disclosure-group-trigger[aria-expanded="true"] > .openapi-disclosure-group-icon > svg {
|
||||||
@apply rotate-90;
|
@apply rotate-90;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-group:hover .openapi-disclosure-group-mediatype,
|
|
||||||
.openapi-disclosure-group-mediatype:has(> .openapi-select[data-open="true"]) {
|
|
||||||
@apply opacity-11 visible flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openapi-disclosure-group-mediatype {
|
.openapi-disclosure-group-mediatype {
|
||||||
@apply opacity-0 invisible text-xs transition-opacity duration-300 shrink-0 absolute right-2.5 top-2.5;
|
@apply text-[0.625rem] font-mono shrink-0 grow-0 text-tint-subtle contrast-more:text-tint;
|
||||||
}
|
|
||||||
|
|
||||||
.openapi-disclosure-group-mediatype > span {
|
|
||||||
@apply px-1 bg-tint-6 text-tint-12 rounded-full straight-corners:rounded-md;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disclosure */
|
/* Disclosure */
|
||||||
.openapi-schemas-disclosure > .openapi-disclosure-trigger {
|
.openapi-schemas-disclosure > .openapi-disclosure-trigger {
|
||||||
@apply flex items-center font-mono !w-full transition-all text-tint-strong !text-sm hover:bg-tint-subtle relative flex-1 gap-2.5 p-3 truncate -outline-offset-1;
|
@apply flex items-center font-mono transition-all text-tint-strong !text-sm hover:bg-tint-subtle relative flex-1 gap-2.5 p-3 truncate -outline-offset-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-schemas-disclosure > .openapi-disclosure-trigger,
|
.openapi-schemas-disclosure > .openapi-disclosure-trigger,
|
||||||
@@ -765,51 +733,92 @@ body:has(.openapi-select-popover) {
|
|||||||
@apply straight-corners:!rounded-none;
|
@apply straight-corners:!rounded-none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.openapi-disclosure-panel {
|
||||||
|
@apply ml-1.5 pl-3 border-l border-tint-subtle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-schema .openapi-schema-properties .openapi-schema {
|
||||||
|
@apply animate-fadeIn [animation-fill-mode:both];
|
||||||
|
}
|
||||||
|
|
||||||
.openapi-schemas-disclosure > .openapi-disclosure-trigger[aria-expanded="true"] > svg {
|
.openapi-schemas-disclosure > .openapi-disclosure-trigger[aria-expanded="true"] > svg {
|
||||||
@apply rotate-90;
|
@apply rotate-90;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-trigger {
|
.openapi-disclosure-trigger {
|
||||||
@apply transition-all truncate duration-300 max-w-full hover:text-tint-strong rounded-2xl straight-corners:rounded border border-tint-subtle px-2.5 py-1 text-[0.813rem] text-tint flex flex-row items-center gap-1.5 -outline-offset-1;
|
@apply flex flex-row justify-between flex-wrap relative items-start gap-2 text-left -mx-3 px-3 -my-2.5 py-2.5 pr-10;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-trigger span {
|
.openapi-disclosure {
|
||||||
@apply truncate;
|
@apply -mx-3 px-3 py-2.5 transition-all flex flex-col ring-tint-subtle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure svg {
|
.openapi-disclosure:not(
|
||||||
@apply size-3 shrink-0 transition-transform duration-300;
|
.openapi-disclosure-group .openapi-disclosure,
|
||||||
|
.openapi-schema-alternatives .openapi-disclosure
|
||||||
|
) {
|
||||||
|
@apply rounded-xl;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-disclosure:has(> .openapi-disclosure-trigger:hover) {
|
||||||
|
@apply bg-tint-subtle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-disclosure:has(> .openapi-disclosure-trigger:hover),
|
||||||
|
.openapi-disclosure[data-expanded="true"] {
|
||||||
|
@apply ring-1 shadow-sm;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-disclosure[data-expanded="true"]:not(:first-child) {
|
||||||
|
@apply mt-2;
|
||||||
|
}
|
||||||
|
.openapi-disclosure[data-expanded="true"]:not(:last-child) {
|
||||||
|
@apply mb-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-disclosure-trigger-label {
|
||||||
|
@apply absolute right-3 px-2 h-5 justify-end shrink-0 ring-tint-subtle truncate text-tint duration-300 transition-all rounded straight-corners:rounded-none flex flex-row gap-1 items-center text-xs;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-disclosure-trigger-label span {
|
||||||
|
@apply hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-disclosure-trigger-label svg {
|
||||||
|
@apply size-3 shrink-0 transition-transform duration-300 text-tint-subtle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-disclosure-trigger:hover > .openapi-disclosure-trigger-label,
|
||||||
|
.openapi-disclosure-trigger[aria-expanded="true"] > .openapi-disclosure-trigger-label {
|
||||||
|
@apply shadow ring-1 bg-tint-base;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openapi-disclosure-trigger:hover > .openapi-disclosure-trigger-label span,
|
||||||
|
.openapi-disclosure-trigger[aria-expanded="true"] > .openapi-disclosure-trigger-label span {
|
||||||
|
@apply block animate-fadeIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (hover: none) {
|
||||||
|
/* Make button label always visible on non-hover devices like phones */
|
||||||
|
.openapi-disclosure-trigger-label {
|
||||||
|
@apply relative ring-1 bg-tint-base;
|
||||||
|
}
|
||||||
|
.openapi-disclosure-trigger-label span {
|
||||||
|
@apply block;
|
||||||
|
}
|
||||||
|
.openapi-disclosure-trigger {
|
||||||
|
@apply pr-3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-trigger[aria-expanded="true"] svg {
|
.openapi-disclosure-trigger[aria-expanded="true"] svg {
|
||||||
@apply rotate-45;
|
@apply rotate-45;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-trigger[aria-expanded="true"] {
|
|
||||||
@apply w-full rounded-lg border-b rounded-b-none straight-corners:rounded-b-none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openapi-disclosure-trigger[aria-expanded="false"] {
|
.openapi-disclosure-trigger[aria-expanded="false"] {
|
||||||
@apply w-auto;
|
@apply w-auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.openapi-disclosure-panel[aria-hidden="false"] {
|
|
||||||
@apply border-b border-x border-tint-subtle rounded-b-lg straight-corners:rounded-b;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openapi-disclosure-panel .openapi-schema {
|
|
||||||
@apply p-2.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openapi-disclosure .openapi-schema-properties .openapi-schema:only-child,
|
|
||||||
.openapi-disclosure .openapi-schema-properties .openapi-schema:only-child .openapi-schema-name {
|
|
||||||
@apply !m-0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openapi-disclosure .openapi-schema-properties .openapi-schema-enum {
|
|
||||||
@apply pt-0 mt-0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.openapi-section-body.openapi-schema.openapi-schema-root {
|
.openapi-section-body.openapi-schema.openapi-schema-root {
|
||||||
@apply space-y-2.5;
|
@apply space-y-2.5;
|
||||||
}
|
}
|
||||||
@@ -819,6 +828,16 @@ body:has(.openapi-select-popover) {
|
|||||||
@apply p-2.5;
|
@apply p-2.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.openapi-schema-alternatives {
|
||||||
|
@apply ml-1.5 pl-3 border-l border-tint-subtle;
|
||||||
|
}
|
||||||
|
.openapi-schema-alternative {
|
||||||
|
@apply relative;
|
||||||
|
}
|
||||||
|
.openapi-schema-alternative-separator {
|
||||||
|
@apply p-0.5 tracking-wide leading-none uppercase text-[0.625rem] text-tint-subtle whitespace-nowrap absolute -left-3 -bottom-2.5 -translate-x-1/2 z-10 bg-tint-base border-y border-tint-subtle -rotate-6;
|
||||||
|
}
|
||||||
|
|
||||||
.openapi-tooltip {
|
.openapi-tooltip {
|
||||||
@apply flex items-center gap-1 bg-tint-base border border-tint-subtle text-tint-strong rounded-md straight-corners:rounded-none font-medium px-1.5 py-0.5 shadow-sm text-[13px];
|
@apply flex items-center gap-1 bg-tint-base border border-tint-subtle text-tint-strong rounded-md straight-corners:rounded-none font-medium px-1.5 py-0.5 shadow-sm text-[13px];
|
||||||
}
|
}
|
||||||
@@ -865,11 +884,11 @@ body:has(.openapi-select-popover) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@keyframes popover-leave {
|
@keyframes popover-leave {
|
||||||
0% {
|
from {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translateY(0) scale(1);
|
transform: translateY(0) scale(1);
|
||||||
}
|
}
|
||||||
100% {
|
to {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateY(4px) scale(0.95);
|
transform: translateY(4px) scale(0.95);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,11 +9,12 @@ import { Button, Disclosure, DisclosurePanel } from 'react-aria-components';
|
|||||||
*/
|
*/
|
||||||
export function OpenAPIDisclosure(props: {
|
export function OpenAPIDisclosure(props: {
|
||||||
icon: React.ReactNode;
|
icon: React.ReactNode;
|
||||||
|
header: React.ReactNode;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
label: string | ((isExpanded: boolean) => string);
|
label: string | ((isExpanded: boolean) => string);
|
||||||
className?: string;
|
className?: string;
|
||||||
}): React.JSX.Element {
|
}): React.JSX.Element {
|
||||||
const { icon, children, label, className } = props;
|
const { icon, header, label, children, className } = props;
|
||||||
const [isExpanded, setIsExpanded] = useState(false);
|
const [isExpanded, setIsExpanded] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -31,8 +32,11 @@ export function OpenAPIDisclosure(props: {
|
|||||||
: 'none',
|
: 'none',
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{icon}
|
{header}
|
||||||
<span>{typeof label === 'function' ? label(isExpanded) : label}</span>
|
<div className="openapi-disclosure-trigger-label">
|
||||||
|
<span>{typeof label === 'function' ? label(isExpanded) : label}</span>
|
||||||
|
{icon}
|
||||||
|
</div>
|
||||||
</Button>
|
</Button>
|
||||||
<DisclosurePanel className="openapi-disclosure-panel">
|
<DisclosurePanel className="openapi-disclosure-panel">
|
||||||
{isExpanded ? children : null}
|
{isExpanded ? children : null}
|
||||||
|
|||||||
@@ -96,56 +96,57 @@ function DisclosureItem(props: {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="openapi-disclosure-group" aria-expanded={state.isExpanded}>
|
<div className="openapi-disclosure-group" aria-expanded={state.isExpanded}>
|
||||||
<div className="openapi-disclosure-group-header">
|
<button
|
||||||
<button
|
slot="trigger"
|
||||||
slot="trigger"
|
ref={triggerRef}
|
||||||
ref={triggerRef}
|
{...mergeProps(buttonProps, focusProps)}
|
||||||
{...mergeProps(buttonProps, focusProps)}
|
disabled={isDisabled}
|
||||||
disabled={isDisabled}
|
style={{
|
||||||
style={{
|
outline: isFocusVisible
|
||||||
outline: isFocusVisible
|
? '2px solid rgb(var(--primary-color-500)/0.4)'
|
||||||
? '2px solid rgb(var(--primary-color-500)/0.4)'
|
: 'none',
|
||||||
: 'none',
|
}}
|
||||||
}}
|
className="openapi-disclosure-group-trigger"
|
||||||
className="openapi-disclosure-group-trigger"
|
>
|
||||||
>
|
<div className="openapi-disclosure-group-icon">
|
||||||
<div className="openapi-disclosure-group-icon">
|
{icon || (
|
||||||
{icon || (
|
<svg viewBox="0 0 24 24" className="openapi-disclosure-group-icon">
|
||||||
<svg viewBox="0 0 24 24" className="openapi-disclosure-group-icon">
|
<path d="m8.25 4.5 7.5 7.5-7.5 7.5" />
|
||||||
<path d="m8.25 4.5 7.5 7.5-7.5 7.5" />
|
</svg>
|
||||||
</svg>
|
)}
|
||||||
)}
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<div className="openapi-disclosure-group-label">
|
||||||
{group.label}
|
{group.label}
|
||||||
</button>
|
|
||||||
{group.tabs ? (
|
{group.tabs ? (
|
||||||
<div
|
<div
|
||||||
className="openapi-disclosure-group-mediatype"
|
className="openapi-disclosure-group-mediatype"
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
>
|
>
|
||||||
{group.tabs?.length > 1 ? (
|
{group.tabs?.length > 1 ? (
|
||||||
<OpenAPISelect
|
<OpenAPISelect
|
||||||
icon={selectIcon}
|
icon={selectIcon}
|
||||||
stateKey={selectStateKey}
|
stateKey={selectStateKey}
|
||||||
onSelectionChange={() => {
|
onSelectionChange={() => {
|
||||||
state.expand();
|
state.expand();
|
||||||
}}
|
}}
|
||||||
items={group.tabs}
|
items={group.tabs}
|
||||||
placement="bottom end"
|
placement="bottom end"
|
||||||
>
|
>
|
||||||
{group.tabs.map((tab) => (
|
{group.tabs.map((tab) => (
|
||||||
<OpenAPISelectItem key={tab.key} id={tab.key} value={tab}>
|
<OpenAPISelectItem key={tab.key} id={tab.key} value={tab}>
|
||||||
{tab.label}
|
{tab.label}
|
||||||
</OpenAPISelectItem>
|
</OpenAPISelectItem>
|
||||||
))}
|
))}
|
||||||
</OpenAPISelect>
|
</OpenAPISelect>
|
||||||
) : group.tabs[0]?.label ? (
|
) : group.tabs[0]?.label ? (
|
||||||
<span>{group.tabs[0].label}</span>
|
<span>{group.tabs[0].label}</span>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
</button>
|
||||||
|
|
||||||
{state.isExpanded && selectedTab && (
|
{state.isExpanded && selectedTab && (
|
||||||
<div className="openapi-disclosure-group-panel" ref={panelRef} {...panelProps}>
|
<div className="openapi-disclosure-group-panel" ref={panelRef} {...panelProps}>
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
import type { OpenAPIV3 } from '@gitbook/openapi-parser';
|
||||||
import { OpenAPIDisclosure } from './OpenAPIDisclosure';
|
import { OpenAPIDisclosure } from './OpenAPIDisclosure';
|
||||||
|
import { OpenAPISchemaPresentation } from './OpenAPISchema';
|
||||||
import { OpenAPISchemaProperties } from './OpenAPISchemaServer';
|
import { OpenAPISchemaProperties } from './OpenAPISchemaServer';
|
||||||
import type { OpenAPIClientContext } from './context';
|
import type { OpenAPIClientContext } from './context';
|
||||||
|
import { tString } from './translate';
|
||||||
import { parameterToProperty, resolveDescription } from './utils';
|
import { parameterToProperty, resolveDescription } from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -27,7 +29,31 @@ export function OpenAPIResponse(props: {
|
|||||||
return (
|
return (
|
||||||
<div className="openapi-response-body">
|
<div className="openapi-response-body">
|
||||||
{headers.length > 0 ? (
|
{headers.length > 0 ? (
|
||||||
<OpenAPIDisclosure icon={context.icons.plus} label="Headers">
|
<OpenAPIDisclosure
|
||||||
|
header={
|
||||||
|
<OpenAPISchemaPresentation
|
||||||
|
context={context}
|
||||||
|
property={{
|
||||||
|
propertyName: tString(context.translation, 'headers'),
|
||||||
|
schema: {
|
||||||
|
type: 'object',
|
||||||
|
},
|
||||||
|
required: null,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
icon={context.icons.plus}
|
||||||
|
label={(isExpanded) =>
|
||||||
|
tString(
|
||||||
|
context.translation,
|
||||||
|
isExpanded ? 'hide' : 'show',
|
||||||
|
tString(
|
||||||
|
context.translation,
|
||||||
|
headers.length === 1 ? 'header' : 'headers'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
>
|
||||||
<OpenAPISchemaProperties
|
<OpenAPISchemaProperties
|
||||||
properties={headers.map(([name, header]) =>
|
properties={headers.map(([name, header]) =>
|
||||||
parameterToProperty({ name, ...header })
|
parameterToProperty({ name, ...header })
|
||||||
@@ -40,7 +66,13 @@ export function OpenAPIResponse(props: {
|
|||||||
<div className="openapi-responsebody">
|
<div className="openapi-responsebody">
|
||||||
<OpenAPISchemaProperties
|
<OpenAPISchemaProperties
|
||||||
id={`response-${context.blockKey}`}
|
id={`response-${context.blockKey}`}
|
||||||
properties={[{ schema: mediaType.schema }]}
|
properties={[
|
||||||
|
{
|
||||||
|
schema: mediaType.schema,
|
||||||
|
propertyName: tString(context.translation, 'response'),
|
||||||
|
required: null,
|
||||||
|
},
|
||||||
|
]}
|
||||||
context={context}
|
context={context}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
import type { OpenAPICustomOperationProperties, OpenAPIV3 } from '@gitbook/openapi-parser';
|
import type { OpenAPICustomOperationProperties, OpenAPIV3 } from '@gitbook/openapi-parser';
|
||||||
import { useId } from 'react';
|
import { useId } from 'react';
|
||||||
|
import type { ComponentPropsWithoutRef } from 'react';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { Markdown } from './Markdown';
|
import { Markdown } from './Markdown';
|
||||||
@@ -19,73 +20,98 @@ import { checkIsReference, resolveDescription, resolveFirstExample } from './uti
|
|||||||
type CircularRefsIds = Map<OpenAPIV3.SchemaObject, string>;
|
type CircularRefsIds = Map<OpenAPIV3.SchemaObject, string>;
|
||||||
|
|
||||||
export interface OpenAPISchemaPropertyEntry {
|
export interface OpenAPISchemaPropertyEntry {
|
||||||
propertyName?: string | undefined;
|
propertyName?: string;
|
||||||
required?: boolean | undefined;
|
required?: boolean | null;
|
||||||
schema: OpenAPIV3.SchemaObject;
|
schema: OpenAPIV3.SchemaObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render a property of an OpenAPI schema.
|
* Render a property of an OpenAPI schema.
|
||||||
*/
|
*/
|
||||||
function OpenAPISchemaProperty(props: {
|
function OpenAPISchemaProperty(
|
||||||
property: OpenAPISchemaPropertyEntry;
|
props: {
|
||||||
context: OpenAPIClientContext;
|
property: OpenAPISchemaPropertyEntry;
|
||||||
circularRefs: CircularRefsIds;
|
context: OpenAPIClientContext;
|
||||||
className?: string;
|
circularRefs: CircularRefsIds;
|
||||||
}) {
|
className?: string;
|
||||||
const { circularRefs: parentCircularRefs, context, className, property } = props;
|
} & Omit<ComponentPropsWithoutRef<'div'>, 'property' | 'context' | 'circularRefs' | 'className'>
|
||||||
|
) {
|
||||||
|
const { circularRefs: parentCircularRefs, context, className, property, ...rest } = props;
|
||||||
|
|
||||||
const { schema } = property;
|
const { schema } = property;
|
||||||
|
|
||||||
const id = useId();
|
const id = useId();
|
||||||
|
|
||||||
return (
|
const circularRefId = parentCircularRefs.get(schema);
|
||||||
<div id={id} className={clsx('openapi-schema', className)}>
|
// Avoid recursing infinitely, and instead render a link to the parent schema
|
||||||
<OpenAPISchemaPresentation context={context} property={property} />
|
if (circularRefId) {
|
||||||
{(() => {
|
return <OpenAPISchemaCircularRef id={circularRefId} schema={schema} />;
|
||||||
const circularRefId = parentCircularRefs.get(schema);
|
}
|
||||||
// Avoid recursing infinitely, and instead render a link to the parent schema
|
|
||||||
if (circularRefId) {
|
|
||||||
return <OpenAPISchemaCircularRef id={circularRefId} schema={schema} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
const circularRefs = new Map(parentCircularRefs);
|
const circularRefs = new Map(parentCircularRefs);
|
||||||
circularRefs.set(schema, id);
|
circularRefs.set(schema, id);
|
||||||
|
|
||||||
const properties = getSchemaProperties(schema);
|
const properties = getSchemaProperties(schema);
|
||||||
if (properties?.length) {
|
|
||||||
return (
|
const ancestors = new Set(circularRefs.keys());
|
||||||
<OpenAPIDisclosure
|
const alternatives = getSchemaAlternatives(schema, ancestors);
|
||||||
icon={context.icons.plus}
|
|
||||||
label={(isExpanded) =>
|
const header = <OpenAPISchemaPresentation context={context} property={property} />;
|
||||||
getDisclosureLabel({ schema, isExpanded, context })
|
const content = (() => {
|
||||||
}
|
if (properties?.length) {
|
||||||
>
|
return (
|
||||||
<OpenAPISchemaProperties
|
<OpenAPISchemaProperties
|
||||||
properties={properties}
|
properties={properties}
|
||||||
|
circularRefs={circularRefs}
|
||||||
|
context={context}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alternatives) {
|
||||||
|
return (
|
||||||
|
<div className="openapi-schema-alternatives">
|
||||||
|
{alternatives.map((alternativeSchema, index) => (
|
||||||
|
<div key={index} className="openapi-schema-alternative">
|
||||||
|
<OpenAPISchemaAlternative
|
||||||
|
schema={alternativeSchema}
|
||||||
circularRefs={circularRefs}
|
circularRefs={circularRefs}
|
||||||
context={context}
|
context={context}
|
||||||
/>
|
/>
|
||||||
</OpenAPIDisclosure>
|
{index < alternatives.length - 1 ? (
|
||||||
);
|
<span className="openapi-schema-alternative-separator">
|
||||||
}
|
{(schema.anyOf || schema.oneOf) &&
|
||||||
|
tString(context.translation, 'or')}
|
||||||
|
{schema.allOf && tString(context.translation, 'and')}
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const ancestors = new Set(circularRefs.keys());
|
return null;
|
||||||
const alternatives = getSchemaAlternatives(schema, ancestors);
|
})();
|
||||||
|
|
||||||
if (alternatives) {
|
if (properties?.length) {
|
||||||
return alternatives.map((schema, index) => (
|
return (
|
||||||
<OpenAPISchemaAlternative
|
<OpenAPIDisclosure
|
||||||
key={index}
|
icon={context.icons.plus}
|
||||||
schema={schema}
|
className={clsx('openapi-schema', className)}
|
||||||
circularRefs={circularRefs}
|
header={header}
|
||||||
context={context}
|
label={(isExpanded) => getDisclosureLabel({ schema, isExpanded, context })}
|
||||||
/>
|
{...rest}
|
||||||
));
|
>
|
||||||
}
|
{content}
|
||||||
|
</OpenAPIDisclosure>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return (
|
||||||
})()}
|
<div id={id} {...rest} className={clsx('openapi-schema', className)}>
|
||||||
|
{header}
|
||||||
|
{content}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -115,6 +141,7 @@ function OpenAPISchemaProperties(props: {
|
|||||||
circularRefs={circularRefs}
|
circularRefs={circularRefs}
|
||||||
property={property}
|
property={property}
|
||||||
context={context}
|
context={context}
|
||||||
|
style={{ animationDelay: `${index * 0.02}s` }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@@ -205,34 +232,26 @@ function OpenAPISchemaAlternative(props: {
|
|||||||
context: OpenAPIClientContext;
|
context: OpenAPIClientContext;
|
||||||
}) {
|
}) {
|
||||||
const { schema, circularRefs, context } = props;
|
const { schema, circularRefs, context } = props;
|
||||||
|
|
||||||
const description = resolveDescription(schema);
|
|
||||||
const properties = getSchemaProperties(schema);
|
const properties = getSchemaProperties(schema);
|
||||||
|
|
||||||
return (
|
return properties?.length ? (
|
||||||
<>
|
<OpenAPIDisclosure
|
||||||
{description ? (
|
icon={context.icons.plus}
|
||||||
<Markdown source={description} className="openapi-schema-description" />
|
header={<OpenAPISchemaPresentation property={{ schema }} context={context} />}
|
||||||
) : null}
|
label={(isExpanded) => getDisclosureLabel({ schema, isExpanded, context })}
|
||||||
<OpenAPIDisclosure
|
>
|
||||||
icon={context.icons.plus}
|
<OpenAPISchemaProperties
|
||||||
label={(isExpanded) => getDisclosureLabel({ schema, isExpanded, context })}
|
properties={properties}
|
||||||
>
|
circularRefs={circularRefs}
|
||||||
{properties?.length ? (
|
context={context}
|
||||||
<OpenAPISchemaProperties
|
/>
|
||||||
properties={properties}
|
</OpenAPIDisclosure>
|
||||||
circularRefs={circularRefs}
|
) : (
|
||||||
context={context}
|
<OpenAPISchemaProperty
|
||||||
/>
|
property={{ schema }}
|
||||||
) : (
|
circularRefs={circularRefs}
|
||||||
<OpenAPISchemaProperty
|
context={context}
|
||||||
property={{ schema }}
|
/>
|
||||||
circularRefs={circularRefs}
|
|
||||||
context={context}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</OpenAPIDisclosure>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,7 +312,7 @@ function OpenAPISchemaEnum(props: {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<span className="openapi-schema-enum">
|
<span className="openapi-schema-enum">
|
||||||
Available options:{' '}
|
{tString(context.translation, 'possible_values')}:{' '}
|
||||||
{enumValues.map((item, index) => (
|
{enumValues.map((item, index) => (
|
||||||
<span key={index} className="openapi-schema-enum-value">
|
<span key={index} className="openapi-schema-enum-value">
|
||||||
<OpenAPICopyButton
|
<OpenAPICopyButton
|
||||||
@@ -313,7 +332,7 @@ function OpenAPISchemaEnum(props: {
|
|||||||
/**
|
/**
|
||||||
* Render the top row of a schema. e.g: name, type, and required status.
|
* Render the top row of a schema. e.g: name, type, and required status.
|
||||||
*/
|
*/
|
||||||
function OpenAPISchemaPresentation(props: {
|
export function OpenAPISchemaPresentation(props: {
|
||||||
property: OpenAPISchemaPropertyEntry;
|
property: OpenAPISchemaPropertyEntry;
|
||||||
context: OpenAPIClientContext;
|
context: OpenAPIClientContext;
|
||||||
}) {
|
}) {
|
||||||
@@ -612,16 +631,14 @@ function getDisclosureLabel(props: {
|
|||||||
if (schema.type === 'array' && !!schema.items) {
|
if (schema.type === 'array' && !!schema.items) {
|
||||||
if (schema.items.oneOf) {
|
if (schema.items.oneOf) {
|
||||||
label = tString(context.translation, 'available_items').toLowerCase();
|
label = tString(context.translation, 'available_items').toLowerCase();
|
||||||
}
|
} else if (schema.items.enum || schema.items.type === 'object') {
|
||||||
// Fallback to "child attributes" for enums and objects
|
label = tString(context.translation, 'properties').toLowerCase();
|
||||||
else if (schema.items.enum || schema.items.type === 'object') {
|
|
||||||
label = tString(context.translation, 'child_attributes').toLowerCase();
|
|
||||||
} else {
|
} else {
|
||||||
label = schema.items.title ?? schema.title ?? getSchemaTitle(schema.items);
|
label = schema.items.title ?? schema.title ?? getSchemaTitle(schema.items);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
label = schema.title || tString(context.translation, 'child_attributes').toLowerCase();
|
label = schema.title || tString(context.translation, 'properties').toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
return `${isExpanded ? tString(context.translation, 'hide') : tString(context.translation, 'show')} ${label}`;
|
return tString(context.translation, isExpanded ? 'hide' : 'show', label);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { t, tString } from './translate';
|
|||||||
interface OpenAPISchemaNameProps {
|
interface OpenAPISchemaNameProps {
|
||||||
schema?: OpenAPIV3.SchemaObject;
|
schema?: OpenAPIV3.SchemaObject;
|
||||||
propertyName?: string | React.JSX.Element;
|
propertyName?: string | React.JSX.Element;
|
||||||
required?: boolean;
|
required?: boolean | null;
|
||||||
type?: string;
|
type?: string;
|
||||||
context: OpenAPIClientContext;
|
context: OpenAPIClientContext;
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,7 @@ export function OpenAPISchemaName(props: OpenAPISchemaNameProps) {
|
|||||||
{t(context.translation, 'write_only')}
|
{t(context.translation, 'write_only')}
|
||||||
</span>
|
</span>
|
||||||
) : null}
|
) : null}
|
||||||
{required ? (
|
{required === null ? null : required ? (
|
||||||
<span className="openapi-schema-required">
|
<span className="openapi-schema-required">
|
||||||
{t(context.translation, 'required')}
|
{t(context.translation, 'required')}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export function SectionHeader(props: ComponentPropsWithoutRef<'div'>) {
|
|||||||
{...props}
|
{...props}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'openapi-section-header',
|
'openapi-section-header',
|
||||||
props.className && `${props.className}-header`
|
props.className ? `${props.className}-header` : undefined
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
getOpenAPIClientContext,
|
getOpenAPIClientContext,
|
||||||
resolveOpenAPIContext,
|
resolveOpenAPIContext,
|
||||||
} from '../context';
|
} from '../context';
|
||||||
import { t } from '../translate';
|
import { t, tString } from '../translate';
|
||||||
import { getExampleFromSchema } from '../util/example';
|
import { getExampleFromSchema } from '../util/example';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -89,7 +89,10 @@ export function OpenAPISchemas(props: {
|
|||||||
className="openapi-schemas-disclosure"
|
className="openapi-schemas-disclosure"
|
||||||
key={name}
|
key={name}
|
||||||
icon={context.icons.chevronRight}
|
icon={context.icons.chevronRight}
|
||||||
label={name}
|
header={name}
|
||||||
|
label={(isExpanded) =>
|
||||||
|
tString(context.translation, isExpanded ? 'hide' : 'show')
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Section className="openapi-section-schemas">
|
<Section className="openapi-section-schemas">
|
||||||
<SectionBody>
|
<SectionBody>
|
||||||
|
|||||||
@@ -18,9 +18,11 @@ export const de = {
|
|||||||
nullable: 'Nullfähig',
|
nullable: 'Nullfähig',
|
||||||
body: 'Rumpf',
|
body: 'Rumpf',
|
||||||
payload: 'Nutzlast',
|
payload: 'Nutzlast',
|
||||||
headers: 'Kopfzeilen',
|
headers: 'Header',
|
||||||
|
header: 'Header',
|
||||||
authorizations: 'Autorisierungen',
|
authorizations: 'Autorisierungen',
|
||||||
responses: 'Antworten',
|
responses: 'Antworten',
|
||||||
|
response: 'Antwort',
|
||||||
path_parameters: 'Pfadparameter',
|
path_parameters: 'Pfadparameter',
|
||||||
query_parameters: 'Abfrageparameter',
|
query_parameters: 'Abfrageparameter',
|
||||||
header_parameters: 'Header-Parameter',
|
header_parameters: 'Header-Parameter',
|
||||||
@@ -30,8 +32,11 @@ export const de = {
|
|||||||
success: 'Erfolg',
|
success: 'Erfolg',
|
||||||
redirect: 'Umleitung',
|
redirect: 'Umleitung',
|
||||||
error: 'Fehler',
|
error: 'Fehler',
|
||||||
show: 'Anzeigen',
|
show: 'Zeige ${1}',
|
||||||
hide: 'Verstecken',
|
hide: 'Verstecke ${1}',
|
||||||
available_items: 'Verfügbare Elemente',
|
available_items: 'Verfügbare Elemente',
|
||||||
child_attributes: 'Unterattribute',
|
properties: 'Eigenschaften',
|
||||||
|
or: 'oder',
|
||||||
|
and: 'und',
|
||||||
|
possible_values: 'Mögliche Werte',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,8 +19,10 @@ export const en = {
|
|||||||
body: 'Body',
|
body: 'Body',
|
||||||
payload: 'Payload',
|
payload: 'Payload',
|
||||||
headers: 'Headers',
|
headers: 'Headers',
|
||||||
|
header: 'Header',
|
||||||
authorizations: 'Authorizations',
|
authorizations: 'Authorizations',
|
||||||
responses: 'Responses',
|
responses: 'Responses',
|
||||||
|
response: 'Response',
|
||||||
path_parameters: 'Path parameters',
|
path_parameters: 'Path parameters',
|
||||||
query_parameters: 'Query parameters',
|
query_parameters: 'Query parameters',
|
||||||
header_parameters: 'Header parameters',
|
header_parameters: 'Header parameters',
|
||||||
@@ -30,8 +32,11 @@ export const en = {
|
|||||||
success: 'Success',
|
success: 'Success',
|
||||||
redirect: 'Redirect',
|
redirect: 'Redirect',
|
||||||
error: 'Error',
|
error: 'Error',
|
||||||
show: 'Show',
|
show: 'Show ${1}',
|
||||||
hide: 'Hide',
|
hide: 'Hide ${1}',
|
||||||
available_items: 'Available items',
|
available_items: 'Available items',
|
||||||
child_attributes: 'Child attributes',
|
possible_values: 'Possible values',
|
||||||
|
properties: 'Properties',
|
||||||
|
or: 'or',
|
||||||
|
and: 'and',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,9 +18,11 @@ export const es = {
|
|||||||
nullable: 'Nulo',
|
nullable: 'Nulo',
|
||||||
body: 'Cuerpo',
|
body: 'Cuerpo',
|
||||||
payload: 'Caga útil',
|
payload: 'Caga útil',
|
||||||
headers: 'Encabezados',
|
headers: 'Headers',
|
||||||
|
header: 'Header',
|
||||||
authorizations: 'Autorizaciones',
|
authorizations: 'Autorizaciones',
|
||||||
responses: 'Respuestas',
|
responses: 'Respuestas',
|
||||||
|
response: 'Respuesta',
|
||||||
path_parameters: 'Parámetros de ruta',
|
path_parameters: 'Parámetros de ruta',
|
||||||
query_parameters: 'Parámetros de consulta',
|
query_parameters: 'Parámetros de consulta',
|
||||||
header_parameters: 'Parámetros de encabezado',
|
header_parameters: 'Parámetros de encabezado',
|
||||||
@@ -30,8 +32,11 @@ export const es = {
|
|||||||
success: 'Éxito',
|
success: 'Éxito',
|
||||||
redirect: 'Redirección',
|
redirect: 'Redirección',
|
||||||
error: 'Error',
|
error: 'Error',
|
||||||
show: 'Mostrar',
|
show: 'Mostrar ${1}',
|
||||||
hide: 'Ocultar',
|
hide: 'Ocultar ${1}',
|
||||||
available_items: 'Elementos disponibles',
|
available_items: 'Elementos disponibles',
|
||||||
child_attributes: 'Atributos secundarios',
|
properties: 'Propiedades',
|
||||||
|
or: 'o',
|
||||||
|
and: 'y',
|
||||||
|
possible_values: 'Valores posibles',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,20 +18,25 @@ export const fr = {
|
|||||||
nullable: 'Nullable',
|
nullable: 'Nullable',
|
||||||
body: 'Corps',
|
body: 'Corps',
|
||||||
payload: 'Charge utile',
|
payload: 'Charge utile',
|
||||||
headers: 'En-têtes',
|
headers: 'Headers',
|
||||||
|
header: 'Header',
|
||||||
authorizations: 'Autorisations',
|
authorizations: 'Autorisations',
|
||||||
responses: 'Réponses',
|
responses: 'Réponses',
|
||||||
|
response: 'Réponse',
|
||||||
path_parameters: 'Paramètres de chemin',
|
path_parameters: 'Paramètres de chemin',
|
||||||
query_parameters: 'Paramètres de requête',
|
query_parameters: 'Paramètres de requête',
|
||||||
header_parameters: 'Paramètres d’en-tête',
|
header_parameters: "Paramètres d'en-tête",
|
||||||
attributes: 'Attributs',
|
attributes: 'Attributs',
|
||||||
test_it: 'Tester',
|
test_it: 'Tester',
|
||||||
information: 'Information',
|
information: 'Information',
|
||||||
success: 'Succès',
|
success: 'Succès',
|
||||||
redirect: 'Redirection',
|
redirect: 'Redirection',
|
||||||
error: 'Erreur',
|
error: 'Erreur',
|
||||||
show: 'Afficher',
|
show: 'Afficher ${1}',
|
||||||
hide: 'Masquer',
|
hide: 'Masquer ${1}',
|
||||||
available_items: 'Éléments disponibles',
|
available_items: 'Éléments disponibles',
|
||||||
child_attributes: 'Attributs enfants',
|
properties: 'Propriétés',
|
||||||
|
or: 'ou',
|
||||||
|
and: 'et',
|
||||||
|
possible_values: 'Valeurs possibles',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,8 +19,10 @@ export const ja = {
|
|||||||
body: '本文',
|
body: '本文',
|
||||||
payload: 'ペイロード',
|
payload: 'ペイロード',
|
||||||
headers: 'ヘッダー',
|
headers: 'ヘッダー',
|
||||||
|
header: 'ヘッダー',
|
||||||
authorizations: '認可',
|
authorizations: '認可',
|
||||||
responses: 'レスポンス',
|
responses: 'レスポンス',
|
||||||
|
response: 'レスポンス',
|
||||||
path_parameters: 'パスパラメータ',
|
path_parameters: 'パスパラメータ',
|
||||||
query_parameters: 'クエリパラメータ',
|
query_parameters: 'クエリパラメータ',
|
||||||
header_parameters: 'ヘッダーパラメータ',
|
header_parameters: 'ヘッダーパラメータ',
|
||||||
@@ -30,8 +32,11 @@ export const ja = {
|
|||||||
success: '成功',
|
success: '成功',
|
||||||
redirect: 'リダイレクト',
|
redirect: 'リダイレクト',
|
||||||
error: 'エラー',
|
error: 'エラー',
|
||||||
show: '表示',
|
show: '${1}を表示',
|
||||||
hide: '非表示',
|
hide: '${1}を非表示',
|
||||||
available_items: '利用可能なアイテム',
|
available_items: '利用可能なアイテム',
|
||||||
child_attributes: '子属性',
|
properties: 'プロパティ',
|
||||||
|
or: 'または',
|
||||||
|
and: 'かつ',
|
||||||
|
possible_values: '可能な値',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,8 +19,10 @@ export const nl = {
|
|||||||
body: 'Body',
|
body: 'Body',
|
||||||
payload: 'Payload',
|
payload: 'Payload',
|
||||||
headers: 'Headers',
|
headers: 'Headers',
|
||||||
|
header: 'Header',
|
||||||
authorizations: 'Autorisaties',
|
authorizations: 'Autorisaties',
|
||||||
responses: 'Reacties',
|
responses: 'Reacties',
|
||||||
|
response: 'Reactie',
|
||||||
path_parameters: 'Padparameters',
|
path_parameters: 'Padparameters',
|
||||||
query_parameters: 'Queryparameters',
|
query_parameters: 'Queryparameters',
|
||||||
header_parameters: 'Headerparameters',
|
header_parameters: 'Headerparameters',
|
||||||
@@ -30,8 +32,11 @@ export const nl = {
|
|||||||
success: 'Succes',
|
success: 'Succes',
|
||||||
redirect: 'Omleiding',
|
redirect: 'Omleiding',
|
||||||
error: 'Fout',
|
error: 'Fout',
|
||||||
show: 'Toon',
|
show: 'Toon ${1}',
|
||||||
hide: 'Verbergen',
|
hide: 'Verberg ${1}',
|
||||||
available_items: 'Beschikbare items',
|
available_items: 'Beschikbare items',
|
||||||
child_attributes: 'Kindattributen',
|
properties: 'Eigenschappen',
|
||||||
|
or: 'of',
|
||||||
|
and: 'en',
|
||||||
|
possible_values: 'Mogelijke waarden',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,9 +18,11 @@ export const no = {
|
|||||||
nullable: 'Kan være null',
|
nullable: 'Kan være null',
|
||||||
body: 'Brødtekst',
|
body: 'Brødtekst',
|
||||||
payload: 'Nyttelast',
|
payload: 'Nyttelast',
|
||||||
headers: 'Overskrifter',
|
headers: 'Headers',
|
||||||
|
header: 'Header',
|
||||||
authorizations: 'Autorisasjoner',
|
authorizations: 'Autorisasjoner',
|
||||||
responses: 'Responser',
|
responses: 'Responser',
|
||||||
|
response: 'Respons',
|
||||||
path_parameters: 'Sti-parametere',
|
path_parameters: 'Sti-parametere',
|
||||||
query_parameters: 'Forespørselsparametere',
|
query_parameters: 'Forespørselsparametere',
|
||||||
header_parameters: 'Header-parametere',
|
header_parameters: 'Header-parametere',
|
||||||
@@ -30,8 +32,11 @@ export const no = {
|
|||||||
success: 'Suksess',
|
success: 'Suksess',
|
||||||
redirect: 'Viderekobling',
|
redirect: 'Viderekobling',
|
||||||
error: 'Feil',
|
error: 'Feil',
|
||||||
show: 'Vis',
|
show: 'Vis ${1}',
|
||||||
hide: 'Skjul',
|
hide: 'Skjul ${1}',
|
||||||
available_items: 'Tilgjengelige elementer',
|
available_items: 'Tilgjengelige elementer',
|
||||||
child_attributes: 'Barneattributter',
|
properties: 'Egenskaper',
|
||||||
|
or: 'eller',
|
||||||
|
and: 'og',
|
||||||
|
possible_values: 'Mulige verdier',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,9 +18,11 @@ export const pt_br = {
|
|||||||
nullable: 'Nulo',
|
nullable: 'Nulo',
|
||||||
body: 'Corpo',
|
body: 'Corpo',
|
||||||
payload: 'Carga útil',
|
payload: 'Carga útil',
|
||||||
headers: 'Cabeçalhos',
|
headers: 'Headers',
|
||||||
|
header: 'Header',
|
||||||
authorizations: 'Autorizações',
|
authorizations: 'Autorizações',
|
||||||
responses: 'Respostas',
|
responses: 'Respostas',
|
||||||
|
response: 'Resposta',
|
||||||
path_parameters: 'Parâmetros de rota',
|
path_parameters: 'Parâmetros de rota',
|
||||||
query_parameters: 'Parâmetros de consulta',
|
query_parameters: 'Parâmetros de consulta',
|
||||||
header_parameters: 'Parâmetros de cabeçalho',
|
header_parameters: 'Parâmetros de cabeçalho',
|
||||||
@@ -30,8 +32,11 @@ export const pt_br = {
|
|||||||
success: 'Sucesso',
|
success: 'Sucesso',
|
||||||
redirect: 'Redirecionamento',
|
redirect: 'Redirecionamento',
|
||||||
error: 'Erro',
|
error: 'Erro',
|
||||||
show: 'Mostrar',
|
show: 'Mostrar ${1}',
|
||||||
hide: 'Ocultar',
|
hide: 'Ocultar ${1}',
|
||||||
available_items: 'Itens disponíveis',
|
available_items: 'Itens disponíveis',
|
||||||
child_attributes: 'Atributos filhos',
|
properties: 'Propriedades',
|
||||||
|
or: 'ou',
|
||||||
|
and: 'e',
|
||||||
|
possible_values: 'Valores possíveis',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,9 +18,11 @@ export const zh = {
|
|||||||
nullable: '可为 null',
|
nullable: '可为 null',
|
||||||
body: '请求体',
|
body: '请求体',
|
||||||
payload: '有效载荷',
|
payload: '有效载荷',
|
||||||
headers: '头部信息',
|
headers: '头字段',
|
||||||
|
header: '头部',
|
||||||
authorizations: '授权',
|
authorizations: '授权',
|
||||||
responses: '响应',
|
responses: '响应',
|
||||||
|
response: '响应',
|
||||||
path_parameters: '路径参数',
|
path_parameters: '路径参数',
|
||||||
query_parameters: '查询参数',
|
query_parameters: '查询参数',
|
||||||
header_parameters: '头参数',
|
header_parameters: '头参数',
|
||||||
@@ -30,8 +32,11 @@ export const zh = {
|
|||||||
success: '成功',
|
success: '成功',
|
||||||
redirect: '重定向',
|
redirect: '重定向',
|
||||||
error: '错误',
|
error: '错误',
|
||||||
show: '显示',
|
show: '显示${1}',
|
||||||
hide: '隐藏',
|
hide: '隐藏${1}',
|
||||||
available_items: '可用项',
|
available_items: '可用项',
|
||||||
child_attributes: '子属性',
|
properties: '属性',
|
||||||
|
or: '或',
|
||||||
|
and: '和',
|
||||||
|
possible_values: '可能的值',
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user