import gradio as gr import re import json # 初始文件结构 initial_files = { "children": [ {"name": "index.html", "type": "file", "content": "\n\n\n
\n{html_str}'
# 文件选择处理函数
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("<", "<").replace(">", ">")
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()