SopaHugging / app.py
Wina-Repo's picture
Create app.py
b519c8f verified
Raw
History Blame Contribute Delete
5.58 kB
import gradio as gr
import re
import json
# 初始文件结构
initial_files = {
"children": [
{"name": "index.html", "type": "file", "content": "<!DOCTYPE html>\n<!-- 注释示例 -->\n<html>\n<head>\n <title>示例</title>\n</head>\n<body>\n <h1 class=\"title\">Hello World</h1>\n</body>\n</html>"},
{"name": "styles", "type": "folder", "children": [
{"name": "main.css", "type": "file", "content": "/* CSS文件 */\nbody {\n background-color: #f0f0f0;\n}"}
]}
]
}
# HTML语法高亮函数
def highlight_html(html_str):
# 处理注释
html_str = re.sub(r'(&lt;!--.*?--&gt;)', r'<span style="color:#888;font-style:italic">\1</span>', html_str)
# 处理元素名
html_str = re.sub(r'(&lt;/?\w+)', r'<span style="color:#e06c75">\1</span>', html_str)
# 处理属性名
html_str = re.sub(r'(\s\w+)=', r'<span style="color:#d19a66">\1</span>=', html_str)
# 处理属性值
html_str = re.sub(r'=("[^"]*"|\'[^\']*\')', r'=<span style="color:#98c379">\1</span>', html_str)
# 处理结束符
html_str = re.sub(r'(&gt;)', r'<span style="color:#e06c75">\1</span>', html_str)
return f'<pre style="background:#2c2c2c;color:#abb2bf;padding:20px;border-radius:5px">{html_str}</pre>'
# 文件选择处理函数
def handle_file_select(evt: gr.SelectData):
if evt.value["type"] == "file":
content = evt.value["content"]
if evt.value["name"].endswith(".html"):
escaped = content.replace("<", "&lt;").replace(">", "&gt;")
return highlight_html(escaped), content
return gr.update(visible=False), content
return gr.update(visible=False), ""
# 创建新文件
def create_file(file_name, current_tree):
if not file_name.strip():
return current_tree, "文件名不能为空!"
new_file = {
"name": file_name,
"type": "file",
"content": f"// {file_name} 的内容"
}
updated_tree = json.loads(current_tree)
updated_tree["children"].append(new_file)
return json.dumps(updated_tree), f"已创建文件: {file_name}"
# 创建新文件夹
def create_folder(folder_name, current_tree):
if not folder_name.strip():
return current_tree, "文件夹名不能为空!"
new_folder = {
"name": folder_name,
"type": "folder",
"children": []
}
updated_tree = json.loads(current_tree)
updated_tree["children"].append(new_folder)
return json.dumps(updated_tree), f"已创建文件夹: {folder_name}"
# 保存文件内容
def save_file_content(file_tree, file_content, selected_file):
if not selected_file:
return "未选择文件!", file_tree
tree_data = json.loads(file_tree)
def update_content(node):
if node.get("name") == selected_file:
node["content"] = file_content
return True
if "children" in node:
for child in node["children"]:
if update_content(child):
return True
return False
if update_content(tree_data):
return "文件已保存!", json.dumps(tree_data)
return "保存失败!", file_tree
# 创建文件树组件
def create_file_tree():
return gr.Tree(
value=initial_files,
label="文件浏览器",
show_label=True,
elem_classes=["file-tree"],
)
# Gradio界面
with gr.Blocks(theme=gr.themes.Soft(), css=".file-tree {height: 500px;}") as demo:
gr.Markdown("# 🧩 网页开发IDE")
file_tree = gr.State(json.dumps(initial_files))
selected_file = gr.State("")
with gr.Row():
# 左侧文件操作面板
with gr.Column(scale=1, min_width=250):
create_file_btn = gr.Button("📄 新建文件", variant="primary")
new_file_name = gr.Textbox(placeholder="输入文件名 (如: script.js)")
create_folder_btn = gr.Button("📁 新建文件夹")
new_folder_name = gr.Textbox(placeholder="输入文件夹名")
status = gr.Textbox(label="操作状态", interactive=False)
tree = create_file_tree()
# 右侧代码编辑区
with gr.Column(scale=3):
file_name_display = gr.Textbox(label="当前文件", interactive=False)
html_preview = gr.HTML(visible=False)
code_editor = gr.Code(
language="html",
label="代码编辑器",
lines=20,
interactive=True
)
save_btn = gr.Button("💾 保存文件", variant="primary")
save_status = gr.Textbox(interactive=False)
# 事件处理
tree.select(handle_file_select, outputs=[html_preview, code_editor])
tree.select(lambda evt: evt.value["name"] if evt.value["type"]=="file" else "", outputs=[file_name_display])
tree.select(lambda evt: evt.value["name"] if evt.value["type"]=="file" else "", outputs=[selected_file])
create_file_btn.click(
create_file,
[new_file_name, file_tree],
[file_tree, status]
).then(lambda: gr.Tree(value=json.loads(file_tree.value)), tree)
create_folder_btn.click(
create_folder,
[new_folder_name, file_tree],
[file_tree, status]
).then(lambda: gr.Tree(value=json.loads(file_tree.value)), tree)
save_btn.click(
save_file_content,
[file_tree, code_editor, selected_file],
[save_status, file_tree]
)
if __name__ == "__main__":
demo.launch()