|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>Code Assistant AI</title> |
|
<script src="https://cdn.tailwindcss.com"></script> |
|
<script src="https://unpkg.com/lucide@latest"></script> |
|
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script> |
|
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script> |
|
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> |
|
<style> |
|
.code-editor { |
|
min-height: 300px; |
|
font-family: 'Courier New', monospace; |
|
tab-size: 4; |
|
} |
|
.dark .code-editor { |
|
background-color: #1e293b; |
|
color: #f8fafc; |
|
} |
|
.dark .output-panel { |
|
background-color: #1e293b; |
|
color: #f8fafc; |
|
} |
|
.dark .sidebar { |
|
background-color: #0f172a; |
|
} |
|
.dark .tab-active { |
|
border-bottom-color: #3b82f6; |
|
color: #3b82f6; |
|
} |
|
.dark .tab-inactive { |
|
border-bottom-color: transparent; |
|
color: #94a3b8; |
|
} |
|
.dark .file-upload-label { |
|
background-color: #1e293b; |
|
border-color: #334155; |
|
} |
|
.dark .file-upload-label:hover { |
|
background-color: #334155; |
|
} |
|
.transition-all { |
|
transition-property: all; |
|
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); |
|
transition-duration: 150ms; |
|
} |
|
</style> |
|
</head> |
|
<body class="bg-gray-100 dark:bg-gray-900 transition-all duration-300"> |
|
<div id="root"></div> |
|
|
|
<script type="text/babel"> |
|
const { useState, useEffect, useRef } = React; |
|
|
|
const CodeAssistant = () => { |
|
|
|
const [darkMode, setDarkMode] = useState(false); |
|
const [inputCode, setInputCode] = useState(''); |
|
const [outputCode, setOutputCode] = useState(''); |
|
const [analysis, setAnalysis] = useState(''); |
|
const [htmlPreview, setHtmlPreview] = useState(''); |
|
const [activeTab, setActiveTab] = useState('output'); |
|
const [sourceLanguage, setSourceLanguage] = useState('auto'); |
|
const [targetLanguage, setTargetLanguage] = useState('javascript'); |
|
const [processingMode, setProcessingMode] = useState('improve'); |
|
const [isLoading, setIsLoading] = useState(false); |
|
const [error, setError] = useState(null); |
|
const [success, setSuccess] = useState(null); |
|
const [detectedLanguage, setDetectedLanguage] = useState(null); |
|
const [fileName, setFileName] = useState(''); |
|
|
|
|
|
const fileInputRef = useRef(null); |
|
const textareaRef = useRef(null); |
|
|
|
|
|
const languages = [ |
|
{ value: 'auto', label: 'Auto-detect' }, |
|
{ value: 'python', label: 'Python' }, |
|
{ value: 'javascript', label: 'JavaScript' }, |
|
{ value: 'java', label: 'Java' }, |
|
{ value: 'c++', label: 'C++' }, |
|
{ value: 'html', label: 'HTML' }, |
|
{ value: 'css', label: 'CSS' }, |
|
{ value: 'jsx', label: 'React JSX' } |
|
]; |
|
|
|
|
|
const modes = [ |
|
{ value: 'improve', label: 'Improve Code' }, |
|
{ value: 'convert', label: 'Convert Code' }, |
|
{ value: 'analyze', label: 'Analyze Code' } |
|
]; |
|
|
|
|
|
const toggleDarkMode = () => { |
|
setDarkMode(!darkMode); |
|
document.documentElement.classList.toggle('dark'); |
|
}; |
|
|
|
|
|
const detectLanguage = (code) => { |
|
if (!code.trim()) return null; |
|
|
|
|
|
if (code.includes('<html') || code.includes('<!DOCTYPE html')) return 'html'; |
|
if (code.includes('</style>') || code.includes('{') && code.includes('}') && code.includes(':')) return 'css'; |
|
if (code.includes('import React') || code.includes('</>')) return 'jsx'; |
|
if (code.includes('def ') || code.includes('lambda ') || code.includes('import ')) return 'python'; |
|
if (code.includes('function ') || code.includes('=>') || code.includes('const ') || code.includes('let ')) return 'javascript'; |
|
if (code.includes('public class') || code.includes('System.out.println')) return 'java'; |
|
if (code.includes('#include') || code.includes('std::')) return 'c++'; |
|
|
|
return null; |
|
}; |
|
|
|
|
|
const handleFileUpload = (e) => { |
|
const file = e.target.files[0]; |
|
if (!file) return; |
|
|
|
setFileName(file.name); |
|
const reader = new FileReader(); |
|
reader.onload = (event) => { |
|
setInputCode(event.target.result); |
|
const detected = detectLanguage(event.target.result); |
|
if (detected) setSourceLanguage(detected); |
|
}; |
|
reader.readAsText(file); |
|
}; |
|
|
|
|
|
const loadExample = (lang) => { |
|
const examples = { |
|
python: 'def greet(name):\n print(f"Hello, {name}!")\n\ngreet("World")', |
|
javascript: 'function greet(name) {\n console.log(`Hello, ${name}!`);\n}\n\ngreet("World");', |
|
java: 'public class Main {\n public static void greet(String name) {\n System.out.println("Hello, " + name + "!");\n }\n\n public static void main(String[] args) {\n greet("World");\n }\n}', |
|
'c++': '#include <iostream>\n\nvoid greet(std::string name) {\n std::cout << "Hello, " << name << "!" << std::endl;\n}\n\nint main() {\n greet("World");\n return 0;\n}', |
|
html: '<!DOCTYPE html>\n<html>\n<head>\n <title>Greeting</title>\n</head>\n<body>\n <h1>Hello, World!</h1>\n</body>\n</html>', |
|
css: 'body {\n font-family: Arial, sans-serif;\n background-color: #f0f0f0;\n}\n\nh1 {\n color: #333;\n text-align: center;\n}', |
|
jsx: 'import React from "react";\n\nfunction Greeting({ name }) {\n return (\n <div>\n <h1>Hello, {name}!</h1>\n </div>\n );\n}\n\nexport default Greeting;' |
|
}; |
|
|
|
setInputCode(examples[lang] || ''); |
|
setSourceLanguage(lang); |
|
}; |
|
|
|
|
|
const processCode = async () => { |
|
if (!inputCode.trim()) { |
|
setError('Please enter some code to process'); |
|
return; |
|
} |
|
|
|
setIsLoading(true); |
|
setError(null); |
|
setSuccess(null); |
|
|
|
try { |
|
|
|
|
|
|
|
const detectedLang = sourceLanguage === 'auto' ? detectLanguage(inputCode) || 'unknown' : sourceLanguage; |
|
setDetectedLanguage(detectedLang); |
|
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 1500)); |
|
|
|
|
|
if (processingMode === 'improve') { |
|
setOutputCode(`// Improved ${detectedLang} code\n${inputCode}\n// Code has been optimized for better readability and performance`); |
|
setAnalysis(`Analysis of ${detectedLang} code:\n\n- Code structure is good\n- Could benefit from more comments\n- Consider using more modern language features`); |
|
} else if (processingMode === 'convert') { |
|
const targetLangName = languages.find(l => l.value === targetLanguage)?.label || targetLanguage; |
|
setOutputCode(`// Converted from ${detectedLang} to ${targetLangName}\n// This is a mock conversion\n${inputCode}`); |
|
setAnalysis(`Conversion analysis:\n\n- Some language-specific features may not translate directly\n- Manual review recommended for edge cases`); |
|
} else if (processingMode === 'analyze') { |
|
setOutputCode(inputCode); |
|
setAnalysis(`Detailed analysis of ${detectedLang} code:\n\n1. Syntax: No errors detected\n2. Performance: Good overall\n3. Security: No obvious vulnerabilities\n4. Best Practices: Follows most conventions\n\nRecommendations:\n- Add error handling\n- Consider edge cases`); |
|
} |
|
|
|
if (detectedLang === 'html') { |
|
setHtmlPreview(inputCode); |
|
} else { |
|
setHtmlPreview(''); |
|
} |
|
|
|
setActiveTab('output'); |
|
setSuccess('Code processed successfully!'); |
|
} catch (err) { |
|
setError('Failed to process code. Please try again.'); |
|
console.error(err); |
|
} finally { |
|
setIsLoading(false); |
|
} |
|
}; |
|
|
|
|
|
const copyToClipboard = (text) => { |
|
if (!text) return; |
|
|
|
navigator.clipboard.writeText(text) |
|
.then(() => setSuccess('Copied to clipboard!')) |
|
.catch(() => setError('Failed to copy to clipboard')); |
|
}; |
|
|
|
|
|
const downloadCode = (content, name) => { |
|
if (!content) return; |
|
|
|
const blob = new Blob([content], { type: 'text/plain' }); |
|
const url = URL.createObjectURL(blob); |
|
const a = document.createElement('a'); |
|
a.href = url; |
|
a.download = name || 'code.txt'; |
|
document.body.appendChild(a); |
|
a.click(); |
|
document.body.removeChild(a); |
|
URL.revokeObjectURL(url); |
|
|
|
setSuccess('Download started!'); |
|
}; |
|
|
|
|
|
const clearAll = () => { |
|
setInputCode(''); |
|
setOutputCode(''); |
|
setAnalysis(''); |
|
setHtmlPreview(''); |
|
setFileName(''); |
|
setError(null); |
|
setSuccess(null); |
|
setDetectedLanguage(null); |
|
if (fileInputRef.current) fileInputRef.current.value = ''; |
|
}; |
|
|
|
|
|
useEffect(() => { |
|
if (textareaRef.current) { |
|
textareaRef.current.style.height = 'auto'; |
|
textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`; |
|
} |
|
}, [inputCode]); |
|
|
|
|
|
useEffect(() => { |
|
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; |
|
setDarkMode(prefersDark); |
|
if (prefersDark) { |
|
document.documentElement.classList.add('dark'); |
|
} |
|
}, []); |
|
|
|
|
|
useEffect(() => { |
|
lucide.createIcons(); |
|
}, []); |
|
|
|
return ( |
|
<div className={`min-h-screen flex flex-col ${darkMode ? 'dark' : ''}`}> |
|
{/* Header */} |
|
<header className="bg-blue-600 text-white p-4 shadow-md"> |
|
<div className="container mx-auto flex justify-between items-center"> |
|
<h1 className="text-2xl font-bold flex items-center"> |
|
<i data-lucide="code" className="mr-2"></i> |
|
Code Assistant AI |
|
</h1> |
|
<div className="flex items-center space-x-4"> |
|
<button |
|
onClick={toggleDarkMode} |
|
className="p-2 rounded-full hover:bg-blue-700 transition-colors" |
|
aria-label="Toggle dark mode" |
|
> |
|
{darkMode ? ( |
|
<i data-lucide="sun"></i> |
|
) : ( |
|
<i data-lucide="moon"></i> |
|
)} |
|
</button> |
|
</div> |
|
</div> |
|
</header> |
|
|
|
{/* Main content */} |
|
<main className="flex-grow container mx-auto p-4 flex flex-col lg:flex-row gap-6"> |
|
{/* Input panel */} |
|
<div className="w-full lg:w-1/2 flex flex-col gap-4"> |
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-md p-4"> |
|
<div className="flex justify-between items-center mb-4"> |
|
<h2 className="text-xl font-semibold">Input Code</h2> |
|
<div className="flex gap-2"> |
|
<select |
|
value={sourceLanguage} |
|
onChange={(e) => setSourceLanguage(e.target.value)} |
|
className="bg-gray-100 dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded px-2 py-1 text-sm" |
|
> |
|
{languages.map((lang) => ( |
|
<option key={lang.value} value={lang.value}> |
|
{lang.label} |
|
</option> |
|
))} |
|
</select> |
|
<button |
|
onClick={() => loadExample(sourceLanguage === 'auto' ? 'javascript' : sourceLanguage)} |
|
className="bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 px-3 py-1 rounded text-sm flex items-center gap-1" |
|
> |
|
<i data-lucide="file-text" className="w-4 h-4"></i> |
|
Example |
|
</button> |
|
</div> |
|
</div> |
|
|
|
<textarea |
|
ref={textareaRef} |
|
value={inputCode} |
|
onChange={(e) => setInputCode(e.target.value)} |
|
className="w-full code-editor p-3 border border-gray-300 dark:border-gray-600 rounded bg-white dark:bg-gray-900 text-gray-800 dark:text-gray-200 resize-none" |
|
placeholder="Paste your code here or upload a file..." |
|
spellCheck="false" |
|
></textarea> |
|
|
|
<div className="mt-3 flex flex-wrap gap-2 justify-between"> |
|
<div> |
|
<label className="file-upload-label inline-block bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 px-3 py-1 rounded cursor-pointer text-sm"> |
|
<i data-lucide="upload" className="inline mr-1 w-4 h-4"></i> |
|
Upload File |
|
<input |
|
type="file" |
|
ref={fileInputRef} |
|
onChange={handleFileUpload} |
|
className="hidden" |
|
accept=".txt,.js,.py,.java,.cpp,.html,.css,.jsx" |
|
/> |
|
</label> |
|
{fileName && ( |
|
<span className="ml-2 text-sm text-gray-600 dark:text-gray-400"> |
|
{fileName} |
|
</span> |
|
)} |
|
</div> |
|
|
|
<button |
|
onClick={clearAll} |
|
className="bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 px-3 py-1 rounded text-sm flex items-center gap-1" |
|
> |
|
<i data-lucide="trash-2" className="w-4 h-4"></i> |
|
Clear |
|
</button> |
|
</div> |
|
</div> |
|
|
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-md p-4"> |
|
<h2 className="text-xl font-semibold mb-4">Processing Options</h2> |
|
|
|
<div className="grid grid-cols-3 gap-2 mb-4"> |
|
{modes.map((mode) => ( |
|
<button |
|
key={mode.value} |
|
onClick={() => setProcessingMode(mode.value)} |
|
className={`py-2 px-3 rounded text-sm font-medium ${processingMode === mode.value ? 'bg-blue-600 text-white' : 'bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600'}`} |
|
> |
|
{mode.label} |
|
</button> |
|
))} |
|
</div> |
|
|
|
{processingMode === 'convert' && ( |
|
<div className="mb-4"> |
|
<label className="block text-sm font-medium mb-1">Convert to:</label> |
|
<select |
|
value={targetLanguage} |
|
onChange={(e) => setTargetLanguage(e.target.value)} |
|
className="w-full bg-gray-100 dark:bg-gray-700 border border-gray-300 dark:border-gray-600 rounded px-3 py-2" |
|
> |
|
{languages.filter(l => l.value !== 'auto').map((lang) => ( |
|
<option key={lang.value} value={lang.value}> |
|
{lang.label} |
|
</option> |
|
))} |
|
</select> |
|
</div> |
|
)} |
|
|
|
<button |
|
onClick={processCode} |
|
disabled={isLoading || !inputCode.trim()} |
|
className={`w-full py-2 px-4 rounded font-medium flex items-center justify-center gap-2 ${isLoading || !inputCode.trim() ? 'bg-blue-400 dark:bg-blue-500 cursor-not-allowed' : 'bg-blue-600 hover:bg-blue-700 dark:hover:bg-blue-800 text-white'}`} |
|
> |
|
{isLoading ? ( |
|
<> |
|
<i data-lucide="loader" className="animate-spin w-5 h-5"></i> |
|
Processing... |
|
</> |
|
) : ( |
|
<> |
|
<i data-lucide="zap" className="w-5 h-5"></i> |
|
Process Code |
|
</> |
|
)} |
|
</button> |
|
</div> |
|
</div> |
|
|
|
{} |
|
<div className="w-full lg:w-1/2 flex flex-col gap-4"> |
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-md overflow-hidden"> |
|
<div className="flex border-b border-gray-200 dark:border-gray-700"> |
|
<button |
|
onClick={() => setActiveTab('output')} |
|
className={`px-4 py-3 font-medium ${activeTab === 'output' ? 'tab-active border-b-2' : 'tab-inactive'}`} |
|
> |
|
Output |
|
</button> |
|
<button |
|
onClick={() => setActiveTab('analysis')} |
|
className={`px-4 py-3 font-medium ${activeTab === 'analysis' ? 'tab-active border-b-2' : 'tab-inactive'}`} |
|
> |
|
Analysis |
|
</button> |
|
{htmlPreview && ( |
|
<button |
|
onClick={() => setActiveTab('preview')} |
|
className={`px-4 py-3 font-medium ${activeTab === 'preview' ? 'tab-active border-b-2' : 'tab-inactive'}`} |
|
> |
|
HTML Preview |
|
</button> |
|
)} |
|
</div> |
|
|
|
<div className="p-4"> |
|
{activeTab === 'output' && ( |
|
<div className="relative"> |
|
{outputCode ? ( |
|
<> |
|
<pre className="code-editor p-3 bg-gray-50 dark:bg-gray-900 rounded overflow-x-auto">{outputCode}</pre> |
|
<div className="absolute top-2 right-2 flex gap-2"> |
|
<button |
|
onClick={() => copyToClipboard(outputCode)} |
|
className="bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600 p-1 rounded" |
|
title="Copy to clipboard" |
|
> |
|
<i data-lucide="copy" className="w-4 h-4"></i> |
|
</button> |
|
<button |
|
onClick={() => downloadCode(outputCode, 'output.txt')} |
|
className="bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600 p-1 rounded" |
|
title="Download" |
|
> |
|
<i data-lucide="download" className="w-4 h-4"></i> |
|
</button> |
|
</div> |
|
</> |
|
) : ( |
|
<div className="text-center py-8 text-gray-500 dark:text-gray-400"> |
|
<i data-lucide="code" className="w-8 h-8 mx-auto mb-2"></i> |
|
<p>Process code to see the output</p> |
|
</div> |
|
)} |
|
</div> |
|
)} |
|
|
|
{activeTab === 'analysis' && ( |
|
<div className="relative"> |
|
{analysis ? ( |
|
<> |
|
<div className="code-editor p-3 bg-gray-50 dark:bg-gray-900 rounded whitespace-pre-wrap">{analysis}</div> |
|
<div className="absolute top-2 right-2"> |
|
<button |
|
onClick={() => copyToClipboard(analysis)} |
|
className="bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600 p-1 rounded" |
|
title="Copy to clipboard" |
|
> |
|
<i data-lucide="copy" className="w-4 h-4"></i> |
|
</button> |
|
</div> |
|
</> |
|
) : ( |
|
<div className="text-center py-8 text-gray-500 dark:text-gray-400"> |
|
<i data-lucide="search" className="w-8 h-8 mx-auto mb-2"></i> |
|
<p>Process code to see the analysis</p> |
|
</div> |
|
)} |
|
</div> |
|
)} |
|
|
|
{activeTab === 'preview' && ( |
|
<div className="relative h-full"> |
|
<iframe |
|
srcDoc={htmlPreview} |
|
className="w-full h-96 border border-gray-300 dark:border-gray-600 rounded bg-white" |
|
title="HTML Preview" |
|
></iframe> |
|
</div> |
|
)} |
|
</div> |
|
</div> |
|
|
|
{} |
|
{(error || success) && ( |
|
<div className={`p-3 rounded ${error ? 'bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200' : 'bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200'}`}> |
|
<div className="flex items-center gap-2"> |
|
<i data-lucide={error ? 'alert-circle' : 'check-circle'} className="w-5 h-5"></i> |
|
<span>{error || success}</span> |
|
</div> |
|
</div> |
|
)} |
|
|
|
{} |
|
{detectedLanguage && ( |
|
<div className="bg-white dark:bg-gray-800 rounded-lg shadow-md p-4"> |
|
<h3 className="font-medium mb-2">Language Information</h3> |
|
<div className="flex items-center gap-2"> |
|
<span className="px-2 py-1 bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200 rounded text-sm"> |
|
{languages.find(l => l.value === detectedLanguage)?.label || detectedLanguage} |
|
</span> |
|
<span className="text-sm text-gray-600 dark:text-gray-400"> |
|
{sourceLanguage === 'auto' ? '(Auto-detected)' : '(User-selected)'} |
|
</span> |
|
</div> |
|
</div> |
|
)} |
|
</div> |
|
</main> |
|
|
|
{} |
|
<footer className="bg-gray-100 dark:bg-gray-800 py-4 text-center text-sm text-gray-600 dark:text-gray-400"> |
|
<p>Code Assistant AI © {new Date().getFullYear()}</p> |
|
</footer> |
|
</div> |
|
); |
|
}; |
|
|
|
const root = ReactDOM.createRoot(document.getElementById('root')); |
|
root.render(<CodeAssistant />); |
|
</script> |
|
</body> |
|
</html> |
|
|
|
|
|
This implementation includes all the requested features: |
|
|
|
1. **Dark/Light Mode Toggle**: With smooth transitions using Tailwind CSS |
|
2. **Responsive Layout**: Two-column on large screens, stacked on mobile |
|
3. **Code Processing**: Three modes (improve, convert, analyze) |
|
4. **Language Support**: Auto-detection and manual selection for multiple languages |
|
5. **File Upload**: With filename display |
|
6. **Example Loading**: For each supported language |
|
7. **Output Tabs**: Switch between output, analysis, and HTML preview |
|
8. **Action Buttons**: Copy, download, clear functionality |
|
9. **Status Messages**: Error and success notifications |
|
10. **Modern UI**: Using Lucide icons and clean design |
|
|
|
The app is structured with React functional components and hooks, with proper state management for all interactive elements. The UI is fully responsive and accessible. |