使用 mantine UI 的 CopyButton 组件注入复制按键到文章代码块中

在 anflext press 应用中使用了 tiptap 组件来编辑文章。之后发布 html 内容,代码块(html 的 pre 标记)会正常突出显示出来。

有时可能需要通过复制来提取代码使用。这时一个最简单的办法就是通过 Ctrl+C 快捷键或鼠标右键菜单来操作,不及友好。正常的网站会提供一个复制按键在代码块上,我也想实现这个实用功能。

谷歌了一下,我发现有一篇讨论这个问题的文章值得参考学习: Inject Copy Button into Code Block Using MutationObserver in a React Application 。研读了代码,学习了一下,我就用 mantine UI 的 CopyButton 组件来执行这个操作。代码类似于:

import { ActionIcon, CopyButton, MantineProvider, Tooltip, Typography } from "@mantine/core";
import { IconCheck, IconCopy } from '@tabler/icons-react';
import theme from './theme.js';

// Use the below article code and replace with CopyButton
// https://www.alexandru-barbulescu.com/posts/inject-copy-button-into-code-block-using-mutationobserver-in-a-react-application
const CopyButtonsInjector = () => {

  useEffect(() => {
    const pres = document.querySelectorAll('pre');

    pres.forEach(pre => {
      if (pre.querySelector('.copy-btn-wrapper')) return;
      if (!pre.textContent?.trim()) return;

      const wrapper = document.createElement('div');
      wrapper.className = 'copy-btn-wrapper';
      wrapper.style.position = 'absolute';
      wrapper.style.top = '0.1rem';
      wrapper.style.right = '0.5rem';
      wrapper.style.zIndex = '10';

      pre.style.position = 'relative';
      pre.appendChild(wrapper);

      const root = createRoot(wrapper);
      root.render(
        <MantineProvider theme={theme}>
        <CopyButton value={pre.textContent}>
          {({ copied, copy }) => (
            <Tooltip label={copied ? 'Copied' : 'Copy'} withArrow position="right">
              <ActionIcon color={copied ? 'teal' : 'gray'} variant="subtle" onClick={copy}>
                {copied ? <IconCheck size={16} /> : <IconCopy size={16} />}
              </ActionIcon>
            </Tooltip>
          )}
        </CopyButton></MantineProvider>
      );
    });
  });

  return null;
};


export default function Article() {
// some other code
    return (
      <>
        <CopyButtonsInjector />
        <Typography dangerouslySetInnerHTML={{ __html: '<p>test only</p>' }} />
      </>
    );
}

注意: 那个 theme 组件必须要导入进来放到 MantineProvider 的 theme 属性中。我用的布局组件中使用了 MantineProvider, 如果不这么使用的话就会报运行时错误,添加的复制按钮就显示不出来了。

但功能实现后,却发现在 dark 模式下 code 标记的背景与父 pre 标记的背景不一样,看起来不那么美观,就像这样:

我只好去调试检查了一下默认的 @mantine/core/styles.css 文件,然后手动将这两个标记的颜色设置成一样的:

// @mantine/core/styles.css:7678
// pills variant
  :where([data-mantine-color-scheme='dark']) .m_d08caa0 :where(pre) {
      background-color: var(--mantine-color-dark-8);
}

// Changed to

  :where([data-mantine-color-scheme='dark']) .m_d08caa0 :where(pre) {
      background-color: var(--mantine-color-dark-5);
}

最终结果看着就好看多了:

21

Top articles