Skip to content

Commit 2a9cfc9

Browse files
Added the ability to show/hide line numbers in a code block (#1333)
* Added line numbers dropdown * Added a state to update the dropdown * Get data-linenumbers in the EditorContent component * Updated the CSS styles to render line number only when data-linenumbers is specified * [TEMP] Update OverlayManager story for demo purposes * Fixed codeblock padding * Revert "[TEMP] Update OverlayManager story for demo purposes" This reverts commit 9e3b964. --------- Co-authored-by: Praveen Murali <[email protected]>
1 parent 6a123cf commit 2a9cfc9

File tree

7 files changed

+91
-33
lines changed

7 files changed

+91
-33
lines changed

Diff for: src/components/Editor/CustomExtensions/CodeBlock/CodeBlockComponent.jsx

+31-1
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,17 @@ import { Dropdown, Input, Button } from "neetoui";
77
import { difference, intersection, union } from "ramda";
88
import { useTranslation } from "react-i18next";
99

10-
import { SORTED_LANGUAGE_LIST } from "./constants";
10+
import { LINE_NUMBER_OPTIONS, SORTED_LANGUAGE_LIST } from "./constants";
1111
import { codeBlockHighlightKey } from "./plugins";
1212

1313
const { Menu, MenuItem } = Dropdown;
1414

1515
const CodeBlockComponent = ({ node, editor, updateAttributes }) => {
1616
const [keyword, setKeyword] = useState("");
1717
const [showHighlightButton, setShowHighlightButton] = useState(false);
18+
const [showLineNumbers, setShowLineNumbers] = useState(
19+
node.attrs.linenumbers
20+
);
1821
const ref = useRef();
1922

2023
const { t } = useTranslation();
@@ -104,6 +107,33 @@ const CodeBlockComponent = ({ node, editor, updateAttributes }) => {
104107
className="neeto-editor-codeblock-options"
105108
contentEditable={false}
106109
>
110+
<Dropdown
111+
appendTo={() => document.body}
112+
buttonSize="small"
113+
buttonStyle="tertiary"
114+
icon={Down}
115+
strategy="fixed"
116+
zIndex={99999}
117+
label={
118+
showLineNumbers === "true"
119+
? LINE_NUMBER_OPTIONS[0].label
120+
: LINE_NUMBER_OPTIONS[1].label
121+
}
122+
>
123+
<Menu className="neeto-editor-codeblock-options__menu">
124+
{LINE_NUMBER_OPTIONS.map(({ label, value }) => (
125+
<MenuItem.Button
126+
key={label}
127+
onClick={() => {
128+
setShowLineNumbers(value);
129+
updateAttributes({ linenumbers: value });
130+
}}
131+
>
132+
{label}
133+
</MenuItem.Button>
134+
))}
135+
</Menu>
136+
</Dropdown>
107137
<Dropdown
108138
appendTo={() => document.body}
109139
buttonSize="small"

Diff for: src/components/Editor/CustomExtensions/CodeBlock/ExtensionConfig.js

+8
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ export default CodeBlockLowlight.extend({
2121
attributes.highlightedLines?.join(",") ?? "",
2222
}),
2323
},
24+
linenumbers: {
25+
default: "false",
26+
parseHTML: element => element.dataset.linenumbers || "false",
27+
renderHTML: attributes =>
28+
attributes.linenumbers === "true"
29+
? { "data-linenumbers": "true" }
30+
: {},
31+
},
2432
};
2533
},
2634
addProseMirrorPlugins() {
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1+
import { t } from "i18next";
12
import { lowlight } from "lowlight";
23

34
export const SORTED_LANGUAGE_LIST = [
45
...lowlight.listLanguages(),
56
"html",
67
].sort();
8+
9+
export const LINE_NUMBER_OPTIONS = [
10+
{ label: t("neetoEditor.codeblock.showLineNumbers"), value: "true" },
11+
{ label: t("neetoEditor.codeblock.hideLineNumbers"), value: "false" },
12+
];

Diff for: src/components/EditorContent/index.jsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import ImagePreview from "./ImagePreview";
1818
import {
1919
substituteVariables,
2020
applyLineHighlighting,
21-
applySyntaxHighlighting,
21+
applySyntaxHighlightingAndLineNumbers,
2222
} from "./utils";
2323
import { buildHeaderLinks } from "./utils/headers";
2424

@@ -34,7 +34,7 @@ const EditorContent = ({
3434
const editorContentRef = useRef(null);
3535

3636
const htmlContent = substituteVariables(
37-
applySyntaxHighlighting(content),
37+
applySyntaxHighlightingAndLineNumbers(content),
3838
variables
3939
);
4040
const sanitize = DOMPurify.sanitize;

Diff for: src/components/EditorContent/utils/index.js

+12-6
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,14 @@ export const highlightLinesElement = (code, options) => {
6464
highlightLinesCode(code, options);
6565
};
6666

67-
export const applySyntaxHighlighting = content => {
67+
export const applySyntaxHighlightingAndLineNumbers = content => {
6868
lowlight.highlightAuto("");
6969
let highlightedAST = {};
7070

7171
return content.replace(CODE_BLOCK_REGEX, (_, language, code) => {
72-
const regex = /data-highlighted-lines="([^"]*)"/;
73-
const match = content.match(regex);
72+
const highlightRegex = /data-highlighted-lines="([^"]*)"/;
73+
const linenumbersRegex = /data-linenumbers/;
74+
const highlightMatch = content.match(highlightRegex);
7475

7576
if (language && LANGUAGE_LIST.includes(language)) {
7677
highlightedAST = lowlight.highlight(language, transformCode(code));
@@ -85,9 +86,14 @@ export const applySyntaxHighlighting = content => {
8586
buildReactElementFromAST
8687
);
8788

88-
return `<pre data-highlighted-lines=${
89-
match?.[1] ?? ""
90-
}><code>${renderToString(highlightedNode)}</code></pre>`;
89+
const dataHighlight = `data-highlighted-lines=${highlightMatch?.[1] ?? ""}`;
90+
const dataLinenumbers = content.match(linenumbersRegex)
91+
? `data-linenumbers="true"`
92+
: "";
93+
94+
return `<pre ${dataLinenumbers} ${dataHighlight}><code>${renderToString(
95+
highlightedNode
96+
)}</code></pre>`;
9197
});
9298
};
9399

Diff for: src/styles/editor/editor-content.scss

+28-24
Original file line numberDiff line numberDiff line change
@@ -370,31 +370,31 @@
370370
}
371371

