Download components/CodeDisplay.tsx from RosticFACE/UI-Generator-from-Image: direct link, hf CLI and curl.
- Browser
- Download file 8.89 kB
-
https://huggingface.co/spaces/RosticFACE/UI-Generator-from-Image/resolve/main/components/CodeDisplay.tsx
- Command line
-
hf download hf://spaces/RosticFACE/UI-Generator-from-Image/components/CodeDisplay.tsx
-
curl -L -o CodeDisplay.tsx https://huggingface.co/spaces/RosticFACE/UI-Generator-from-Image/resolve/main/components/CodeDisplay.tsx
8.89 kB
| import React, { useState, useEffect, useRef } from 'react'; | |
| import JSZip from 'jszip'; | |
| import CopyIcon from './icons/CopyIcon'; | |
| import DownloadIcon from './icons/DownloadIcon'; | |
| import { AppStatus, AppType } from '../types'; | |
| interface CodeDisplayProps { | |
| appType: AppType; | |
| pythonCode?: string; | |
| cppFiles?: Record<string, string> | null; | |
| status: AppStatus; | |
| } | |
| const PythonCodeView: React.FC<{ code: string }> = ({ code }) => { | |
| const [copyText, setCopyText] = useState('Copy Code'); | |
| const codeRef = useRef<HTMLElement>(null); | |
| const finalCode = code.replace(/\n```$/, '').trim(); | |
| useEffect(() => { | |
| // @ts-ignore | |
| if (window.hljs && codeRef.current) { | |
| // @ts-ignore | |
| window.hljs.highlightElement(codeRef.current); | |
| } | |
| }, [finalCode]); | |
| const handleCopy = () => { | |
| navigator.clipboard.writeText(finalCode).then(() => { | |
| setCopyText('Copied!'); | |
| setTimeout(() => setCopyText('Copy Code'), 2000); | |
| }); | |
| }; | |
| const handleDownload = () => { | |
| const blob = new Blob([finalCode], { type: 'text/python' }); | |
| const url = URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = 'generated_app.py'; | |
| document.body.appendChild(a); | |
| a.click(); | |
| document.body.removeChild(a); | |
| URL.revokeObjectURL(url); | |
| }; | |
| return ( | |
| <div className="relative h-full"> | |
| <div className="absolute top-4 right-4 flex items-center gap-2 z-10"> | |
| <button onClick={handleDownload} className="flex items-center gap-2 bg-gray-700 text-white py-2 px-4 rounded-lg hover:bg-gray-600 transition-all duration-200 text-sm font-semibold" aria-label="Download code"> | |
| <DownloadIcon className="w-5 h-5" /> | |
| Download | |
| </button> | |
| <button onClick={handleCopy} className="flex items-center gap-2 bg-gray-700 text-white py-2 px-4 rounded-lg hover:bg-gray-600 transition-all duration-200 text-sm font-semibold" aria-label="Copy code"> | |
| <CopyIcon className="w-5 h-5" /> | |
| {copyText} | |
| </button> | |
| </div> | |
| <pre className="h-full w-full overflow-auto p-6 pt-20"> | |
| <code ref={codeRef} className="language-python text-sm font-code whitespace-pre-wrap text-gray-300"> | |
| {finalCode} | |
| </code> | |
| </pre> | |
| </div> | |
| ); | |
| }; | |
| type BuildSystem = 'makefile' | 'cmake' | 'meson'; | |
| const CppCodeView: React.FC<{ files: Record<string, string> }> = ({ files }) => { | |
| const [activeFile, setActiveFile] = useState(Object.keys(files)[0] || ''); | |
| const [buildSystem, setBuildSystem] = useState<BuildSystem>('cmake'); | |
| const [isDownloading, setIsDownloading] = useState(false); | |
| const codeRef = useRef<HTMLElement>(null); | |
| useEffect(() => { | |
| // @ts-ignore | |
| if (window.hljs && codeRef.current) { | |
| // @ts-ignore | |
| window.hljs.highlightElement(codeRef.current); | |
| } | |
| }, [activeFile, files]); | |
| const getBuildFileContent = (): { filename: string, content: string } => { | |
| const targetName = "MyApp"; | |
| const sources = Object.keys(files).filter(f => f.endsWith('.cpp')).join(' '); | |
| const headers = Object.keys(files).filter(f => f.endsWith('.h')).join(' '); | |
| switch(buildSystem) { | |
| case 'makefile': | |
| return { | |
| filename: 'Makefile', | |
| content: ` | |
| CXX = g++ | |
| CXXFLAGS = -std=c++17 -fPIC \`pkg-config --cflags Qt6Widgets Qt6Gui Qt6Core Qt6WebEngineWidgets\` | |
| LDFLAGS = \`pkg-config --libs Qt6Widgets Qt6Gui Qt6Core Qt6WebEngineWidgets\` | |
| TARGET = ${targetName} | |
| SOURCES = ${sources} | |
| OBJECTS = $(SOURCES:.cpp=.o) | |
| .PHONY: all clean | |
| all: $(TARGET) | |
| $(TARGET): $(OBJECTS) | |
| \t$(CXX) $(OBJECTS) -o $(TARGET) $(LDFLAGS) | |
| %.o: %.cpp ${headers} | |
| \t$(CXX) $(CXXFLAGS) -c $< -o $@ | |
| clean: | |
| \trm -f $(OBJECTS) $(TARGET) | |
| `.trim() | |
| }; | |
| case 'cmake': | |
| return { | |
| filename: 'CMakeLists.txt', | |
| content: ` | |
| cmake_minimum_required(VERSION 3.16) | |
| project(${targetName} VERSION 1.0) | |
| set(CMAKE_CXX_STANDARD 17) | |
| set(CMAKE_CXX_STANDARD_REQUIRED ON) | |
| set(CMAKE_AUTOMOC ON) | |
| set(CMAKE_AUTORCC ON) | |
| set(CMAKE_AUTOUIC ON) | |
| find_package(Qt6 COMPONENTS Widgets Gui Core WebEngineWidgets REQUIRED) | |
| add_executable(\${PROJECT_NAME} | |
| ${sources.split(' ').join('\n ')} | |
| ${headers.split(' ').join('\n ')} | |
| ) | |
| target_link_libraries(\${PROJECT_NAME} PRIVATE Qt6::Widgets Qt6::Gui Qt6::Core Qt6::WebEngineWidgets) | |
| `.trim() | |
| }; | |
| case 'meson': | |
| return { | |
| filename: 'meson.build', | |
| content: ` | |
| project('${targetName}', 'cpp', version : '1.0', default_options : ['cpp_std=c++17']) | |
| qt6 = dependency('qt6', modules: ['Core', 'Gui', 'Widgets', 'WebEngineWidgets'], required: true) | |
| executable( | |
| '${targetName}', | |
| files(${sources.split(' ').map(s=>`'${s}'`).join(', ')}), | |
| dependencies: [qt6], | |
| install: true | |
| ) | |
| `.trim() | |
| }; | |
| } | |
| } | |
| const handleDownloadZip = async () => { | |
| setIsDownloading(true); | |
| const zip = new JSZip(); | |
| Object.entries(files).forEach(([name, content]) => { | |
| zip.file(name, content); | |
| }); | |
| const buildFile = getBuildFileContent(); | |
| zip.file(buildFile.filename, buildFile.content); | |
| try { | |
| const content = await zip.generateAsync({type:"blob"}); | |
| const url = URL.createObjectURL(content); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = 'qt_app.zip'; | |
| document.body.appendChild(a); | |
| a.click(); | |
| document.body.removeChild(a); | |
| URL.revokeObjectURL(url); | |
| } catch (e) { | |
| console.error("Failed to generate ZIP", e); | |
| } finally { | |
| setIsDownloading(false); | |
| } | |
| }; | |
| if (!activeFile) return <div className="p-4 text-gray-400">No files were generated.</div> | |
| return ( | |
| <div className="h-full flex flex-col"> | |
| <div className="flex-shrink-0 flex items-center justify-between border-b border-gray-700 p-2 gap-2 flex-wrap"> | |
| <div className="flex items-center gap-1 flex-wrap"> | |
| {Object.keys(files).map(name => ( | |
| <button key={name} onClick={() => setActiveFile(name)} className={`px-3 py-2 text-sm rounded-md transition-colors ${activeFile === name ? 'bg-blue-600 text-white font-semibold' : 'bg-gray-800 hover:bg-gray-700 text-gray-300'}`}> | |
| {name} | |
| </button> | |
| ))} | |
| </div> | |
| </div> | |
| <div className="flex-shrink-0 flex items-center justify-end border-b border-gray-700 p-2 gap-2 flex-wrap bg-gray-800/50"> | |
| <div className="flex items-center gap-2"> | |
| <label htmlFor="build-system" className="text-sm font-medium text-gray-300">Build System:</label> | |
| <select id="build-system" value={buildSystem} onChange={e => setBuildSystem(e.target.value as BuildSystem)} className="bg-gray-700 text-white py-2 px-3 rounded-lg text-sm font-semibold border-0 focus:ring-2 focus:ring-blue-500"> | |
| <option value="cmake">CMake</option> | |
| <option value="makefile">Makefile</option> | |
| <option value="meson">Meson</option> | |
| </select> | |
| </div> | |
| <button onClick={handleDownloadZip} disabled={isDownloading} className="flex items-center gap-2 bg-green-600 text-white py-2 px-4 rounded-lg hover:bg-green-500 transition-all duration-200 text-sm font-semibold disabled:bg-gray-500"> | |
| <DownloadIcon className="w-5 h-5" /> | |
| {isDownloading ? 'Zipping...' : 'Download ZIP'} | |
| </button> | |
| </div> | |
| <div className="relative flex-grow overflow-hidden"> | |
| <pre className="h-full w-full overflow-auto p-6"> | |
| <code ref={codeRef} className="language-cpp text-sm font-code whitespace-pre-wrap text-gray-300"> | |
| {files[activeFile]} | |
| </code> | |
| </pre> | |
| </div> | |
| </div> | |
| ); | |
| }; | |
| const CodeDisplay: React.FC<CodeDisplayProps> = ({ appType, pythonCode, cppFiles, status }) => { | |
| if (status !== AppStatus.SUCCESS) { | |
| return <div className="p-4">Generating...</div>; | |
| } | |
| return ( | |
| <div className="h-full flex flex-col bg-gray-900 rounded-b-2xl"> | |
| {appType === 'python' && pythonCode ? ( | |
| <PythonCodeView code={pythonCode} /> | |
| ) : appType === 'c++' && cppFiles ? ( | |
| <CppCodeView files={cppFiles} /> | |
| ) : ( | |
| <div className="p-4 text-gray-400">Code generation complete, but no output received.</div> | |
| )} | |
| </div> | |
| ); | |
| }; | |
| export default CodeDisplay; |