Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(theme-classic): allow collapsing part of code blocks #5783

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions packages/docusaurus-theme-classic/src/theme-classic.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,17 @@ declare module '@theme/IconEdit' {
export default IconEdit;
}

declare module '@theme/IconExpand' {
import type {ComponentProps} from 'react';

export interface Props extends ComponentProps<'svg'> {
expanded?: boolean;
}

const IconExpand: (props: Props) => JSX.Element;
export default IconExpand;
}

declare module '@theme/IconMenu' {
import type {ComponentProps} from 'react';

Expand Down
72 changes: 68 additions & 4 deletions packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
usePrismTheme,
} from '@docusaurus/theme-common';
import type {Props} from '@theme/CodeBlock';
import IconExpand from '@theme/IconExpand';

import styles from './styles.module.css';

Expand All @@ -33,6 +34,8 @@ export default function CodeBlock({

const [showCopied, setShowCopied] = useState(false);
const [mounted, setMounted] = useState(false);
const [collapsed, setCollapsed] = useState(true);
const [highlightExpanded, setHighlightExpanded] = useState(false);
// 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
Expand All @@ -50,6 +53,14 @@ export default function CodeBlock({
const codeBlockTitle = parseCodeBlockTitle(metastring) || title;
const prismTheme = usePrismTheme();

useEffect(() => {
setHighlightExpanded(true);
const timer = window.setTimeout(() => {
setHighlightExpanded(false);
}, 0);
return () => clearTimeout(timer);
}, [collapsed]);

// <pre> tags in markdown map to CodeBlocks and they may contain JSX children.
// When the children is not a simple string, we just return a styled block without actually highlighting.
if (React.Children.toArray(children).some((el) => isValidElement(el))) {
Expand Down Expand Up @@ -87,7 +98,11 @@ export default function CodeBlock({

const language =
languageProp ?? parseLanguage(blockClassName) ?? prism.defaultLanguage;
const {highlightLines, code} = parseLines(content, metastring, language);

const {lineClassNames, code} = parseLines(content, metastring, {
language,
magicComments: prism.magicComments,
});

const handleCopyCode = () => {
copy(code);
Expand All @@ -96,6 +111,10 @@ export default function CodeBlock({
setTimeout(() => setShowCopied(false), 2000);
};

const collapsible = Object.values(lineClassNames).some((line) =>
line.includes('docusaurus-collapsible-code-line'),
);

return (
<Highlight
{...defaultProps}
Expand All @@ -114,9 +133,34 @@ export default function CodeBlock({
},
ThemeClassNames.common.codeBlock,
)}>
{codeBlockTitle && (
{(codeBlockTitle || collapsible) && (
<div style={style} className={styles.codeBlockTitle}>
{codeBlockTitle}
{collapsible && (
<button
type="button"
tabIndex={0}
aria-label={translate({
id: 'theme.CodeBlock.expandButtonAriaLabel',
message: 'Expand code block',
description:
'The ARIA label for expanding code blocks button',
})}
className={clsx(
ThemeClassNames.common.expandCodeBlockButton,
styles.expandButton,
'clean-btn',
)}
onClick={() => setCollapsed(!collapsed)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault();
setCollapsed(!collapsed);
}
}}>
<IconExpand expanded={!collapsed} />
</button>
)}
</div>
)}
<div className={clsx(styles.codeBlockContent, language)}>
Expand All @@ -132,9 +176,29 @@ export default function CodeBlock({
}

const lineProps = getLineProps({line, key: i});
const customClassNames = lineClassNames[i] ?? [];

lineProps.className += ` ${customClassNames.join(' ')}`;

if (highlightLines.includes(i)) {
lineProps.className += ' docusaurus-highlight-code-line';
if (collapsible) {
if (collapsed) {
if (
!customClassNames.includes(
'docusaurus-collapsible-code-line',
)
) {
return null;
}
} else if (
!customClassNames.includes(
'docusaurus-collapsible-code-line',
)
) {
if (highlightExpanded) {
lineProps.className +=
' docusaurus-collapsible-code-line-highlighted';
}
}
}

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
font-size: var(--ifm-code-font-size);
font-weight: 500;
padding: 0.75rem var(--ifm-pre-padding);
min-height: calc(1.5rem + 20px);
border-top-left-radius: var(--ifm-global-radius);
border-top-right-radius: var(--ifm-global-radius);
}
Expand Down Expand Up @@ -69,6 +70,12 @@
padding: var(--ifm-pre-padding);
}

.expandButton {
float: right;
width: 20px;
height: 20px;
}

@media print {
.codeBlockLines {
white-space: pre-wrap;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import React from 'react';

import type {Props} from '@theme/IconExpand';

const IconExpand = ({expanded, ...props}: Props): JSX.Element => {
if (expanded) {
return (
<svg
viewBox="0 0 1024 1024"
width="20"
height="20"
fill="currentColor"
{...props}>
<path d="M783.915092 1009.031953l-271.898251-277.615587-271.930737 277.550617a49.214558 49.214558 0 0 1-70.752018 0 51.780862 51.780862 0 0 1 0-72.246322l307.274261-313.706262a49.279528 49.279528 0 0 1 70.784503 0l307.33923 313.706262a51.975771 51.975771 0 0 1 0 72.311292 49.409467 49.409467 0 0 1-70.816988 0z m-307.306745-608.05155L169.269117 87.274141A51.975771 51.975771 0 0 1 169.269117 14.96285a49.409467 49.409467 0 0 1 70.816987 0l271.930737 277.615586L783.850122 14.96285a49.409467 49.409467 0 0 1 70.816988 0 51.975771 51.975771 0 0 1 0 72.311291l-307.33923 313.706262a49.376982 49.376982 0 0 1-70.719533 0z" />
</svg>
);
}
return (
<svg
viewBox="0 0 1024 1024"
width="20"
height="20"
fill="currentColor"
{...props}>
<path d="M476.612887 1009.12034L169.240699 695.380437a51.981345 51.981345 0 0 1 0-72.319045 49.382277 49.382277 0 0 1 70.824582 0l271.959897 277.645356 271.862433-277.645356a49.382277 49.382277 0 0 1 70.824582 0 51.981345 51.981345 0 0 1 0 72.319045l-307.307212 313.739903a49.447254 49.447254 0 0 1-70.792094 0z m307.274724-608.116755L511.99269 123.455693l-271.959897 277.645357a49.382277 49.382277 0 0 1-70.824582 0 51.981345 51.981345 0 0 1 0-72.319045L476.580399 15.042102a49.382277 49.382277 0 0 1 70.727117 0l307.372188 313.739903a51.981345 51.981345 0 0 1 0 72.319045 49.414766 49.414766 0 0 1-70.824582 0z" />
</svg>
);
};

export default IconExpand;
20 changes: 20 additions & 0 deletions packages/docusaurus-theme-classic/src/validateThemeConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@ const DEFAULT_CONFIG = {
metadata: [],
prism: {
additionalLanguages: [],
magicComments: [
{
className: 'docusaurus-highlight-code-line',
line: 'highlight-next-line',
block: ['highlight-start', 'highlight-end'],
},
{
className: 'docusaurus-collapsible-code-line',
block: ['sample-start', 'sample-end'],
},
],
},
navbar: {
hideOnScroll: false,
Expand Down Expand Up @@ -348,6 +359,15 @@ const ThemeConfigSchema = Joi.object({
additionalLanguages: Joi.array()
.items(Joi.string())
.default(DEFAULT_CONFIG.prism.additionalLanguages),
magicComments: Joi.array()
.items(
Joi.object({
className: Joi.string().required(),
line: Joi.string(),
block: Joi.array().items(Joi.string()).length(2),
}),
)
.default(DEFAULT_CONFIG.prism.magicComments),
})
.default(DEFAULT_CONFIG.prism)
.unknown(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export const ThemeClassNames = {
editThisPage: 'theme-edit-this-page',
lastUpdated: 'theme-last-updated',
backToTopButton: 'theme-back-to-top-button',
expandCodeBlockButton: 'theme-expand-code-block-button',
codeBlock: 'theme-code-block',
},
layout: {
Expand Down
Loading