diff --git a/src/components/MessageRenderer/CodeBlock/CodeBlockDarkTheme.ts b/src/components/MessageRenderer/CodeBlock/CodeBlockDarkTheme.ts new file mode 100644 index 0000000..0a9d6a4 --- /dev/null +++ b/src/components/MessageRenderer/CodeBlock/CodeBlockDarkTheme.ts @@ -0,0 +1,102 @@ +import type { CSSProperties } from 'react'; + +const darkTheme = { + 'hljs-comment': { + color: '#8b949e', + }, + 'hljs-quote': { + color: '#8b949e', + }, + 'hljs-variable': { + color: '#ff7b72', + }, + 'hljs-template-variable': { + color: '#ff7b72', + }, + 'hljs-tag': { + color: '#ff7b72', + }, + 'hljs-name': { + color: '#ff7b72', + }, + 'hljs-selector-id': { + color: '#ff7b72', + }, + 'hljs-selector-class': { + color: '#ff7b72', + }, + 'hljs-regexp': { + color: '#ff7b72', + }, + 'hljs-deletion': { + color: '#ff7b72', + }, + 'hljs-number': { + color: '#f2cc60', + }, + 'hljs-built_in': { + color: '#f2cc60', + }, + 'hljs-builtin-name': { + color: '#f2cc60', + }, + 'hljs-literal': { + color: '#f2cc60', + }, + 'hljs-type': { + color: '#f2cc60', + }, + 'hljs-params': { + color: '#f2cc60', + }, + 'hljs-meta': { + color: '#f2cc60', + }, + 'hljs-link': { + color: '#f2cc60', + }, + 'hljs-attribute': { + color: '#58a6ff', + }, + 'hljs-string': { + color: '#7ee787', + }, + 'hljs-symbol': { + color: '#7ee787', + }, + 'hljs-bullet': { + color: '#7ee787', + }, + 'hljs-addition': { + color: '#7ee787', + }, + 'hljs-title': { + color: '#79c0ff', + }, + 'hljs-section': { + color: '#79c0ff', + }, + 'hljs-keyword': { + color: '#c297ff', + }, + 'hljs-selector-tag': { + color: '#c297ff', + }, + hljs: { + display: 'block', + overflowX: 'auto', + background: '#0d1117', + color: '#c9d1d9', + padding: '0.75em', + border: '1px solid #21262d', + borderRadius: '10px', + }, + 'hljs-emphasis': { + fontStyle: 'italic', + }, + 'hljs-strong': { + fontWeight: 'bold', + }, +} satisfies Record; + +export default darkTheme; diff --git a/src/components/MessageRenderer/CodeBlock/CodeBlockLightTheme.ts b/src/components/MessageRenderer/CodeBlock/CodeBlockLightTheme.ts new file mode 100644 index 0000000..758dbac --- /dev/null +++ b/src/components/MessageRenderer/CodeBlock/CodeBlockLightTheme.ts @@ -0,0 +1,102 @@ +import type { CSSProperties } from 'react'; + +const lightTheme = { + 'hljs-comment': { + color: '#6e7781', + }, + 'hljs-quote': { + color: '#6e7781', + }, + 'hljs-variable': { + color: '#d73a49', + }, + 'hljs-template-variable': { + color: '#d73a49', + }, + 'hljs-tag': { + color: '#d73a49', + }, + 'hljs-name': { + color: '#d73a49', + }, + 'hljs-selector-id': { + color: '#d73a49', + }, + 'hljs-selector-class': { + color: '#d73a49', + }, + 'hljs-regexp': { + color: '#d73a49', + }, + 'hljs-deletion': { + color: '#d73a49', + }, + 'hljs-number': { + color: '#b08800', + }, + 'hljs-built_in': { + color: '#b08800', + }, + 'hljs-builtin-name': { + color: '#b08800', + }, + 'hljs-literal': { + color: '#b08800', + }, + 'hljs-type': { + color: '#b08800', + }, + 'hljs-params': { + color: '#b08800', + }, + 'hljs-meta': { + color: '#b08800', + }, + 'hljs-link': { + color: '#b08800', + }, + 'hljs-attribute': { + color: '#0a64ae', + }, + 'hljs-string': { + color: '#22863a', + }, + 'hljs-symbol': { + color: '#22863a', + }, + 'hljs-bullet': { + color: '#22863a', + }, + 'hljs-addition': { + color: '#22863a', + }, + 'hljs-title': { + color: '#005cc5', + }, + 'hljs-section': { + color: '#005cc5', + }, + 'hljs-keyword': { + color: '#6f42c1', + }, + 'hljs-selector-tag': { + color: '#6f42c1', + }, + hljs: { + display: 'block', + overflowX: 'auto', + background: '#ffffff', + color: '#24292f', + padding: '0.75em', + border: '1px solid #e8edf1', + borderRadius: '10px', + }, + 'hljs-emphasis': { + fontStyle: 'italic', + }, + 'hljs-strong': { + fontWeight: 'bold', + }, +} satisfies Record; + +export default lightTheme; diff --git a/src/components/MessageRenderer/CodeBlock/index.tsx b/src/components/MessageRenderer/CodeBlock/index.tsx new file mode 100644 index 0000000..493a0d0 --- /dev/null +++ b/src/components/MessageRenderer/CodeBlock/index.tsx @@ -0,0 +1,64 @@ +'use client'; + +import { CheckIcon, CopyIcon } from '@phosphor-icons/react'; +import React, { useEffect, useMemo, useState } from 'react'; +import { useTheme } from 'next-themes'; +import SyntaxHighlighter from 'react-syntax-highlighter'; +import darkTheme from './CodeBlockDarkTheme'; +import lightTheme from './CodeBlockLightTheme'; + +const CodeBlock = ({ + language, + children, +}: { + language: string; + children: React.ReactNode; +}) => { + const { resolvedTheme } = useTheme(); + const [mounted, setMounted] = useState(false); + + const [copied, setCopied] = useState(false); + + useEffect(() => { + setMounted(true); + }, []); + + const syntaxTheme = useMemo(() => { + if (!mounted) return lightTheme; + return resolvedTheme === 'dark' ? darkTheme : lightTheme; + }, [mounted, resolvedTheme]); + + return ( +
+ + + {children as string} + +
+ ); +}; + +export default CodeBlock;