mirror of
https://github.com/stackblitz-labs/bolt.diy
synced 2025-06-26 10:16:01 +00:00
* feat: Add reusable UI components and fix GitHub repository display * style: Fix linting issues in UI components * fix: Add close icon to GitHub Connection Required dialog * fix: Add CloseButton component to fix white background issue in dialog close icons * Fix close button styling in dialog components to address ghost white issue in dark mode * fix: update icon color to tertiary for consistency The icon color was changed from `text-bolt-elements-icon-info` to `text-bolt-elements-icon-tertiary` * fix: improve repository selection dialog tab styling for dark mode - Update tab menu styling to prevent white background in dark mode - Use explicit color values for better dark/light mode compatibility - Improve hover and active states for better visual hierarchy - Remove unused Tabs imports --------- Co-authored-by: KevIsDev <zennerd404@gmail.com>
104 lines
3.9 KiB
TypeScript
104 lines
3.9 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { classNames } from '~/utils/classNames';
|
|
import { motion } from 'framer-motion';
|
|
import { FileIcon } from './FileIcon';
|
|
import { Tooltip } from './Tooltip';
|
|
|
|
interface CodeBlockProps {
|
|
code: string;
|
|
language?: string;
|
|
filename?: string;
|
|
showLineNumbers?: boolean;
|
|
highlightLines?: number[];
|
|
maxHeight?: string;
|
|
className?: string;
|
|
onCopy?: () => void;
|
|
}
|
|
|
|
export function CodeBlock({
|
|
code,
|
|
language,
|
|
filename,
|
|
showLineNumbers = true,
|
|
highlightLines = [],
|
|
maxHeight = '400px',
|
|
className,
|
|
onCopy,
|
|
}: CodeBlockProps) {
|
|
const [copied, setCopied] = useState(false);
|
|
|
|
const handleCopy = () => {
|
|
navigator.clipboard.writeText(code);
|
|
setCopied(true);
|
|
setTimeout(() => setCopied(false), 2000);
|
|
onCopy?.();
|
|
};
|
|
|
|
const lines = code.split('\n');
|
|
|
|
return (
|
|
<div
|
|
className={classNames(
|
|
'rounded-lg overflow-hidden border border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark',
|
|
'bg-bolt-elements-background-depth-2 dark:bg-bolt-elements-background-depth-3',
|
|
className,
|
|
)}
|
|
>
|
|
{/* Header */}
|
|
<div className="flex items-center justify-between px-4 py-2 bg-bolt-elements-background-depth-3 dark:bg-bolt-elements-background-depth-4 border-b border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark">
|
|
<div className="flex items-center gap-2">
|
|
{filename && (
|
|
<>
|
|
<FileIcon filename={filename} size="sm" />
|
|
<span className="text-xs font-medium text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark">
|
|
{filename}
|
|
</span>
|
|
</>
|
|
)}
|
|
{language && !filename && (
|
|
<span className="text-xs font-medium text-bolt-elements-textSecondary dark:text-bolt-elements-textSecondary-dark uppercase">
|
|
{language}
|
|
</span>
|
|
)}
|
|
</div>
|
|
<Tooltip content={copied ? 'Copied!' : 'Copy code'}>
|
|
<motion.button
|
|
onClick={handleCopy}
|
|
className="p-1.5 rounded-md text-bolt-elements-textTertiary hover:text-bolt-elements-textSecondary dark:text-bolt-elements-textTertiary-dark dark:hover:text-bolt-elements-textSecondary-dark hover:bg-bolt-elements-background-depth-2 dark:hover:bg-bolt-elements-background-depth-3 transition-colors"
|
|
whileHover={{ scale: 1.05 }}
|
|
whileTap={{ scale: 0.95 }}
|
|
>
|
|
{copied ? <span className="i-ph:check w-4 h-4 text-green-500" /> : <span className="i-ph:copy w-4 h-4" />}
|
|
</motion.button>
|
|
</Tooltip>
|
|
</div>
|
|
|
|
{/* Code content */}
|
|
<div className={classNames('overflow-auto', 'font-mono text-sm', 'custom-scrollbar')} style={{ maxHeight }}>
|
|
<table className="min-w-full border-collapse">
|
|
<tbody>
|
|
{lines.map((line, index) => (
|
|
<tr
|
|
key={index}
|
|
className={classNames(
|
|
highlightLines.includes(index + 1) ? 'bg-purple-500/10 dark:bg-purple-500/20' : '',
|
|
'hover:bg-bolt-elements-background-depth-3 dark:hover:bg-bolt-elements-background-depth-4',
|
|
)}
|
|
>
|
|
{showLineNumbers && (
|
|
<td className="py-1 pl-4 pr-2 text-right select-none text-bolt-elements-textTertiary dark:text-bolt-elements-textTertiary-dark border-r border-bolt-elements-borderColor dark:border-bolt-elements-borderColor-dark">
|
|
<span className="inline-block min-w-[1.5rem] text-xs">{index + 1}</span>
|
|
</td>
|
|
)}
|
|
<td className="py-1 pl-4 pr-4 text-bolt-elements-textPrimary dark:text-bolt-elements-textPrimary-dark whitespace-pre">
|
|
{line || ' '}
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|