Restyle openapi blocks (#3169)

This commit is contained in:
Zeno Kapitein
2025-04-24 16:53:29 +02:00
committed by GitHub
parent 90f0127ada
commit 326e28e9b0
21 changed files with 472 additions and 309 deletions
+6
View File
@@ -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}>
+34 -2
View File
@@ -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>
+99 -82
View File
@@ -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>
+1 -1
View File
@@ -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',
}; };
+10 -5
View File
@@ -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 den-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: '可能的值',
}; };