123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- 'use client';
- import React from 'react';
- import { useClipboard } from '@/hooks';
- import clsx from 'clsx';
- import { html as beautifyHtml } from 'js-beautify';
- import SyntaxHighlighter from 'react-syntax-highlighter';
- import Icon from '@/components/Icon';
- export default function CodeBlock({
- html,
- children,
- className,
- language = 'xml',
- copyable = true,
- beautify = false,
- hideLinks = false,
- }:{
- html?: string,
- children?: React.ReactNode,
- className?: string,
- language?: string,
- copyable?: boolean,
- beautify?: boolean,
- hideLinks?: boolean,
- }) {
- let code = html ?? (children || '').toString();
- const clipboard = useClipboard();
- if (hideLinks) {
- code = code
- .replace(/url\([^\)]+\)/g, 'url(...)')
- .replace(/img src="[^"]+"/g, 'img src="..."')
- .replace(
- /(\n?)(\s*)<svg[^>]+icon-tabler-([^"]+).*?<\/svg>/gms,
- '$1$2<!-- SVG icon from http://tabler-icons.io/i/$3 -->\n$2<svg>...</svg>'
- );
- }
- if (beautify) {
- code = beautifyHtml(code, {
- inline: 'strong',
- indent_size: 2,
- });
- }
- const languageNames = {
- js: 'JavaScript',
- ts: 'TypeScript',
- javascript: 'JavaScript',
- typescript: 'TypeScript',
- php: 'PHP',
- python: 'Python',
- ruby: 'Ruby',
- go: 'Go',
- };
- if (language === 'js') {
- language = 'javascript';
- } else if (language === 'html') {
- language = 'xml';
- }
- return (
- <div className="codeblock">
- {copyable && (
- <div className="codeblock-copy">
- <button
- className={clsx('btn btn-icon', clipboard.copied ? 'btn-green' : 'btn-dark')}
- onClick={() => clipboard.copy(html || '')}
- >
- {clipboard.copied ? <Icon name="check" /> : <Icon name="clipboard" />}
- </button>
- </div>
- )}
- <SyntaxHighlighter
- className={clsx(`language-${language}`, className)}
- language={language}
- useInlineStyles={false}
- >
- {code}
- </SyntaxHighlighter>
- </div>
- );
- }
|