Skip to content

Commit be5b147

Browse files
committed
improved code block UI
1 parent b455a92 commit be5b147

File tree

1 file changed

+132
-34
lines changed

1 file changed

+132
-34
lines changed

src/components/ui/code-group.tsx

Lines changed: 132 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import React, { useState } from 'react'
22
import { cn } from '@/lib/utils'
3+
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
4+
import { oneDark } from 'react-syntax-highlighter/dist/cjs/styles/prism'
35

46
/**
57
* CodeGroup component for displaying multiple code blocks in tabs
@@ -128,6 +130,21 @@ const LANGUAGE_NAMES: { [key: string]: string } = {
128130
http: 'HTTP',
129131
}
130132

133+
// Custom syntax highlighting theme based on oneDark
134+
const customTheme = {
135+
...oneDark,
136+
'pre[class*="language-"]': {
137+
...oneDark['pre[class*="language-"]'],
138+
background: 'transparent',
139+
margin: 0,
140+
padding: 0,
141+
},
142+
'code[class*="language-"]': {
143+
...oneDark['code[class*="language-"]'],
144+
background: 'transparent',
145+
}
146+
}
147+
131148
// Add this function before the CodeGroup component
132149
/**
133150
* Preprocesses code content to fix common MDX parsing issues:
@@ -166,42 +183,90 @@ export function CodeGroup({ children, className }: CodeGroupProps) {
166183
// Preprocess the code content
167184
const processedCode = preprocessCode(code);
168185

169-
return React.createElement('div', {
170-
key: `${index}-${displayTitle}`,
171-
className: "font-mono text-sm processed-code-block",
172-
'data-type': 'processed',
173-
'data-language': language,
174-
'data-title': displayTitle,
175-
children: processedCode
176-
});
186+
return (
187+
<div key={`${index}-${displayTitle}`} className="relative">
188+
<SyntaxHighlighter
189+
language={language.toLowerCase()}
190+
style={customTheme}
191+
showLineNumbers
192+
wrapLines
193+
customStyle={{
194+
margin: 0,
195+
padding: '1rem',
196+
background: 'transparent',
197+
fontSize: '0.875rem',
198+
}}
199+
lineNumberStyle={{
200+
minWidth: '2.5em',
201+
paddingRight: '1em',
202+
textAlign: 'right',
203+
color: 'rgba(156, 163, 175, 0.5)',
204+
userSelect: 'none',
205+
}}
206+
codeTagProps={{
207+
style: {
208+
fontSize: 'inherit',
209+
lineHeight: '1.5',
210+
}
211+
}}
212+
>
213+
{processedCode}
214+
</SyntaxHighlighter>
215+
</div>
216+
);
177217
}
178218
}
179219

180220
// Handle regular JSX components (likely our <Code> component)
181221
if (React.isValidElement(child)) {
182222
const element = child as React.ReactElement<ElementProps>;
223+
let language = '';
224+
let code = '';
183225

184-
// If the child has string content, preprocess it
185-
if (typeof element.props.children === 'string') {
186-
return React.cloneElement(element, {
187-
...element.props,
188-
children: preprocessCode(element.props.children)
189-
});
226+
// Extract language from className
227+
if (element.props.className) {
228+
const match = String(element.props.className).match(/language-(\w+)/);
229+
if (match) {
230+
language = match[1].toLowerCase();
231+
}
190232
}
191233

192-
// If the child has nested content, process it recursively
193-
if (React.isValidElement(element.props.children)) {
194-
const nestedElement = element.props.children as React.ReactElement<ElementProps>;
195-
if (nestedElement.props?.children && typeof nestedElement.props.children === 'string') {
196-
return React.cloneElement(element, {
197-
...element.props,
198-
children: React.cloneElement(nestedElement, {
199-
...nestedElement.props,
200-
children: preprocessCode(nestedElement.props.children)
201-
})
202-
});
203-
}
234+
// Extract code content
235+
if (typeof element.props.children === 'string') {
236+
code = preprocessCode(element.props.children);
204237
}
238+
239+
return (
240+
<div key={index} className="relative">
241+
<SyntaxHighlighter
242+
language={language || 'text'}
243+
style={customTheme}
244+
showLineNumbers
245+
wrapLines
246+
customStyle={{
247+
margin: 0,
248+
padding: '1rem',
249+
background: 'transparent',
250+
fontSize: '0.875rem',
251+
}}
252+
lineNumberStyle={{
253+
minWidth: '2.5em',
254+
paddingRight: '1em',
255+
textAlign: 'right',
256+
color: 'rgba(156, 163, 175, 0.5)',
257+
userSelect: 'none',
258+
}}
259+
codeTagProps={{
260+
style: {
261+
fontSize: 'inherit',
262+
lineHeight: '1.5',
263+
}
264+
}}
265+
>
266+
{code}
267+
</SyntaxHighlighter>
268+
</div>
269+
);
205270
}
206271

207272
return child;
@@ -299,12 +364,13 @@ export function CodeGroup({ children, className }: CodeGroupProps) {
299364

300365
return (
301366
<div className={cn(
302-
"relative my-6 overflow-hidden rounded-3xl border border-gray-200/50 dark:border-gray-800/80",
367+
"relative my-6 overflow-hidden rounded-xl border border-gray-200/50 dark:border-gray-800/80",
303368
"shadow-sm hover:shadow-md transition-all duration-300 backdrop-blur-sm",
369+
"bg-gray-50/50 dark:bg-gray-900/50",
304370
className
305371
)}>
306372
{/* Tabs */}
307-
<div className="flex overflow-x-auto border-b border-gray-200/50 dark:border-gray-800/80 scrollbar-none">
373+
<div className="flex overflow-x-auto border-b border-gray-200/50 dark:border-gray-800/80 bg-white/50 dark:bg-black/50 scrollbar-none">
308374
{processedChildren.map((child, index) => {
309375
const { title } = getTabInfo(child, index);
310376

@@ -315,7 +381,7 @@ export function CodeGroup({ children, className }: CodeGroupProps) {
315381
className={cn(
316382
'px-5 py-3 text-sm font-medium whitespace-nowrap transition-all duration-200',
317383
activeTab === index
318-
? 'border-b-2 border-gray-800 text-gray-900 dark:border-gray-200 dark:text-gray-100'
384+
? 'border-b-2 border-primary text-primary bg-primary/5'
319385
: 'text-gray-600 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-200'
320386
)}
321387
>
@@ -325,19 +391,51 @@ export function CodeGroup({ children, className }: CodeGroupProps) {
325391
})}
326392
</div>
327393

328-
{/* Content - clean minimal style */}
329-
<div className="relative p-5 font-mono text-sm text-gray-800 dark:text-gray-200">
394+
{/* Content - modern IDE style */}
395+
<div className="relative font-mono text-sm text-gray-800 dark:text-gray-200 bg-gray-50/80 dark:bg-gray-900/80">
330396
{processedChildren[activeTab]}
331397
<CopyButton value={getContentToCopy()} />
332398
</div>
333399
</div>
334400
)
335401
}
336402

