docs: redesigned code blocks (#2745)
* docs: redesigned code blocks to include titles * docs: added a title where necessary
This commit is contained in:
+37
-24
@@ -47,37 +47,23 @@ html[data-theme="dark"] .docusaurus-highlight-code-line {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.code-tabs .tabs,
|
||||
.code-header {
|
||||
padding: 8px 16px;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.code-header {
|
||||
background-color: #161616;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
justify-content: space-between;
|
||||
border-radius: var(--ifm-code-border-radius) var(--ifm-code-border-radius) 0px 0px;
|
||||
}
|
||||
|
||||
.code-tabs .tabs {
|
||||
background-color: transparent;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
overflow-x: auto;
|
||||
|
||||
backface-visibility: hidden;
|
||||
-ms-overflow-style: none; /* Internet Explorer 10+ */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
}
|
||||
|
||||
.code-tabs .tabs::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.code-tabs .tabs__item {
|
||||
color: #6F6F6F;
|
||||
color: var(--ifm-code-tabs-color);
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
padding: 0 12px;
|
||||
@@ -90,6 +76,12 @@ html[data-theme="dark"] .docusaurus-highlight-code-line {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.code-title {
|
||||
font-size: 13px;
|
||||
line-height: var(--ifm-line-height-base);
|
||||
color: var(--ifm-code-title-color);
|
||||
}
|
||||
|
||||
.code-tabs .tabs__item--active {
|
||||
border-color: #393939;
|
||||
background-color: var(--ifm-code-tabs-active-bg);
|
||||
@@ -97,7 +89,8 @@ html[data-theme="dark"] .docusaurus-highlight-code-line {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.theme-code-block:not(.no-header-block) {
|
||||
.theme-code-block:not(.no-header-block),
|
||||
.code-tabs .theme-code-block {
|
||||
border-radius: 0 0 var(--ifm-code-border-radius) var(--ifm-code-border-radius) !important;
|
||||
}
|
||||
|
||||
@@ -132,11 +125,11 @@ a.code-action {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.theme-code-block:not(.no-header-block) [class*=buttonGroup] {
|
||||
/* .theme-code-block:not(.no-header-block) [class*=buttonGroup] {
|
||||
display: none;
|
||||
}
|
||||
} */
|
||||
|
||||
.theme-code-block.no-header-block [class*=buttonGroup] button {
|
||||
.theme-code-block [class*=buttonGroup] button {
|
||||
opacity: 1 !important;
|
||||
border: none;
|
||||
}
|
||||
@@ -170,9 +163,29 @@ html:not([data-theme="dark"]) .theme-code-block:not(.no-header-block) {
|
||||
}
|
||||
|
||||
@media screen and (min-width: 568px) {
|
||||
.code-tabs .tabs {
|
||||
.prism-code {
|
||||
max-width: 90%;
|
||||
}
|
||||
|
||||
.prism-code:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: calc(10% + 24px);
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #17171700, #262626 24px);
|
||||
}
|
||||
|
||||
.prism-code:not(:hover)::-webkit-scrollbar-thumb,
|
||||
.prism-code:not(:hover)::-webkit-scrollbar-track {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.prism-code:hover::-webkit-scrollbar-thumb,
|
||||
.prism-code:hover::-webkit-scrollbar-track {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 567px) {
|
||||
@@ -180,7 +193,7 @@ html:not([data-theme="dark"]) .theme-code-block:not(.no-header-block) {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.code-tabs .tabs {
|
||||
max-width: 100%;
|
||||
.tablist-wrapper.code-header .code-title {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -129,7 +129,7 @@ html:not([data-theme="dark"]) .doc-footer {
|
||||
z-index: var(--ifm-z-index-overlay);
|
||||
}
|
||||
|
||||
.tabs-wrapper:not(.code-tabs) .tabs-container > div {
|
||||
.tabs-wrapper:not(.code-tabs) > .tabs-container > div:not(.tablist-wrapper) {
|
||||
padding-top: var(--ifm-base-margin-vertical);
|
||||
}
|
||||
|
||||
|
||||
@@ -83,11 +83,13 @@
|
||||
--ifm-code-border-color: #E5E7EB;
|
||||
--ifm-code-background: #F9FAFB;
|
||||
--ifm-code-color: #4B5563;
|
||||
--ifm-code-tabs-color: #6F6F6F;
|
||||
--ifm-code-tabs-active-bg: transparent;
|
||||
--ifm-code-tabs-active-color: #F4F4F4;
|
||||
--ifm-code-action-hover-bg: rgba(141, 141, 141, 0.16);
|
||||
--ifm-pre-padding: 16px;
|
||||
--docusaurus-highlighted-code-line-bg: #393939;
|
||||
--ifm-code-title-color: #737373;
|
||||
|
||||
/* Tooltip */
|
||||
--ifm-tooltip-background-color: #fff;
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
import React from 'react';
|
||||
import clsx from 'clsx';
|
||||
import {useThemeConfig, usePrismTheme} from '@docusaurus/theme-common';
|
||||
import Highlight, {defaultProps} from 'prism-react-renderer';
|
||||
import React, { useEffect } from 'react';
|
||||
import {
|
||||
containsLineNumbers,
|
||||
parseCodeBlockTitle,
|
||||
parseLanguage,
|
||||
parseLines,
|
||||
containsLineNumbers,
|
||||
useCodeWordWrap,
|
||||
} from '@docusaurus/theme-common/internal';
|
||||
import Highlight, {defaultProps} from 'prism-react-renderer';
|
||||
import Line from '@theme/CodeBlock/Line';
|
||||
import {usePrismTheme, useThemeConfig} from '@docusaurus/theme-common';
|
||||
|
||||
import Container from '@theme/CodeBlock/Container';
|
||||
import styles from './styles.module.css';
|
||||
import CopyButton from '../../CopyButton';
|
||||
import Line from '@theme/CodeBlock/Line';
|
||||
import ThemedImage from '@theme/ThemedImage';
|
||||
import Tooltip from '../../Tooltip';
|
||||
import clsx from 'clsx';
|
||||
import styles from './styles.module.css';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
import useIsBrowser from '@docusaurus/useIsBrowser';
|
||||
|
||||
export default function CodeBlockString({
|
||||
children,
|
||||
@@ -23,14 +26,17 @@ export default function CodeBlockString({
|
||||
title: titleProp,
|
||||
showLineNumbers: showLineNumbersProp,
|
||||
language: languageProp,
|
||||
noReport = false
|
||||
}) {
|
||||
const {
|
||||
prism: {defaultLanguage, magicComments},
|
||||
reportCodeLinkPrefix
|
||||
} = useThemeConfig();
|
||||
const language =
|
||||
languageProp ?? parseLanguage(blockClassName) ?? defaultLanguage;
|
||||
const prismTheme = usePrismTheme();
|
||||
const wordWrap = useCodeWordWrap();
|
||||
const isBrowser = useIsBrowser();
|
||||
// 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\""
|
||||
@@ -63,7 +69,7 @@ export default function CodeBlockString({
|
||||
/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */
|
||||
tabIndex={0}
|
||||
ref={wordWrap.codeBlockRef}
|
||||
className={clsx(className, styles.codeBlock, 'thin-scrollbar')}>
|
||||
className={clsx(className, styles.codeBlock, 'thin-scrollbar', tokens.length === 1 ? styles.thinCodeWrapper : '')}>
|
||||
<code
|
||||
className={clsx(
|
||||
styles.codeBlockLines,
|
||||
@@ -85,7 +91,16 @@ export default function CodeBlockString({
|
||||
)}
|
||||
</Highlight>
|
||||
<div className={styles.buttonGroup}>
|
||||
{/* <CopyButton className={styles.codeButton} code={code} /> */}
|
||||
{!noReport && (
|
||||
<Tooltip text="Report Incorrect Code">
|
||||
<a href={`${reportCodeLinkPrefix}&title=${encodeURIComponent(`Docs(Code Issue): Code Issue in ${isBrowser ? location.pathname : ''}`)}`} target="_blank" className='report-code code-action img-url'>
|
||||
<ThemedImage alt='Report Incorrect Code' sources={{
|
||||
light: useBaseUrl('/img/alert-code.png'),
|
||||
dark: useBaseUrl('/img/alert-code-dark.png')
|
||||
}} className="no-zoom-img" />
|
||||
</a>
|
||||
</Tooltip>
|
||||
)}
|
||||
<CopyButton buttonClassName='code-action' text={code}>
|
||||
<ThemedImage alt='Copy to Clipboard' sources={{
|
||||
light: useBaseUrl('/img/clipboard-copy.png'),
|
||||
|
||||
@@ -58,11 +58,11 @@
|
||||
display: flex;
|
||||
column-gap: 0.2rem;
|
||||
position: absolute;
|
||||
right: calc(var(--ifm-pre-padding) / 4 - 2px);
|
||||
top: calc(var(--ifm-pre-padding) / 4 - 2px);
|
||||
right: var(--ifm-pre-padding);
|
||||
top: var(--ifm-pre-padding);
|
||||
}
|
||||
|
||||
.buttonGroup button {
|
||||
.buttonGroup .code-action {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: var(--prism-background-color);
|
||||
@@ -80,6 +80,10 @@
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.thinCodeWrapper + .buttonGroup {
|
||||
top: calc(var(--ifm-pre-padding) / 4 - 2px) !important;
|
||||
}
|
||||
|
||||
:global(.theme-code-block:hover) .buttonGroup button {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
import React, {isValidElement} from 'react';
|
||||
|
||||
import CopyButton from '../CopyButton';
|
||||
import ElementContent from '@theme/CodeBlock/Content/Element';
|
||||
import StringContent from '@theme/CodeBlock/Content/String';
|
||||
import ThemedImage from '@theme/ThemedImage';
|
||||
import Tooltip from '../Tooltip';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
import useIsBrowser from '@docusaurus/useIsBrowser';
|
||||
import {useThemeConfig} from '@docusaurus/theme-common';
|
||||
|
||||
/**
|
||||
* Best attempt to make the children a plain string so it is copyable. If there
|
||||
@@ -22,7 +17,7 @@ function maybeStringifyChildren(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, noHeader = false, ...props}) {
|
||||
export default function CodeBlock({children: rawChildren, noReport = false, ...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
|
||||
@@ -31,29 +26,18 @@ export default function CodeBlock({children: rawChildren, noHeader = false, ...p
|
||||
const children = maybeStringifyChildren(rawChildren);
|
||||
const CodeBlockComp =
|
||||
typeof children === 'string' ? StringContent : ElementContent;
|
||||
const {reportCodeLinkPrefix} = useThemeConfig();
|
||||
|
||||
const title = props.title;
|
||||
delete props.title;
|
||||
|
||||
return (
|
||||
<div className='code-wrapper'>
|
||||
{!noHeader && (
|
||||
{title && (
|
||||
<div className='code-header'>
|
||||
<Tooltip text="Report Incorrect Code">
|
||||
<a href={`${reportCodeLinkPrefix}&title=${encodeURIComponent(`Docs(Code Issue): Code Issue in ${isBrowser ? location.pathname : ''}`)}`} target="_blank" className='report-code code-action img-url'>
|
||||
<ThemedImage alt='Report Incorrect Code' sources={{
|
||||
light: useBaseUrl('/img/alert-code.png'),
|
||||
dark: useBaseUrl('/img/alert-code-dark.png')
|
||||
}} className="no-zoom-img" />
|
||||
</a>
|
||||
</Tooltip>
|
||||
<CopyButton buttonClassName='code-action' text={children}>
|
||||
<ThemedImage alt='Copy to Clipboard' sources={{
|
||||
light: useBaseUrl('/img/clipboard-copy.png'),
|
||||
dark: useBaseUrl('/img/clipboard-copy-dark.png')
|
||||
}} className="no-zoom-img" />
|
||||
</CopyButton>
|
||||
{title}
|
||||
</div>
|
||||
)}
|
||||
<CodeBlockComp key={String(isBrowser)} {...props} className={noHeader ? 'no-header-block' : ''}>
|
||||
<CodeBlockComp key={String(isBrowser)} {...props} noReport={noReport} className={title ? '' : 'no-header-block'}>
|
||||
{children}
|
||||
</CodeBlockComp>
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import React, {useState, cloneElement, isValidElement, useEffect} from 'react';
|
||||
import clsx from 'clsx';
|
||||
import useIsBrowser from '@docusaurus/useIsBrowser';
|
||||
import {duplicates} from '@docusaurus/theme-common';
|
||||
import React, {cloneElement, isValidElement, useEffect, useState} from 'react';
|
||||
import {
|
||||
useScrollPositionBlocker,
|
||||
useTabGroupChoice,
|
||||
} from '@docusaurus/theme-common/internal';
|
||||
|
||||
import clsx from 'clsx';
|
||||
import {duplicates} from '@docusaurus/theme-common';
|
||||
import styles from './styles.module.css';
|
||||
import useIsBrowser from '@docusaurus/useIsBrowser';
|
||||
|
||||
// A very rough duck type, but good enough to guard against mistakes while
|
||||
// allowing customization
|
||||
function isTabItem(comp) {
|
||||
@@ -20,6 +22,8 @@ function TabsComponent(props) {
|
||||
values: valuesProp,
|
||||
groupId,
|
||||
className,
|
||||
isCodeTabs = false,
|
||||
codeTitle
|
||||
} = props;
|
||||
const children = React.Children.map(props.children, (child) => {
|
||||
if (isValidElement(child) && isTabItem(child)) {
|
||||
@@ -113,39 +117,42 @@ function TabsComponent(props) {
|
||||
};
|
||||
return (
|
||||
<div className={clsx('tabs-container', styles.tabList)}>
|
||||
<ul
|
||||
role="tablist"
|
||||
aria-orientation="horizontal"
|
||||
className={clsx(
|
||||
'tabs',
|
||||
{
|
||||
'tabs--block': block,
|
||||
},
|
||||
className,
|
||||
)}>
|
||||
{values.map(({value, label, attributes}) => (
|
||||
<li
|
||||
role="tab"
|
||||
tabIndex={selectedValue === value ? 0 : -1}
|
||||
aria-selected={selectedValue === value}
|
||||
key={value}
|
||||
ref={(tabControl) => tabRefs.push(tabControl)}
|
||||
onKeyDown={handleKeydown}
|
||||
onFocus={handleTabChange}
|
||||
onClick={handleTabChange}
|
||||
{...attributes}
|
||||
className={clsx(
|
||||
'tabs__item',
|
||||
styles.tabItem,
|
||||
attributes?.className,
|
||||
{
|
||||
'tabs__item--active': selectedValue === value,
|
||||
},
|
||||
)}>
|
||||
{label ?? value}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<div className={`tablist-wrapper ${isCodeTabs ? 'code-header' : ''}`}>
|
||||
{isCodeTabs && <span className='code-title'>{codeTitle}</span>}
|
||||
<ul
|
||||
role="tablist"
|
||||
aria-orientation="horizontal"
|
||||
className={clsx(
|
||||
'tabs',
|
||||
{
|
||||
'tabs--block': block,
|
||||
},
|
||||
className,
|
||||
)}>
|
||||
{values.map(({value, label, attributes}) => (
|
||||
<li
|
||||
role="tab"
|
||||
tabIndex={selectedValue === value ? 0 : -1}
|
||||
aria-selected={selectedValue === value}
|
||||
key={value}
|
||||
ref={(tabControl) => tabRefs.push(tabControl)}
|
||||
onKeyDown={handleKeydown}
|
||||
onFocus={handleTabChange}
|
||||
onClick={handleTabChange}
|
||||
{...attributes}
|
||||
className={clsx(
|
||||
'tabs__item',
|
||||
styles.tabItem,
|
||||
attributes?.className,
|
||||
{
|
||||
'tabs__item--active': selectedValue === value,
|
||||
},
|
||||
)}>
|
||||
{label ?? value}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{lazy ? (
|
||||
cloneElement(
|
||||
@@ -183,6 +190,7 @@ export default function Tabs(props) {
|
||||
// Remount tabs after hydration
|
||||
// Temporary fix for https://github.com/facebook/docusaurus/issues/5653
|
||||
key={String(isBrowser)}
|
||||
isCodeTabs={props.wrapperClassName?.search('code-tabs') !== -1 || props.groupId === 'npm2yarn'}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user