gatsby-theme-mdx-blog
gatsby-theme-mdx-blog copied to clipboard
Add Prism code highlighting
Kind of like Kent C. Dodds does in his website, I'd love for Prism code highlighting (and specific code lines highlighted too)
Reference: Kent C. Dodds' src/components/mdx/code.js
Ah! Think I missed this in the readme, but you can shadow src/components.js
to add a custom code
component for syntax highlighting etc – can add that to the docs, but maybe that helps you move forward for now
but you can shadow src/components.js to add a custom code component for syntax highlighting etc
@jxnblk Not seeing how I can do this ... could you maybe give an example?
can add that to the docs
For sure ... let me just understand what is going on first and how to use it properly
I have the following code in src/@jxnblk/gatsby-theme-mdx-blog/components.js
:
import components from "@jxnblk/gatsby-theme-mdx-blog/src/components.js";
import Code from "../../components/mdx/code";
export default {
...components,
code: Code
};
Where ../../components/mdx/code
is Kent C. Dodds' src/components/mdx/code.js
But I get this error:
TypeError: undefined is not an object (evaluating 'token.type')
normalizeTokens
node_modules/prism-react-renderer/es/utils/normalizeTokens.js:42
39 | types = stackIndex > 0 ? types : ["plain"];
40 | content = token;
41 | } else {
> 42 | types = types[0] === token.type ? types : types.concat(token.type);
43 | content = token.content;
44 | } // If token.content is an array, increase the stack depth and repeat this while-loop
45 |
Looks like you have the part in src/@jxnblk/gatsby-theme-mdx-blog/components.js
correct, but that error seems to be coming from somewhere else... maybe the Code
component?
maybe the Code component?
@jxnblk I'll take a look ... thanks for the help. I'll keep you posted
@jxnblk Still not working ... I'm not getting any error (like before), it just doesn't colour the code.
src/@jxnblk/gatsby-theme-mdx-blog/components.js
:
import components from "@jxnblk/gatsby-theme-mdx-blog/src/components.js";
import mdxComponents from "../../components/mdx";
export default {
...components,
...mdxComponents
};
Note that the following code was taken from Kent C Dodds website
src/components/mdx/index.js
:
import React from "react";
import Code from "./code";
export default {
pre: preProps => {
const props = preToCodeBlock(preProps);
// if there's a codeString and some props, we passed the test
if (props) {
return <Code {...props} />;
} else {
// it's possible to have a pre without a code in it
return <pre {...preProps} />;
}
}
};
function preToCodeBlock(preProps) {
if (
// children is MDXTag
preProps.children &&
// MDXTag props
preProps.children.props &&
// if MDXTag is going to render a <code>
preProps.children.props.name === "code"
) {
// we have a <pre><code> situation
const {
children: codeString,
props: { className, ...props }
} = preProps.children.props;
return {
codeString: codeString.trim(),
language: className && className.split("-")[1],
...props
};
}
}
src/components/mdx/code.js
:
import React from "react";
import { css } from "@emotion/core";
import theme from "prism-react-renderer/themes/oceanicNext";
import Highlight, { defaultProps } from "prism-react-renderer";
const RE = /{([\d,-]+)}/;
const wrapperStyles = css`
overflow: auto;
`;
const preStyles = css`
float: left;
min-width: 100%;
overflow: initial;
`;
function calculateLinesToHighlight(meta) {
if (RE.test(meta)) {
const lineNumbers = RE.exec(meta)[1]
.split(",")
.map(v => v.split("-").map(y => parseInt(y, 10)));
return index => {
const lineNumber = index + 1;
const inRange = lineNumbers.some(([start, end]) =>
end ? lineNumber >= start && lineNumber <= end : lineNumber === start
);
return inRange;
};
} else {
return () => false;
}
}
function Code({ codeString, language, metastring }) {
const shouldHighlightLine = calculateLinesToHighlight(metastring);
return (
<Highlight
{...defaultProps}
code={codeString}
language={language}
theme={theme}
>
{({ className, style, tokens, getLineProps, getTokenProps }) => (
<div css={wrapperStyles}>
<pre className={className} style={style} css={preStyles}>
{tokens.map((line, i) => (
<div
key={i}
{...getLineProps({
line,
key: i,
className: shouldHighlightLine(i) ? "highlight-line" : ""
})}
>
<span
css={css`
display: inline-block;
width: 2em;
user-select: none;
opacity: 0.3;
`}
>
{i + 1}
</span>
{line.map((token, key) => (
<span key={key} {...getTokenProps({ token, key })} />
))}
</div>
))}
</pre>
</div>
)}
</Highlight>
);
}
export default Code;