mirror of
https://github.com/wavetermdev/docusaurus-og.git
synced 2026-08-05 13:46:35 -07:00
swizzle required components
This commit is contained in:
@@ -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 (
|
||||
<svg viewBox="0 0 14 16">
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
function TipIcon() {
|
||||
return (
|
||||
<svg viewBox="0 0 12 16">
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
function DangerIcon() {
|
||||
return (
|
||||
<svg viewBox="0 0 12 16">
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
function InfoIcon() {
|
||||
return (
|
||||
<svg viewBox="0 0 14 16">
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
function CautionIcon() {
|
||||
return (
|
||||
<svg viewBox="0 0 16 16">
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style
|
||||
const AdmonitionConfigs = {
|
||||
note: {
|
||||
infimaClassName: 'secondary',
|
||||
iconComponent: NoteIcon,
|
||||
label: (
|
||||
<Translate
|
||||
id="theme.admonition.note"
|
||||
description="The default label used for the Note admonition (:::note)"
|
||||
>
|
||||
note
|
||||
</Translate>
|
||||
),
|
||||
},
|
||||
tip: {
|
||||
infimaClassName: 'success',
|
||||
iconComponent: TipIcon,
|
||||
label: (
|
||||
<Translate
|
||||
id="theme.admonition.tip"
|
||||
description="The default label used for the Tip admonition (:::tip)"
|
||||
>
|
||||
tip
|
||||
</Translate>
|
||||
),
|
||||
},
|
||||
danger: {
|
||||
infimaClassName: 'danger',
|
||||
iconComponent: DangerIcon,
|
||||
label: (
|
||||
<Translate
|
||||
id="theme.admonition.danger"
|
||||
description="The default label used for the Danger admonition (:::danger)"
|
||||
>
|
||||
danger
|
||||
</Translate>
|
||||
),
|
||||
},
|
||||
info: {
|
||||
infimaClassName: 'info',
|
||||
iconComponent: InfoIcon,
|
||||
label: (
|
||||
<Translate
|
||||
id="theme.admonition.info"
|
||||
description="The default label used for the Info admonition (:::info)"
|
||||
>
|
||||
info
|
||||
</Translate>
|
||||
),
|
||||
},
|
||||
caution: {
|
||||
infimaClassName: 'warning',
|
||||
iconComponent: CautionIcon,
|
||||
label: (
|
||||
<Translate
|
||||
id="theme.admonition.caution"
|
||||
description="The default label used for the Caution admonition (:::caution)"
|
||||
>
|
||||
caution
|
||||
</Translate>
|
||||
),
|
||||
},
|
||||
}
|
||||
// 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
|
||||
}
|
||||
console.warn(
|
||||
`No admonition config found for admonition type "${type}". Using Info as fallback.`,
|
||||
)
|
||||
return AdmonitionConfigs.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 ?? <IconComponent />
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
ThemeClassNames.common.admonition,
|
||||
ThemeClassNames.common.admonitionType(props.type),
|
||||
'alert',
|
||||
`alert--${typeConfig.infimaClassName}`,
|
||||
styles.admonition,
|
||||
)}
|
||||
>
|
||||
<div className={styles.admonitionHeading}>
|
||||
<span className={styles.admonitionIcon}>{icon}</span>
|
||||
{titleLabel}
|
||||
</div>
|
||||
<div className={styles.admonitionContent}>{children}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
.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;
|
||||
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;
|
||||
fill: var(--ifm-alert-foreground-color);
|
||||
}
|
||||
|
||||
.admonitionContent > :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import React from 'react'
|
||||
import clsx from 'clsx'
|
||||
import { ThemeClassNames, usePrismTheme } from '@docusaurus/theme-common'
|
||||
import { getPrismCssVariables } from '@docusaurus/theme-common/internal'
|
||||
import styles from './styles.module.css'
|
||||
export default function CodeBlockContainer({ as: As, ...props }) {
|
||||
const prismTheme = usePrismTheme()
|
||||
const prismCssVariables = getPrismCssVariables(prismTheme)
|
||||
return (
|
||||
<As
|
||||
// Polymorphic components are hard to type, without `oneOf` generics
|
||||
{...props}
|
||||
style={prismCssVariables}
|
||||
className={clsx(
|
||||
props.className,
|
||||
styles.codeBlockContainer,
|
||||
ThemeClassNames.common.codeBlock,
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
.codeBlockContainer {
|
||||
background: var(--prism-background-color);
|
||||
color: var(--prism-color);
|
||||
margin-bottom: var(--ifm-leading);
|
||||
box-shadow: var(--ifm-global-shadow-lw);
|
||||
border-radius: var(--ifm-code-border-radius);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import React from 'react'
|
||||
import clsx from 'clsx'
|
||||
import Container from '@theme/CodeBlock/Container'
|
||||
import styles from './styles.module.css'
|
||||
// <pre> 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 (
|
||||
<Container
|
||||
as="pre"
|
||||
tabIndex={0}
|
||||
className={clsx(styles.codeBlockStandalone, 'thin-scrollbar', className)}
|
||||
>
|
||||
<code className={styles.codeBlockLines}>{children}</code>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
@@ -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 (
|
||||
<Container
|
||||
as="div"
|
||||
className={clsx(
|
||||
blockClassName,
|
||||
language &&
|
||||
!blockClassName.includes(`language-${language}`) &&
|
||||
`language-${language}`,
|
||||
)}
|
||||
>
|
||||
{title && <div className={styles.codeBlockTitle}>{title}</div>}
|
||||
<div className={styles.codeBlockContent}>
|
||||
<Highlight
|
||||
{...defaultProps}
|
||||
theme={prismTheme}
|
||||
code={code}
|
||||
language={language ?? 'text'}
|
||||
>
|
||||
{({ className, tokens, getLineProps, getTokenProps }) => (
|
||||
<pre
|
||||
/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
|
||||
tabIndex={0}
|
||||
ref={wordWrap.codeBlockRef}
|
||||
className={clsx(className, styles.codeBlock, 'thin-scrollbar')}
|
||||
>
|
||||
<code
|
||||
className={clsx(
|
||||
styles.codeBlockLines,
|
||||
showLineNumbers && styles.codeBlockLinesWithNumbering,
|
||||
)}
|
||||
>
|
||||
{tokens.map((line, i) => (
|
||||
<Line
|
||||
key={i}
|
||||
line={line}
|
||||
getLineProps={getLineProps}
|
||||
getTokenProps={getTokenProps}
|
||||
classNames={lineClassNames[i]}
|
||||
showLineNumbers={showLineNumbers}
|
||||
/>
|
||||
))}
|
||||
</code>
|
||||
</pre>
|
||||
)}
|
||||
</Highlight>
|
||||
<div className={styles.buttonGroup}>
|
||||
{(wordWrap.isEnabled || wordWrap.isCodeScrollable) && (
|
||||
<WordWrapButton
|
||||
className={styles.codeButton}
|
||||
onClick={() => wordWrap.toggle()}
|
||||
isEnabled={wordWrap.isEnabled}
|
||||
/>
|
||||
)}
|
||||
<CopyButton className={styles.codeButton} code={code} />
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 (
|
||||
<button
|
||||
type="button"
|
||||
aria-label={
|
||||
isCopied
|
||||
? translate({
|
||||
id: 'theme.CodeBlock.copied',
|
||||
message: 'Copied',
|
||||
description: 'The copied button label on code blocks',
|
||||
})
|
||||
: translate({
|
||||
id: 'theme.CodeBlock.copyButtonAriaLabel',
|
||||
message: 'Copy code to clipboard',
|
||||
description: 'The ARIA label for copy code blocks button',
|
||||
})
|
||||
}
|
||||
title={translate({
|
||||
id: 'theme.CodeBlock.copy',
|
||||
message: 'Copy',
|
||||
description: 'The copy button label on code blocks',
|
||||
})}
|
||||
className={clsx(
|
||||
'clean-btn',
|
||||
className,
|
||||
styles.copyButton,
|
||||
isCopied && styles.copyButtonCopied,
|
||||
)}
|
||||
onClick={handleCopyCode}
|
||||
>
|
||||
<span className={styles.copyButtonIcons} aria-hidden="true">
|
||||
<IconCopy className={styles.copyButtonIcon} />
|
||||
<IconSuccess className={styles.copyButtonSuccessIcon} />
|
||||
</span>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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) => (
|
||||
<span key={key} {...getTokenProps({ token, key })} />
|
||||
))
|
||||
return (
|
||||
<span {...lineProps}>
|
||||
{showLineNumbers ? (
|
||||
<>
|
||||
<span className={styles.codeLineNumber} />
|
||||
<span className={styles.codeLineContent}>{lineTokens}</span>
|
||||
</>
|
||||
) : (
|
||||
lineTokens
|
||||
)}
|
||||
<br />
|
||||
</span>
|
||||
)
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 (
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClick}
|
||||
className={clsx(
|
||||
'clean-btn',
|
||||
className,
|
||||
isEnabled && styles.wordWrapButtonEnabled,
|
||||
)}
|
||||
aria-label={title}
|
||||
title={title}
|
||||
>
|
||||
<IconWordWrap className={styles.wordWrapButtonIcon} aria-hidden="true" />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
.wordWrapButtonIcon {
|
||||
width: 1.2rem;
|
||||
height: 1.2rem;
|
||||
}
|
||||
|
||||
.wordWrapButtonEnabled .wordWrapButtonIcon {
|
||||
color: var(--ifm-color-primary);
|
||||
}
|
||||
@@ -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 (
|
||||
<CodeBlockComp key={String(isBrowser)} {...props}>
|
||||
{children}
|
||||
</CodeBlockComp>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import React from 'react'
|
||||
import clsx from 'clsx'
|
||||
export default function FooterLayout({ style, links, logo, copyright }) {
|
||||
return (
|
||||
<footer
|
||||
className={clsx('footer', {
|
||||
'footer--dark': style === 'dark',
|
||||
})}
|
||||
>
|
||||
<div className="container container-fluid">
|
||||
{links}
|
||||
{(logo || copyright) && (
|
||||
<div className="footer__bottom text--center">
|
||||
{logo && <div className="margin-bottom--sm">{logo}</div>}
|
||||
{copyright}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
@@ -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 (
|
||||
<Link
|
||||
className="footer__link-item"
|
||||
{...(href
|
||||
? {
|
||||
href: prependBaseUrlToHref ? normalizedHref : href,
|
||||
}
|
||||
: {
|
||||
to: toUrl,
|
||||
})}
|
||||
{...props}
|
||||
>
|
||||
{label}
|
||||
{href && !isInternalUrl(href) && <IconExternalLink />}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import React from 'react'
|
||||
import LinkItem from '@theme/Footer/LinkItem'
|
||||
function ColumnLinkItem({ item }) {
|
||||
return item.html ? (
|
||||
<li
|
||||
className="footer__item"
|
||||
// Developer provided the HTML, so assume it's safe.
|
||||
// eslint-disable-next-line react/no-danger
|
||||
dangerouslySetInnerHTML={{ __html: item.html }}
|
||||
/>
|
||||
) : (
|
||||
<li key={item.href ?? item.to} className="footer__item">
|
||||
<LinkItem item={item} />
|
||||
</li>
|
||||
)
|
||||
}
|
||||
function Column({ column }) {
|
||||
return (
|
||||
<div className="col footer__col">
|
||||
<div className="footer__title">{column.title}</div>
|
||||
<ul className="footer__items clean-list">
|
||||
{column.items.map((item, i) => (
|
||||
<ColumnLinkItem key={i} item={item} />
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default function FooterLinksMultiColumn({ columns }) {
|
||||
return (
|
||||
<div className="row footer__links">
|
||||
{columns.map((column, i) => (
|
||||
<Column key={i} column={column} />
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import React from 'react'
|
||||
import { isMultiColumnFooterLinks } from '@docusaurus/theme-common'
|
||||
import FooterLinksMultiColumn from '@theme/Footer/Links/MultiColumn'
|
||||
import FooterLinksSimple from '@theme/Footer/Links/Simple'
|
||||
export default function FooterLinks({ links }) {
|
||||
return isMultiColumnFooterLinks(links) ? (
|
||||
<FooterLinksMultiColumn columns={links} />
|
||||
) : (
|
||||
<FooterLinksSimple links={links} />
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import React from 'react'
|
||||
import clsx from 'clsx'
|
||||
import Link from '@docusaurus/Link'
|
||||
import { useBaseUrlUtils } from '@docusaurus/useBaseUrl'
|
||||
import ThemedImage from '@theme/ThemedImage'
|
||||
import styles from './styles.module.css'
|
||||
function LogoImage({ logo }) {
|
||||
const { withBaseUrl } = useBaseUrlUtils()
|
||||
const sources = {
|
||||
light: withBaseUrl(logo.src),
|
||||
dark: withBaseUrl(logo.srcDark ?? logo.src),
|
||||
}
|
||||
return (
|
||||
<ThemedImage
|
||||
className={clsx('footer__logo', logo.className)}
|
||||
alt={logo.alt}
|
||||
sources={sources}
|
||||
width={logo.width}
|
||||
height={logo.height}
|
||||
style={logo.style}
|
||||
/>
|
||||
)
|
||||
}
|
||||
export default function FooterLogo({ logo }) {
|
||||
return logo.href ? (
|
||||
<Link
|
||||
href={logo.href}
|
||||
className={styles.footerLogoLink}
|
||||
target={logo.target}
|
||||
>
|
||||
<LogoImage logo={logo} />
|
||||
</Link>
|
||||
) : (
|
||||
<LogoImage logo={logo} />
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
.footerLogoLink {
|
||||
opacity: 0.5;
|
||||
transition: opacity var(--ifm-transition-fast)
|
||||
var(--ifm-transition-timing-default);
|
||||
}
|
||||
|
||||
.footerLogoLink:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user