Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>HTML to React Converter</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| .dropzone { | |
| border: 2px dashed #9CA3AF; | |
| transition: all 0.3s ease; | |
| } | |
| .dropzone.active { | |
| border-color: #3B82F6; | |
| background-color: #EFF6FF; | |
| } | |
| .code-block { | |
| font-family: 'Courier New', monospace; | |
| background-color: #1E293B; | |
| color: #F8FAFC; | |
| border-radius: 0.5rem; | |
| overflow-x: auto; | |
| } | |
| .tab-button { | |
| transition: all 0.2s ease; | |
| } | |
| .tab-button.active { | |
| border-bottom: 2px solid #3B82F6; | |
| color: #3B82F6; | |
| } | |
| .spinner { | |
| animation: spin 1s linear infinite; | |
| } | |
| @keyframes spin { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-50 min-h-screen"> | |
| <div class="container mx-auto px-4 py-8 max-w-6xl"> | |
| <!-- Header --> | |
| <header class="mb-10 text-center"> | |
| <h1 class="text-4xl font-bold text-gray-800 mb-2"> | |
| <span class="text-blue-600">HTML</span> to <span class="text-cyan-500">React</span> Converter | |
| </h1> | |
| <p class="text-gray-600 max-w-2xl mx-auto"> | |
| Transform your HTML, CSS, and JavaScript files into fully functional React components using AI. | |
| Upload your files and let our system generate clean, modern React code. | |
| </p> | |
| </header> | |
| <!-- Main Content --> | |
| <main> | |
| <!-- Upload Section --> | |
| <div class="bg-white rounded-xl shadow-md p-6 mb-8"> | |
| <div class="flex flex-col items-center"> | |
| <div | |
| id="dropzone" | |
| class="dropzone w-full max-w-3xl rounded-lg p-12 text-center cursor-pointer mb-4" | |
| > | |
| <div class="flex flex-col items-center justify-center"> | |
| <i class="fas fa-cloud-upload-alt text-4xl text-gray-400 mb-4"></i> | |
| <h3 class="text-lg font-medium text-gray-700 mb-2"> | |
| Drag & drop your files here | |
| </h3> | |
| <p class="text-gray-500 text-sm mb-4"> | |
| Or click to browse your files (HTML, CSS, JS) | |
| </p> | |
| <button class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-md transition"> | |
| Select Files | |
| </button> | |
| </div> | |
| <input | |
| type="file" | |
| id="fileInput" | |
| class="hidden" | |
| multiple | |
| accept=".html,.css,.js,.jsx,.ts,.tsx" | |
| > | |
| </div> | |
| <div id="fileList" class="w-full max-w-3xl space-y-2 hidden"></div> | |
| </div> | |
| </div> | |
| <!-- Configuration Options --> | |
| <div class="bg-white rounded-xl shadow-md p-6 mb-8"> | |
| <h2 class="text-xl font-semibold text-gray-800 mb-4">Conversion Options</h2> | |
| <div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
| <div> | |
| <label class="block text-sm font-medium text-gray-700 mb-1">React Version</label> | |
| <select class="w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"> | |
| <option>React 18 (Latest)</option> | |
| <option>React 17</option> | |
| <option>React 16</option> | |
| </select> | |
| </div> | |
| <div> | |
| <label class="block text-sm font-medium text-gray-700 mb-1">JavaScript Type</label> | |
| <select class="w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"> | |
| <option>JavaScript (ES6+)</option> | |
| <option>TypeScript</option> | |
| </select> | |
| </div> | |
| <div> | |
| <label class="block text-sm font-medium text-gray-700 mb-1">CSS Handling</label> | |
| <select class="w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"> | |
| <option>CSS Modules</option> | |
| <option>Styled Components</option> | |
| <option>Tailwind CSS</option> | |
| <option>Plain CSS</option> | |
| </select> | |
| </div> | |
| <div> | |
| <label class="block text-sm font-medium text-gray-700 mb-1">Component Type</label> | |
| <select class="w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500"> | |
| <option>Functional Components</option> | |
| <option>Class Components</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div class="mt-6"> | |
| <label class="inline-flex items-center"> | |
| <input type="checkbox" class="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-300 focus:ring focus:ring-offset-0 focus:ring-blue-200 focus:ring-opacity-50"> | |
| <span class="ml-2 text-sm text-gray-700">Include React Router setup</span> | |
| </label> | |
| </div> | |
| </div> | |
| <!-- Processing Section --> | |
| <div id="processingSection" class="hidden bg-white rounded-xl shadow-md p-6 mb-8"> | |
| <div class="flex flex-col items-center justify-center py-8"> | |
| <div class="spinner text-4xl text-blue-600 mb-4"> | |
| <i class="fas fa-cog"></i> | |
| </div> | |
| <h3 class="text-xl font-medium text-gray-800 mb-2">Processing your files</h3> | |
| <p class="text-gray-600 mb-4">Our AI is analyzing your code and generating React components...</p> | |
| <div class="w-full max-w-md bg-gray-200 rounded-full h-2.5"> | |
| <div id="progressBar" class="bg-blue-600 h-2.5 rounded-full" style="width: 0%"></div> | |
| </div> | |
| <p id="progressText" class="text-sm text-gray-500 mt-2">0% complete</p> | |
| </div> | |
| </div> | |
| <!-- Results Section --> | |
| <div id="resultsSection" class="hidden bg-white rounded-xl shadow-md p-6"> | |
| <div class="flex justify-between items-center mb-6"> | |
| <h2 class="text-xl font-semibold text-gray-800">Generated React Application</h2> | |
| <button id="downloadAll" class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-md text-sm flex items-center"> | |
| <i class="fas fa-download mr-2"></i> Download All | |
| </button> | |
| </div> | |
| <div class="border-b border-gray-200 mb-4"> | |
| <nav class="-mb-px flex space-x-8"> | |
| <button class="tab-button active py-4 px-1 border-b-2 font-medium text-sm"> | |
| Components | |
| </button> | |
| <button class="tab-button py-4 px-1 border-b-2 font-medium text-sm"> | |
| App.js | |
| </button> | |
| <button class="tab-button py-4 px-1 border-b-2 font-medium text-sm"> | |
| Styles | |
| </button> | |
| <button class="tab-button py-4 px-1 border-b-2 font-medium text-sm"> | |
| Package.json | |
| </button> | |
| </nav> | |
| </div> | |
| <div class="mb-4 flex justify-between items-center"> | |
| <div class="flex space-x-2"> | |
| <button class="bg-gray-100 hover:bg-gray-200 text-gray-800 px-3 py-1 rounded-md text-sm"> | |
| <i class="fas fa-copy mr-1"></i> Copy | |
| </button> | |
| <button class="bg-gray-100 hover:bg-gray-200 text-gray-800 px-3 py-1 rounded-md text-sm"> | |
| <i class="fas fa-download mr-1"></i> Download | |
| </button> | |
| </div> | |
| <div class="text-sm text-gray-500"> | |
| <span class="font-medium">File:</span> MainComponent.jsx | |
| </div> | |
| </div> | |
| <div class="code-block p-4 mb-6"> | |
| <pre id="generatedCode" class="text-sm"><code class="language-javascript">// Generated code will appear here</code></pre> | |
| </div> | |
| <div class="bg-blue-50 border-l-4 border-blue-400 p-4 mb-6"> | |
| <div class="flex"> | |
| <div class="flex-shrink-0"> | |
| <i class="fas fa-info-circle text-blue-400"></i> | |
| </div> | |
| <div class="ml-3"> | |
| <h3 class="text-sm font-medium text-blue-800">AI Suggestions</h3> | |
| <div class="mt-2 text-sm text-blue-700"> | |
| <p> | |
| The AI detected that your HTML includes form elements. Consider using React Hook Form | |
| for better form management. Would you like to add this dependency to your package.json? | |
| </p> | |
| </div> | |
| <div class="mt-4"> | |
| <button class="inline-flex items-center px-3 py-1 border border-transparent text-xs font-medium rounded shadow-sm text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"> | |
| Add React Hook Form | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-gray-50 p-4 rounded-md"> | |
| <h3 class="text-sm font-medium text-gray-800 mb-2">Project Structure</h3> | |
| <div class="text-sm text-gray-700 font-mono"> | |
| <div class="pl-4">├── src/</div> | |
| <div class="pl-8">├── components/</div> | |
| <div class="pl-12">├── MainComponent.jsx</div> | |
| <div class="pl-12">├── Header.jsx</div> | |
| <div class="pl-12">└── Footer.jsx</div> | |
| <div class="pl-8">├── styles/</div> | |
| <div class="pl-12">└── main.module.css</div> | |
| <div class="pl-8">├── App.js</div> | |
| <div class="pl-8">└── index.js</div> | |
| <div class="pl-4">├── public/</div> | |
| <div class="pl-4">├── package.json</div> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| <!-- Footer --> | |
| <footer class="mt-12 text-center text-gray-500 text-sm"> | |
| <p>Powered by AI technology. This tool uses open-source LLMs to analyze and convert your code.</p> | |
| <p class="mt-1">Not affiliated with Facebook or the React team.</p> | |
| </footer> | |
| </div> | |
| <script> | |
| document.addEventListener('DOMContentLoaded', function() { | |
| const dropzone = document.getElementById('dropzone'); | |
| const fileInput = document.getElementById('fileInput'); | |
| const fileList = document.getElementById('fileList'); | |
| const processingSection = document.getElementById('processingSection'); | |
| const resultsSection = document.getElementById('resultsSection'); | |
| const progressBar = document.getElementById('progressBar'); | |
| const progressText = document.getElementById('progressText'); | |
| const generatedCode = document.getElementById('generatedCode'); | |
| const downloadAll = document.getElementById('downloadAll'); | |
| // Tab switching | |
| const tabButtons = document.querySelectorAll('.tab-button'); | |
| tabButtons.forEach(button => { | |
| button.addEventListener('click', () => { | |
| tabButtons.forEach(btn => btn.classList.remove('active')); | |
| button.classList.add('active'); | |
| }); | |
| }); | |
| // Dropzone highlight | |
| ['dragenter', 'dragover'].forEach(eventName => { | |
| dropzone.addEventListener(eventName, highlight, false); | |
| }); | |
| ['dragleave', 'drop'].forEach(eventName => { | |
| dropzone.addEventListener(eventName, unhighlight, false); | |
| }); | |
| function highlight(e) { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| dropzone.classList.add('active'); | |
| } | |
| function unhighlight(e) { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| dropzone.classList.remove('active'); | |
| } | |
| // Handle dropped files | |
| dropzone.addEventListener('drop', handleDrop, false); | |
| dropzone.addEventListener('click', () => fileInput.click()); | |
| fileInput.addEventListener('change', handleFiles); | |
| function handleDrop(e) { | |
| const dt = e.dataTransfer; | |
| const files = dt.files; | |
| handleFiles({ target: { files } }); | |
| } | |
| function handleFiles(e) { | |
| const files = e.target.files; | |
| if (files.length === 0) return; | |
| fileList.innerHTML = ''; | |
| fileList.classList.remove('hidden'); | |
| for (let i = 0; i < files.length; i++) { | |
| const file = files[i]; | |
| const fileItem = document.createElement('div'); | |
| fileItem.className = 'flex items-center p-3 bg-gray-50 rounded-md'; | |
| fileItem.innerHTML = ` | |
| <i class="fas ${getFileIcon(file.name)} text-gray-500 mr-3"></i> | |
| <div class="flex-1"> | |
| <div class="text-sm font-medium text-gray-800">${file.name}</div> | |
| <div class="text-xs text-gray-500">${formatFileSize(file.size)}</div> | |
| </div> | |
| <button class="text-red-500 hover:text-red-700"> | |
| <i class="fas fa-times"></i> | |
| </button> | |
| `; | |
| fileList.appendChild(fileItem); | |
| // Remove file handler | |
| fileItem.querySelector('button').addEventListener('click', () => { | |
| fileItem.remove(); | |
| if (fileList.children.length === 0) { | |
| fileList.classList.add('hidden'); | |
| } | |
| }); | |
| } | |
| // Show process button if not already showing | |
| if (!document.getElementById('processBtn')) { | |
| const processBtn = document.createElement('button'); | |
| processBtn.id = 'processBtn'; | |
| processBtn.className = 'bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-md transition mt-4 flex items-center justify-center w-full max-w-xs mx-auto'; | |
| processBtn.innerHTML = '<i class="fas fa-magic mr-2"></i> Convert to React'; | |
| processBtn.addEventListener('click', processFiles); | |
| dropzone.parentNode.insertBefore(processBtn, dropzone.nextSibling); | |
| } | |
| } | |
| function getFileIcon(filename) { | |
| const ext = filename.split('.').pop().toLowerCase(); | |
| if (['html', 'htm'].includes(ext)) return 'fa-file-code'; | |
| if (['css'].includes(ext)) return 'fa-file-alt'; | |
| if (['js', 'jsx', 'ts', 'tsx'].includes(ext)) return 'fa-file-code'; | |
| return 'fa-file'; | |
| } | |
| function formatFileSize(bytes) { | |
| if (bytes === 0) return '0 Bytes'; | |
| const k = 1024; | |
| const sizes = ['Bytes', 'KB', 'MB', 'GB']; | |
| const i = Math.floor(Math.log(bytes) / Math.log(k)); | |
| return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; | |
| } | |
| function processFiles() { | |
| processingSection.classList.remove('hidden'); | |
| // Simulate processing with progress updates | |
| let progress = 0; | |
| const interval = setInterval(() => { | |
| progress += Math.random() * 10; | |
| if (progress > 100) progress = 100; | |
| progressBar.style.width = `${progress}%`; | |
| progressText.textContent = `${Math.round(progress)}% complete`; | |
| if (progress === 100) { | |
| clearInterval(interval); | |
| setTimeout(showResults, 500); | |
| } | |
| }, 500); | |
| } | |
| function showResults() { | |
| processingSection.classList.add('hidden'); | |
| resultsSection.classList.remove('hidden'); | |
| // Scroll to results | |
| resultsSection.scrollIntoView({ behavior: 'smooth' }); | |
| // Generate sample React code (in a real app, this would come from the AI) | |
| generatedCode.innerHTML = ` | |
| import React from 'react'; | |
| import styles from './MainComponent.module.css'; | |
| const MainComponent = () => { | |
| const [count, setCount] = React.useState(0); | |
| const handleClick = () => { | |
| setCount(prev => prev + 1); | |
| }; | |
| return ( | |
| <div className={styles.container}> | |
| <h1 className={styles.title}>Converted to React!</h1> | |
| <p className={styles.description}> | |
| This component was automatically generated from your HTML. | |
| </p> | |
| <button | |
| onClick={handleClick} | |
| className={styles.button} | |
| > | |
| Click me: {count} | |
| </button> | |
| </div> | |
| ); | |
| }; | |
| export default MainComponent; | |
| `.trim(); | |
| // Highlight code (in a real app, you'd use a proper syntax highlighter) | |
| generatedCode.innerHTML = generatedCode.innerHTML | |
| .replace(/\/\/.*$/gm, '<span class="text-gray-400">$&</span>') | |
| .replace(/(['"])(?:(?=(\\?))\2.)*?\1/g, '<span class="text-green-400">$&</span>') | |
| .replace(/\b(import|from|export|default|const|return|React\.useState)\b/g, '<span class="text-purple-400">$&</span>') | |
| .replace(/\b(div|h1|p|button)\b/g, '<span class="text-blue-400">$&</span>') | |
| .replace(/\b(className|onClick)\b/g, '<span class="text-yellow-400">$&</span>'); | |
| } | |
| // Download all handler | |
| downloadAll.addEventListener('click', () => { | |
| alert('In a real implementation, this would download a zip file with all generated React files.'); | |
| }); | |
| }); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=hharris928/html-to-react" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |