diff --git a/packages/docusaurus-playground/src/theme/Admonition/index.js b/packages/docusaurus-playground/src/theme/Admonition/index.js
new file mode 100644
index 0000000..cc4218e
--- /dev/null
+++ b/packages/docusaurus-playground/src/theme/Admonition/index.js
@@ -0,0 +1,188 @@
+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 TipIcon() {
+ return (
+
+ )
+}
+function DangerIcon() {
+ return (
+
+ )
+}
+function InfoIcon() {
+ return (
+
+ )
+}
+function CautionIcon() {
+ return (
+
+ )
+}
+// eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style
+const AdmonitionConfigs = {
+ note: {
+ infimaClassName: 'secondary',
+ iconComponent: NoteIcon,
+ label: (
+
tags in markdown map to CodeBlocks. They may contain JSX children. When
+// the children is not a simple string, we just return a styled block without
+// actually highlighting.
+export default function CodeBlockJSX({ children, className }) {
+ return (
+
+ {children}
+
+ )
+}
diff --git a/packages/docusaurus-playground/src/theme/CodeBlock/Content/String.js b/packages/docusaurus-playground/src/theme/CodeBlock/Content/String.js
new file mode 100644
index 0000000..420a492
--- /dev/null
+++ b/packages/docusaurus-playground/src/theme/CodeBlock/Content/String.js
@@ -0,0 +1,100 @@
+import React from 'react'
+import clsx from 'clsx'
+import { useThemeConfig, usePrismTheme } from '@docusaurus/theme-common'
+import {
+ parseCodeBlockTitle,
+ parseLanguage,
+ parseLines,
+ containsLineNumbers,
+ useCodeWordWrap,
+} from '@docusaurus/theme-common/internal'
+import Highlight, { defaultProps } 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'
+export default function CodeBlockString({
+ children,
+ className: blockClassName = '',
+ metastring,
+ title: titleProp,
+ showLineNumbers: showLineNumbersProp,
+ language: languageProp,
+}) {
+ const {
+ prism: { defaultLanguage, magicComments },
+ } = useThemeConfig()
+ const language =
+ 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
+ // future. Note that MDX doesn't strip quotes when parsing metastring:
+ // "title=\"xyz\"" => title: "\"xyz\""
+ const title = parseCodeBlockTitle(metastring) || titleProp
+ const { lineClassNames, code } = parseLines(children, {
+ metastring,
+ language,
+ magicComments,
+ })
+ const showLineNumbers = showLineNumbersProp ?? containsLineNumbers(metastring)
+ return (
+
+ {title && {title}}
+
+
+ {({ className, tokens, getLineProps, getTokenProps }) => (
+
+
+ {tokens.map((line, i) => (
+
+ ))}
+
+
+ )}
+
+
+ {(wordWrap.isEnabled || wordWrap.isCodeScrollable) && (
+ wordWrap.toggle()}
+ isEnabled={wordWrap.isEnabled}
+ />
+ )}
+
+
+
+
+ )
+}
diff --git a/packages/docusaurus-playground/src/theme/CodeBlock/Content/styles.module.css b/packages/docusaurus-playground/src/theme/CodeBlock/Content/styles.module.css
new file mode 100644
index 0000000..c2103cd
--- /dev/null
+++ b/packages/docusaurus-playground/src/theme/CodeBlock/Content/styles.module.css
@@ -0,0 +1,80 @@
+.codeBlockContent {
+ position: relative;
+ /* rtl:ignore */
+ direction: ltr;
+ border-radius: inherit;
+}
+
+.codeBlockTitle {
+ border-bottom: 1px solid var(--ifm-color-emphasis-300);
+ font-size: var(--ifm-code-font-size);
+ font-weight: 500;
+ padding: 0.75rem var(--ifm-pre-padding);
+ border-top-left-radius: inherit;
+ border-top-right-radius: inherit;
+}
+
+.codeBlock {
+ --ifm-pre-background: var(--prism-background-color);
+ margin: 0;
+ padding: 0;
+}
+
+.codeBlockTitle + .codeBlockContent .codeBlock {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+}
+
+.codeBlockStandalone {
+ padding: 0;
+}
+
+.codeBlockLines {
+ font: inherit;
+ /* rtl:ignore */
+ float: left;
+ min-width: 100%;
+ padding: var(--ifm-pre-padding);
+}
+
+.codeBlockLinesWithNumbering {
+ display: table;
+ padding: var(--ifm-pre-padding) 0;
+}
+
+@media print {
+ .codeBlockLines {
+ white-space: pre-wrap;
+ }
+}
+
+.buttonGroup {
+ display: flex;
+ column-gap: 0.2rem;
+ position: absolute;
+ /* rtl:ignore */
+ right: calc(var(--ifm-pre-padding) / 2);
+ top: calc(var(--ifm-pre-padding) / 2);
+}
+
+.buttonGroup button {
+ display: flex;
+ align-items: center;
+ background: var(--prism-background-color);
+ color: var(--prism-color);
+ border: 1px solid var(--ifm-color-emphasis-300);
+ border-radius: var(--ifm-global-radius);
+ padding: 0.4rem;
+ line-height: 0;
+ transition: opacity var(--ifm-transition-fast) ease-in-out;
+ opacity: 0;
+}
+
+.buttonGroup button:focus-visible,
+.buttonGroup button:hover {
+ opacity: 1 !important;
+}
+
+:global(.theme-code-block:hover) .buttonGroup button {
+ opacity: 0.4;
+}
diff --git a/packages/docusaurus-playground/src/theme/CodeBlock/CopyButton/index.js b/packages/docusaurus-playground/src/theme/CodeBlock/CopyButton/index.js
new file mode 100644
index 0000000..f21e974
--- /dev/null
+++ b/packages/docusaurus-playground/src/theme/CodeBlock/CopyButton/index.js
@@ -0,0 +1,55 @@
+import React, { useCallback, useState, useRef, useEffect } from 'react'
+import clsx from 'clsx'
+// @ts-expect-error: TODO, we need to make theme-classic have type: module
+import copy from 'copy-text-to-clipboard'
+import { translate } from '@docusaurus/Translate'
+import IconCopy from '@theme/Icon/Copy'
+import IconSuccess from '@theme/Icon/Success'
+import styles from './styles.module.css'
+export default function CopyButton({ code, className }) {
+ const [isCopied, setIsCopied] = useState(false)
+ const copyTimeout = useRef(undefined)
+ const handleCopyCode = useCallback(() => {
+ copy(code)
+ setIsCopied(true)
+ copyTimeout.current = window.setTimeout(() => {
+ setIsCopied(false)
+ }, 1000)
+ }, [code])
+ useEffect(() => () => window.clearTimeout(copyTimeout.current), [])
+ return (
+
+ )
+}
diff --git a/packages/docusaurus-playground/src/theme/CodeBlock/CopyButton/styles.module.css b/packages/docusaurus-playground/src/theme/CodeBlock/CopyButton/styles.module.css
new file mode 100644
index 0000000..d5268e9
--- /dev/null
+++ b/packages/docusaurus-playground/src/theme/CodeBlock/CopyButton/styles.module.css
@@ -0,0 +1,40 @@
+:global(.theme-code-block:hover) .copyButtonCopied {
+ opacity: 1 !important;
+}
+
+.copyButtonIcons {
+ position: relative;
+ width: 1.125rem;
+ height: 1.125rem;
+}
+
+.copyButtonIcon,
+.copyButtonSuccessIcon {
+ position: absolute;
+ top: 0;
+ left: 0;
+ fill: currentColor;
+ opacity: inherit;
+ width: inherit;
+ height: inherit;
+ transition: all var(--ifm-transition-fast) ease;
+}
+
+.copyButtonSuccessIcon {
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%) scale(0.33);
+ opacity: 0;
+ color: #00d600;
+}
+
+.copyButtonCopied .copyButtonIcon {
+ transform: scale(0.33);
+ opacity: 0;
+}
+
+.copyButtonCopied .copyButtonSuccessIcon {
+ transform: translate(-50%, -50%) scale(1);
+ opacity: 1;
+ transition-delay: 0.075s;
+}
diff --git a/packages/docusaurus-playground/src/theme/CodeBlock/Line/index.js b/packages/docusaurus-playground/src/theme/CodeBlock/Line/index.js
new file mode 100644
index 0000000..bdfd277
--- /dev/null
+++ b/packages/docusaurus-playground/src/theme/CodeBlock/Line/index.js
@@ -0,0 +1,34 @@
+import React from 'react'
+import clsx from 'clsx'
+import styles from './styles.module.css'
+export default function CodeBlockLine({
+ line,
+ classNames,
+ showLineNumbers,
+ getLineProps,
+ getTokenProps,
+}) {
+ if (line.length === 1 && line[0].content === '\n') {
+ line[0].content = ''
+ }
+ const lineProps = getLineProps({
+ line,
+ className: clsx(classNames, showLineNumbers && styles.codeLine),
+ })
+ const lineTokens = line.map((token, key) => (
+
+ ))
+ return (
+
+ {showLineNumbers ? (
+ <>
+
+ {lineTokens}
+ >
+ ) : (
+ lineTokens
+ )}
+
+
+ )
+}
diff --git a/packages/docusaurus-playground/src/theme/CodeBlock/Line/styles.module.css b/packages/docusaurus-playground/src/theme/CodeBlock/Line/styles.module.css
new file mode 100644
index 0000000..7c28ed9
--- /dev/null
+++ b/packages/docusaurus-playground/src/theme/CodeBlock/Line/styles.module.css
@@ -0,0 +1,45 @@
+/* Intentionally has zero specificity, so that to be able to override
+the background in custom CSS file due bug https://github.com/facebook/docusaurus/issues/3678 */
+:where(:root) {
+ --docusaurus-highlighted-code-line-bg: rgb(72 77 91);
+}
+
+:where([data-theme='dark']) {
+ --docusaurus-highlighted-code-line-bg: rgb(100 100 100);
+}
+
+:global(.theme-code-block-highlighted-line) {
+ background-color: var(--docusaurus-highlighted-code-line-bg);
+ display: block;
+ margin: 0 calc(-1 * var(--ifm-pre-padding));
+ padding: 0 var(--ifm-pre-padding);
+}
+
+.codeLine {
+ display: table-row;
+ counter-increment: line-count;
+}
+
+.codeLineNumber {
+ display: table-cell;
+ text-align: right;
+ width: 1%;
+ position: sticky;
+ left: 0;
+ padding: 0 var(--ifm-pre-padding);
+ background: var(--ifm-pre-background);
+ overflow-wrap: normal;
+}
+
+.codeLineNumber::before {
+ content: counter(line-count);
+ opacity: 0.4;
+}
+
+:global(.theme-code-block-highlighted-line) .codeLineNumber::before {
+ opacity: 0.8;
+}
+
+.codeLineContent {
+ padding-right: var(--ifm-pre-padding);
+}
diff --git a/packages/docusaurus-playground/src/theme/CodeBlock/WordWrapButton/index.js b/packages/docusaurus-playground/src/theme/CodeBlock/WordWrapButton/index.js
new file mode 100644
index 0000000..bdd76ad
--- /dev/null
+++ b/packages/docusaurus-playground/src/theme/CodeBlock/WordWrapButton/index.js
@@ -0,0 +1,28 @@
+import React from 'react'
+import clsx from 'clsx'
+import { translate } from '@docusaurus/Translate'
+import IconWordWrap from '@theme/Icon/WordWrap'
+import styles from './styles.module.css'
+export default function WordWrapButton({ className, onClick, isEnabled }) {
+ const title = translate({
+ id: 'theme.CodeBlock.wordWrapToggle',
+ message: 'Toggle word wrap',
+ description:
+ 'The title attribute for toggle word wrapping button of code block lines',
+ })
+ return (
+
+ )
+}
diff --git a/packages/docusaurus-playground/src/theme/CodeBlock/WordWrapButton/styles.module.css b/packages/docusaurus-playground/src/theme/CodeBlock/WordWrapButton/styles.module.css
new file mode 100644
index 0000000..fdbc894
--- /dev/null
+++ b/packages/docusaurus-playground/src/theme/CodeBlock/WordWrapButton/styles.module.css
@@ -0,0 +1,8 @@
+.wordWrapButtonIcon {
+ width: 1.2rem;
+ height: 1.2rem;
+}
+
+.wordWrapButtonEnabled .wordWrapButtonIcon {
+ color: var(--ifm-color-primary);
+}
diff --git a/packages/docusaurus-playground/src/theme/CodeBlock/index.js b/packages/docusaurus-playground/src/theme/CodeBlock/index.js
new file mode 100644
index 0000000..e31fcbb
--- /dev/null
+++ b/packages/docusaurus-playground/src/theme/CodeBlock/index.js
@@ -0,0 +1,32 @@
+import React, { isValidElement } from 'react'
+import useIsBrowser from '@docusaurus/useIsBrowser'
+import ElementContent from '@theme/CodeBlock/Content/Element'
+import StringContent from '@theme/CodeBlock/Content/String'
+/**
+ * Best attempt to make the children a plain string so it is copyable. If there
+ * are react elements, we will not be able to copy the content, and it will
+ * return `children` as-is; otherwise, it concatenates the string children
+ * together.
+ */
+function maybeStringifyChildren(children) {
+ if (React.Children.toArray(children).some((el) => isValidElement(el))) {
+ return children
+ }
+ // The children is now guaranteed to be one/more plain strings
+ return Array.isArray(children) ? children.join('') : children
+}
+export default function CodeBlock({ children: rawChildren, ...props }) {
+ // The Prism theme on SSR is always the default theme but the site theme can
+ // be in a different mode. React hydration doesn't update DOM styles that come
+ // from SSR. Hence force a re-render after mounting to apply the current
+ // relevant styles.
+ const isBrowser = useIsBrowser()
+ const children = maybeStringifyChildren(rawChildren)
+ const CodeBlockComp =
+ typeof children === 'string' ? StringContent : ElementContent
+ return (
+
+ {children}
+
+ )
+}
diff --git a/packages/docusaurus-playground/src/theme/Footer/Layout/index.js b/packages/docusaurus-playground/src/theme/Footer/Layout/index.js
new file mode 100644
index 0000000..797b405
--- /dev/null
+++ b/packages/docusaurus-playground/src/theme/Footer/Layout/index.js
@@ -0,0 +1,21 @@
+import React from 'react'
+import clsx from 'clsx'
+export default function FooterLayout({ style, links, logo, copyright }) {
+ return (
+
+ )
+}
diff --git a/packages/docusaurus-playground/src/theme/Footer/LinkItem/index.js b/packages/docusaurus-playground/src/theme/Footer/LinkItem/index.js
new file mode 100644
index 0000000..89e1001
--- /dev/null
+++ b/packages/docusaurus-playground/src/theme/Footer/LinkItem/index.js
@@ -0,0 +1,26 @@
+import React from 'react'
+import Link from '@docusaurus/Link'
+import useBaseUrl from '@docusaurus/useBaseUrl'
+import isInternalUrl from '@docusaurus/isInternalUrl'
+import IconExternalLink from '@theme/Icon/ExternalLink'
+export default function FooterLinkItem({ item }) {
+ const { to, href, label, prependBaseUrlToHref, ...props } = item
+ const toUrl = useBaseUrl(to)
+ const normalizedHref = useBaseUrl(href, { forcePrependBaseUrl: true })
+ return (
+
+ {label}
+ {href && !isInternalUrl(href) && }
+
+ )
+}
diff --git a/packages/docusaurus-playground/src/theme/Footer/Links/MultiColumn/index.js b/packages/docusaurus-playground/src/theme/Footer/Links/MultiColumn/index.js
new file mode 100644
index 0000000..bf8b308
--- /dev/null
+++ b/packages/docusaurus-playground/src/theme/Footer/Links/MultiColumn/index.js
@@ -0,0 +1,37 @@
+import React from 'react'
+import LinkItem from '@theme/Footer/LinkItem'
+function ColumnLinkItem({ item }) {
+ return item.html ? (
+
+ ) : (
+