From 0a45c7fdb9036ad626caf4aba64e97d0f17437f4 Mon Sep 17 00:00:00 2001 From: Steven Serrata Date: Thu, 5 Sep 2024 14:28:42 -0400 Subject: [PATCH 01/10] add missing languages --- .../src/theme/ApiExplorer/CodeSnippets/code-snippets-types.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeSnippets/code-snippets-types.ts b/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeSnippets/code-snippets-types.ts index e46ed106d..3f8f03a38 100644 --- a/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeSnippets/code-snippets-types.ts +++ b/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeSnippets/code-snippets-types.ts @@ -22,10 +22,12 @@ export type CodeSampleLanguage = | "JavaScript" | "Kotlin" | "Objective-C" + | "OCaml" | "Perl" | "PHP" | "PowerShell" | "Python" + | "R" | "Ruby" | "Rust" | "Scala" From 56b056b7780fd15dc167040d3ff044d31124a695 Mon Sep 17 00:00:00 2001 From: Steven Serrata Date: Thu, 5 Sep 2024 14:29:31 -0400 Subject: [PATCH 02/10] add function for generating languageSet --- .../theme/ApiExplorer/CodeSnippets/index.tsx | 114 +----------------- .../ApiExplorer/CodeSnippets/languages.ts | 25 ++++ 2 files changed, 27 insertions(+), 112 deletions(-) diff --git a/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeSnippets/index.tsx b/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeSnippets/index.tsx index aa1873453..001f0d288 100644 --- a/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeSnippets/index.tsx +++ b/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeSnippets/index.tsx @@ -27,120 +27,10 @@ import { getCodeSampleSourceFromLanguage, mergeArraysbyLanguage, mergeCodeSampleLanguage, + generateLanguageSet, } from "./languages"; -export const languageSet: Language[] = [ - { - highlight: "bash", - language: "curl", - codeSampleLanguage: "Shell", - logoClass: "bash", - options: { - longFormat: false, - followRedirect: true, - trimRequestBody: true, - }, - variant: "cURL", - variants: ["curl"], - }, - { - highlight: "python", - language: "python", - codeSampleLanguage: "Python", - logoClass: "python", - options: { - followRedirect: true, - trimRequestBody: true, - }, - variant: "requests", - variants: ["requests", "http.client"], - }, - { - highlight: "go", - language: "go", - codeSampleLanguage: "Go", - logoClass: "go", - options: { - followRedirect: true, - trimRequestBody: true, - }, - variant: "native", - variants: ["native"], - }, - { - highlight: "javascript", - language: "nodejs", - codeSampleLanguage: "JavaScript", - logoClass: "nodejs", - options: { - ES6_enabled: true, - followRedirect: true, - trimRequestBody: true, - }, - variant: "axios", - variants: ["axios", "native"], - }, - { - highlight: "ruby", - language: "ruby", - codeSampleLanguage: "Ruby", - logoClass: "ruby", - options: { - followRedirect: true, - trimRequestBody: true, - }, - variant: "Net::HTTP", - variants: ["net::http"], - }, - { - highlight: "csharp", - language: "csharp", - codeSampleLanguage: "C#", - logoClass: "csharp", - options: { - followRedirect: true, - trimRequestBody: true, - }, - variant: "RestSharp", - variants: ["restsharp", "httpclient"], - }, - { - highlight: "php", - language: "php", - codeSampleLanguage: "PHP", - logoClass: "php", - options: { - followRedirect: true, - trimRequestBody: true, - }, - variant: "cURL", - variants: ["curl", "guzzle", "pecl_http", "http_request2"], - }, - { - highlight: "java", - language: "java", - codeSampleLanguage: "Java", - logoClass: "java", - options: { - followRedirect: true, - trimRequestBody: true, - }, - variant: "OkHttp", - variants: ["okhttp", "unirest"], - }, - { - highlight: "powershell", - language: "powershell", - codeSampleLanguage: "PowerShell", - logoClass: "powershell", - options: { - followRedirect: true, - trimRequestBody: true, - }, - variant: "RestMethod", - variants: ["restmethod"], - }, -]; +export const languageSet: Language[] = generateLanguageSet(); export interface Props { postman: sdk.Request; diff --git a/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeSnippets/languages.ts b/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeSnippets/languages.ts index 71346684e..a51439a60 100644 --- a/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeSnippets/languages.ts +++ b/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeSnippets/languages.ts @@ -9,6 +9,7 @@ import find from "lodash/find"; import isArray from "lodash/isArray"; import mergeWith from "lodash/mergeWith"; import unionBy from "lodash/unionBy"; +import codegen from "postman-code-generators"; import { CodeSample, Language } from "./code-snippets-types"; @@ -73,3 +74,27 @@ export function getCodeSampleSourceFromLanguage(language: Language) { return ""; } + +export function generateLanguageSet() { + const languageSet: Language[] = []; + codegen.getLanguageList().forEach((language: any) => { + const variants: any = []; + language.variants.forEach((variant: any) => { + variants.push(variant.key); + }); + languageSet.push({ + highlight: language.syntax_mode, + language: language.key, + codeSampleLanguage: language.label, + logoClass: language.key, + options: { + longFormat: false, + followRedirect: true, + trimRequestBody: true, + }, + variant: variants[0], + variants: variants, + }); + }); + return languageSet; +} From bf1cadff516c9a4e85e4e693bd4f6905bf424683 Mon Sep 17 00:00:00 2001 From: Steven Serrata Date: Thu, 5 Sep 2024 14:30:29 -0400 Subject: [PATCH 03/10] add additional language tab styles --- .../theme/ApiExplorer/CodeTabs/_CodeTabs.scss | 148 +++++++++++++++++- 1 file changed, 146 insertions(+), 2 deletions(-) diff --git a/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeTabs/_CodeTabs.scss b/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeTabs/_CodeTabs.scss index a734be72e..4d6301f41 100644 --- a/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeTabs/_CodeTabs.scss +++ b/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeTabs/_CodeTabs.scss @@ -146,6 +146,24 @@ body[class="ReactModal__Body--open"] { } } +.openapi-tabs__code-item--dart { + color: var(--ifm-color-info); + + &::after { + content: ""; + width: var(--code-tab-logo-width); + height: var(--code-tab-logo-height); + background: url("https://raw.githubusercontent.com/devicons/devicon/master/icons/dart/dart-original.svg") + no-repeat; + margin-block: auto; + } + + &.active { + box-shadow: 0 0 0 3px var(--openapi-code-tab-shadow-color-dart); + border-color: var(--openapi-code-tab-border-color-dart); + } +} + .openapi-tabs__code-item--javascript { color: var(--ifm-color-warning); @@ -164,7 +182,7 @@ body[class="ReactModal__Body--open"] { } } -.openapi-tabs__code-item--bash { +.openapi-tabs__code-item--curl { color: var(--ifm-color-danger); &::after { @@ -179,7 +197,7 @@ body[class="ReactModal__Body--open"] { } &.active { - box-shadow: 0 0 0 3px var(--openapi-code-tab-shadow-color-bash); + box-shadow: 0 0 0 3px var(--openapi-code-tab-shadow-color-curl); border-color: var(--ifm-color-danger); } } @@ -220,6 +238,96 @@ body[class="ReactModal__Body--open"] { } } +.openapi-tabs__code-item--r { + color: var(--ifm-color-gray-500); + + &::after { + content: ""; + width: var(--code-tab-logo-width); + height: var(--code-tab-logo-height); + background: url("https://raw.githubusercontent.com/devicons/devicon/master/icons/r/r-original.svg") + no-repeat; + margin-block: auto; + } + + &.active { + box-shadow: 0 0 0 3px var(--openapi-code-tab-shadow-color-r); + border-color: var(--openapi-code-tab-border-color-r); + } +} + +.openapi-tabs__code-item--swift { + color: var(--ifm-color-danger); + + &::after { + content: ""; + width: var(--code-tab-logo-width); + height: var(--code-tab-logo-height); + background: url("https://raw.githubusercontent.com/devicons/devicon/master/icons/swift/swift-original.svg") + no-repeat; + margin-block: auto; + } + + &.active { + box-shadow: 0 0 0 3px var(--openapi-code-tab-shadow-color-swift); + border-color: var(--openapi-code-tab-border-color-swift); + } +} + +.openapi-tabs__code-item--c { + color: var(--ifm-color-info); + + &::after { + content: ""; + width: var(--code-tab-logo-width); + height: var(--code-tab-logo-height); + background: url("https://raw.githubusercontent.com/devicons/devicon/master/icons/c/c-original.svg") + no-repeat; + margin-block: auto; + } + + &.active { + box-shadow: 0 0 0 3px var(--openapi-code-tab-shadow-color-c); + border-color: var(--openapi-code-tab-border-color-c); + } +} + +.openapi-tabs__code-item--objective-c { + color: var(--ifm-color-info); + + &::after { + content: ""; + width: var(--code-tab-logo-width); + height: var(--code-tab-logo-height); + background: url("https://raw.githubusercontent.com/devicons/devicon/master/icons/objectivec/objectivec-plain.svg") + no-repeat; + margin-block: auto; + } + + &.active { + box-shadow: 0 0 0 3px var(--openapi-code-tab-shadow-color-objective-c); + border-color: var(--openapi-code-tab-border-color-objective-c); + } +} + +.openapi-tabs__code-item--ocaml { + color: var(--ifm-color-warning); + + &::after { + content: ""; + width: var(--code-tab-logo-width); + height: var(--code-tab-logo-height); + background: url("https://raw.githubusercontent.com/devicons/devicon/master/icons/ocaml/ocaml-original.svg") + no-repeat; + margin-block: auto; + } + + &.active { + box-shadow: 0 0 0 3px var(--openapi-code-tab-shadow-color-objective-ocaml); + border-color: var(--openapi-code-tab-border-color-objective-ocaml); + } +} + .openapi-tabs__code-item--nodejs { color: var(--ifm-color-success); @@ -256,6 +364,42 @@ body[class="ReactModal__Body--open"] { } } +.openapi-tabs__code-item--kotlin { + color: var(--ifm-color-gray-500); + + &::after { + content: ""; + width: var(--code-tab-logo-width); + height: var(--code-tab-logo-height); + background: url("https://raw.githubusercontent.com/devicons/devicon/master/icons/kotlin/kotlin-original.svg") + no-repeat; + margin-block: auto; + } + + &.active { + box-shadow: 0 0 0 3px var(--openapi-code-tab-shadow-color-kotlin); + border-color: var(--openapi-code-tab-border-color-kotlin); + } +} + +.openapi-tabs__code-item--rust { + color: var(--ifm-color-gray-500); + + &::after { + content: ""; + width: var(--code-tab-logo-width); + height: var(--code-tab-logo-height); + background: url("https://raw.githubusercontent.com/devicons/devicon/master/icons/rust/rust-original.svg") + no-repeat; + margin-block: auto; + } + + &.active { + box-shadow: 0 0 0 3px var(--openapi-code-tab-shadow-color-rust); + border-color: var(--openapi-code-tab-border-color-rust); + } +} + .openapi-tabs__code-item--java { color: var(--ifm-color-warning); From cc02f1e2accd5ade0a41c11cd9a53969ae909cb2 Mon Sep 17 00:00:00 2001 From: Steven Serrata Date: Thu, 5 Sep 2024 14:30:53 -0400 Subject: [PATCH 04/10] demonstrate overriding language tab styles --- demo/src/css/custom.css | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/demo/src/css/custom.css b/demo/src/css/custom.css index 4ca833446..d0a8c6b0f 100644 --- a/demo/src/css/custom.css +++ b/demo/src/css/custom.css @@ -146,3 +146,21 @@ div[class^="announcementBar_"] { ); font-weight: bold; } + +.openapi-tabs__code-item--python { + color: var(--ifm-color-success); + + &::after { + content: ""; + width: var(--code-tab-logo-width); + height: var(--code-tab-logo-height); + background: url("https://raw.githubusercontent.com/devicons/devicon/master/icons/python/python-plain.svg") + no-repeat !important; + margin-block: auto; + } + + &.active { + box-shadow: 0 0 0 3px var(--openapi-code-tab-shadow-color-python); + border-color: var(--openapi-code-tab-border-color-python); + } +} From a712ed0b5f9cca3f82b04b62d95f84ff6b12d1cf Mon Sep 17 00:00:00 2001 From: Steven Serrata Date: Thu, 5 Sep 2024 14:31:12 -0400 Subject: [PATCH 05/10] expand supported languages in demo --- demo/docusaurus.config.ts | 48 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/demo/docusaurus.config.ts b/demo/docusaurus.config.ts index ed511aece..241523dfb 100644 --- a/demo/docusaurus.config.ts +++ b/demo/docusaurus.config.ts @@ -145,6 +145,9 @@ const config: Config = { "powershell", "json", "bash", + "dart", + "objectivec", + "r", ], }, languageTabs: [ @@ -194,6 +197,51 @@ const config: Config = { language: "powershell", logoClass: "powershell", }, + { + highlight: "dart", + language: "dart", + logoClass: "dart", + }, + { + highlight: "javascript", + language: "javascript", + logoClass: "javascript", + }, + { + highlight: "c", + language: "c", + logoClass: "c", + }, + { + highlight: "objective-c", + language: "objective-c", + logoClass: "objective-c", + }, + { + highlight: "ocaml", + language: "ocaml", + logoClass: "ocaml", + }, + { + highlight: "r", + language: "r", + logoClass: "r", + }, + { + highlight: "swift", + language: "swift", + logoClass: "swift", + }, + { + highlight: "kotlin", + language: "kotlin", + logoClass: "kotlin", + }, + { + highlight: "rust", + language: "rust", + logoClass: "rust", + }, ], algolia: { apiKey: "441074cace987cbf4640c039ebed303c", From d6865199a65d5530d80bf41bf2e68602533f651c Mon Sep 17 00:00:00 2001 From: Steven Serrata Date: Thu, 5 Sep 2024 15:47:17 -0400 Subject: [PATCH 06/10] convert python styles to css --- demo/src/css/custom.css | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/demo/src/css/custom.css b/demo/src/css/custom.css index d0a8c6b0f..4955703cf 100644 --- a/demo/src/css/custom.css +++ b/demo/src/css/custom.css @@ -149,18 +149,16 @@ div[class^="announcementBar_"] { .openapi-tabs__code-item--python { color: var(--ifm-color-success); - - &::after { - content: ""; - width: var(--code-tab-logo-width); - height: var(--code-tab-logo-height); - background: url("https://raw.githubusercontent.com/devicons/devicon/master/icons/python/python-plain.svg") - no-repeat !important; - margin-block: auto; - } - - &.active { - box-shadow: 0 0 0 3px var(--openapi-code-tab-shadow-color-python); - border-color: var(--openapi-code-tab-border-color-python); - } +} +.openapi-tabs__code-item--python::after { + content: ""; + width: var(--code-tab-logo-width); + height: var(--code-tab-logo-height); + background: url("https://raw.githubusercontent.com/devicons/devicon/master/icons/python/python-plain.svg") + no-repeat; + margin-block: auto; +} +.openapi-tabs__code-item--python.active { + box-shadow: 0 0 0 3px var(--openapi-code-tab-shadow-color-python); + border-color: var(--openapi-code-tab-border-color-python); } From 3cf6f791c46f5eef0eee507778a6f925db67ded4 Mon Sep 17 00:00:00 2001 From: Steven Serrata Date: Thu, 5 Sep 2024 15:47:51 -0400 Subject: [PATCH 07/10] define defaultValue for language and add code comments to improve clarity --- .../src/theme/ApiExplorer/CodeSnippets/index.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeSnippets/index.tsx b/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeSnippets/index.tsx index 001f0d288..e78c29a6e 100644 --- a/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeSnippets/index.tsx +++ b/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeSnippets/index.tsx @@ -229,6 +229,7 @@ function CodeSnippets({ postman, codeSamples }: Props) { return ( <> + {/* Outer language tabs */} {mergedLangs.map((lang) => { @@ -249,6 +251,7 @@ function CodeSnippets({ postman, codeSamples }: Props) { className: `openapi-tabs__code-item--${lang.logoClass}`, }} > + {/* Inner x-codeSamples tabs */} {lang.samples && ( )} + {/* Inner generated code snippets */} Date: Thu, 5 Sep 2024 15:49:56 -0400 Subject: [PATCH 08/10] use first variant in variants array as default --- .../src/theme/ApiExplorer/CodeTabs/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeTabs/index.tsx b/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeTabs/index.tsx index 15d5c067e..3361c2201 100644 --- a/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeTabs/index.tsx +++ b/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeTabs/index.tsx @@ -80,7 +80,7 @@ function TabList({ newLanguage = languageSet.filter( (lang: Language) => lang.language === newTabValue )[0]; - action.setSelectedVariant(newLanguage.variant.toLowerCase()); + action.setSelectedVariant(newLanguage.variants[0].toLowerCase()); action.setSelectedSample(newLanguage.sample); } action.setLanguage(newLanguage); From ae26ab6f9d70581177d33806ad53207e12b5daa1 Mon Sep 17 00:00:00 2001 From: Steven Serrata Date: Thu, 5 Sep 2024 16:16:41 -0400 Subject: [PATCH 09/10] auto scroll to default language --- .../src/theme/ApiExplorer/CodeTabs/index.tsx | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeTabs/index.tsx b/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeTabs/index.tsx index 3361c2201..81311a38d 100644 --- a/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeTabs/index.tsx +++ b/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeTabs/index.tsx @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. * ========================================================================== */ -import React, { cloneElement, ReactElement } from "react"; +import React, { cloneElement, ReactElement, useEffect, useRef } from "react"; import { sanitizeTabsChildren, @@ -43,10 +43,23 @@ function TabList({ selectValue, tabValues, }: CodeTabsProps & ReturnType) { - const tabRefs: (HTMLLIElement | null)[] = []; + const tabRefs = useRef<(HTMLLIElement | null)[]>([]); const { blockElementScrollPositionUntilNextRender } = useScrollPositionBlocker(); + useEffect(() => { + const activeTab = tabRefs.current.find( + (tab) => tab?.getAttribute("aria-selected") === "true" + ); + if (activeTab) { + activeTab.scrollIntoView({ + behavior: "auto", + block: "center", + inline: "start", + }); + } + }, []); + const handleTabChange = ( event: | React.FocusEvent @@ -54,7 +67,7 @@ function TabList({ | React.KeyboardEvent ) => { const newTab = event.currentTarget; - const newTabIndex = tabRefs.indexOf(newTab); + const newTabIndex = tabRefs.current.indexOf(newTab); const newTabValue = tabValues[newTabIndex]!.value; if (newTabValue !== selectedValue) { @@ -96,13 +109,15 @@ function TabList({ break; } case "ArrowRight": { - const nextTab = tabRefs.indexOf(event.currentTarget) + 1; - focusElement = tabRefs[nextTab] ?? tabRefs[0]!; + const nextTab = tabRefs.current.indexOf(event.currentTarget) + 1; + focusElement = tabRefs.current[nextTab] ?? tabRefs.current[0]!; break; } case "ArrowLeft": { - const prevTab = tabRefs.indexOf(event.currentTarget) - 1; - focusElement = tabRefs[prevTab] ?? tabRefs[tabRefs.length - 1]!; + const prevTab = tabRefs.current.indexOf(event.currentTarget) - 1; + focusElement = + tabRefs.current[prevTab] ?? + tabRefs.current[tabRefs.current.length - 1]!; break; } default: @@ -132,7 +147,7 @@ function TabList({ tabIndex={selectedValue === value ? 0 : -1} aria-selected={selectedValue === value} key={value} - ref={(tabControl) => tabRefs.push(tabControl)} + ref={(tabControl) => tabRefs.current.push(tabControl)} onKeyDown={handleKeydown} onClick={handleTabChange} {...attributes} From 433b233a24b40006ff0e35f04666dcf841691115 Mon Sep 17 00:00:00 2001 From: Steven Serrata Date: Thu, 5 Sep 2024 16:27:48 -0400 Subject: [PATCH 10/10] add fall back in case language not already in localStorage --- .../src/theme/ApiExplorer/CodeSnippets/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeSnippets/index.tsx b/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeSnippets/index.tsx index e78c29a6e..b138fc8ca 100644 --- a/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeSnippets/index.tsx +++ b/packages/docusaurus-theme-openapi-docs/src/theme/ApiExplorer/CodeSnippets/index.tsx @@ -238,7 +238,7 @@ function CodeSnippets({ postman, codeSamples }: Props) { setSelectedSample: setSelectedSample, }} languageSet={mergedLangs} - defaultValue={defaultLang[0].language} + defaultValue={defaultLang[0]?.language ?? mergedLangs[0].language} lazy > {mergedLangs.map((lang) => {