diff --git a/package.json b/package.json index f30efac8345..770b279aa98 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "next-intl": "^3.26.3", "next-mdx-remote": "^5.0.0", "next-themes": "^0.3.0", - "prism-react-renderer": "1.1.0", + "prism-react-renderer": "2.4.1", "prismjs": "^1.30.0", "react": "^19.2.4", "react-chartjs-2": "^5.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3d794663f4e..d2311b5a126 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -169,8 +169,8 @@ importers: specifier: ^0.3.0 version: 0.3.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) prism-react-renderer: - specifier: 1.1.0 - version: 1.1.0(react@19.2.4) + specifier: 2.4.1 + version: 2.4.1(react@19.2.4) prismjs: specifier: ^1.30.0 version: 1.30.0 @@ -4662,6 +4662,9 @@ packages: '@types/pg@8.15.6': resolution: {integrity: sha512-NoaMtzhxOrubeL/7UZuNTrejB4MPAJ0RpxZqXQf2qXuVlTPuG6Y8p4u9dKRaue4yjmC7ZhzVO2/Yyyn25znrPQ==} + '@types/prismjs@1.26.6': + resolution: {integrity: sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==} + '@types/react-dom@19.2.3': resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} peerDependencies: @@ -8531,8 +8534,8 @@ packages: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - prism-react-renderer@1.1.0: - resolution: {integrity: sha512-WZAw+mBoxk1qZDD1h1WOg0BVHgyk9zqbuIBFNgP+Z71i515jGL0WZIN1FIF8EgOyh06x8Rr7HAUXxsRsoUZKyg==} + prism-react-renderer@2.4.1: + resolution: {integrity: sha512-ey8Ls/+Di31eqzUxC46h8MksNuGx/n0AAC8uKpwFau4RPDYLuE3EXTp8N8G2vX2N7UC/+IXeNUnlWBGGcAG+Ig==} peerDependencies: react: ^19.2.4 @@ -16071,6 +16074,8 @@ snapshots: pg-protocol: 1.10.3 pg-types: 2.2.0 + '@types/prismjs@1.26.6': {} + '@types/react-dom@19.2.3(@types/react@19.2.14)': dependencies: '@types/react': 19.2.14 @@ -21054,8 +21059,10 @@ snapshots: ansi-styles: 5.2.0 react-is: 17.0.2 - prism-react-renderer@1.1.0(react@19.2.4): + prism-react-renderer@2.4.1(react@19.2.4): dependencies: + '@types/prismjs': 1.26.6 + clsx: 2.1.1 react: 19.2.4 prismjs@1.30.0: {} diff --git a/src/components/Codeblock.tsx b/src/components/Codeblock.tsx index 461c99adf91..db86c80fc7c 100644 --- a/src/components/Codeblock.tsx +++ b/src/components/Codeblock.tsx @@ -1,196 +1,42 @@ "use client" + import React, { useState } from "react" import { Clipboard, ClipboardCheck } from "lucide-react" -import Highlight, { - defaultProps, - Language, - PrismTheme, -} from "prism-react-renderer" -import Prism from "prism-react-renderer/prism" +import { useTheme } from "next-themes" +import { Highlight, Prism, type PrismTheme, themes } from "prism-react-renderer" -// https://github.com/FormidableLabs/prism-react-renderer/tree/master#custom-language-support import CopyToClipboard from "@/components/CopyToClipboard" +import { Button } from "@/components/ui/buttons/Button" import { Flex } from "@/components/ui/flex" import { cn } from "@/lib/utils/cn" import { LINES_BEFORE_COLLAPSABLE } from "@/lib/constants" -import useColorModeValue from "@/hooks/useColorModeValue" import { useTranslation } from "@/hooks/useTranslation" + +// Register Solidity language support +// https://github.com/FormidableLabs/prism-react-renderer#custom-language-support ;(typeof global !== "undefined" ? global : window).Prism = Prism require("prismjs/components/prism-solidity") -const TopBarItem = ({ - className, - ...props -}: React.HTMLAttributes) => { - return ( -
- ) -} +const makeTransparent = (theme: PrismTheme): PrismTheme => ({ + ...theme, + plain: { ...theme.plain, backgroundColor: "transparent" }, +}) -const codeTheme = { - light: { - styles: [ - { - style: { color: "#6c6783" }, - types: ["comment", "prolog", "doctype", "cdata", "punctuation"], - }, - { - style: { opacity: 0.7 }, - types: ["namespace"], - }, - { - style: { color: "#e09142" }, - types: ["tag", "operator", "number"], - }, - { - style: { color: "#ff7324" }, - types: ["property", "function"], - }, - { - style: { color: "#888888" }, - types: ["tag-id", "selector", "atrule-id"], - }, - { - style: { color: "#474b5e" }, - types: ["attr-name"], - }, - { - style: { color: "#498bb5" }, - types: [ - "boolean", - "string", - "entity", - "url", - "attr-value", - "keyword", - "control", - "directive", - "unit", - "statement", - "regex", - "at-rule", - "placeholder", - "variable", - ], - }, - { - style: { textDecorationLine: "line-through" }, - types: ["deleted"], - }, - { - style: { textDecorationLine: "underline" }, - types: ["inserted"], - }, - { - style: { fontStyle: "italic" }, - types: ["italic"], - }, - { - style: { fontWeight: "bold" }, - types: ["important", "bold"], - }, - { - style: { color: "#c4b9fe" }, - types: ["important"], - }, - ], - }, - dark: { - // Pulled from `defaultProps.theme` for potential customization - styles: [ - { - style: { color: "#6c6783" }, - types: ["comment", "prolog", "doctype", "cdata", "punctuation"], - }, - { - style: { opacity: 0.7 }, - types: ["namespace"], - }, - { - style: { color: "#e09142" }, - types: ["tag", "operator", "number"], - }, - { - style: { color: "#9a86fd" }, - types: ["property", "function"], - }, - { - style: { color: "#eeebff" }, - types: ["tag-id", "selector", "atrule-id"], - }, - { - style: { color: "#c4b9fe" }, - types: ["attr-name"], - }, - { - style: { color: "#ffcc99" }, - types: [ - "boolean", - "string", - "entity", - "url", - "attr-value", - "keyword", - "control", - "directive", - "unit", - "statement", - "regex", - "at-rule", - "placeholder", - "variable", - ], - }, - { - style: { textDecorationLine: "line-through" }, - types: ["deleted"], - }, - { - style: { textDecorationLine: "underline" }, - types: ["inserted"], - }, - { - style: { fontStyle: "italic" }, - types: ["italic"], - }, - { - style: { fontWeight: "bold" }, - types: ["important", "bold"], - }, - { - style: { color: "#c4b9fe" }, - types: ["important"], - }, - ], - }, -} +const lightTheme = makeTransparent(themes.oneLight) +const darkTheme = makeTransparent(themes.duotoneDark) -const getValidChildrenForCodeblock = (child) => { +const getValidChildrenForCodeblock = (child: unknown): string | undefined => { try { if (typeof child !== "string") { - return getValidChildrenForCodeblock(child.props.children) + const element = child as React.ReactElement<{ children: unknown }> + return getValidChildrenForCodeblock(element.props.children) } else { return child } - } catch (e) { - /*For now available: code without wrappers like div - * example: - * - const web3 = new Web3("wss://eth-mainnet.ws.alchemyapi.io/ws/your-api-key"){"\n"} - web3.eth.getBlockNumber().then(console.log) - - * */ + } catch { console.error(`Codeblock children is not valid`) } } @@ -209,7 +55,8 @@ const Codeblock = ({ className, }: CodeblockProps) => { const { t } = useTranslation("common") - const selectedTheme = useColorModeValue(codeTheme.light, codeTheme.dark) + const { resolvedTheme } = useTheme() + const codeTheme = resolvedTheme === "dark" ? darkTheme : lightTheme const codeText = React.Children.toArray(children) .map((child) => { @@ -244,35 +91,28 @@ const Codeblock = ({ /* Context: https://github.com/ethereum/ethereum-org-website/issues/6202 */
- - {({ className, style, tokens, getLineProps, getTokenProps }) => ( + + {({ style, tokens, getLineProps, getTokenProps }) => (
               {tokens.map((line, i) => {
-                return i === tokens.length - 1 &&
-                  line[0].content === "" ? null : (
+                return i === tokens.length - 1 && line[0].empty ? null : (
                   
{shouldShowLineNumbers && ( @@ -281,40 +121,48 @@ const Codeblock = ({ )} {line.map((token, key) => ( - + ))}
) })} {!fromHomepage && ( - + {allowCollapse && totalLines - 1 > LINES_BEFORE_COLLAPSABLE && ( - setIsCollapsed(!isCollapsed)}> + )} {shouldShowCopyWidget && ( - - {(isCopied) => ( - - {!isCopied ? ( + )} )}