337-
export function Code({ title, children, className }: CodeProps) {
403+
export function Code({ title, children, className, language }: CodeProps) {
338404
return (
339-
<div className={cn("font-mono text-sm", className)}>
340-
{children}
405+
<div className={cn("relative", className)}>
406+
{title && (
407+
<div className="px-4 py-2 text-xs font-medium text-gray-600 dark:text-gray-400 border-b border-gray-200/50 dark:border-gray-800/80 bg-white/50 dark:bg-black/50">
408+
{title}
409+
</div>
410+
)}
411+
<SyntaxHighlighter
412+
language={language || 'text'}
413+
style={customTheme}
414+
showLineNumbers
415+
wrapLines
416+
customStyle={{
417+
margin: 0,
418+
padding: '1rem',
419+
background: 'transparent',
420+
fontSize: '0.875rem',
421+
}}
422+
lineNumberStyle={{
423+
minWidth: '2.5em',
424+
paddingRight: '1em',
425+
textAlign: 'right',
426+
color: 'rgba(156, 163, 175, 0.5)',
427+
userSelect: 'none',
428+
}}
429+
codeTagProps={{
430+
style: {
431+
fontSize: 'inherit',
432+
lineHeight: '1.5',
433+
}
434+
}}
435+
>
436+
{typeof children === 'string' ? children : ''}
437+
</SyntaxHighlighter>
438+
{typeof children === 'string' && <CopyButton value={children} className={title ? "top-11" : ""} />}
341439
</div>
342440
)
343441
}

0 commit comments

Comments
 (0)