feat: github fix and ui improvements (#1685)
* 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>
This commit is contained in:
103
app/components/ui/CodeBlock.tsx
Normal file
103
app/components/ui/CodeBlock.tsx
Normal file
@@ -0,0 +1,103 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user