import CopyButton from "../CopyButton"; import { styled } from "../../lib/styles/stitches.config"; import type { ComponentProps } from "react"; const Code = styled("code", { fontSize: "0.925em", color: "$codeText", pageBreakInside: "avoid", backgroundColor: "$codeBackground", border: "1px solid $kindaLight", borderRadius: "$rounded", // light-dark theme switch fading transition: "background 0.25s ease, border 0.25s ease", variants: { // the following sub-classes MUST be global -- the prism rehype plugin isn't aware of this file showLineNumbers: { true: { ".line-number::before": { display: "inline-block", width: "1.5em", marginRight: "1.5em", textAlign: "right", color: "$codeComment", content: "attr(line)", // added to spans by prism userSelect: "none", }, // leave room for clipboard button to the right of the first line ".code-line:first-of-type": { marginRight: "3em", }, }, }, highlight: { true: { ".token": { "&.comment, &.prolog, &.cdata": { color: "$codeComment", }, "&.delimiter, &.boolean, &.keyword, &.selector, &.important, &.doctype, &.atrule, &.url": { color: "$codeKeyword", }, "&.tag, &.builtin, &.regex": { color: "$codeNamespace", }, "&.property, &.constant, &.variable, &.attr-value, &.class-name, &.string, &.char": { color: "$codeVariable", }, "&.literal-property, &.attr-name": { color: "$codeAttribute", }, "&.function": { color: "$codeLiteral", }, "&.tag .punctuation, &.attr-value .punctuation": { color: "$codePunctuation", }, "&.inserted": { color: "$codeAddition", }, "&.deleted": { color: "$codeDeletion", }, "&.url": { textDecoration: "underline" }, "&.bold": { fontWeight: "bold" }, "&.italic": { fontStyle: "italic" }, }, }, }, }, defaultVariants: { showLineNumbers: true, }, }); const InlineCode = styled(Code, { padding: "0.2em 0.3em", }); const Block = styled("div", { position: "relative", width: "100%", margin: "1em auto", [`& ${Code}`]: { display: "block", overflowX: "auto", padding: "1em", tabSize: 2, }, }); const CornerCopyButton = styled(CopyButton, { position: "absolute", top: 0, right: 0, padding: "0.65em", backgroundColor: "$backgroundInner", border: "1px solid $kindaLight", borderTopRightRadius: "$rounded", borderBottomLeftRadius: "$rounded", // light-dark theme switch fading transition: "background 0.25s ease, border 0.25s ease", }); export type CodeBlockProps = ComponentProps & { forceBlock?: boolean; }; const CodeBlock = ({ forceBlock, className, children, ...rest }: CodeBlockProps) => { // detect if this input has already been touched by prism.js via rehype const prismEnabled = className?.split(" ").includes("code-highlight"); if (prismEnabled || forceBlock) { // full multi-line code blocks with copy-to-clipboard button // automatic if highlighted by prism, otherwise can be forced (rather than inlined) with `forceBlock={true}` return ( {children} ); } else { // inline code in paragraphs, headings, etc. (not highlighted) return ( {children} ); } }; export default CodeBlock;