From 2b5bb92fc16af52cfb4ad40962c18f1bac0c7530 Mon Sep 17 00:00:00 2001 From: Joro Date: Mon, 2 Dec 2024 16:32:51 +0200 Subject: [PATCH 01/37] admonition --- src/css/custom.css | 37 ++ src/theme/Admonition/Icon/Danger.js | 21 ++ src/theme/Admonition/Icon/Goal.js | 25 ++ src/theme/Admonition/Icon/Info.js | 23 ++ src/theme/Admonition/Icon/Note.js | 23 ++ src/theme/Admonition/Icon/Tip.js | 22 ++ src/theme/Admonition/Icon/Troubleshoot.js | 19 ++ src/theme/Admonition/Icon/Warning.js | 32 ++ src/theme/Admonition/Layout/index.js | 39 +++ src/theme/Admonition/Layout/styles.module.css | 67 ++++ src/theme/Admonition/Type/Caution.js | 28 ++ src/theme/Admonition/Type/Danger.js | 26 ++ src/theme/Admonition/Type/Goal.js | 28 ++ src/theme/Admonition/Type/Info.js | 26 ++ src/theme/Admonition/Type/Note.js | 28 ++ src/theme/Admonition/Type/Tip.js | 26 ++ src/theme/Admonition/Type/Troubleshoot.js | 30 ++ src/theme/Admonition/Type/Warning.js | 26 ++ src/theme/Admonition/Types.js | 34 ++ src/theme/Admonition/index.js | 315 +----------------- src/theme/Admonition/styles.module.css | 53 --- 21 files changed, 573 insertions(+), 355 deletions(-) create mode 100644 src/theme/Admonition/Icon/Danger.js create mode 100644 src/theme/Admonition/Icon/Goal.js create mode 100644 src/theme/Admonition/Icon/Info.js create mode 100644 src/theme/Admonition/Icon/Note.js create mode 100644 src/theme/Admonition/Icon/Tip.js create mode 100644 src/theme/Admonition/Icon/Troubleshoot.js create mode 100644 src/theme/Admonition/Icon/Warning.js create mode 100644 src/theme/Admonition/Layout/index.js create mode 100644 src/theme/Admonition/Layout/styles.module.css create mode 100644 src/theme/Admonition/Type/Caution.js create mode 100644 src/theme/Admonition/Type/Danger.js create mode 100644 src/theme/Admonition/Type/Goal.js create mode 100644 src/theme/Admonition/Type/Info.js create mode 100644 src/theme/Admonition/Type/Note.js create mode 100644 src/theme/Admonition/Type/Tip.js create mode 100644 src/theme/Admonition/Type/Troubleshoot.js create mode 100644 src/theme/Admonition/Type/Warning.js create mode 100644 src/theme/Admonition/Types.js delete mode 100644 src/theme/Admonition/styles.module.css diff --git a/src/css/custom.css b/src/css/custom.css index 8d019167..29378e02 100755 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -537,4 +537,41 @@ html[data-theme="dark"] .dropdown-version .navbar__item--version:before { margin-left: 0.5rem; } +.alert--goal { + padding: 0; + background: var(--ifm-color-warning-contrast-background); + overflow: hidden; +} + +.alert--goal div:first-child { + padding: 0.75rem var(--ifm-alert-padding-horizontal); + background: var(--ifm-color-warning-dark); + line-height: 1; + color: var(--ifm-alert-foreground-color); +} + +.alert--goal div:last-child { + padding: var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal); +} + +.alert--goal svg { + stroke: currentColor !important; +} + +html[data-theme="dark"] .alert--goal div:first-child { + color: var(--ifm-background-color); +} + +.alert--troubleshoot { + --ifm-alert-background-color: var(--ifm-color-info-contrast-background); + --ifm-alert-background-color-highlight: rgba(84, 199, 236, 0.15); + --ifm-alert-foreground-color: var(--ifm-color-info-contrast-foreground); + --ifm-alert-border-color: var(--ifm-color-info-dark); +} + +.alert--troubleshoot svg { + fill: var(--ifm-alert-foreground-color); + stroke: none !important; +} + @tailwind utilities; diff --git a/src/theme/Admonition/Icon/Danger.js b/src/theme/Admonition/Icon/Danger.js new file mode 100644 index 00000000..ca249370 --- /dev/null +++ b/src/theme/Admonition/Icon/Danger.js @@ -0,0 +1,21 @@ +import React from "react"; +export default function AdmonitionIconDanger(props) { + return ( + + + + + ); +} diff --git a/src/theme/Admonition/Icon/Goal.js b/src/theme/Admonition/Icon/Goal.js new file mode 100644 index 00000000..048c2c7b --- /dev/null +++ b/src/theme/Admonition/Icon/Goal.js @@ -0,0 +1,25 @@ +import React from "react"; +export default function AdmonitionIconGoal(props) { + return ( + + + + + + + + + ); +} diff --git a/src/theme/Admonition/Icon/Info.js b/src/theme/Admonition/Icon/Info.js new file mode 100644 index 00000000..c4c5522c --- /dev/null +++ b/src/theme/Admonition/Icon/Info.js @@ -0,0 +1,23 @@ +import React from "react"; +export default function AdmonitionIconInfo(props) { + return ( + + + + + + + ); +} diff --git a/src/theme/Admonition/Icon/Note.js b/src/theme/Admonition/Icon/Note.js new file mode 100644 index 00000000..44108ba7 --- /dev/null +++ b/src/theme/Admonition/Icon/Note.js @@ -0,0 +1,23 @@ +import React from "react"; +export default function AdmonitionIconNote(props) { + return ( + + + + + ); +} diff --git a/src/theme/Admonition/Icon/Tip.js b/src/theme/Admonition/Icon/Tip.js new file mode 100644 index 00000000..c22586f0 --- /dev/null +++ b/src/theme/Admonition/Icon/Tip.js @@ -0,0 +1,22 @@ +import React from "react"; +export default function AdmonitionIconTip(props) { + return ( + + + + + + ); +} diff --git a/src/theme/Admonition/Icon/Troubleshoot.js b/src/theme/Admonition/Icon/Troubleshoot.js new file mode 100644 index 00000000..edcb4540 --- /dev/null +++ b/src/theme/Admonition/Icon/Troubleshoot.js @@ -0,0 +1,19 @@ +import React from "react"; +export default function AdmonitionIconTroubleshoot(props) { + return ( + + + + ); +} diff --git a/src/theme/Admonition/Icon/Warning.js b/src/theme/Admonition/Icon/Warning.js new file mode 100644 index 00000000..a4264abd --- /dev/null +++ b/src/theme/Admonition/Icon/Warning.js @@ -0,0 +1,32 @@ +import React from "react"; +export default function AdmonitionIconCaution(props) { + return ( + + + + + + ); +} diff --git a/src/theme/Admonition/Layout/index.js b/src/theme/Admonition/Layout/index.js new file mode 100644 index 00000000..074a1c54 --- /dev/null +++ b/src/theme/Admonition/Layout/index.js @@ -0,0 +1,39 @@ +import React from 'react'; +import clsx from 'clsx'; +import {ThemeClassNames} from '@docusaurus/theme-common'; +import styles from './styles.module.css'; +function AdmonitionContainer({type, className, children}) { + return ( +
+ {children} +
+ ); +} +function AdmonitionHeading({icon, title}) { + return ( +
+ {icon} + {title} +
+ ); +} +function AdmonitionContent({children}) { + return children ? ( +
{children}
+ ) : null; +} +export default function AdmonitionLayout(props) { + const {type, icon, title, children, className} = props; + return ( + + {title || icon ? : null} + {children} + + ); +} diff --git a/src/theme/Admonition/Layout/styles.module.css b/src/theme/Admonition/Layout/styles.module.css new file mode 100644 index 00000000..2d61d4f0 --- /dev/null +++ b/src/theme/Admonition/Layout/styles.module.css @@ -0,0 +1,67 @@ +.admonition { + margin-bottom: 1em; +} + +.admonitionHeading { + font: var(--ifm-heading-font-weight) var(--ifm-h5-font-size) / + var(--ifm-heading-line-height) var(--ifm-heading-font-family); + text-transform: uppercase; +} + +/* Heading alone without content (does not handle fragment content) */ +.admonitionHeading:not(:last-child) { + margin-bottom: 0.3rem; +} + +.admonitionHeading code { + text-transform: none; +} + +.admonitionIcon { + display: inline-block; + vertical-align: middle; + margin-right: 0.4em; +} + +.admonitionIcon svg { + display: inline-block; + height: 1.6em; + width: 1.6em; + stroke: var(--ifm-alert-foreground-color); +} + +.admonitionContent > :last-child { + margin-bottom: 0; +} + +.admonition { + margin-bottom: 2em; +} + +.admonitionHeading { + font: var(--ifm-heading-font-weight) var(--ifm-h5-font-size) / + var(--ifm-heading-line-height) var(--ifm-heading-font-family); + text-transform: uppercase; + margin-bottom: 0.3rem; +} + +.admonitionHeading code { + text-transform: none; +} + +.admonitionIcon { + display: inline-block; + vertical-align: middle; + margin-right: 0.4em; +} + +.admonitionIcon svg { + display: inline-block; + height: 1.25rem; + width: 1.25rem; + stroke-color: var(--ifm-alert-foreground-color); +} + +.admonitionContent > :last-child { + margin-bottom: 0; +} diff --git a/src/theme/Admonition/Type/Caution.js b/src/theme/Admonition/Type/Caution.js new file mode 100644 index 00000000..7890ef7c --- /dev/null +++ b/src/theme/Admonition/Type/Caution.js @@ -0,0 +1,28 @@ +import React from 'react'; +import clsx from 'clsx'; +import Translate from '@docusaurus/Translate'; +import AdmonitionLayout from '@theme/Admonition/Layout'; +import IconWarning from '@theme/Admonition/Icon/Warning'; +const infimaClassName = 'alert alert--warning'; +const defaultProps = { + icon: , + title: ( + + caution + + ), +}; +// TODO remove before v4: Caution replaced by Warning +// see https://github.com/facebook/docusaurus/issues/7558 +export default function AdmonitionTypeCaution(props) { + return ( + + {props.children} + + ); +} diff --git a/src/theme/Admonition/Type/Danger.js b/src/theme/Admonition/Type/Danger.js new file mode 100644 index 00000000..7a8eb840 --- /dev/null +++ b/src/theme/Admonition/Type/Danger.js @@ -0,0 +1,26 @@ +import React from 'react'; +import clsx from 'clsx'; +import Translate from '@docusaurus/Translate'; +import AdmonitionLayout from '@theme/Admonition/Layout'; +import IconDanger from '@theme/Admonition/Icon/Danger'; +const infimaClassName = 'alert alert--danger'; +const defaultProps = { + icon: , + title: ( + + danger + + ), +}; +export default function AdmonitionTypeDanger(props) { + return ( + + {props.children} + + ); +} diff --git a/src/theme/Admonition/Type/Goal.js b/src/theme/Admonition/Type/Goal.js new file mode 100644 index 00000000..79268beb --- /dev/null +++ b/src/theme/Admonition/Type/Goal.js @@ -0,0 +1,28 @@ +import React from "react"; +import clsx from "clsx"; +import Translate from "@docusaurus/Translate"; +import AdmonitionLayout from "@theme/Admonition/Layout"; +import IconGoal from "@theme/Admonition/Icon/Goal"; +const infimaClassName = "alert alert--goal"; +const defaultProps = { + icon: , + title: ( + + goal + + ), +}; +export default function AdmonitionTypeGoal(props) { + return ( + + {props.children} + + ); +} diff --git a/src/theme/Admonition/Type/Info.js b/src/theme/Admonition/Type/Info.js new file mode 100644 index 00000000..f0e9d2b6 --- /dev/null +++ b/src/theme/Admonition/Type/Info.js @@ -0,0 +1,26 @@ +import React from 'react'; +import clsx from 'clsx'; +import Translate from '@docusaurus/Translate'; +import AdmonitionLayout from '@theme/Admonition/Layout'; +import IconInfo from '@theme/Admonition/Icon/Info'; +const infimaClassName = 'alert alert--info'; +const defaultProps = { + icon: , + title: ( + + info + + ), +}; +export default function AdmonitionTypeInfo(props) { + return ( + + {props.children} + + ); +} diff --git a/src/theme/Admonition/Type/Note.js b/src/theme/Admonition/Type/Note.js new file mode 100644 index 00000000..6fb240dd --- /dev/null +++ b/src/theme/Admonition/Type/Note.js @@ -0,0 +1,28 @@ +import React from "react"; +import clsx from "clsx"; +import Translate from "@docusaurus/Translate"; +import AdmonitionLayout from "@theme/Admonition/Layout"; +import IconNote from "@theme/Admonition/Icon/Note"; +const infimaClassName = "alert alert--info"; +const defaultProps = { + icon: , + title: ( + + note + + ), +}; +export default function AdmonitionTypeNote(props) { + return ( + + {props.children} + + ); +} diff --git a/src/theme/Admonition/Type/Tip.js b/src/theme/Admonition/Type/Tip.js new file mode 100644 index 00000000..f31e4208 --- /dev/null +++ b/src/theme/Admonition/Type/Tip.js @@ -0,0 +1,26 @@ +import React from 'react'; +import clsx from 'clsx'; +import Translate from '@docusaurus/Translate'; +import AdmonitionLayout from '@theme/Admonition/Layout'; +import IconTip from '@theme/Admonition/Icon/Tip'; +const infimaClassName = 'alert alert--success'; +const defaultProps = { + icon: , + title: ( + + tip + + ), +}; +export default function AdmonitionTypeTip(props) { + return ( + + {props.children} + + ); +} diff --git a/src/theme/Admonition/Type/Troubleshoot.js b/src/theme/Admonition/Type/Troubleshoot.js new file mode 100644 index 00000000..4dfc3fce --- /dev/null +++ b/src/theme/Admonition/Type/Troubleshoot.js @@ -0,0 +1,30 @@ +import React from "react"; +import clsx from "clsx"; +import Translate from "@docusaurus/Translate"; +import AdmonitionLayout from "@theme/Admonition/Layout"; +import IconTroubleshoot from "@theme/Admonition/Icon/Troubleshoot"; +const infimaClassName = "alert alert--troubleshoot"; +const defaultProps = { + icon: , + title: ( + + troubleshoot + + ), +}; +// TODO remove before v4: Caution replaced by Warning +// see https://github.com/facebook/docusaurus/issues/7558 +export default function AdmonitionTypeTroubleshoot(props) { + return ( + + {props.children} + + ); +} diff --git a/src/theme/Admonition/Type/Warning.js b/src/theme/Admonition/Type/Warning.js new file mode 100644 index 00000000..b507d8d9 --- /dev/null +++ b/src/theme/Admonition/Type/Warning.js @@ -0,0 +1,26 @@ +import React from 'react'; +import clsx from 'clsx'; +import Translate from '@docusaurus/Translate'; +import AdmonitionLayout from '@theme/Admonition/Layout'; +import IconWarning from '@theme/Admonition/Icon/Warning'; +const infimaClassName = 'alert alert--warning'; +const defaultProps = { + icon: , + title: ( + + warning + + ), +}; +export default function AdmonitionTypeWarning(props) { + return ( + + {props.children} + + ); +} diff --git a/src/theme/Admonition/Types.js b/src/theme/Admonition/Types.js new file mode 100644 index 00000000..f5618dbb --- /dev/null +++ b/src/theme/Admonition/Types.js @@ -0,0 +1,34 @@ +import React from "react"; +import AdmonitionTypeNote from "@theme/Admonition/Type/Note"; +import AdmonitionTypeTip from "@theme/Admonition/Type/Tip"; +import AdmonitionTypeInfo from "@theme/Admonition/Type/Info"; +import AdmonitionTypeWarning from "@theme/Admonition/Type/Warning"; +import AdmonitionTypeDanger from "@theme/Admonition/Type/Danger"; +import AdmonitionTypeCaution from "@theme/Admonition/Type/Caution"; +import AdmonitionTypeTroubleshoot from "@theme/Admonition/Type/Troubleshoot"; +import AdmonitionTypeGoal from "@theme/Admonition/Type/Goal"; +const admonitionTypes = { + note: AdmonitionTypeNote, + tip: AdmonitionTypeTip, + info: AdmonitionTypeInfo, + warning: AdmonitionTypeWarning, + danger: AdmonitionTypeDanger, + troubleshoot: AdmonitionTypeCaution, + goal: AdmonitionTypeGoal, +}; +// Undocumented legacy admonition type aliases +// Provide hardcoded/untranslated retrocompatible label +// See also https://github.com/facebook/docusaurus/issues/7767 +const admonitionAliases = { + secondary: (props) => , + important: (props) => , + success: (props) => , + caution: AdmonitionTypeCaution, + troubleshoot: (props) => ( + + ), +}; +export default { + ...admonitionTypes, + ...admonitionAliases, +}; diff --git a/src/theme/Admonition/index.js b/src/theme/Admonition/index.js index b3c89ea4..a6ecab74 100644 --- a/src/theme/Admonition/index.js +++ b/src/theme/Admonition/index.js @@ -1,307 +1,18 @@ -import React from "react"; -import clsx from "clsx"; -import { ThemeClassNames } from "@docusaurus/theme-common"; -import Translate from "@docusaurus/Translate"; -import styles from "./styles.module.css"; -function NoteIcon() { - return ( - - - - - ); -} -function TroubleshootIcon() { - return ( - - - - ); -} -function TipIcon() { - return ( - - - - - - ); -} -function DangerIcon() { - return ( - - - - - ); -} -function InfoIcon() { - return ( - - - - - - - ); -} -function CautionIcon() { - return ( - - - - - - - ); -} -function GoalIcon() { - return ( - - - - - - - - - ); -} -// eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style -const AdmonitionConfigs = { - note: { - infimaClassName: "info", - iconComponent: NoteIcon, - label: ( - - note - - ), - }, - troubleshoot: { - infimaClassName: "info", - iconComponent: TroubleshootIcon, - label: ( - - troubleshoot - - ), - }, - tip: { - infimaClassName: "success", - iconComponent: TipIcon, - label: ( - - tip - - ), - }, - danger: { - infimaClassName: "danger", - iconComponent: DangerIcon, - label: ( - - danger - - ), - }, - info: { - infimaClassName: "info", - iconComponent: InfoIcon, - label: ( - - info - - ), - }, - caution: { - infimaClassName: "warning", - iconComponent: CautionIcon, - label: ( - - caution - - ), - }, - goal: { - infimaClassName: "goal", - iconComponent: GoalIcon, - label: ( - - Section Goal - - ), - }, -}; -// Legacy aliases, undocumented but kept for retro-compatibility -const aliases = { - secondary: "note", - important: "info", - success: "tip", - warning: "danger", -}; -function getAdmonitionConfig(unsafeType) { - const type = aliases[unsafeType] ?? unsafeType; - const config = AdmonitionConfigs[type]; - if (config) { - return config; +import React from 'react'; +import {processAdmonitionProps} from '@docusaurus/theme-common'; +import AdmonitionTypes from '@theme/Admonition/Types'; +function getAdmonitionTypeComponent(type) { + const component = AdmonitionTypes[type]; + if (component) { + return component; } console.warn( - `No admonition config found for admonition type "${type}". Using Info as fallback.` + `No admonition component found for admonition type "${type}". Using Info as fallback.`, ); - return AdmonitionConfigs.info; + return AdmonitionTypes.info; } -// Workaround because it's difficult in MDX v1 to provide a MDX title as props -// See https://github.com/facebook/docusaurus/pull/7152#issuecomment-1145779682 -function extractMDXAdmonitionTitle(children) { - const items = React.Children.toArray(children); - const mdxAdmonitionTitle = items.find( - (item) => - React.isValidElement(item) && item.props?.mdxType === "mdxAdmonitionTitle" - ); - const rest = <>{items.filter((item) => item !== mdxAdmonitionTitle)}; - return { - mdxAdmonitionTitle, - rest, - }; -} -function processAdmonitionProps(props) { - const { mdxAdmonitionTitle, rest } = extractMDXAdmonitionTitle( - props.children - ); - return { - ...props, - title: props.title ?? mdxAdmonitionTitle, - children: rest, - }; -} -export default function Admonition(props) { - const { - children, - type, - title, - icon: iconProp, - } = processAdmonitionProps(props); - const typeConfig = getAdmonitionConfig(type); - const titleLabel = title ?? typeConfig.label; - const { iconComponent: IconComponent } = typeConfig; - const icon = iconProp ?? ; - - return ( -
-
- {icon} - {titleLabel} -
-
{children}
-
- ); +export default function Admonition(unprocessedProps) { + const props = processAdmonitionProps(unprocessedProps); + const AdmonitionTypeComponent = getAdmonitionTypeComponent(props.type); + return ; } diff --git a/src/theme/Admonition/styles.module.css b/src/theme/Admonition/styles.module.css deleted file mode 100644 index 126a0488..00000000 --- a/src/theme/Admonition/styles.module.css +++ /dev/null @@ -1,53 +0,0 @@ -.admonition { - margin-bottom: 2em; -} - -.admonitionHeading { - font: var(--ifm-heading-font-weight) var(--ifm-h5-font-size) / - var(--ifm-heading-line-height) var(--ifm-heading-font-family); - text-transform: uppercase; - margin-bottom: 0.3rem; -} - -.admonitionHeading code { - text-transform: none; -} - -.admonitionIcon { - display: inline-block; - vertical-align: middle; - margin-right: 0.4em; -} - -.admonitionIcon svg { - display: inline-block; - height: 1.25rem; - width: 1.25rem; - stroke-color: var(--ifm-alert-foreground-color); -} - -.admonitionContent > :last-child { - margin-bottom: 0; -} - -/* Goal */ -.admonition-goal { - padding: 0; - background: var(--ifm-color-warning-contrast-background); - overflow: hidden; -} - -.admonition-goal .admonitionHeading { - padding: 0.75rem var(--ifm-alert-padding-horizontal); - background: var(--ifm-color-warning-dark); - line-height: 1; - color: var(--ifm-alert-foreground-color); -} - -html[data-theme="dark"] .admonition-goal .admonitionHeading { - color: var(--ifm-background-color); -} - -.admonition-goal .admonitionContent { - padding: var(--ifm-alert-padding-vertical) var(--ifm-alert-padding-horizontal); -} From 7bc5244d3697f600e697b29514d43c3f3413521d Mon Sep 17 00:00:00 2001 From: Joro Date: Mon, 2 Dec 2024 16:44:38 +0200 Subject: [PATCH 02/37] announcement bar --- .../CloseButton/styles.module.css | 1 + src/theme/AnnouncementBar/Content/index.js | 41 ++++++----- src/theme/AnnouncementBar/index.js | 68 ++++++------------- 3 files changed, 41 insertions(+), 69 deletions(-) diff --git a/src/theme/AnnouncementBar/CloseButton/styles.module.css b/src/theme/AnnouncementBar/CloseButton/styles.module.css index 0494ec0d..02d15534 100644 --- a/src/theme/AnnouncementBar/CloseButton/styles.module.css +++ b/src/theme/AnnouncementBar/CloseButton/styles.module.css @@ -1,4 +1,5 @@ .closeButton { padding: 0; line-height: 0; + color: currentColor; } diff --git a/src/theme/AnnouncementBar/Content/index.js b/src/theme/AnnouncementBar/Content/index.js index a776c5ca..a79a8ef5 100644 --- a/src/theme/AnnouncementBar/Content/index.js +++ b/src/theme/AnnouncementBar/Content/index.js @@ -1,4 +1,4 @@ -import React, { useEffect, useMemo, useState } from "react"; +import React, { useEffect, useState, useMemo } from "react"; import clsx from "clsx"; import { useThemeConfig } from "@docusaurus/theme-common"; import styles from "./styles.module.css"; @@ -18,6 +18,22 @@ const client = createPublicClient({ transport, }); +function formatNumber(num) { + const absNum = Math.abs(num); + + if (absNum >= 1000000000000) { + return (num / 1000000000000).toFixed(1) + "T"; + } else if (absNum >= 1000000000) { + return (num / 1000000000).toFixed(1) + "B"; + } else if (absNum >= 1000000) { + return (num / 1000000).toFixed(1) + "M"; + } else if (absNum >= 1000) { + return (num / 1000).toFixed(1) + "K"; + } else { + return num.toString(); + } +} + export default function AnnouncementBarContent(props) { const { announcementBar } = useThemeConfig(); const { content } = announcementBar; @@ -26,22 +42,6 @@ export default function AnnouncementBarContent(props) { const [dynamicContent, setDynamicContent] = useState(content); const [balanceLoaded, setBalanceLoaded] = useState(false); - function formatNumber(num) { - const absNum = Math.abs(num); - - if (absNum >= 1000000000000) { - return (num / 1000000000000).toFixed(1) + "T"; - } else if (absNum >= 1000000000) { - return (num / 1000000000).toFixed(1) + "B"; - } else if (absNum >= 1000000) { - return (num / 1000000).toFixed(1) + "M"; - } else if (absNum >= 1000) { - return (num / 1000).toFixed(1) + "K"; - } else { - return num.toString(); - } - } - // Fetch data for variables in the content const getBalance = async () => { if (typeof window === "undefined") { @@ -93,17 +93,16 @@ export default function AnnouncementBarContent(props) { } updateContent(); - }, [contentVars, balanceLoaded]); + console.log("Content Vars: ", contentVars); + }, [contentVars, balanceLoaded]); return (
); } diff --git a/src/theme/AnnouncementBar/index.js b/src/theme/AnnouncementBar/index.js index d7227a70..182d21e3 100644 --- a/src/theme/AnnouncementBar/index.js +++ b/src/theme/AnnouncementBar/index.js @@ -1,60 +1,32 @@ -import React, { useEffect, useMemo } from "react"; +import React from "react"; import { useThemeConfig } from "@docusaurus/theme-common"; import { useAnnouncementBar } from "@docusaurus/theme-common/internal"; import AnnouncementBarCloseButton from "@theme/AnnouncementBar/CloseButton"; import AnnouncementBarContent from "@theme/AnnouncementBar/Content"; -import { CookiesProvider, useCookies } from "react-cookie"; - import styles from "./styles.module.css"; + export default function AnnouncementBar() { const { announcementBar } = useThemeConfig(); const { isActive, close } = useAnnouncementBar(); - - const COOKIE_EXPIRY = 1000 * 60 * 60 * 24 * 2; - // const COOKIE_EXPIRY = 1000 * 10; - const COOKIE_NAME = "docusaurus.announcement.dismissExpiry"; - - const [cookies, setCookie] = useCookies([COOKIE_NAME]); - - const handleClose = () => { - setCookie(COOKIE_NAME, true, { - expires: new Date(Date.now() + COOKIE_EXPIRY), - }); - close(); - }; - - const cookieExpired = useMemo(() => { - return !cookies[COOKIE_NAME]; - }, [cookies]); - - const showAnnouncementBar = useMemo(() => { - return isActive ? isActive : cookieExpired; - }, [isActive, cookieExpired]); - - useEffect(() => { - if (!showAnnouncementBar) return; - document.documentElement.dataset.announcementBarInitiallyDismissed = false; - }, [showAnnouncementBar]); - + if (!isActive) { + return null; + } const { backgroundColor, textColor, isCloseable } = announcementBar; + return ( - - {showAnnouncementBar ? ( -
- {isCloseable &&
} - - {isCloseable && ( - - )} -
- ) : null} - +
+ {isCloseable &&
} + + {isCloseable && ( + + )} +
); } From a3761874882adaf42b428558ff54a758807b1d61 Mon Sep 17 00:00:00 2001 From: Joro Date: Mon, 2 Dec 2024 16:53:42 +0200 Subject: [PATCH 03/37] api item --- src/theme/ApiItem/Layout/index.js | 150 +++++++++++++------- src/theme/ApiItem/hooks.js | 7 + src/theme/ApiItem/index.js | 223 ++++++++++++++++++++++++++++++ src/theme/ApiItem/store.js | 47 +++++++ 4 files changed, 380 insertions(+), 47 deletions(-) create mode 100644 src/theme/ApiItem/hooks.js create mode 100644 src/theme/ApiItem/index.js create mode 100644 src/theme/ApiItem/store.js diff --git a/src/theme/ApiItem/Layout/index.js b/src/theme/ApiItem/Layout/index.js index d8d73baa..80c77d65 100644 --- a/src/theme/ApiItem/Layout/index.js +++ b/src/theme/ApiItem/Layout/index.js @@ -1,63 +1,119 @@ -import React from "react"; -import { useWindowSize } from "@docusaurus/theme-common"; -import { useDoc } from "@docusaurus/theme-common/internal"; -import DocBreadcrumbs from "@theme/DocBreadcrumbs"; -import DocItemContent from "@theme/DocItem/Content"; -import DocItemFooter from "@theme/DocItem/Footer"; -import DocItemPaginator from "@theme/DocItem/Paginator"; -import DocItemTOCDesktop from "@theme/DocItem/TOC/Desktop"; -import DocItemTOCMobile from "@theme/DocItem/TOC/Mobile"; -import DocVersionBanner from "@theme/DocVersionBanner"; -import clsx from "clsx"; -import styles from "./styles.module.css"; - +"use strict"; +var __importDefault = + (this && this.__importDefault) || + function (mod) { + return mod && mod.__esModule ? mod : { default: mod }; + }; +Object.defineProperty(exports, "__esModule", { value: true }); +const react_1 = __importDefault(require("react")); +const client_1 = require("@docusaurus/plugin-content-docs/client"); +const theme_common_1 = require("@docusaurus/theme-common"); +const ContentVisibility_1 = __importDefault( + require("@theme/ContentVisibility") +); +const DocBreadcrumbs_1 = __importDefault(require("@theme/DocBreadcrumbs")); +const Content_1 = __importDefault(require("@theme/DocItem/Content")); +const Footer_1 = __importDefault(require("@theme/DocItem/Footer")); +const Paginator_1 = __importDefault(require("@theme/DocItem/Paginator")); +const Desktop_1 = __importDefault(require("@theme/DocItem/TOC/Desktop")); +const Mobile_1 = __importDefault(require("@theme/DocItem/TOC/Mobile")); +const DocVersionBadge_1 = __importDefault(require("@theme/DocVersionBadge")); +const DocVersionBanner_1 = __importDefault(require("@theme/DocVersionBanner")); +const clsx_1 = __importDefault(require("clsx")); +const styles_module_css_1 = __importDefault(require("./styles.module.css")); /** * Decide if the toc should be rendered, on mobile or desktop viewports */ function useDocTOC() { - const { frontMatter, toc } = useDoc(); - const windowSize = useWindowSize(); + const { frontMatter, toc } = (0, client_1.useDoc)(); + const windowSize = (0, theme_common_1.useWindowSize)(); const hidden = frontMatter.hide_table_of_contents; const canRender = !hidden && toc.length > 0; - const mobile = canRender ? : undefined; + const mobile = canRender + ? react_1.default.createElement(Mobile_1.default, null) + : undefined; const desktop = - canRender && (windowSize === "desktop" || windowSize === "ssr") ? ( - - ) : undefined; + canRender && (windowSize === "desktop" || windowSize === "ssr") + ? react_1.default.createElement(Desktop_1.default, null) + : undefined; return { hidden, mobile, desktop, }; } -export default function DocItemLayout({ children }) { +function DocItemLayout({ children }) { const docTOC = useDocTOC(); - const { - frontMatter: { api }, - } = useDoc(); - return ( -
-
- -
-
- - {docTOC.mobile} - {children} -
- -
-
-
- -
-
-
- {docTOC.desktop && ( -
-
{docTOC.desktop}
-
- )} -
+ const { metadata } = (0, client_1.useDoc)(); + const { frontMatter } = (0, client_1.useDoc)(); + const api = frontMatter.api; + const schema = frontMatter.schema; + return react_1.default.createElement( + "div", + { className: "row" }, + react_1.default.createElement( + "div", + { + className: (0, clsx_1.default)( + "col", + !docTOC.hidden && styles_module_css_1.default.docItemCol + ), + }, + react_1.default.createElement(ContentVisibility_1.default, { + metadata: metadata, + }), + react_1.default.createElement(DocVersionBanner_1.default, null), + react_1.default.createElement( + "div", + { className: styles_module_css_1.default.docItemContainer }, + react_1.default.createElement( + "article", + null, + react_1.default.createElement(DocBreadcrumbs_1.default, null), + react_1.default.createElement(DocVersionBadge_1.default, null), + docTOC.mobile, + react_1.default.createElement(Content_1.default, null, children), + react_1.default.createElement( + "div", + { className: "row" }, + react_1.default.createElement( + "div", + { + className: (0, clsx_1.default)( + "col", + api || schema ? "col--7" : "col--12" + ), + }, + react_1.default.createElement(Footer_1.default, null) + ) + ) + ), + react_1.default.createElement( + "div", + { className: "row" }, + react_1.default.createElement( + "div", + { + className: (0, clsx_1.default)( + "col", + api || schema ? "col--7" : "col--12" + ), + }, + react_1.default.createElement(Paginator_1.default, null) + ) + ) + ) + ), + docTOC.desktop && + react_1.default.createElement( + "div", + { className: "col col--3" }, + react_1.default.createElement( + "div", + { className: "toc-column" }, + docTOC.desktop + ) + ) ); } +exports.default = DocItemLayout; diff --git a/src/theme/ApiItem/hooks.js b/src/theme/ApiItem/hooks.js new file mode 100644 index 00000000..0d97c9cc --- /dev/null +++ b/src/theme/ApiItem/hooks.js @@ -0,0 +1,7 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.useTypedSelector = exports.useTypedDispatch = void 0; +const react_redux_1 = require("react-redux"); +const useTypedDispatch = () => (0, react_redux_1.useDispatch)(); +exports.useTypedDispatch = useTypedDispatch; +exports.useTypedSelector = react_redux_1.useSelector; diff --git a/src/theme/ApiItem/index.js b/src/theme/ApiItem/index.js new file mode 100644 index 00000000..12049852 --- /dev/null +++ b/src/theme/ApiItem/index.js @@ -0,0 +1,223 @@ +"use strict"; +var __importDefault = + (this && this.__importDefault) || + function (mod) { + return mod && mod.__esModule ? mod : { default: mod }; + }; +Object.defineProperty(exports, "__esModule", { value: true }); +const zlib_1 = __importDefault(require("zlib")); +const react_1 = __importDefault(require("react")); +const BrowserOnly_1 = __importDefault(require("@docusaurus/BrowserOnly")); +const ExecutionEnvironment_1 = __importDefault( + require("@docusaurus/ExecutionEnvironment") +); +const client_1 = require("@docusaurus/plugin-content-docs/client"); +const theme_common_1 = require("@docusaurus/theme-common"); +const useDocusaurusContext_1 = __importDefault( + require("@docusaurus/useDocusaurusContext") +); +const useIsBrowser_1 = __importDefault(require("@docusaurus/useIsBrowser")); +const slice_1 = require("@theme/ApiExplorer/Authorization/slice"); +const persistanceMiddleware_1 = require("@theme/ApiExplorer/persistanceMiddleware"); +const Layout_1 = __importDefault(require("@theme/ApiItem/Layout")); +const CodeBlock_1 = __importDefault(require("@theme/CodeBlock")); +const Metadata_1 = __importDefault(require("@theme/DocItem/Metadata")); +const SkeletonLoader_1 = __importDefault(require("@theme/SkeletonLoader")); +const clsx_1 = __importDefault(require("clsx")); +const react_redux_1 = require("react-redux"); +const store_1 = require("./store"); +let ApiExplorer = (_) => react_1.default.createElement("div", null); +if (ExecutionEnvironment_1.default.canUseDOM) { + ApiExplorer = require("@theme/ApiExplorer").default; +} +// @ts-ignore +function ApiItem(props) { + const docHtmlClassName = `docs-doc-id-${props.content.metadata.id}`; + const MDXComponent = props.content; + const { frontMatter } = MDXComponent; + const { info_path: infoPath } = frontMatter; + let { api } = frontMatter; + const { schema } = frontMatter; + const { sample } = frontMatter; + // decompress and parse + if (api) { + try { + api = JSON.parse( + zlib_1.default.inflateSync(Buffer.from(api, "base64")).toString() + ); + } catch {} + } + const { siteConfig } = (0, useDocusaurusContext_1.default)(); + const themeConfig = siteConfig.themeConfig; + const options = themeConfig.api; + const isBrowser = (0, useIsBrowser_1.default)(); + // Regex for 2XX status + const statusRegex = new RegExp("(20[0-9]|2[1-9][0-9])"); + // Define store2 + let store2 = {}; + const persistanceMiddleware = (0, + persistanceMiddleware_1.createPersistanceMiddleware)(options); + // Init store for SSR + if (!isBrowser) { + store2 = (0, store_1.createStoreWithoutState)({}, [persistanceMiddleware]); + } + // Init store for CSR to hydrate components + if (isBrowser) { + // Create list of only 2XX response content types to create request samples from + let acceptArray = []; + for (const [code, content] of Object.entries(api?.responses ?? [])) { + if (statusRegex.test(code)) { + acceptArray.push(Object.keys(content.content ?? {})); + } + } + acceptArray = acceptArray.flat(); + const content = api?.requestBody?.content ?? {}; + const contentTypeArray = Object.keys(content); + const servers = api?.servers ?? []; + const params = { + path: [], + query: [], + header: [], + cookie: [], + }; + api?.parameters?.forEach((param) => { + const paramType = param.in; + const paramsArray = params[paramType]; + paramsArray.push(param); + }); + const auth = (0, slice_1.createAuth)({ + security: api?.security, + securitySchemes: api?.securitySchemes, + options, + }); + // TODO: determine way to rehydrate without flashing + // const acceptValue = window?.sessionStorage.getItem("accept"); + // const contentTypeValue = window?.sessionStorage.getItem("contentType"); + const server = window?.sessionStorage.getItem("server"); + const serverObject = JSON.parse(server) ?? {}; + store2 = (0, store_1.createStoreWithState)( + { + accept: { + value: acceptArray[0], + options: acceptArray, + }, + contentType: { + value: contentTypeArray[0], + options: contentTypeArray, + }, + server: { + value: serverObject.url ? serverObject : undefined, + options: servers, + }, + response: { value: undefined }, + body: { type: "empty" }, + params, + auth, + }, + [persistanceMiddleware] + ); + } + if (api) { + return react_1.default.createElement( + client_1.DocProvider, + { content: props.content }, + react_1.default.createElement( + theme_common_1.HtmlClassNameProvider, + { className: docHtmlClassName }, + react_1.default.createElement(Metadata_1.default, null), + react_1.default.createElement( + Layout_1.default, + null, + react_1.default.createElement( + react_redux_1.Provider, + { store: store2 }, + react_1.default.createElement( + "div", + { className: (0, clsx_1.default)("row", "theme-api-markdown") }, + react_1.default.createElement( + "div", + { className: "col col--7 openapi-left-panel__container" }, + react_1.default.createElement(MDXComponent, null) + ), + react_1.default.createElement( + "div", + { className: "col col--5 openapi-right-panel__container" }, + react_1.default.createElement( + BrowserOnly_1.default, + { + fallback: react_1.default.createElement( + SkeletonLoader_1.default, + { size: "lg" } + ), + }, + () => { + return react_1.default.createElement(ApiExplorer, { + item: api, + infoPath: infoPath, + }); + } + ) + ) + ) + ) + ) + ) + ); + } else if (schema) { + return react_1.default.createElement( + client_1.DocProvider, + { content: props.content }, + react_1.default.createElement( + theme_common_1.HtmlClassNameProvider, + { className: docHtmlClassName }, + react_1.default.createElement(Metadata_1.default, null), + react_1.default.createElement( + Layout_1.default, + null, + react_1.default.createElement( + "div", + { className: (0, clsx_1.default)("row", "theme-api-markdown") }, + react_1.default.createElement( + "div", + { className: "col col--7 openapi-left-panel__container schema" }, + react_1.default.createElement(MDXComponent, null) + ), + react_1.default.createElement( + "div", + { className: "col col--5 openapi-right-panel__container" }, + react_1.default.createElement( + CodeBlock_1.default, + { language: "json", title: `${frontMatter.title}` }, + JSON.stringify(sample, null, 2) + ) + ) + ) + ) + ) + ); + } + // Non-API docs + return react_1.default.createElement( + client_1.DocProvider, + { content: props.content }, + react_1.default.createElement( + theme_common_1.HtmlClassNameProvider, + { className: docHtmlClassName }, + react_1.default.createElement(Metadata_1.default, null), + react_1.default.createElement( + Layout_1.default, + null, + react_1.default.createElement( + "div", + { className: "row" }, + react_1.default.createElement( + "div", + { className: "col col--12 markdown" }, + react_1.default.createElement(MDXComponent, null) + ) + ) + ) + ) + ); +} +exports.default = ApiItem; diff --git a/src/theme/ApiItem/store.js b/src/theme/ApiItem/store.js new file mode 100644 index 00000000..747b2fdb --- /dev/null +++ b/src/theme/ApiItem/store.js @@ -0,0 +1,47 @@ +"use strict"; +var __importDefault = + (this && this.__importDefault) || + function (mod) { + return mod && mod.__esModule ? mod : { default: mod }; + }; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.createStoreWithoutState = exports.createStoreWithState = void 0; +const toolkit_1 = require("@reduxjs/toolkit"); +const slice_1 = __importDefault(require("@theme/ApiExplorer/Accept/slice")); +const slice_2 = __importDefault( + require("@theme/ApiExplorer/Authorization/slice") +); +const slice_3 = __importDefault(require("@theme/ApiExplorer/Body/slice")); +const slice_4 = __importDefault( + require("@theme/ApiExplorer/ContentType/slice") +); +const slice_5 = __importDefault( + require("@theme/ApiExplorer/ParamOptions/slice") +); +const slice_6 = __importDefault(require("@theme/ApiExplorer/Response/slice")); +const slice_7 = __importDefault(require("@theme/ApiExplorer/Server/slice")); +const rootReducer = (0, toolkit_1.combineReducers)({ + accept: slice_1.default, + contentType: slice_4.default, + response: slice_6.default, + server: slice_7.default, + body: slice_3.default, + params: slice_5.default, + auth: slice_2.default, +}); +const createStoreWithState = (preloadedState, middlewares) => + (0, toolkit_1.configureStore)({ + reducer: rootReducer, + preloadedState, + middleware: (getDefaultMiddleware) => + getDefaultMiddleware().concat(...middlewares), + }); +exports.createStoreWithState = createStoreWithState; +const createStoreWithoutState = (preloadedState, middlewares) => + (0, toolkit_1.configureStore)({ + reducer: rootReducer, + preloadedState, + middleware: (getDefaultMiddleware) => + getDefaultMiddleware().concat(...middlewares), + }); +exports.createStoreWithoutState = createStoreWithoutState; From d9d3cd3352b5977be25feefafb977708e77bb611 Mon Sep 17 00:00:00 2001 From: Joro Date: Mon, 2 Dec 2024 16:54:58 +0200 Subject: [PATCH 04/37] api tabs --- src/theme/ApiTabs/_ApiTabs.scss | 136 +++++++++++++++++ src/theme/ApiTabs/index.js | 250 ++++++++++++++++++++++++++++++++ 2 files changed, 386 insertions(+) create mode 100644 src/theme/ApiTabs/_ApiTabs.scss create mode 100644 src/theme/ApiTabs/index.js diff --git a/src/theme/ApiTabs/_ApiTabs.scss b/src/theme/ApiTabs/_ApiTabs.scss new file mode 100644 index 00000000..801c2fe7 --- /dev/null +++ b/src/theme/ApiTabs/_ApiTabs.scss @@ -0,0 +1,136 @@ +.openapi-tabs__container { + margin-left: -1px; +} + +.openapi-tabs__response-header { + &.openapi-tabs__heading { + margin-bottom: 0; + } +} + +.openapi-tabs__response-code-item { + border: 1px solid transparent; + margin-top: 0 !important; + margin-right: 0.5rem; + padding: 0.35rem 0.85rem; + border-radius: var(--ifm-global-radius); + font-weight: var(--ifm-font-weight-bold); + font-size: 12px; + transition: 300ms; + color: var(--ifm-font-color-secondary); + + &.success.active { + background-color: var(--ifm-color-success); + color: var(--ifm-color-white); + } + + &.danger.active { + background-color: var(--ifm-color-danger); + color: var(--ifm-color-white); + } + + &.info.active { + background-color: var(--ifm-color-info); + color: var(--ifm-color-white); + } + + &.active, + &:hover { + opacity: 1; + } + + &:hover:not(.active) { + background-color: transparent; + border: 1px solid var(--ifm-toc-border-color); + } +} + +.openapi-tabs__response-code-item:not(.active) { + opacity: 0.65; +} + +.openapi-tabs__response-code-item:hover { + opacity: 1; +} + +.openapi-tabs__response-code-item:last-child { + margin-right: 0 !important; +} + +/* Open API Response Code Tabs */ +.openapi-tabs__response-header-section { + border-top: 1px solid var(--ifm-toc-border-color); + margin-top: 2rem; + padding-top: 2rem; + display: flex; + justify-content: space-between; + align-items: center; +} + +.openapi-tabs__response-container { + display: flex; + align-items: center; + max-width: 390px; + padding-left: 1rem; + overflow: hidden; +} + +.openapi-tabs__response-list-container { + padding: 0 0.25rem; + overflow-y: hidden; + overflow-x: scroll; + scroll-behavior: smooth; + scrollbar-width: none; +} + +.openapi-tabs__response-list-container::-webkit-scrollbar { + display: none; +} + +/* Response Code Tabs - Colored Dots */ +.openapi-tabs__response-dot { + width: 12.5px; + height: 12.5px; + margin-right: 5px; + border-radius: 50%; +} + +.openapi-tabs__response-schema-container { + max-width: 600px; +} + +/* Tab Arrows */ +.openapi-tabs__arrow { + content: ""; + height: 1.25rem; + width: 1.25rem; + border: none; + min-width: 1.25rem; + background: var(--ifm-menu-link-sublist-icon) 50% / 2rem 2rem; + filter: var(--ifm-menu-link-sublist-icon-filter); + + &:hover { + cursor: pointer; + } + + &.left { + transform: rotate(270deg); + } + + &.right { + transform: rotate(90deg); + } +} + +@media screen and (max-width: 500px) { + .openapi-tabs__response-header-section { + flex-direction: column; + align-items: flex-start; + } + + .openapi-tabs__response-container { + width: 100%; + margin-top: var(--ifm-spacing-vertical); + padding: 0; + } +} diff --git a/src/theme/ApiTabs/index.js b/src/theme/ApiTabs/index.js new file mode 100644 index 00000000..71297c9d --- /dev/null +++ b/src/theme/ApiTabs/index.js @@ -0,0 +1,250 @@ +"use strict"; +var __createBinding = + (this && this.__createBinding) || + (Object.create + ? function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if ( + !desc || + ("get" in desc ? !m.__esModule : desc.writable || desc.configurable) + ) { + desc = { + enumerable: true, + get: function () { + return m[k]; + }, + }; + } + Object.defineProperty(o, k2, desc); + } + : function (o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); +var __setModuleDefault = + (this && this.__setModuleDefault) || + (Object.create + ? function (o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); + } + : function (o, v) { + o["default"] = v; + }); +var __importStar = + (this && this.__importStar) || + function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) + for (var k in mod) + if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) + __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; + }; +var __importDefault = + (this && this.__importDefault) || + function (mod) { + return mod && mod.__esModule ? mod : { default: mod }; + }; +Object.defineProperty(exports, "__esModule", { value: true }); +const react_1 = __importStar(require("react")); +const internal_1 = require("@docusaurus/theme-common/internal"); +const useIsBrowser_1 = __importDefault(require("@docusaurus/useIsBrowser")); +const Heading_1 = __importDefault(require("@theme/Heading")); +const clsx_1 = __importDefault(require("clsx")); +function TabList({ + className, + block, + selectedValue, + selectValue, + tabValues, + label = "Responses", + id = "responses", +}) { + const tabRefs = []; + const { blockElementScrollPositionUntilNextRender } = (0, + internal_1.useScrollPositionBlocker)(); + const handleTabChange = (event) => { + const newTab = event.currentTarget; + const newTabIndex = tabRefs.indexOf(newTab); + const newTabValue = tabValues[newTabIndex].value; + if (newTabValue !== selectedValue) { + blockElementScrollPositionUntilNextRender(newTab); + selectValue(newTabValue); + } + }; + const handleKeydown = (event) => { + let focusElement = null; + switch (event.key) { + case "Enter": { + handleTabChange(event); + break; + } + case "ArrowRight": { + const nextTab = tabRefs.indexOf(event.currentTarget) + 1; + focusElement = tabRefs[nextTab] ?? tabRefs[0]; + break; + } + case "ArrowLeft": { + const prevTab = tabRefs.indexOf(event.currentTarget) - 1; + focusElement = tabRefs[prevTab] ?? tabRefs[tabRefs.length - 1]; + break; + } + default: + break; + } + focusElement?.focus(); + }; + const tabItemListContainerRef = (0, react_1.useRef)(null); + const [showTabArrows, setShowTabArrows] = (0, react_1.useState)(false); + (0, react_1.useEffect)(() => { + const resizeObserver = new ResizeObserver((entries) => { + for (let entry of entries) { + requestAnimationFrame(() => { + if (entry.target.clientWidth < entry.target.scrollWidth) { + setShowTabArrows(true); + } else { + setShowTabArrows(false); + } + }); + } + }); + resizeObserver.observe(tabItemListContainerRef.current); + return () => { + resizeObserver.disconnect(); + }; + }, []); + const handleRightClick = () => { + tabItemListContainerRef.current.scrollLeft += 90; + }; + const handleLeftClick = () => { + tabItemListContainerRef.current.scrollLeft -= 90; + }; + return react_1.default.createElement( + "div", + { className: "openapi-tabs__response-header-section" }, + react_1.default.createElement( + Heading_1.default, + { + as: "h2", + id: id, + className: "openapi-tabs__heading openapi-tabs__response-header", + }, + label + ), + react_1.default.createElement( + "div", + { className: "openapi-tabs__response-container" }, + showTabArrows && + react_1.default.createElement("button", { + className: "openapi-tabs__arrow left", + onClick: handleLeftClick, + }), + react_1.default.createElement( + "ul", + { + ref: tabItemListContainerRef, + role: "tablist", + "aria-orientation": "horizontal", + className: (0, clsx_1.default)( + "openapi-tabs__response-list-container", + "tabs", + { + "tabs--block": block, + }, + className + ), + }, + tabValues.map(({ value, label, attributes }) => + react_1.default.createElement( + "li", + { + // TODO extract TabListItem + role: "tab", + tabIndex: selectedValue === value ? 0 : -1, + "aria-selected": selectedValue === value, + key: value, + ref: (tabControl) => tabRefs.push(tabControl), + onKeyDown: handleKeydown, + onClick: handleTabChange, + ...attributes, + className: (0, clsx_1.default)( + "tabs__item", + "openapi-tabs__response-code-item", + attributes?.className, + parseInt(value) >= 400 + ? "danger" + : parseInt(value) >= 200 && parseInt(value) < 300 + ? "success" + : "info", + { + active: selectedValue === value, + } + ), + }, + label ?? value + ) + ) + ), + showTabArrows && + react_1.default.createElement("button", { + className: "openapi-tabs__arrow right", + onClick: handleRightClick, + }) + ) + ); +} +function TabContent({ lazy, children, selectedValue }) { + const childTabs = (Array.isArray(children) ? children : [children]).filter( + Boolean + ); + if (lazy) { + const selectedTabItem = childTabs.find( + (tabItem) => tabItem.props.value === selectedValue + ); + if (!selectedTabItem) { + // fail-safe or fail-fast? not sure what's best here + return null; + } + return (0, react_1.cloneElement)(selectedTabItem, { + className: "margin-top--md", + }); + } + return react_1.default.createElement( + "div", + { className: "margin-top--md" }, + childTabs.map((tabItem, i) => + (0, react_1.cloneElement)(tabItem, { + key: i, + hidden: tabItem.props.value !== selectedValue, + }) + ) + ); +} +function TabsComponent(props) { + const tabs = (0, internal_1.useTabs)(props); + return react_1.default.createElement( + "div", + { className: "openapi-tabs__container" }, + react_1.default.createElement(TabList, { ...props, ...tabs }), + react_1.default.createElement(TabContent, { ...props, ...tabs }) + ); +} +function ApiTabs(props) { + const isBrowser = (0, useIsBrowser_1.default)(); + return react_1.default.createElement( + TabsComponent, + // Remount tabs after hydration + // Temporary fix for https://github.com/facebook/docusaurus/issues/5653 + { + // Remount tabs after hydration + // Temporary fix for https://github.com/facebook/docusaurus/issues/5653 + key: String(isBrowser), + ...props, + }, + (0, internal_1.sanitizeTabsChildren)(props.children) + ); +} +exports.default = ApiTabs; From 9587157c44e193a2cadf28454d3382c8456ea101 Mon Sep 17 00:00:00 2001 From: Joro Date: Mon, 2 Dec 2024 16:56:17 +0200 Subject: [PATCH 05/37] code block --- src/theme/CodeBlock/Content/String.js | 24 +++++++++++-------- src/theme/CodeBlock/Content/styles.module.css | 2 +- src/theme/CodeBlock/CopyButton/index.js | 1 - src/theme/CodeBlock/Line/index.js | 2 +- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/theme/CodeBlock/Content/String.js b/src/theme/CodeBlock/Content/String.js index b54aa192..57b1c510 100644 --- a/src/theme/CodeBlock/Content/String.js +++ b/src/theme/CodeBlock/Content/String.js @@ -8,12 +8,18 @@ import { containsLineNumbers, useCodeWordWrap, } from '@docusaurus/theme-common/internal'; -import Highlight, {defaultProps} from 'prism-react-renderer'; +import {Highlight} from 'prism-react-renderer'; import Line from '@theme/CodeBlock/Line'; import CopyButton from '@theme/CodeBlock/CopyButton'; import WordWrapButton from '@theme/CodeBlock/WordWrapButton'; import Container from '@theme/CodeBlock/Container'; import styles from './styles.module.css'; +// Prism languages are always lowercase +// We want to fail-safe and allow both "php" and "PHP" +// See https://github.com/facebook/docusaurus/issues/9012 +function normalizeLanguage(language) { + return language?.toLowerCase(); +} export default function CodeBlockString({ children, className: blockClassName = '', @@ -25,8 +31,9 @@ export default function CodeBlockString({ const { prism: {defaultLanguage, magicComments}, } = useThemeConfig(); - const language = - languageProp ?? parseLanguage(blockClassName) ?? defaultLanguage; + const language = normalizeLanguage( + languageProp ?? parseLanguage(blockClassName) ?? defaultLanguage, + ); const prismTheme = usePrismTheme(); const wordWrap = useCodeWordWrap(); // We still parse the metastring in case we want to support more syntax in the @@ -51,17 +58,14 @@ export default function CodeBlockString({ )}> {title &&
{title}
}
- - {({className, tokens, getLineProps, getTokenProps}) => ( + + {({className, style, tokens, getLineProps, getTokenProps}) => (
+              className={clsx(className, styles.codeBlock, 'thin-scrollbar')}
+              style={style}>
                (
-    
+    
   ));
   return (
     

From 98f4df583a250af6e024f34890c5f2a25cf03a4b Mon Sep 17 00:00:00 2001
From: Joro 
Date: Mon, 2 Dec 2024 17:03:48 +0200
Subject: [PATCH 06/37] doc breadcrumbs

---
 src/theme/DocBreadcrumbs/index.js | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/src/theme/DocBreadcrumbs/index.js b/src/theme/DocBreadcrumbs/index.js
index 0f5cfd6c..10d5c114 100644
--- a/src/theme/DocBreadcrumbs/index.js
+++ b/src/theme/DocBreadcrumbs/index.js
@@ -1,10 +1,8 @@
 import React from "react";
 import clsx from "clsx";
 import { ThemeClassNames } from "@docusaurus/theme-common";
-import {
-  useSidebarBreadcrumbs,
-  useHomePageRoute,
-} from "@docusaurus/theme-common/internal";
+import { useSidebarBreadcrumbs } from "@docusaurus/plugin-content-docs/client";
+import { useHomePageRoute } from "@docusaurus/theme-common/internal";
 import Link from "@docusaurus/Link";
 import { translate } from "@docusaurus/Translate";
 import HomeBreadcrumbItem from "@theme/DocBreadcrumbs/Items/Home";
@@ -52,8 +50,8 @@ function BreadcrumbsItem({ children, active, index, addMicrodata }) {
 }
 export default function DocBreadcrumbs() {
   const breadcrumbs = useSidebarBreadcrumbs();
-  // const homePageRoute = useHomePageRoute();
-  if (!breadcrumbs || breadcrumbs.length === 1) {
+  const homePageRoute = useHomePageRoute();
+  if (!breadcrumbs) {
     return null;
   }
   return (
@@ -76,14 +74,18 @@ export default function DocBreadcrumbs() {
         {/* {homePageRoute && } */}
         {breadcrumbs.map((item, idx) => {
           const isLast = idx === breadcrumbs.length - 1;
+          const href =
+            item.type === "category" && item.linkUnlisted
+              ? undefined
+              : item.href;
           return (
             
-              
+              
                 {item.label}
               
             

From 44436daaf25e79a64fcbf035c2677035b531b6a0 Mon Sep 17 00:00:00 2001
From: Joro 
Date: Mon, 2 Dec 2024 17:08:55 +0200
Subject: [PATCH 07/37] doc card

---
 src/theme/DocCard/index.js          | 51 ++++++++++++++++++++---------
 src/theme/DocCard/styles.module.css |  1 -
 2 files changed, 35 insertions(+), 17 deletions(-)

diff --git a/src/theme/DocCard/index.js b/src/theme/DocCard/index.js
index 7a67e6f2..86d8b5b2 100644
--- a/src/theme/DocCard/index.js
+++ b/src/theme/DocCard/index.js
@@ -2,12 +2,30 @@ import React from "react";
 import clsx from "clsx";
 import Link from "@docusaurus/Link";
 import {
-  findFirstCategoryLink,
   useDocById,
-} from "@docusaurus/theme-common/internal";
+  findFirstSidebarItemLink,
+} from "@docusaurus/plugin-content-docs/client";
+import { usePluralForm } from "@docusaurus/theme-common";
 import isInternalUrl from "@docusaurus/isInternalUrl";
 import { translate } from "@docusaurus/Translate";
+import Heading from "@theme/Heading";
 import styles from "./styles.module.css";
+function useCategoryItemsPlural() {
+  const { selectMessage } = usePluralForm();
+  return (count) =>
+    selectMessage(
+      count,
+      translate(
+        {
+          message: "1 item|{count} items",
+          id: "theme.docs.DocCard.categoryDescription.plurals",
+          description:
+            "The default description for a category card in the generated index about how many items this category includes",
+        },
+        { count }
+      )
+    );
+}
 function CardContainer({ href, children }) {
   return (
     
   );
 }
-function CardLayout({ href, title, description }) {
+function CardLayout({ href, icon, title, description }) {
   return (
     
-      

+ + {/* {icon} */} {title} -

+ {description && (

); } function CardLink({ item }) { + const icon = isInternalUrl(item.href) ? "📄️" : "🔗"; const doc = useDocById(item.docId ?? undefined); return ( ); } diff --git a/src/theme/DocCard/styles.module.css b/src/theme/DocCard/styles.module.css index 94e8f513..4f7ad27f 100644 --- a/src/theme/DocCard/styles.module.css +++ b/src/theme/DocCard/styles.module.css @@ -20,7 +20,6 @@ .cardTitle { font-size: 1.2rem; - color: var(--ifm-color-emphasis-900); } .cardDescription { From bd9009b0ec403a6ae25826ae5b374af59aa9dc23 Mon Sep 17 00:00:00 2001 From: Joro Date: Mon, 2 Dec 2024 17:12:15 +0200 Subject: [PATCH 08/37] doc generated index --- src/theme/DocCategoryGeneratedIndexPage/index.js | 11 +++++------ .../DocCategoryGeneratedIndexPage/styles.module.css | 1 + 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/theme/DocCategoryGeneratedIndexPage/index.js b/src/theme/DocCategoryGeneratedIndexPage/index.js index 442fa541..47a64a35 100644 --- a/src/theme/DocCategoryGeneratedIndexPage/index.js +++ b/src/theme/DocCategoryGeneratedIndexPage/index.js @@ -1,13 +1,11 @@ import React from "react"; -import clsx from "clsx"; -import { - PageMetadata, - useCurrentSidebarCategory, -} from "@docusaurus/theme-common"; +import { PageMetadata } from "@docusaurus/theme-common"; +import { useCurrentSidebarCategory } from "@docusaurus/plugin-content-docs/client"; import useBaseUrl from "@docusaurus/useBaseUrl"; import DocCardList from "@theme/DocCardList"; import DocPaginator from "@theme/DocPaginator"; import DocVersionBanner from "@theme/DocVersionBanner"; +import DocVersionBadge from "@theme/DocVersionBadge"; import DocBreadcrumbs from "@theme/DocBreadcrumbs"; import Heading from "@theme/Heading"; import styles from "./styles.module.css"; @@ -28,6 +26,7 @@ function DocCategoryGeneratedIndexPageContent({ categoryGeneratedIndex }) {

+ {/* */}
{categoryGeneratedIndex.title} @@ -36,7 +35,7 @@ function DocCategoryGeneratedIndexPageContent({ categoryGeneratedIndex }) {

{categoryGeneratedIndex.description}

)}
-
+