Eeppa commited on
Commit
0d19d5e
Β·
verified Β·
1 Parent(s): 2e7546e

Create code_shower.py

Browse files
Files changed (1) hide show
  1. code_shower.py +183 -0
code_shower.py ADDED
@@ -0,0 +1,183 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from typing import Dict, Optional, Tuple
3
+ from file_manager import FileManager, CodeFile, Language
4
+ from preview_handler import PreviewHandler
5
+
6
+ class CodeShower:
7
+ """Right panel component for code display, file tree, and previews"""
8
+
9
+ def __init__(self):
10
+ self.current_files: Dict[str, CodeFile] = {}
11
+ self.active_file: Optional[str] = None
12
+ self.preview_handler = PreviewHandler()
13
+ self.file_manager = FileManager()
14
+
15
+ def create_ui(self):
16
+ """Create the Gradio UI components for the code shower"""
17
+ with gr.Column(visible=True, elem_classes="code-shower") as code_column:
18
+ gr.Markdown("### πŸ“ Code Shower")
19
+
20
+ with gr.Tabs():
21
+ with gr.TabItem("πŸ“‚ Files"):
22
+ self.file_tree = gr.HTML(
23
+ label="",
24
+ value='<div class="file-tree-empty">No files yet.<br>Generate code to see files here.</div>'
25
+ )
26
+
27
+ with gr.TabItem("πŸ‘οΈ Preview"):
28
+ self.preview_area = gr.HTML(
29
+ label="",
30
+ value='<div class="preview-placeholder">Select a file to preview</div>'
31
+ )
32
+
33
+ with gr.TabItem("πŸ“ View Code"):
34
+ self.code_area = gr.Code(
35
+ label="",
36
+ language="python",
37
+ value="# Select a file to view code",
38
+ interactive=False
39
+ )
40
+
41
+ # Language selector for new files
42
+ with gr.Row():
43
+ self.new_lang = gr.Dropdown(
44
+ choices=["python", "javascript", "html", "css", "json"],
45
+ value="python",
46
+ label="New file language"
47
+ )
48
+ self.new_filename = gr.Textbox(
49
+ placeholder="filename.py",
50
+ label="Filename",
51
+ scale=2
52
+ )
53
+ self.add_file_btn = gr.Button("βž• Add File", size="sm", scale=1)
54
+
55
+ return {
56
+ "file_tree": self.file_tree,
57
+ "preview_area": self.preview_area,
58
+ "code_area": self.code_area,
59
+ "new_lang": self.new_lang,
60
+ "new_filename": self.new_filename,
61
+ "add_file_btn": self.add_file_btn
62
+ }
63
+
64
+ def update_files_display(self):
65
+ """Update the file tree HTML based on current files"""
66
+ if not self.current_files:
67
+ return '<div class="file-tree-empty">πŸ“‚ No files yet<br><small>Generate code to see files here</small></div>'
68
+
69
+ html = '<div class="file-tree">'
70
+ for name, file in self.current_files.items():
71
+ active_class = "active" if self.active_file == name else ""
72
+ html += f'''
73
+ <div class="file-item {active_class}"
74
+ data-filename="{name}"
75
+ data-language="{file.language.value}"
76
+ onclick="window.selectFileFromTree('{name}')">
77
+ <span class="file-logo">{file.logo}</span>
78
+ <span class="file-name">{name}</span>
79
+ <span class="file-badge">{file.language.value}</span>
80
+ <button class="file-delete" onclick="event.stopPropagation(); window.deleteFileFromTree('{name}')">πŸ—‘οΈ</button>
81
+ </div>
82
+ '''
83
+ html += '</div>'
84
+
85
+ # Add JavaScript handlers (will be injected via Gradio's JS)
86
+ html += '''
87
+ <script>
88
+ window.selectFileFromTree = function(filename) {
89
+ const gradioEl = document.querySelector('gradio-app');
90
+ const data = { fn: "select_file", data: [filename] };
91
+ gradioEl.dispatchEvent(new CustomEvent('gradio', { detail: data }));
92
+ };
93
+ window.deleteFileFromTree = function(filename) {
94
+ const gradioEl = document.querySelector('gradio-app');
95
+ const data = { fn: "delete_file", data: [filename] };
96
+ gradioEl.dispatchEvent(new CustomEvent('gradio', { detail: data }));
97
+ };
98
+ </script>
99
+ '''
100
+ return html
101
+
102
+ def display_file(self, filename: str):
103
+ """Display a file's content and preview"""
104
+ if filename not in self.current_files:
105
+ return "File not found", "File not found", ""
106
+
107
+ file = self.current_files[filename]
108
+ self.active_file = filename
109
+
110
+ # Generate preview
111
+ preview = self.preview_handler.create_preview(file)
112
+
113
+ # Format code
114
+ code_view = self.preview_handler.format_code_with_syntax(file.content, file.language.value)
115
+
116
+ return preview, code_view, file.content
117
+
118
+ def add_new_file(self, lang: str, filename: str):
119
+ """Add a new empty file"""
120
+ if not filename:
121
+ # Generate default filename
122
+ ext_map = {
123
+ "python": "new_file.py",
124
+ "javascript": "new_file.js",
125
+ "html": "new_file.html",
126
+ "css": "new_file.css",
127
+ "json": "new_file.json",
128
+ }
129
+ filename = ext_map.get(lang, "new_file.txt")
130
+
131
+ # Template content based on language
132
+ templates = {
133
+ "python": '# New Python file\n\n\ndef main():\n print("Hello World")\n\nif __name__ == "__main__":\n main()',
134
+ "javascript": '// New JavaScript file\n\nconsole.log("Hello World");',
135
+ "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>',
136
+ "css": '/* New CSS file */\n\nbody {\n font-family: Arial, sans-serif;\n margin: 0;\n padding: 20px;\n}',
137
+ "json": '{\n "name": "example",\n "version": "1.0.0"\n}',
138
+ }
139
+
140
+ content = templates.get(lang, "# New file")
141
+ language = self.file_manager.detect_language(filename, content)
142
+
143
+ self.current_files[filename] = CodeFile(
144
+ name=filename,
145
+ content=content,
146
+ language=language,
147
+ logo=self.file_manager.get_logo(language),
148
+ extension="." + lang if lang != "javascript" else ".js",
149
+ can_preview=language in self.file_manager.PREVIEWABLE
150
+ )
151
+
152
+ return self.update_files_display(), *self.display_file(filename)
153
+
154
+ def delete_file(self, filename: str):
155
+ """Delete a file from the current collection"""
156
+ if filename in self.current_files:
157
+ del self.current_files[filename]
158
+ if self.active_file == filename:
159
+ self.active_file = None
160
+
161
+ if self.current_files:
162
+ first_file = list(self.current_files.keys())[0]
163
+ return self.update_files_display(), *self.display_file(first_file)
164
+ else:
165
+ empty_preview = '<div class="preview-placeholder">No files to preview</div>'
166
+ empty_code = '# No files to view'
167
+ return self.update_files_display(), empty_preview, empty_code, ""
168
+
169
+ def extract_and_add_files(self, response_text: str):
170
+ """Parse AI response and extract code blocks as files"""
171
+ files = self.file_manager.extract_files_from_code(response_text)
172
+
173
+ # Add/update files
174
+ for name, file in files.items():
175
+ self.current_files[name] = file
176
+
177
+ # Select first file if any
178
+ if self.current_files:
179
+ first_file = list(self.current_files.keys())[0]
180
+ self.active_file = first_file
181
+ return self.update_files_display(), *self.display_file(first_file)
182
+
183
+ return self.update_files_display(), '<div>No code blocks found</div>', '# No code', ""