Spaces:
Configuration error
Configuration error
| import gradio as gr | |
| from typing import Dict, Optional, Tuple | |
| from file_manager import FileManager, CodeFile, Language | |
| from preview_handler import PreviewHandler | |
| class CodeShower: | |
| """Right panel component for code display, file tree, and previews""" | |
| def __init__(self): | |
| self.current_files: Dict[str, CodeFile] = {} | |
| self.active_file: Optional[str] = None | |
| self.preview_handler = PreviewHandler() | |
| self.file_manager = FileManager() | |
| def create_ui(self): | |
| """Create the Gradio UI components for the code shower""" | |
| with gr.Column(visible=True, elem_classes="code-shower") as code_column: | |
| gr.Markdown("### 📁 Code Shower") | |
| with gr.Tabs(): | |
| with gr.TabItem("📂 Files"): | |
| self.file_tree = gr.HTML( | |
| label="", | |
| value='<div class="file-tree-empty">No files yet.<br>Generate code to see files here.</div>' | |
| ) | |
| with gr.TabItem("👁️ Preview"): | |
| self.preview_area = gr.HTML( | |
| label="", | |
| value='<div class="preview-placeholder">Select a file to preview</div>' | |
| ) | |
| with gr.TabItem("📝 View Code"): | |
| self.code_area = gr.Code( | |
| label="", | |
| language="python", | |
| value="# Select a file to view code", | |
| interactive=False | |
| ) | |
| # Language selector for new files | |
| with gr.Row(): | |
| self.new_lang = gr.Dropdown( | |
| choices=["python", "javascript", "html", "css", "json"], | |
| value="python", | |
| label="New file language" | |
| ) | |
| self.new_filename = gr.Textbox( | |
| placeholder="filename.py", | |
| label="Filename", | |
| scale=2 | |
| ) | |
| self.add_file_btn = gr.Button("➕ Add File", size="sm", scale=1) | |
| return { | |
| "file_tree": self.file_tree, | |
| "preview_area": self.preview_area, | |
| "code_area": self.code_area, | |
| "new_lang": self.new_lang, | |
| "new_filename": self.new_filename, | |
| "add_file_btn": self.add_file_btn | |
| } | |
| def update_files_display(self): | |
| """Update the file tree HTML based on current files""" | |
| if not self.current_files: | |
| return '<div class="file-tree-empty">📂 No files yet<br><small>Generate code to see files here</small></div>' | |
| html = '<div class="file-tree">' | |
| for name, file in self.current_files.items(): | |
| active_class = "active" if self.active_file == name else "" | |
| html += f''' | |
| <div class="file-item {active_class}" | |
| data-filename="{name}" | |
| data-language="{file.language.value}" | |
| onclick="window.selectFileFromTree('{name}')"> | |
| <span class="file-logo">{file.logo}</span> | |
| <span class="file-name">{name}</span> | |
| <span class="file-badge">{file.language.value}</span> | |
| <button class="file-delete" onclick="event.stopPropagation(); window.deleteFileFromTree('{name}')">🗑️</button> | |
| </div> | |
| ''' | |
| html += '</div>' | |
| # Add JavaScript handlers (will be injected via Gradio's JS) | |
| html += ''' | |
| <script> | |
| window.selectFileFromTree = function(filename) { | |
| const gradioEl = document.querySelector('gradio-app'); | |
| const data = { fn: "select_file", data: [filename] }; | |
| gradioEl.dispatchEvent(new CustomEvent('gradio', { detail: data })); | |
| }; | |
| window.deleteFileFromTree = function(filename) { | |
| const gradioEl = document.querySelector('gradio-app'); | |
| const data = { fn: "delete_file", data: [filename] }; | |
| gradioEl.dispatchEvent(new CustomEvent('gradio', { detail: data })); | |
| }; | |
| </script> | |
| ''' | |
| return html | |
| def display_file(self, filename: str): | |
| """Display a file's content and preview""" | |
| if filename not in self.current_files: | |
| return "File not found", "File not found", "" | |
| file = self.current_files[filename] | |
| self.active_file = filename | |
| # Generate preview | |
| preview = self.preview_handler.create_preview(file) | |
| # Format code | |
| code_view = self.preview_handler.format_code_with_syntax(file.content, file.language.value) | |
| return preview, code_view, file.content | |
| def add_new_file(self, lang: str, filename: str): | |
| """Add a new empty file""" | |
| if not filename: | |
| # Generate default filename | |
| ext_map = { | |
| "python": "new_file.py", | |
| "javascript": "new_file.js", | |
| "html": "new_file.html", | |
| "css": "new_file.css", | |
| "json": "new_file.json", | |
| } | |
| filename = ext_map.get(lang, "new_file.txt") | |
| # Template content based on language | |
| templates = { | |
| "python": '# New Python file\n\n\ndef main():\n print("Hello World")\n\nif __name__ == "__main__":\n main()', | |
| "javascript": '// New JavaScript file\n\nconsole.log("Hello World");', | |
| "html": '<!DOCTYPE html>\n<html>\n<head>\n <title>New Page</title>\n</head>\n<body>\n <h1>Hello World</h1>\n</body>\n</html>', | |
| "css": '/* New CSS file */\n\nbody {\n font-family: Arial, sans-serif;\n margin: 0;\n padding: 20px;\n}', | |
| "json": '{\n "name": "example",\n "version": "1.0.0"\n}', | |
| } | |
| content = templates.get(lang, "# New file") | |
| language = self.file_manager.detect_language(filename, content) | |
| self.current_files[filename] = CodeFile( | |
| name=filename, | |
| content=content, | |
| language=language, | |
| logo=self.file_manager.get_logo(language), | |
| extension="." + lang if lang != "javascript" else ".js", | |
| can_preview=language in self.file_manager.PREVIEWABLE | |
| ) | |
| return self.update_files_display(), *self.display_file(filename) | |
| def delete_file(self, filename: str): | |
| """Delete a file from the current collection""" | |
| if filename in self.current_files: | |
| del self.current_files[filename] | |
| if self.active_file == filename: | |
| self.active_file = None | |
| if self.current_files: | |
| first_file = list(self.current_files.keys())[0] | |
| return self.update_files_display(), *self.display_file(first_file) | |
| else: | |
| empty_preview = '<div class="preview-placeholder">No files to preview</div>' | |
| empty_code = '# No files to view' | |
| return self.update_files_display(), empty_preview, empty_code, "" | |
| def extract_and_add_files(self, response_text: str): | |
| """Parse AI response and extract code blocks as files""" | |
| files = self.file_manager.extract_files_from_code(response_text) | |
| # Add/update files | |
| for name, file in files.items(): | |
| self.current_files[name] = file | |
| # Select first file if any | |
| if self.current_files: | |
| first_file = list(self.current_files.keys())[0] | |
| self.active_file = first_file | |
| return self.update_files_display(), *self.display_file(first_file) | |
| return self.update_files_display(), '<div>No code blocks found</div>', '# No code', "" |