372372
counter-reset: line-number;
373+
}
373374

374-
.highlight-line {
375-
position: relative;
376-
padding-left: 3.125rem;
377-
378-
&::before {
379-
color: rgba(var(--neeto-editor-content-code-line-number-color));
380-
content: counter(line-number);
381-
counter-increment: line-number;
382-
font-size: 85%;
383-
font-weight: 400;
384-
position: absolute;
385-
left: 0;
386-
padding-left: 0.625rem;
387-
padding-right: 1rem;
388-
width: 3.125rem;
389-
height: 100%;
390-
display: flex;
391-
align-items: center;
392-
justify-content: flex-end;
393-
}
375+
pre[data-linenumbers] .highlight-line {
376+
position: relative;
377+
padding-left: 3.125rem;
378+
379+
&::before {
380+
color: rgba(var(--neeto-editor-content-code-line-number-color));
381+
content: counter(line-number);
382+
counter-increment: line-number;
383+
font-size: 85%;
384+
font-weight: 400;
385+
position: absolute;
386+
left: 0;
387+
padding-left: 0.625rem;
388+
padding-right: 1rem;
389+
width: 3.125rem;
390+
height: 100%;
391+
display: flex;
392+
align-items: center;
393+
justify-content: flex-end;
394+
}
394395

395-
&:last-child::before {
396-
content: "";
397-
}
396+
&:last-child::before {
397+
content: "";
398398
}
399399
}
400400

@@ -410,7 +410,11 @@
410410
display: block;
411411
width: 100%;
412412
overflow-x: auto;
413-
padding: 0.75rem 0.75rem 0.75rem 0px;
413+
padding: 0.75rem;
414+
}
415+
416+
pre[data-linenumbers]>code {
417+
padding-left: 0;
414418
}
415419

416420
// Blockquote

Diff for: src/translations/en.json

+4
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@
147147
},
148148
"editorContent": {
149149
"imagePreviewAltText": "Image Preview"
150+
},
151+
"codeblock": {
152+
"showLineNumbers": "Show line numbers",
153+
"hideLineNumbers": "Hide line numbers"
150154
}
151155
}
152156
}

0 commit comments

Comments
 (0)