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 14 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 @@ -732,6 +732,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
62 changes: 60 additions & 2 deletions packages/docusaurus-theme-classic/src/theme/CodeBlock/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ import {
parseCodeBlockTitle,
parseLanguage,
parseLines,
ThemeClassNames,
} from '@docusaurus/theme-common';
import usePrismTheme from '@theme/hooks/usePrismTheme';
import type {Props} from '@theme/CodeBlock';
import IconExpand from '@theme/IconExpand';

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

Expand All @@ -31,6 +33,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 @@ -55,7 +59,11 @@ export default function CodeBlock({

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

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

const collapsible = sampleLines.length > 0;

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

return (
<Highlight
{...defaultProps}
Expand All @@ -73,9 +91,34 @@ export default function CodeBlock({
language={language}>
{({className, style, tokens, getLineProps, getTokenProps}) => (
<div className={clsx(styles.codeBlockContainer, blockClassName)}>
{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 @@ -96,6 +139,21 @@ export default function CodeBlock({
lineProps.className += ' docusaurus-highlight-code-line';
}

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

return (
<span key={i} {...lineProps}>
{line.map((token, key) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
font-size: var(--ifm-code-font-size);
font-weight: 500;
padding: 0.75rem var(--ifm-pre-padding);
min-height: calc(1.5rem + 20px);
}

.codeBlock {
Expand Down Expand Up @@ -58,6 +59,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;
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',
},
layout: {
// TODO add other stable classNames here
Expand Down
20 changes: 17 additions & 3 deletions packages/docusaurus-theme-common/src/utils/codeBlockUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ const magicCommentDirectives = [
'highlight-next-line',
'highlight-start',
'highlight-end',
'sample-start',
'sample-end',
];

const getMagicCommentDirectiveRegex = (
Expand Down Expand Up @@ -110,6 +112,7 @@ export function parseLines(
language?: Language,
): {
highlightLines: number[];
sampleLines: number[];
code: string;
} {
let code = content.replace(/\n$/, '');
Expand All @@ -119,16 +122,18 @@ export function parseLines(
const highlightLines = rangeParser(highlightLinesRange)
.filter((n) => n > 0)
.map((n) => n - 1);
return {highlightLines, code};
return {highlightLines, sampleLines: [], code};
}
if (language === undefined) {
return {highlightLines: [], code};
return {highlightLines: [], sampleLines: [], code};
}
const directiveRegex = magicCommentDirectiveRegex(language);
// go through line by line
const lines = code.split('\n');
let highlightBlockStart: number;
let highlightRange = '';
let sampleBlockStart: number;
let sampleRange = '';
// loop through lines
for (let lineNumber = 0; lineNumber < lines.length; ) {
const line = lines[lineNumber];
Expand All @@ -148,6 +153,14 @@ export function parseLines(
highlightRange += `${highlightBlockStart!}-${lineNumber - 1},`;
break;

case 'sample-start':
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wonder if sample is the best marker name? 🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is directly from the Kotlin docs example in #2215: // sampleStart in that case. We can certainly bikeshed about this, and if we are to just build a generic API, maybe even no bikeshedding at all :D

sampleBlockStart = lineNumber;
break;

case 'sample-end':
sampleRange += `${sampleBlockStart!}-${lineNumber - 1},`;
break;

default:
break;
}
Expand All @@ -158,6 +171,7 @@ export function parseLines(
}
}
const highlightLines = rangeParser(highlightRange);
const sampleLines = rangeParser(sampleRange);
code = lines.join('\n');
return {highlightLines, code};
return {highlightLines, sampleLines, code};
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"theme.CodeBlock.copied": "تم النسخ",
"theme.CodeBlock.copy": "نسخ",
"theme.CodeBlock.copyButtonAriaLabel": "نسخ الرمز إلى الحافظة",
"theme.CodeBlock.expandButtonAriaLabel": "Expand code block",
"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": "Toggle the collapsible sidebar category '{label}'",
"theme.ErrorPageContent.title": "This page crashed.",
"theme.ErrorPageContent.tryAgain": "Try again",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
"theme.CodeBlock.copy___DESCRIPTION": "The copy button label on code blocks",
"theme.CodeBlock.copyButtonAriaLabel": "Copy code to clipboard",
"theme.CodeBlock.copyButtonAriaLabel___DESCRIPTION": "The ARIA label for copy code blocks button",
"theme.CodeBlock.expandButtonAriaLabel": "Expand code block",
"theme.CodeBlock.expandButtonAriaLabel___DESCRIPTION": "The ARIA label for expanding code blocks button",
"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": "Toggle the collapsible sidebar category '{label}'",
"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel___DESCRIPTION": "The ARIA label to toggle the collapsible sidebar category",
"theme.ErrorPageContent.title": "This page crashed.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"theme.CodeBlock.copied": "কপিড",
"theme.CodeBlock.copy": "কপি",
"theme.CodeBlock.copyButtonAriaLabel": "ক্লিপবোর্ডে কোড কপি করুন",
"theme.CodeBlock.expandButtonAriaLabel": "Expand code block",
"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": "Toggle the collapsible sidebar category '{label}'",
"theme.ErrorPageContent.title": "This page crashed.",
"theme.ErrorPageContent.tryAgain": "Try again",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"theme.CodeBlock.copied": "Zkopírováno",
"theme.CodeBlock.copy": "Zkopírovat",
"theme.CodeBlock.copyButtonAriaLabel": "Zkopírovat kód do schránky",
"theme.CodeBlock.expandButtonAriaLabel": "Expand code block",
"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": "Toggle the collapsible sidebar category '{label}'",
"theme.ErrorPageContent.title": "This page crashed.",
"theme.ErrorPageContent.tryAgain": "Try again",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"theme.CodeBlock.copied": "Kopieret",
"theme.CodeBlock.copy": "Kopier",
"theme.CodeBlock.copyButtonAriaLabel": "Kopier kode til udklipsholder",
"theme.CodeBlock.expandButtonAriaLabel": "Expand code block",
"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": "Toggle the collapsible sidebar category '{label}'",
"theme.ErrorPageContent.title": "This page crashed.",
"theme.ErrorPageContent.tryAgain": "Try again",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"theme.CodeBlock.copied": "Kopiert",
"theme.CodeBlock.copy": "Kopieren",
"theme.CodeBlock.copyButtonAriaLabel": "In die Zwischenablage kopieren",
"theme.CodeBlock.expandButtonAriaLabel": "Expand code block",
"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": "Toggle the collapsible sidebar category '{label}'",
"theme.ErrorPageContent.title": "This page crashed.",
"theme.ErrorPageContent.tryAgain": "Try again",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"theme.CodeBlock.copied": "Copiado",
"theme.CodeBlock.copy": "Copiar",
"theme.CodeBlock.copyButtonAriaLabel": "Copiar código al portapapeles",
"theme.CodeBlock.expandButtonAriaLabel": "Expand code block",
"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": "Toggle the collapsible sidebar category '{label}'",
"theme.ErrorPageContent.title": "This page crashed.",
"theme.ErrorPageContent.tryAgain": "Try again",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"theme.CodeBlock.copied": "کپی شد",
"theme.CodeBlock.copy": "کپی",
"theme.CodeBlock.copyButtonAriaLabel": "کپی به کلیپ بورد",
"theme.CodeBlock.expandButtonAriaLabel": "Expand code block",
"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": "Toggle the collapsible sidebar category '{label}'",
"theme.ErrorPageContent.title": "This page crashed.",
"theme.ErrorPageContent.tryAgain": "Try again",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"theme.CodeBlock.copied": "Kinopya",
"theme.CodeBlock.copy": "Kopyahin",
"theme.CodeBlock.copyButtonAriaLabel": "Kopyahin ang code sa clipboard",
"theme.CodeBlock.expandButtonAriaLabel": "Expand code block",
"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": "Toggle the collapsible sidebar category '{label}'",
"theme.ErrorPageContent.title": "This page crashed.",
"theme.ErrorPageContent.tryAgain": "Try again",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"theme.CodeBlock.copied": "Copié",
"theme.CodeBlock.copy": "Copier",
"theme.CodeBlock.copyButtonAriaLabel": "Copier le code",
"theme.CodeBlock.expandButtonAriaLabel": "Expand code block",
"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": "Toggle the collapsible sidebar category '{label}'",
"theme.ErrorPageContent.title": "Cette page a planté.",
"theme.ErrorPageContent.tryAgain": "Réessayer",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"theme.CodeBlock.copied": "הועתק",
"theme.CodeBlock.copy": "העתק",
"theme.CodeBlock.copyButtonAriaLabel": "העתק קוד ללוח העריכה",
"theme.CodeBlock.expandButtonAriaLabel": "Expand code block",
"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": "Toggle the collapsible sidebar category '{label}'",
"theme.ErrorPageContent.title": "This page crashed.",
"theme.ErrorPageContent.tryAgain": "Try again",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"theme.CodeBlock.copied": "कॉपीड",
"theme.CodeBlock.copy": "कॉपी",
"theme.CodeBlock.copyButtonAriaLabel": "क्लिपबोर्ड पर कोड कॉपी करें",
"theme.CodeBlock.expandButtonAriaLabel": "Expand code block",
"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": "Toggle the collapsible sidebar category '{label}'",
"theme.ErrorPageContent.title": "This page crashed.",
"theme.ErrorPageContent.tryAgain": "Try again",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"theme.CodeBlock.copied": "コピーしました",
"theme.CodeBlock.copy": "コピー",
"theme.CodeBlock.copyButtonAriaLabel": "クリップボードにコードをコピー",
"theme.CodeBlock.expandButtonAriaLabel": "Expand code block",
"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": "Toggle the collapsible sidebar category '{label}'",
"theme.ErrorPageContent.title": "This page crashed.",
"theme.ErrorPageContent.tryAgain": "Try again",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"theme.CodeBlock.copied": "복사했습니다",
"theme.CodeBlock.copy": "복사",
"theme.CodeBlock.copyButtonAriaLabel": "클립보드에 코드 복사",
"theme.CodeBlock.expandButtonAriaLabel": "Expand code block",
"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": "Toggle the collapsible sidebar category '{label}'",
"theme.ErrorPageContent.title": "This page crashed.",
"theme.ErrorPageContent.tryAgain": "Try again",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"theme.CodeBlock.copied": "Skopiowano!",
"theme.CodeBlock.copy": "Kopiuj",
"theme.CodeBlock.copyButtonAriaLabel": "Kopiuj do schowka",
"theme.CodeBlock.expandButtonAriaLabel": "Expand code block",
"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": "Toggle the collapsible sidebar category '{label}'",
"theme.ErrorPageContent.title": "This page crashed.",
"theme.ErrorPageContent.tryAgain": "Try again",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"theme.CodeBlock.copied": "Copiado",
"theme.CodeBlock.copy": "Copiar",
"theme.CodeBlock.copyButtonAriaLabel": "Copiar código para a área de transferência",
"theme.CodeBlock.expandButtonAriaLabel": "Expand code block",
"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": "Toggle the collapsible sidebar category '{label}'",
"theme.ErrorPageContent.title": "This page crashed.",
"theme.ErrorPageContent.tryAgain": "Try again",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"theme.CodeBlock.copied": "Copiado",
"theme.CodeBlock.copy": "Copiar",
"theme.CodeBlock.copyButtonAriaLabel": "Copiar código para a área de transferência",
"theme.CodeBlock.expandButtonAriaLabel": "Expand code block",
"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": "Toggle the collapsible sidebar category '{label}'",
"theme.ErrorPageContent.title": "This page crashed.",
"theme.ErrorPageContent.tryAgain": "Try again",
Expand Down
Loading