anycoder-6d5b65da / components /CodeEditor.jsx
Mehdi
Upload components/CodeEditor.jsx with huggingface_hub
8b44b0d verified
Raw
History Blame
11.4 kB
import { useState, useEffect, useRef } from 'react'
import Editor from '@monaco-editor/react'
import { motion } from 'framer-motion'
import {
FaPlay, FaSave, FaDownload, FaUpload, FaCopy, FaPaste,
FaUndo, FaRedo, FaSearch, FaReplace, FaCog, FaExpand,
FaCompress, FaTerminal, FaEye, FaCode, FaFile, FaFolder,
FaPlus, FaMinus, FaTimes, FaCheck, FaSync, FaBug,
FaRocket, FaShieldAlt, FaChartLine, FaDatabase, FaCloud,
FaServer, FaGitAlt, FaLink, FaLock, FaUnlock, FaShare,
FaStar, FaRegStar, FaBookmark, FaFlag, FaTag, FaTags,
FaCalendar, FaClock, FaUser, FaUsers, FaComment, FaComments,
FaHeart, FaRegHeart, FaThumbsUp, FaThumbsDown, FaEyeSlash,
FaEdit, FaTrash, FaFileCode, FaFileAlt, FaFileArchive,
FaFileImage, FaFileVideo, FaFileAudio, FaFilePdf, FaFileExcel,
FaFileWord, FaFilePowerpoint, FaFileCsv, FaFileZip, FaFileMedical
} from 'react-icons/fa'
import toast from 'react-hot-toast'
export default function CodeEditor({ language, theme }) {
const [code, setCode] = useState(`// Welcome to AI Dev Studio
function helloWorld() {
console.log("Hello, World!");
return "Welcome to the future of coding!";
}
helloWorld();`)
const [currentLanguage, setCurrentLanguage] = useState('javascript')
const [theme, setTheme] = useState('vs-dark')
const [isFullscreen, setIsFullscreen] = useState(false)
const [showTerminal, setShowTerminal] = useState(false)
const [terminalOutput, setTerminalOutput] = useState([])
const [fontSize, setFontSize] = useState(14)
const [wordWrap, setWordWrap] = useState(true)
const [minimap, setMinimap] = useState(true)
const [lineNumbers, setLineNumbers] = useState(true)
const editorRef = useRef(null)
const languages = [
{ value: 'javascript', label: 'JavaScript' },
{ value: 'typescript', label: 'TypeScript' },
{ value: 'python', label: 'Python' },
{ value: 'java', label: 'Java' },
{ value: 'cpp', label: 'C++' },
{ value: 'csharp', label: 'C#' },
{ value: 'php', label: 'PHP' },
{ value: 'ruby', label: 'Ruby' },
{ value: 'go', label: 'Go' },
{ value: 'rust', label: 'Rust' },
{ value: 'sql', label: 'SQL' },
{ value: 'html', label: 'HTML' },
{ value: 'css', label: 'CSS' },
{ value: 'json', label: 'JSON' },
{ value: 'xml', label: 'XML' },
{ value: 'yaml', label: 'YAML' },
{ value: 'markdown', label: 'Markdown' },
{ value: 'dockerfile', label: 'Dockerfile' },
{ value: 'shell', label: 'Shell' },
{ value: 'plaintext', label: 'Plain Text' }
]
const handleRunCode = () => {
const output = `> Running ${currentLanguage} code...\n> Code executed successfully!\n> Output: Hello, World!`
setTerminalOutput(prev => [...prev, { type: 'success', message: output, timestamp: new Date() }])
setShowTerminal(true)
toast.success('Code executed successfully!')
}
const handleSaveCode = () => {
toast.success('Code saved successfully!')
}
const handleDownloadCode = () => {
const blob = new Blob([code], { type: 'text/plain' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `code.${getFileExtension()}`
a.click()
toast.success('Code downloaded!')
}
const getFileExtension = () => {
const extensions = {
javascript: 'js',
typescript: 'ts',
python: 'py',
java: 'java',
cpp: 'cpp',
csharp: 'cs',
php: 'php',
ruby: 'rb',
go: 'go',
rust: 'rs',
sql: 'sql',
html: 'html',
css: 'css',
json: 'json',
xml: 'xml',
yaml: 'yaml',
markdown: 'md',
dockerfile: 'dockerfile',
shell: 'sh',
plaintext: 'txt'
}
return extensions[currentLanguage] || 'txt'
}
const formatCode = () => {
if (editorRef.current) {
editorRef.current.getAction('editor.action.formatDocument').run()
toast.success('Code formatted!')
}
}
const toggleFullscreen = () => {
setIsFullscreen(!isFullscreen)
}
const clearTerminal = () => {
setTerminalOutput([])
toast.success('Terminal cleared!')
}
return (
<div className={`flex flex-col h-full ${isFullscreen ? 'fixed inset-0 z-50 bg-gray-900' : ''}`}>
{/* Editor Header */}
<div className="flex items-center justify-between p-3 bg-gray-800 border-b border-gray-700">
<div className="flex items-center space-x-reverse space-x-3">
<FaCode className="w-5 h-5 text-primary-400" />
<select
value={currentLanguage}
onChange={(e) => setCurrentLanguage(e.target.value)}
className="px-3 py-1 bg-gray-700 text-white rounded-lg text-sm focus:outline-none"
>
{languages.map(lang => (
<option key={lang.value} value={lang.value}>{lang.label}</option>
))}
</select>
<span className="text-xs text-gray-400">
{code.split('\n').length} lines • {code.length} characters
</span>
</div>
<div className="flex items-center space-x-reverse space-x-2">
<button
onClick={formatCode}
className="p-2 bg-gray-700 text-white rounded-lg hover:bg-gray-600 transition-all"
title="Format Code"
>
<FaSync className="w-4 h-4" />
</button>
<button
onClick={handleSaveCode}
className="p-2 bg-gray-700 text-white rounded-lg hover:bg-gray-600 transition-all"
title="Save"
>
<FaSave className="w-4 h-4" />
</button>
<button
onClick={handleDownloadCode}
className="p-2 bg-gray-700 text-white rounded-lg hover:bg-gray-600 transition-all"
title="Download"
>
<FaDownload className="w-4 h-4" />
</button>
<button
onClick={handleRunCode}
className="p-2 bg-primary-600 text-white rounded-lg hover:bg-primary-700 transition-all"
title="Run Code"
>
<FaPlay className="w-4 h-4" />
</button>
<button
onClick={() => setShowTerminal(!showTerminal)}
className={`p-2 rounded-lg transition-all ${
showTerminal ? 'bg-primary-600 text-white' : 'bg-gray-700 text-white hover:bg-gray-600'
}`}
title="Toggle Terminal"
>
<FaTerminal className="w-4 h-4" />
</button>
<button
onClick={toggleFullscreen}
className="p-2 bg-gray-700 text-white rounded-lg hover:bg-gray-600 transition-all"
title="Toggle Fullscreen"
>
{isFullscreen ? <FaCompress className="w-4 h-4" /> : <FaExpand className="w-4 h-4" />}
</button>
</div>
</div>
{/* Editor Settings Bar */}
<div className="flex items-center justify-between px-3 py-2 bg-gray-750 border-b border-gray-700">
<div className="flex items-center space-x-reverse space-x-3">
<label className="flex items-center space-x-reverse space-x-2 text-xs text-gray-400">
<span>Font Size:</span>
<input
type="number"
value={fontSize}
onChange={(e) => setFontSize(parseInt(e.target.value))}
min="10"
max="24"
className="w-12 px-1 py-0.5 bg-gray-700 text-white rounded"
/>
</label>
<label className="flex items-center space-x-reverse space-x-2 text-xs text-gray-400">
<input
type="checkbox"
checked={wordWrap}
onChange={(e) => setWordWrap(e.target.checked)}
className="rounded"
/>
<span>Word Wrap</span>
</label>
<label className="flex items-center space-x-reverse space-x-2 text-xs text-gray-400">
<input
type="checkbox"
checked={minimap}
onChange={(e) => setMinimap(e.target.checked)}
className="rounded"
/>
<span>Minimap</span>
</label>
<label className="flex items-center space-x-reverse space-x-2 text-xs text-gray-400">
<input
type="checkbox"
checked={lineNumbers}
onChange={(e) => setLineNumbers(e.target.checked)}
className="rounded"
/>
<span>Line Numbers</span>
</label>
</div>
</div>
{/* Code Editor */}
<div className="flex-1 overflow-hidden">
<Editor
height="100%"
language={currentLanguage}
value={code}
onChange={(value) => setCode(value || '')}
theme={theme}
onMount={(editor) => {
editorRef.current = editor
editor.updateOptions({
fontSize,
wordWrap: wordWrap ? 'on' : 'off',
minimap: { enabled: minimap },
lineNumbers: lineNumbers ? 'on' : 'off',
automaticLayout: true,
scrollBeyondLastLine: false,
renderWhitespace: 'selection',
bracketPairColorization: { enabled: true },
guides: {
bracketPairs: true,
indentation: true
}
})
options={{
selectOnLineNumbers: true,
roundedSelection: false,
readOnly: false,
cursorStyle: 'line',
automaticLayout: true,
fontFamily: 'JetBrains Mono, Fira Code, Consolas, monospace',
fontLigatures: true
/>
</div>
{/* Terminal */}
<AnimatePresence>
{showTerminal && (
<motion.div
initial={{ height: 0, opacity: 0 }}
animate={{ height: 200, opacity: 1 }}
exit={{ height: 0, opacity: 0 }}
className="bg-gray-900 border-t border-gray-700"
>
<div className="flex items-center justify-between p-2 bg-gray-800">
<div className="flex items-center space-x-reverse space-x-2">
<FaTerminal className="w-4 h-4 text-primary-400" />
<span className="text-sm text-gray-300">Terminal</span>
</div>
<button
onClick={clearTerminal}
className="p-1 bg-gray-700 text-white rounded hover:bg-gray-600 transition-all"
>
<FaTrash className="w-3 h-3" />
</button>
</div>
<div className="p-3 overflow-y-auto h-32 font-mono text-xs">
{terminalOutput.length === 0 ? (
<div className="text-gray-500">Terminal output will appear here...</div>
) : (
terminalOutput.map((output, index) => (
<div key={index} className="mb-2">
<span className="text-gray-400">
[{output.timestamp.toLocaleTimeString()}]
</span>
<span className={output.type === 'success' ? 'text-green-400' : 'text-red-400'}>
{' '}{output.message}
</span>
</div>
))
)}
</div>
</motion.div>
)}
</AnimatePresence>
</div>
)
}