Upload folder using huggingface_hub
Browse files- .gitignore +12 -0
- README.md +264 -7
- __init__.py +0 -0
- app.py +172 -0
- css.css +157 -0
- requirements.txt +1 -0
- space.py +293 -0
- src/.gitignore +12 -0
- src/README.md +269 -0
- src/backend/gradio_gradiodesigner/__init__.py +4 -0
- src/backend/gradio_gradiodesigner/gradiodesigner.py +232 -0
- src/backend/gradio_gradiodesigner/templates/component/index.js +1450 -0
- src/backend/gradio_gradiodesigner/templates/component/style.css +1 -0
- src/backend/gradio_gradiodesigner/templates/example/index.js +126 -0
- src/backend/gradio_gradiodesigner/templates/example/style.css +1 -0
- src/demo/__init__.py +0 -0
- src/demo/app.py +172 -0
- src/demo/css.css +157 -0
- src/demo/requirements.txt +1 -0
- src/demo/space.py +293 -0
- src/frontend/Example.svelte +45 -0
- src/frontend/Index.svelte +890 -0
- src/frontend/gradio.config.js +9 -0
- src/frontend/package-lock.json +0 -0
- src/frontend/package.json +42 -0
- src/frontend/tsconfig.json +14 -0
- src/pyproject.toml +51 -0
.gitignore
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.eggs/
|
2 |
+
dist/
|
3 |
+
*.pyc
|
4 |
+
__pycache__/
|
5 |
+
*.py[cod]
|
6 |
+
*$py.class
|
7 |
+
__tmp/*
|
8 |
+
*.pyi
|
9 |
+
.mypycache
|
10 |
+
.ruff_cache
|
11 |
+
node_modules
|
12 |
+
backend/**/templates/
|
README.md
CHANGED
@@ -1,12 +1,269 @@
|
|
1 |
---
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
|
|
6 |
sdk: gradio
|
7 |
-
sdk_version: 5.33.1
|
8 |
-
app_file: app.py
|
9 |
pinned: false
|
|
|
10 |
---
|
11 |
|
12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
---
|
2 |
+
tags: [gradio-custom-component, SimpleTextbox, designer, drag and drop, custom designs]
|
3 |
+
title: gradio_gradiodesigner
|
4 |
+
short_description: gradio designer
|
5 |
+
colorFrom: blue
|
6 |
+
colorTo: yellow
|
7 |
sdk: gradio
|
|
|
|
|
8 |
pinned: false
|
9 |
+
app_file: space.py
|
10 |
---
|
11 |
|
12 |
+
# `gradio_gradiodesigner`
|
13 |
+
<img alt="Static Badge" src="https://img.shields.io/badge/version%20-%200.0.1%20-%20orange">
|
14 |
+
|
15 |
+
gradio designer
|
16 |
+
|
17 |
+
## Installation
|
18 |
+
|
19 |
+
```bash
|
20 |
+
pip install gradio_gradiodesigner
|
21 |
+
```
|
22 |
+
|
23 |
+
## Usage
|
24 |
+
|
25 |
+
```python
|
26 |
+
import gradio as gr
|
27 |
+
from gradio_gradiodesigner import GradioDesigner
|
28 |
+
import json
|
29 |
+
|
30 |
+
def analyze_design(design_config):
|
31 |
+
"""Analyze the design configuration"""
|
32 |
+
if not design_config or not isinstance(design_config, dict):
|
33 |
+
return "No design configuration provided"
|
34 |
+
|
35 |
+
components = design_config.get('components', [])
|
36 |
+
|
37 |
+
# Count components by type
|
38 |
+
component_types = {}
|
39 |
+
for comp in components:
|
40 |
+
comp_type = comp.get('type', 'Unknown')
|
41 |
+
component_types[comp_type] = component_types.get(comp_type, 0) + 1
|
42 |
+
|
43 |
+
# Calculate coverage area
|
44 |
+
if components:
|
45 |
+
positions = [(comp['position']['x'], comp['position']['y']) for comp in components]
|
46 |
+
min_x, min_y = min(pos[0] for pos in positions), min(pos[1] for pos in positions)
|
47 |
+
max_x, max_y = max(pos[0] for pos in positions), max(pos[1] for pos in positions)
|
48 |
+
coverage = f"{max_x - min_x} x {max_y - min_y} pixels"
|
49 |
+
else:
|
50 |
+
coverage = "No components"
|
51 |
+
|
52 |
+
analysis = f"""📊 **Design Analysis**
|
53 |
+
|
54 |
+
**Component Summary:**
|
55 |
+
• Total components: {len(components)}
|
56 |
+
• Component types: {dict(component_types)}
|
57 |
+
• Canvas coverage: {coverage}
|
58 |
+
|
59 |
+
**Component Details:**
|
60 |
+
"""
|
61 |
+
|
62 |
+
for i, comp in enumerate(components, 1):
|
63 |
+
analysis += f"\n{i}. **{comp['type']}** (`{comp['id']}`)"
|
64 |
+
analysis += f"\n - Position: ({comp['position']['x']}, {comp['position']['y']})"
|
65 |
+
analysis += f"\n - Size: {comp['size']['width']}×{comp['size']['height']}"
|
66 |
+
if comp.get('props', {}).get('label'):
|
67 |
+
analysis += f"\n - Label: \"{comp['props']['label']}\""
|
68 |
+
|
69 |
+
return analysis
|
70 |
+
|
71 |
+
def generate_gradio_code(design_config):
|
72 |
+
"""Generate complete Gradio code from design"""
|
73 |
+
if not design_config or not isinstance(design_config, dict):
|
74 |
+
return "# No design to generate code from"
|
75 |
+
|
76 |
+
components = design_config.get('components', [])
|
77 |
+
|
78 |
+
code = '''import gradio as gr
|
79 |
+
|
80 |
+
def process_input(*args):
|
81 |
+
"""Process the inputs from your app"""
|
82 |
+
return "Hello from your generated app!"
|
83 |
+
|
84 |
+
with gr.Blocks(title="Generated Gradio App") as demo:
|
85 |
+
gr.Markdown("# 🚀 Generated Gradio App")
|
86 |
+
gr.Markdown("This app was generated from your visual design!")
|
87 |
+
|
88 |
+
'''
|
89 |
+
|
90 |
+
# Sort components by position (top to bottom, left to right)
|
91 |
+
sorted_components = sorted(components, key=lambda c: (c['position']['y'], c['position']['x']))
|
92 |
+
|
93 |
+
component_vars = []
|
94 |
+
|
95 |
+
for comp in sorted_components:
|
96 |
+
comp_type = comp.get('type', 'Textbox')
|
97 |
+
comp_id = comp.get('id', 'component')
|
98 |
+
props = comp.get('props', {})
|
99 |
+
|
100 |
+
# Build component declaration
|
101 |
+
prop_parts = []
|
102 |
+
for key, value in props.items():
|
103 |
+
if key in ['label', 'placeholder', 'value'] and isinstance(value, str):
|
104 |
+
prop_parts.append(f'{key}="{value}"')
|
105 |
+
elif key in ['minimum', 'maximum', 'step', 'lines', 'max_length', 'precision'] and isinstance(value, (int, float)):
|
106 |
+
prop_parts.append(f'{key}={value}')
|
107 |
+
elif key == 'choices' and isinstance(value, list):
|
108 |
+
prop_parts.append(f'{key}={value}')
|
109 |
+
elif isinstance(value, bool):
|
110 |
+
prop_parts.append(f'{key}={value}')
|
111 |
+
|
112 |
+
prop_string = ", ".join(prop_parts) if prop_parts else ""
|
113 |
+
|
114 |
+
code += f" {comp_id} = gr.{comp_type}({prop_string})\n"
|
115 |
+
component_vars.append(comp_id)
|
116 |
+
|
117 |
+
# Add a simple interaction if there are components
|
118 |
+
if component_vars:
|
119 |
+
inputs = [var for var in component_vars if not var.startswith('button')]
|
120 |
+
outputs = [var for var in component_vars if var.startswith('button')]
|
121 |
+
|
122 |
+
if not outputs:
|
123 |
+
outputs = inputs[:1] # Use first input as output if no buttons
|
124 |
+
|
125 |
+
if inputs and outputs:
|
126 |
+
code += f"\n # Add interactions\n"
|
127 |
+
code += f" # Example: connect inputs to outputs\n"
|
128 |
+
code += f" # {outputs[0]}.click(process_input, inputs=[{', '.join(inputs)}], outputs=[{outputs[0]}])\n"
|
129 |
+
|
130 |
+
code += '''
|
131 |
+
if __name__ == "__main__":
|
132 |
+
demo.launch()
|
133 |
+
'''
|
134 |
+
|
135 |
+
return code
|
136 |
+
|
137 |
+
with gr.Blocks(title="Gradio Visual Designer Pro", theme=gr.themes.Soft()) as demo:
|
138 |
+
gr.Markdown("""
|
139 |
+
# 🎨 Gradio Visual Designer Pro
|
140 |
+
|
141 |
+
**Build your Gradio apps visually!** Drag and drop components, customize properties, and generate production-ready code.
|
142 |
+
|
143 |
+
**Features:** 25+ Gradio components • Real-time editing • Code generation • Export options
|
144 |
+
""")
|
145 |
+
|
146 |
+
with gr.Row():
|
147 |
+
designer = GradioDesigner(
|
148 |
+
label="Visual App Designer",
|
149 |
+
value={"components": [], "layout": "blocks"}
|
150 |
+
)
|
151 |
+
|
152 |
+
with gr.Row():
|
153 |
+
with gr.Column(scale=1):
|
154 |
+
analysis_output = gr.Markdown(
|
155 |
+
value="Design analysis will appear here...",
|
156 |
+
label="Design Analysis"
|
157 |
+
)
|
158 |
+
|
159 |
+
with gr.Column(scale=1):
|
160 |
+
code_output = gr.Code(
|
161 |
+
label="Generated Gradio Code",
|
162 |
+
language="python",
|
163 |
+
value="# Design your app above to see generated code",
|
164 |
+
lines=20
|
165 |
+
)
|
166 |
+
|
167 |
+
with gr.Row():
|
168 |
+
analyze_btn = gr.Button("📊 Analyze Design", variant="secondary")
|
169 |
+
generate_btn = gr.Button("🚀 Generate Code", variant="primary")
|
170 |
+
clear_btn = gr.Button("🗑️ Clear All", variant="stop")
|
171 |
+
|
172 |
+
# Event handlers
|
173 |
+
designer.change(
|
174 |
+
fn=analyze_design,
|
175 |
+
inputs=[designer],
|
176 |
+
outputs=[analysis_output]
|
177 |
+
)
|
178 |
+
|
179 |
+
analyze_btn.click(
|
180 |
+
fn=analyze_design,
|
181 |
+
inputs=[designer],
|
182 |
+
outputs=[analysis_output]
|
183 |
+
)
|
184 |
+
|
185 |
+
generate_btn.click(
|
186 |
+
fn=generate_gradio_code,
|
187 |
+
inputs=[designer],
|
188 |
+
outputs=[code_output]
|
189 |
+
)
|
190 |
+
|
191 |
+
clear_btn.click(
|
192 |
+
fn=lambda: {"components": [], "layout": "blocks"},
|
193 |
+
outputs=[designer]
|
194 |
+
)
|
195 |
+
|
196 |
+
if __name__ == "__main__":
|
197 |
+
demo.launch()
|
198 |
+
|
199 |
+
```
|
200 |
+
|
201 |
+
## `GradioDesigner`
|
202 |
+
|
203 |
+
### Initialization
|
204 |
+
|
205 |
+
<table>
|
206 |
+
<thead>
|
207 |
+
<tr>
|
208 |
+
<th align="left">name</th>
|
209 |
+
<th align="left" style="width: 25%;">type</th>
|
210 |
+
<th align="left">default</th>
|
211 |
+
<th align="left">description</th>
|
212 |
+
</tr>
|
213 |
+
</thead>
|
214 |
+
<tbody>
|
215 |
+
<tr>
|
216 |
+
<td align="left"><code>value</code></td>
|
217 |
+
<td align="left" style="width: 25%;">
|
218 |
+
|
219 |
+
```python
|
220 |
+
dict | None
|
221 |
+
```
|
222 |
+
|
223 |
+
</td>
|
224 |
+
<td align="left"><code>None</code></td>
|
225 |
+
<td align="left">None</td>
|
226 |
+
</tr>
|
227 |
+
|
228 |
+
<tr>
|
229 |
+
<td align="left"><code>label</code></td>
|
230 |
+
<td align="left" style="width: 25%;">
|
231 |
+
|
232 |
+
```python
|
233 |
+
str | None
|
234 |
+
```
|
235 |
+
|
236 |
+
</td>
|
237 |
+
<td align="left"><code>None</code></td>
|
238 |
+
<td align="left">None</td>
|
239 |
+
</tr>
|
240 |
+
</tbody></table>
|
241 |
+
|
242 |
+
|
243 |
+
### Events
|
244 |
+
|
245 |
+
| name | description |
|
246 |
+
|:-----|:------------|
|
247 |
+
| `change` | Triggered when the value of the GradioDesigner changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input. |
|
248 |
+
| `input` | This listener is triggered when the user changes the value of the GradioDesigner. |
|
249 |
+
|
250 |
+
|
251 |
+
|
252 |
+
### User function
|
253 |
+
|
254 |
+
The impact on the users predict function varies depending on whether the component is used as an input or output for an event (or both).
|
255 |
+
|
256 |
+
- When used as an Input, the component only impacts the input signature of the user function.
|
257 |
+
- When used as an output, the component only impacts the return signature of the user function.
|
258 |
+
|
259 |
+
The code snippet below is accurate in cases where the component is used as both an input and an output.
|
260 |
+
|
261 |
+
|
262 |
+
|
263 |
+
```python
|
264 |
+
def predict(
|
265 |
+
value: dict | None
|
266 |
+
) -> dict | None:
|
267 |
+
return value
|
268 |
+
```
|
269 |
+
|
__init__.py
ADDED
File without changes
|
app.py
ADDED
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
from gradio_gradiodesigner import GradioDesigner
|
3 |
+
import json
|
4 |
+
|
5 |
+
def analyze_design(design_config):
|
6 |
+
"""Analyze the design configuration"""
|
7 |
+
if not design_config or not isinstance(design_config, dict):
|
8 |
+
return "No design configuration provided"
|
9 |
+
|
10 |
+
components = design_config.get('components', [])
|
11 |
+
|
12 |
+
# Count components by type
|
13 |
+
component_types = {}
|
14 |
+
for comp in components:
|
15 |
+
comp_type = comp.get('type', 'Unknown')
|
16 |
+
component_types[comp_type] = component_types.get(comp_type, 0) + 1
|
17 |
+
|
18 |
+
# Calculate coverage area
|
19 |
+
if components:
|
20 |
+
positions = [(comp['position']['x'], comp['position']['y']) for comp in components]
|
21 |
+
min_x, min_y = min(pos[0] for pos in positions), min(pos[1] for pos in positions)
|
22 |
+
max_x, max_y = max(pos[0] for pos in positions), max(pos[1] for pos in positions)
|
23 |
+
coverage = f"{max_x - min_x} x {max_y - min_y} pixels"
|
24 |
+
else:
|
25 |
+
coverage = "No components"
|
26 |
+
|
27 |
+
analysis = f"""📊 **Design Analysis**
|
28 |
+
|
29 |
+
**Component Summary:**
|
30 |
+
• Total components: {len(components)}
|
31 |
+
• Component types: {dict(component_types)}
|
32 |
+
• Canvas coverage: {coverage}
|
33 |
+
|
34 |
+
**Component Details:**
|
35 |
+
"""
|
36 |
+
|
37 |
+
for i, comp in enumerate(components, 1):
|
38 |
+
analysis += f"\n{i}. **{comp['type']}** (`{comp['id']}`)"
|
39 |
+
analysis += f"\n - Position: ({comp['position']['x']}, {comp['position']['y']})"
|
40 |
+
analysis += f"\n - Size: {comp['size']['width']}×{comp['size']['height']}"
|
41 |
+
if comp.get('props', {}).get('label'):
|
42 |
+
analysis += f"\n - Label: \"{comp['props']['label']}\""
|
43 |
+
|
44 |
+
return analysis
|
45 |
+
|
46 |
+
def generate_gradio_code(design_config):
|
47 |
+
"""Generate complete Gradio code from design"""
|
48 |
+
if not design_config or not isinstance(design_config, dict):
|
49 |
+
return "# No design to generate code from"
|
50 |
+
|
51 |
+
components = design_config.get('components', [])
|
52 |
+
|
53 |
+
code = '''import gradio as gr
|
54 |
+
|
55 |
+
def process_input(*args):
|
56 |
+
"""Process the inputs from your app"""
|
57 |
+
return "Hello from your generated app!"
|
58 |
+
|
59 |
+
with gr.Blocks(title="Generated Gradio App") as demo:
|
60 |
+
gr.Markdown("# 🚀 Generated Gradio App")
|
61 |
+
gr.Markdown("This app was generated from your visual design!")
|
62 |
+
|
63 |
+
'''
|
64 |
+
|
65 |
+
# Sort components by position (top to bottom, left to right)
|
66 |
+
sorted_components = sorted(components, key=lambda c: (c['position']['y'], c['position']['x']))
|
67 |
+
|
68 |
+
component_vars = []
|
69 |
+
|
70 |
+
for comp in sorted_components:
|
71 |
+
comp_type = comp.get('type', 'Textbox')
|
72 |
+
comp_id = comp.get('id', 'component')
|
73 |
+
props = comp.get('props', {})
|
74 |
+
|
75 |
+
# Build component declaration
|
76 |
+
prop_parts = []
|
77 |
+
for key, value in props.items():
|
78 |
+
if key in ['label', 'placeholder', 'value'] and isinstance(value, str):
|
79 |
+
prop_parts.append(f'{key}="{value}"')
|
80 |
+
elif key in ['minimum', 'maximum', 'step', 'lines', 'max_length', 'precision'] and isinstance(value, (int, float)):
|
81 |
+
prop_parts.append(f'{key}={value}')
|
82 |
+
elif key == 'choices' and isinstance(value, list):
|
83 |
+
prop_parts.append(f'{key}={value}')
|
84 |
+
elif isinstance(value, bool):
|
85 |
+
prop_parts.append(f'{key}={value}')
|
86 |
+
|
87 |
+
prop_string = ", ".join(prop_parts) if prop_parts else ""
|
88 |
+
|
89 |
+
code += f" {comp_id} = gr.{comp_type}({prop_string})\n"
|
90 |
+
component_vars.append(comp_id)
|
91 |
+
|
92 |
+
# Add a simple interaction if there are components
|
93 |
+
if component_vars:
|
94 |
+
inputs = [var for var in component_vars if not var.startswith('button')]
|
95 |
+
outputs = [var for var in component_vars if var.startswith('button')]
|
96 |
+
|
97 |
+
if not outputs:
|
98 |
+
outputs = inputs[:1] # Use first input as output if no buttons
|
99 |
+
|
100 |
+
if inputs and outputs:
|
101 |
+
code += f"\n # Add interactions\n"
|
102 |
+
code += f" # Example: connect inputs to outputs\n"
|
103 |
+
code += f" # {outputs[0]}.click(process_input, inputs=[{', '.join(inputs)}], outputs=[{outputs[0]}])\n"
|
104 |
+
|
105 |
+
code += '''
|
106 |
+
if __name__ == "__main__":
|
107 |
+
demo.launch()
|
108 |
+
'''
|
109 |
+
|
110 |
+
return code
|
111 |
+
|
112 |
+
with gr.Blocks(title="Gradio Visual Designer Pro", theme=gr.themes.Soft()) as demo:
|
113 |
+
gr.Markdown("""
|
114 |
+
# 🎨 Gradio Visual Designer Pro
|
115 |
+
|
116 |
+
**Build your Gradio apps visually!** Drag and drop components, customize properties, and generate production-ready code.
|
117 |
+
|
118 |
+
**Features:** 25+ Gradio components • Real-time editing • Code generation • Export options
|
119 |
+
""")
|
120 |
+
|
121 |
+
with gr.Row():
|
122 |
+
designer = GradioDesigner(
|
123 |
+
label="Visual App Designer",
|
124 |
+
value={"components": [], "layout": "blocks"}
|
125 |
+
)
|
126 |
+
|
127 |
+
with gr.Row():
|
128 |
+
with gr.Column(scale=1):
|
129 |
+
analysis_output = gr.Markdown(
|
130 |
+
value="Design analysis will appear here...",
|
131 |
+
label="Design Analysis"
|
132 |
+
)
|
133 |
+
|
134 |
+
with gr.Column(scale=1):
|
135 |
+
code_output = gr.Code(
|
136 |
+
label="Generated Gradio Code",
|
137 |
+
language="python",
|
138 |
+
value="# Design your app above to see generated code",
|
139 |
+
lines=20
|
140 |
+
)
|
141 |
+
|
142 |
+
with gr.Row():
|
143 |
+
analyze_btn = gr.Button("📊 Analyze Design", variant="secondary")
|
144 |
+
generate_btn = gr.Button("🚀 Generate Code", variant="primary")
|
145 |
+
clear_btn = gr.Button("🗑️ Clear All", variant="stop")
|
146 |
+
|
147 |
+
# Event handlers
|
148 |
+
designer.change(
|
149 |
+
fn=analyze_design,
|
150 |
+
inputs=[designer],
|
151 |
+
outputs=[analysis_output]
|
152 |
+
)
|
153 |
+
|
154 |
+
analyze_btn.click(
|
155 |
+
fn=analyze_design,
|
156 |
+
inputs=[designer],
|
157 |
+
outputs=[analysis_output]
|
158 |
+
)
|
159 |
+
|
160 |
+
generate_btn.click(
|
161 |
+
fn=generate_gradio_code,
|
162 |
+
inputs=[designer],
|
163 |
+
outputs=[code_output]
|
164 |
+
)
|
165 |
+
|
166 |
+
clear_btn.click(
|
167 |
+
fn=lambda: {"components": [], "layout": "blocks"},
|
168 |
+
outputs=[designer]
|
169 |
+
)
|
170 |
+
|
171 |
+
if __name__ == "__main__":
|
172 |
+
demo.launch()
|
css.css
ADDED
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
html {
|
2 |
+
font-family: Inter;
|
3 |
+
font-size: 16px;
|
4 |
+
font-weight: 400;
|
5 |
+
line-height: 1.5;
|
6 |
+
-webkit-text-size-adjust: 100%;
|
7 |
+
background: #fff;
|
8 |
+
color: #323232;
|
9 |
+
-webkit-font-smoothing: antialiased;
|
10 |
+
-moz-osx-font-smoothing: grayscale;
|
11 |
+
text-rendering: optimizeLegibility;
|
12 |
+
}
|
13 |
+
|
14 |
+
:root {
|
15 |
+
--space: 1;
|
16 |
+
--vspace: calc(var(--space) * 1rem);
|
17 |
+
--vspace-0: calc(3 * var(--space) * 1rem);
|
18 |
+
--vspace-1: calc(2 * var(--space) * 1rem);
|
19 |
+
--vspace-2: calc(1.5 * var(--space) * 1rem);
|
20 |
+
--vspace-3: calc(0.5 * var(--space) * 1rem);
|
21 |
+
}
|
22 |
+
|
23 |
+
.app {
|
24 |
+
max-width: 748px !important;
|
25 |
+
}
|
26 |
+
|
27 |
+
.prose p {
|
28 |
+
margin: var(--vspace) 0;
|
29 |
+
line-height: var(--vspace * 2);
|
30 |
+
font-size: 1rem;
|
31 |
+
}
|
32 |
+
|
33 |
+
code {
|
34 |
+
font-family: "Inconsolata", sans-serif;
|
35 |
+
font-size: 16px;
|
36 |
+
}
|
37 |
+
|
38 |
+
h1,
|
39 |
+
h1 code {
|
40 |
+
font-weight: 400;
|
41 |
+
line-height: calc(2.5 / var(--space) * var(--vspace));
|
42 |
+
}
|
43 |
+
|
44 |
+
h1 code {
|
45 |
+
background: none;
|
46 |
+
border: none;
|
47 |
+
letter-spacing: 0.05em;
|
48 |
+
padding-bottom: 5px;
|
49 |
+
position: relative;
|
50 |
+
padding: 0;
|
51 |
+
}
|
52 |
+
|
53 |
+
h2 {
|
54 |
+
margin: var(--vspace-1) 0 var(--vspace-2) 0;
|
55 |
+
line-height: 1em;
|
56 |
+
}
|
57 |
+
|
58 |
+
h3,
|
59 |
+
h3 code {
|
60 |
+
margin: var(--vspace-1) 0 var(--vspace-2) 0;
|
61 |
+
line-height: 1em;
|
62 |
+
}
|
63 |
+
|
64 |
+
h4,
|
65 |
+
h5,
|
66 |
+
h6 {
|
67 |
+
margin: var(--vspace-3) 0 var(--vspace-3) 0;
|
68 |
+
line-height: var(--vspace);
|
69 |
+
}
|
70 |
+
|
71 |
+
.bigtitle,
|
72 |
+
h1,
|
73 |
+
h1 code {
|
74 |
+
font-size: calc(8px * 4.5);
|
75 |
+
word-break: break-word;
|
76 |
+
}
|
77 |
+
|
78 |
+
.title,
|
79 |
+
h2,
|
80 |
+
h2 code {
|
81 |
+
font-size: calc(8px * 3.375);
|
82 |
+
font-weight: lighter;
|
83 |
+
word-break: break-word;
|
84 |
+
border: none;
|
85 |
+
background: none;
|
86 |
+
}
|
87 |
+
|
88 |
+
.subheading1,
|
89 |
+
h3,
|
90 |
+
h3 code {
|
91 |
+
font-size: calc(8px * 1.8);
|
92 |
+
font-weight: 600;
|
93 |
+
border: none;
|
94 |
+
background: none;
|
95 |
+
letter-spacing: 0.1em;
|
96 |
+
text-transform: uppercase;
|
97 |
+
}
|
98 |
+
|
99 |
+
h2 code {
|
100 |
+
padding: 0;
|
101 |
+
position: relative;
|
102 |
+
letter-spacing: 0.05em;
|
103 |
+
}
|
104 |
+
|
105 |
+
blockquote {
|
106 |
+
font-size: calc(8px * 1.1667);
|
107 |
+
font-style: italic;
|
108 |
+
line-height: calc(1.1667 * var(--vspace));
|
109 |
+
margin: var(--vspace-2) var(--vspace-2);
|
110 |
+
}
|
111 |
+
|
112 |
+
.subheading2,
|
113 |
+
h4 {
|
114 |
+
font-size: calc(8px * 1.4292);
|
115 |
+
text-transform: uppercase;
|
116 |
+
font-weight: 600;
|
117 |
+
}
|
118 |
+
|
119 |
+
.subheading3,
|
120 |
+
h5 {
|
121 |
+
font-size: calc(8px * 1.2917);
|
122 |
+
line-height: calc(1.2917 * var(--vspace));
|
123 |
+
|
124 |
+
font-weight: lighter;
|
125 |
+
text-transform: uppercase;
|
126 |
+
letter-spacing: 0.15em;
|
127 |
+
}
|
128 |
+
|
129 |
+
h6 {
|
130 |
+
font-size: calc(8px * 1.1667);
|
131 |
+
font-size: 1.1667em;
|
132 |
+
font-weight: normal;
|
133 |
+
font-style: italic;
|
134 |
+
font-family: "le-monde-livre-classic-byol", serif !important;
|
135 |
+
letter-spacing: 0px !important;
|
136 |
+
}
|
137 |
+
|
138 |
+
#start .md > *:first-child {
|
139 |
+
margin-top: 0;
|
140 |
+
}
|
141 |
+
|
142 |
+
h2 + h3 {
|
143 |
+
margin-top: 0;
|
144 |
+
}
|
145 |
+
|
146 |
+
.md hr {
|
147 |
+
border: none;
|
148 |
+
border-top: 1px solid var(--block-border-color);
|
149 |
+
margin: var(--vspace-2) 0 var(--vspace-2) 0;
|
150 |
+
}
|
151 |
+
.prose ul {
|
152 |
+
margin: var(--vspace-2) 0 var(--vspace-1) 0;
|
153 |
+
}
|
154 |
+
|
155 |
+
.gap {
|
156 |
+
gap: 0;
|
157 |
+
}
|
requirements.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
gradio_gradiodesigner
|
space.py
ADDED
@@ -0,0 +1,293 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
import gradio as gr
|
3 |
+
from app import demo as app
|
4 |
+
import os
|
5 |
+
|
6 |
+
_docs = {'GradioDesigner': {'description': 'A visual designer component for building Gradio layouts with all components', 'members': {'__init__': {'value': {'type': 'dict | None', 'default': 'None', 'description': None}, 'label': {'type': 'str | None', 'default': 'None', 'description': None}}, 'postprocess': {'value': {'type': 'dict | None', 'description': None}}, 'preprocess': {'return': {'type': 'dict | None', 'description': None}, 'value': None}}, 'events': {'change': {'type': None, 'default': None, 'description': 'Triggered when the value of the GradioDesigner changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input.'}, 'input': {'type': None, 'default': None, 'description': 'This listener is triggered when the user changes the value of the GradioDesigner.'}}}, '__meta__': {'additional_interfaces': {}, 'user_fn_refs': {'GradioDesigner': []}}}
|
7 |
+
|
8 |
+
abs_path = os.path.join(os.path.dirname(__file__), "css.css")
|
9 |
+
|
10 |
+
with gr.Blocks(
|
11 |
+
css=abs_path,
|
12 |
+
theme=gr.themes.Default(
|
13 |
+
font_mono=[
|
14 |
+
gr.themes.GoogleFont("Inconsolata"),
|
15 |
+
"monospace",
|
16 |
+
],
|
17 |
+
),
|
18 |
+
) as demo:
|
19 |
+
gr.Markdown(
|
20 |
+
"""
|
21 |
+
# `gradio_gradiodesigner`
|
22 |
+
|
23 |
+
<div style="display: flex; gap: 7px;">
|
24 |
+
<img alt="Static Badge" src="https://img.shields.io/badge/version%20-%200.0.1%20-%20orange">
|
25 |
+
</div>
|
26 |
+
|
27 |
+
gradio designer
|
28 |
+
""", elem_classes=["md-custom"], header_links=True)
|
29 |
+
app.render()
|
30 |
+
gr.Markdown(
|
31 |
+
"""
|
32 |
+
## Installation
|
33 |
+
|
34 |
+
```bash
|
35 |
+
pip install gradio_gradiodesigner
|
36 |
+
```
|
37 |
+
|
38 |
+
## Usage
|
39 |
+
|
40 |
+
```python
|
41 |
+
import gradio as gr
|
42 |
+
from gradio_gradiodesigner import GradioDesigner
|
43 |
+
import json
|
44 |
+
|
45 |
+
def analyze_design(design_config):
|
46 |
+
\"\"\"Analyze the design configuration\"\"\"
|
47 |
+
if not design_config or not isinstance(design_config, dict):
|
48 |
+
return "No design configuration provided"
|
49 |
+
|
50 |
+
components = design_config.get('components', [])
|
51 |
+
|
52 |
+
# Count components by type
|
53 |
+
component_types = {}
|
54 |
+
for comp in components:
|
55 |
+
comp_type = comp.get('type', 'Unknown')
|
56 |
+
component_types[comp_type] = component_types.get(comp_type, 0) + 1
|
57 |
+
|
58 |
+
# Calculate coverage area
|
59 |
+
if components:
|
60 |
+
positions = [(comp['position']['x'], comp['position']['y']) for comp in components]
|
61 |
+
min_x, min_y = min(pos[0] for pos in positions), min(pos[1] for pos in positions)
|
62 |
+
max_x, max_y = max(pos[0] for pos in positions), max(pos[1] for pos in positions)
|
63 |
+
coverage = f"{max_x - min_x} x {max_y - min_y} pixels"
|
64 |
+
else:
|
65 |
+
coverage = "No components"
|
66 |
+
|
67 |
+
analysis = f\"\"\"📊 **Design Analysis**
|
68 |
+
|
69 |
+
**Component Summary:**
|
70 |
+
• Total components: {len(components)}
|
71 |
+
• Component types: {dict(component_types)}
|
72 |
+
• Canvas coverage: {coverage}
|
73 |
+
|
74 |
+
**Component Details:**
|
75 |
+
\"\"\"
|
76 |
+
|
77 |
+
for i, comp in enumerate(components, 1):
|
78 |
+
analysis += f"\n{i}. **{comp['type']}** (`{comp['id']}`)"
|
79 |
+
analysis += f"\n - Position: ({comp['position']['x']}, {comp['position']['y']})"
|
80 |
+
analysis += f"\n - Size: {comp['size']['width']}×{comp['size']['height']}"
|
81 |
+
if comp.get('props', {}).get('label'):
|
82 |
+
analysis += f"\n - Label: \"{comp['props']['label']}\""
|
83 |
+
|
84 |
+
return analysis
|
85 |
+
|
86 |
+
def generate_gradio_code(design_config):
|
87 |
+
\"\"\"Generate complete Gradio code from design\"\"\"
|
88 |
+
if not design_config or not isinstance(design_config, dict):
|
89 |
+
return "# No design to generate code from"
|
90 |
+
|
91 |
+
components = design_config.get('components', [])
|
92 |
+
|
93 |
+
code = '''import gradio as gr
|
94 |
+
|
95 |
+
def process_input(*args):
|
96 |
+
\"\"\"Process the inputs from your app\"\"\"
|
97 |
+
return "Hello from your generated app!"
|
98 |
+
|
99 |
+
with gr.Blocks(title="Generated Gradio App") as demo:
|
100 |
+
gr.Markdown("# 🚀 Generated Gradio App")
|
101 |
+
gr.Markdown("This app was generated from your visual design!")
|
102 |
+
|
103 |
+
'''
|
104 |
+
|
105 |
+
# Sort components by position (top to bottom, left to right)
|
106 |
+
sorted_components = sorted(components, key=lambda c: (c['position']['y'], c['position']['x']))
|
107 |
+
|
108 |
+
component_vars = []
|
109 |
+
|
110 |
+
for comp in sorted_components:
|
111 |
+
comp_type = comp.get('type', 'Textbox')
|
112 |
+
comp_id = comp.get('id', 'component')
|
113 |
+
props = comp.get('props', {})
|
114 |
+
|
115 |
+
# Build component declaration
|
116 |
+
prop_parts = []
|
117 |
+
for key, value in props.items():
|
118 |
+
if key in ['label', 'placeholder', 'value'] and isinstance(value, str):
|
119 |
+
prop_parts.append(f'{key}="{value}"')
|
120 |
+
elif key in ['minimum', 'maximum', 'step', 'lines', 'max_length', 'precision'] and isinstance(value, (int, float)):
|
121 |
+
prop_parts.append(f'{key}={value}')
|
122 |
+
elif key == 'choices' and isinstance(value, list):
|
123 |
+
prop_parts.append(f'{key}={value}')
|
124 |
+
elif isinstance(value, bool):
|
125 |
+
prop_parts.append(f'{key}={value}')
|
126 |
+
|
127 |
+
prop_string = ", ".join(prop_parts) if prop_parts else ""
|
128 |
+
|
129 |
+
code += f" {comp_id} = gr.{comp_type}({prop_string})\n"
|
130 |
+
component_vars.append(comp_id)
|
131 |
+
|
132 |
+
# Add a simple interaction if there are components
|
133 |
+
if component_vars:
|
134 |
+
inputs = [var for var in component_vars if not var.startswith('button')]
|
135 |
+
outputs = [var for var in component_vars if var.startswith('button')]
|
136 |
+
|
137 |
+
if not outputs:
|
138 |
+
outputs = inputs[:1] # Use first input as output if no buttons
|
139 |
+
|
140 |
+
if inputs and outputs:
|
141 |
+
code += f"\n # Add interactions\n"
|
142 |
+
code += f" # Example: connect inputs to outputs\n"
|
143 |
+
code += f" # {outputs[0]}.click(process_input, inputs=[{', '.join(inputs)}], outputs=[{outputs[0]}])\n"
|
144 |
+
|
145 |
+
code += '''
|
146 |
+
if __name__ == "__main__":
|
147 |
+
demo.launch()
|
148 |
+
'''
|
149 |
+
|
150 |
+
return code
|
151 |
+
|
152 |
+
with gr.Blocks(title="Gradio Visual Designer Pro", theme=gr.themes.Soft()) as demo:
|
153 |
+
gr.Markdown(\"\"\"
|
154 |
+
# 🎨 Gradio Visual Designer Pro
|
155 |
+
|
156 |
+
**Build your Gradio apps visually!** Drag and drop components, customize properties, and generate production-ready code.
|
157 |
+
|
158 |
+
**Features:** 25+ Gradio components • Real-time editing • Code generation • Export options
|
159 |
+
\"\"\")
|
160 |
+
|
161 |
+
with gr.Row():
|
162 |
+
designer = GradioDesigner(
|
163 |
+
label="Visual App Designer",
|
164 |
+
value={"components": [], "layout": "blocks"}
|
165 |
+
)
|
166 |
+
|
167 |
+
with gr.Row():
|
168 |
+
with gr.Column(scale=1):
|
169 |
+
analysis_output = gr.Markdown(
|
170 |
+
value="Design analysis will appear here...",
|
171 |
+
label="Design Analysis"
|
172 |
+
)
|
173 |
+
|
174 |
+
with gr.Column(scale=1):
|
175 |
+
code_output = gr.Code(
|
176 |
+
label="Generated Gradio Code",
|
177 |
+
language="python",
|
178 |
+
value="# Design your app above to see generated code",
|
179 |
+
lines=20
|
180 |
+
)
|
181 |
+
|
182 |
+
with gr.Row():
|
183 |
+
analyze_btn = gr.Button("📊 Analyze Design", variant="secondary")
|
184 |
+
generate_btn = gr.Button("🚀 Generate Code", variant="primary")
|
185 |
+
clear_btn = gr.Button("🗑️ Clear All", variant="stop")
|
186 |
+
|
187 |
+
# Event handlers
|
188 |
+
designer.change(
|
189 |
+
fn=analyze_design,
|
190 |
+
inputs=[designer],
|
191 |
+
outputs=[analysis_output]
|
192 |
+
)
|
193 |
+
|
194 |
+
analyze_btn.click(
|
195 |
+
fn=analyze_design,
|
196 |
+
inputs=[designer],
|
197 |
+
outputs=[analysis_output]
|
198 |
+
)
|
199 |
+
|
200 |
+
generate_btn.click(
|
201 |
+
fn=generate_gradio_code,
|
202 |
+
inputs=[designer],
|
203 |
+
outputs=[code_output]
|
204 |
+
)
|
205 |
+
|
206 |
+
clear_btn.click(
|
207 |
+
fn=lambda: {"components": [], "layout": "blocks"},
|
208 |
+
outputs=[designer]
|
209 |
+
)
|
210 |
+
|
211 |
+
if __name__ == "__main__":
|
212 |
+
demo.launch()
|
213 |
+
|
214 |
+
```
|
215 |
+
""", elem_classes=["md-custom"], header_links=True)
|
216 |
+
|
217 |
+
|
218 |
+
gr.Markdown("""
|
219 |
+
## `GradioDesigner`
|
220 |
+
|
221 |
+
### Initialization
|
222 |
+
""", elem_classes=["md-custom"], header_links=True)
|
223 |
+
|
224 |
+
gr.ParamViewer(value=_docs["GradioDesigner"]["members"]["__init__"], linkify=[])
|
225 |
+
|
226 |
+
|
227 |
+
gr.Markdown("### Events")
|
228 |
+
gr.ParamViewer(value=_docs["GradioDesigner"]["events"], linkify=['Event'])
|
229 |
+
|
230 |
+
|
231 |
+
|
232 |
+
|
233 |
+
gr.Markdown("""
|
234 |
+
|
235 |
+
### User function
|
236 |
+
|
237 |
+
The impact on the users predict function varies depending on whether the component is used as an input or output for an event (or both).
|
238 |
+
|
239 |
+
- When used as an Input, the component only impacts the input signature of the user function.
|
240 |
+
- When used as an output, the component only impacts the return signature of the user function.
|
241 |
+
|
242 |
+
The code snippet below is accurate in cases where the component is used as both an input and an output.
|
243 |
+
|
244 |
+
|
245 |
+
|
246 |
+
```python
|
247 |
+
def predict(
|
248 |
+
value: dict | None
|
249 |
+
) -> dict | None:
|
250 |
+
return value
|
251 |
+
```
|
252 |
+
""", elem_classes=["md-custom", "GradioDesigner-user-fn"], header_links=True)
|
253 |
+
|
254 |
+
|
255 |
+
|
256 |
+
|
257 |
+
demo.load(None, js=r"""function() {
|
258 |
+
const refs = {};
|
259 |
+
const user_fn_refs = {
|
260 |
+
GradioDesigner: [], };
|
261 |
+
requestAnimationFrame(() => {
|
262 |
+
|
263 |
+
Object.entries(user_fn_refs).forEach(([key, refs]) => {
|
264 |
+
if (refs.length > 0) {
|
265 |
+
const el = document.querySelector(`.${key}-user-fn`);
|
266 |
+
if (!el) return;
|
267 |
+
refs.forEach(ref => {
|
268 |
+
el.innerHTML = el.innerHTML.replace(
|
269 |
+
new RegExp("\\b"+ref+"\\b", "g"),
|
270 |
+
`<a href="#h-${ref.toLowerCase()}">${ref}</a>`
|
271 |
+
);
|
272 |
+
})
|
273 |
+
}
|
274 |
+
})
|
275 |
+
|
276 |
+
Object.entries(refs).forEach(([key, refs]) => {
|
277 |
+
if (refs.length > 0) {
|
278 |
+
const el = document.querySelector(`.${key}`);
|
279 |
+
if (!el) return;
|
280 |
+
refs.forEach(ref => {
|
281 |
+
el.innerHTML = el.innerHTML.replace(
|
282 |
+
new RegExp("\\b"+ref+"\\b", "g"),
|
283 |
+
`<a href="#h-${ref.toLowerCase()}">${ref}</a>`
|
284 |
+
);
|
285 |
+
})
|
286 |
+
}
|
287 |
+
})
|
288 |
+
})
|
289 |
+
}
|
290 |
+
|
291 |
+
""")
|
292 |
+
|
293 |
+
demo.launch()
|
src/.gitignore
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.eggs/
|
2 |
+
dist/
|
3 |
+
*.pyc
|
4 |
+
__pycache__/
|
5 |
+
*.py[cod]
|
6 |
+
*$py.class
|
7 |
+
__tmp/*
|
8 |
+
*.pyi
|
9 |
+
.mypycache
|
10 |
+
.ruff_cache
|
11 |
+
node_modules
|
12 |
+
backend/**/templates/
|
src/README.md
ADDED
@@ -0,0 +1,269 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
---
|
2 |
+
tags: [gradio-custom-component, SimpleTextbox, designer, drag and drop, custom designs]
|
3 |
+
title: gradio_gradiodesigner
|
4 |
+
short_description: gradio designer
|
5 |
+
colorFrom: blue
|
6 |
+
colorTo: yellow
|
7 |
+
sdk: gradio
|
8 |
+
pinned: false
|
9 |
+
app_file: space.py
|
10 |
+
---
|
11 |
+
|
12 |
+
# `gradio_gradiodesigner`
|
13 |
+
<img alt="Static Badge" src="https://img.shields.io/badge/version%20-%200.0.1%20-%20orange">
|
14 |
+
|
15 |
+
gradio designer
|
16 |
+
|
17 |
+
## Installation
|
18 |
+
|
19 |
+
```bash
|
20 |
+
pip install gradio_gradiodesigner
|
21 |
+
```
|
22 |
+
|
23 |
+
## Usage
|
24 |
+
|
25 |
+
```python
|
26 |
+
import gradio as gr
|
27 |
+
from gradio_gradiodesigner import GradioDesigner
|
28 |
+
import json
|
29 |
+
|
30 |
+
def analyze_design(design_config):
|
31 |
+
"""Analyze the design configuration"""
|
32 |
+
if not design_config or not isinstance(design_config, dict):
|
33 |
+
return "No design configuration provided"
|
34 |
+
|
35 |
+
components = design_config.get('components', [])
|
36 |
+
|
37 |
+
# Count components by type
|
38 |
+
component_types = {}
|
39 |
+
for comp in components:
|
40 |
+
comp_type = comp.get('type', 'Unknown')
|
41 |
+
component_types[comp_type] = component_types.get(comp_type, 0) + 1
|
42 |
+
|
43 |
+
# Calculate coverage area
|
44 |
+
if components:
|
45 |
+
positions = [(comp['position']['x'], comp['position']['y']) for comp in components]
|
46 |
+
min_x, min_y = min(pos[0] for pos in positions), min(pos[1] for pos in positions)
|
47 |
+
max_x, max_y = max(pos[0] for pos in positions), max(pos[1] for pos in positions)
|
48 |
+
coverage = f"{max_x - min_x} x {max_y - min_y} pixels"
|
49 |
+
else:
|
50 |
+
coverage = "No components"
|
51 |
+
|
52 |
+
analysis = f"""📊 **Design Analysis**
|
53 |
+
|
54 |
+
**Component Summary:**
|
55 |
+
• Total components: {len(components)}
|
56 |
+
• Component types: {dict(component_types)}
|
57 |
+
• Canvas coverage: {coverage}
|
58 |
+
|
59 |
+
**Component Details:**
|
60 |
+
"""
|
61 |
+
|
62 |
+
for i, comp in enumerate(components, 1):
|
63 |
+
analysis += f"\n{i}. **{comp['type']}** (`{comp['id']}`)"
|
64 |
+
analysis += f"\n - Position: ({comp['position']['x']}, {comp['position']['y']})"
|
65 |
+
analysis += f"\n - Size: {comp['size']['width']}×{comp['size']['height']}"
|
66 |
+
if comp.get('props', {}).get('label'):
|
67 |
+
analysis += f"\n - Label: \"{comp['props']['label']}\""
|
68 |
+
|
69 |
+
return analysis
|
70 |
+
|
71 |
+
def generate_gradio_code(design_config):
|
72 |
+
"""Generate complete Gradio code from design"""
|
73 |
+
if not design_config or not isinstance(design_config, dict):
|
74 |
+
return "# No design to generate code from"
|
75 |
+
|
76 |
+
components = design_config.get('components', [])
|
77 |
+
|
78 |
+
code = '''import gradio as gr
|
79 |
+
|
80 |
+
def process_input(*args):
|
81 |
+
"""Process the inputs from your app"""
|
82 |
+
return "Hello from your generated app!"
|
83 |
+
|
84 |
+
with gr.Blocks(title="Generated Gradio App") as demo:
|
85 |
+
gr.Markdown("# 🚀 Generated Gradio App")
|
86 |
+
gr.Markdown("This app was generated from your visual design!")
|
87 |
+
|
88 |
+
'''
|
89 |
+
|
90 |
+
# Sort components by position (top to bottom, left to right)
|
91 |
+
sorted_components = sorted(components, key=lambda c: (c['position']['y'], c['position']['x']))
|
92 |
+
|
93 |
+
component_vars = []
|
94 |
+
|
95 |
+
for comp in sorted_components:
|
96 |
+
comp_type = comp.get('type', 'Textbox')
|
97 |
+
comp_id = comp.get('id', 'component')
|
98 |
+
props = comp.get('props', {})
|
99 |
+
|
100 |
+
# Build component declaration
|
101 |
+
prop_parts = []
|
102 |
+
for key, value in props.items():
|
103 |
+
if key in ['label', 'placeholder', 'value'] and isinstance(value, str):
|
104 |
+
prop_parts.append(f'{key}="{value}"')
|
105 |
+
elif key in ['minimum', 'maximum', 'step', 'lines', 'max_length', 'precision'] and isinstance(value, (int, float)):
|
106 |
+
prop_parts.append(f'{key}={value}')
|
107 |
+
elif key == 'choices' and isinstance(value, list):
|
108 |
+
prop_parts.append(f'{key}={value}')
|
109 |
+
elif isinstance(value, bool):
|
110 |
+
prop_parts.append(f'{key}={value}')
|
111 |
+
|
112 |
+
prop_string = ", ".join(prop_parts) if prop_parts else ""
|
113 |
+
|
114 |
+
code += f" {comp_id} = gr.{comp_type}({prop_string})\n"
|
115 |
+
component_vars.append(comp_id)
|
116 |
+
|
117 |
+
# Add a simple interaction if there are components
|
118 |
+
if component_vars:
|
119 |
+
inputs = [var for var in component_vars if not var.startswith('button')]
|
120 |
+
outputs = [var for var in component_vars if var.startswith('button')]
|
121 |
+
|
122 |
+
if not outputs:
|
123 |
+
outputs = inputs[:1] # Use first input as output if no buttons
|
124 |
+
|
125 |
+
if inputs and outputs:
|
126 |
+
code += f"\n # Add interactions\n"
|
127 |
+
code += f" # Example: connect inputs to outputs\n"
|
128 |
+
code += f" # {outputs[0]}.click(process_input, inputs=[{', '.join(inputs)}], outputs=[{outputs[0]}])\n"
|
129 |
+
|
130 |
+
code += '''
|
131 |
+
if __name__ == "__main__":
|
132 |
+
demo.launch()
|
133 |
+
'''
|
134 |
+
|
135 |
+
return code
|
136 |
+
|
137 |
+
with gr.Blocks(title="Gradio Visual Designer Pro", theme=gr.themes.Soft()) as demo:
|
138 |
+
gr.Markdown("""
|
139 |
+
# 🎨 Gradio Visual Designer Pro
|
140 |
+
|
141 |
+
**Build your Gradio apps visually!** Drag and drop components, customize properties, and generate production-ready code.
|
142 |
+
|
143 |
+
**Features:** 25+ Gradio components • Real-time editing • Code generation • Export options
|
144 |
+
""")
|
145 |
+
|
146 |
+
with gr.Row():
|
147 |
+
designer = GradioDesigner(
|
148 |
+
label="Visual App Designer",
|
149 |
+
value={"components": [], "layout": "blocks"}
|
150 |
+
)
|
151 |
+
|
152 |
+
with gr.Row():
|
153 |
+
with gr.Column(scale=1):
|
154 |
+
analysis_output = gr.Markdown(
|
155 |
+
value="Design analysis will appear here...",
|
156 |
+
label="Design Analysis"
|
157 |
+
)
|
158 |
+
|
159 |
+
with gr.Column(scale=1):
|
160 |
+
code_output = gr.Code(
|
161 |
+
label="Generated Gradio Code",
|
162 |
+
language="python",
|
163 |
+
value="# Design your app above to see generated code",
|
164 |
+
lines=20
|
165 |
+
)
|
166 |
+
|
167 |
+
with gr.Row():
|
168 |
+
analyze_btn = gr.Button("📊 Analyze Design", variant="secondary")
|
169 |
+
generate_btn = gr.Button("🚀 Generate Code", variant="primary")
|
170 |
+
clear_btn = gr.Button("🗑️ Clear All", variant="stop")
|
171 |
+
|
172 |
+
# Event handlers
|
173 |
+
designer.change(
|
174 |
+
fn=analyze_design,
|
175 |
+
inputs=[designer],
|
176 |
+
outputs=[analysis_output]
|
177 |
+
)
|
178 |
+
|
179 |
+
analyze_btn.click(
|
180 |
+
fn=analyze_design,
|
181 |
+
inputs=[designer],
|
182 |
+
outputs=[analysis_output]
|
183 |
+
)
|
184 |
+
|
185 |
+
generate_btn.click(
|
186 |
+
fn=generate_gradio_code,
|
187 |
+
inputs=[designer],
|
188 |
+
outputs=[code_output]
|
189 |
+
)
|
190 |
+
|
191 |
+
clear_btn.click(
|
192 |
+
fn=lambda: {"components": [], "layout": "blocks"},
|
193 |
+
outputs=[designer]
|
194 |
+
)
|
195 |
+
|
196 |
+
if __name__ == "__main__":
|
197 |
+
demo.launch()
|
198 |
+
|
199 |
+
```
|
200 |
+
|
201 |
+
## `GradioDesigner`
|
202 |
+
|
203 |
+
### Initialization
|
204 |
+
|
205 |
+
<table>
|
206 |
+
<thead>
|
207 |
+
<tr>
|
208 |
+
<th align="left">name</th>
|
209 |
+
<th align="left" style="width: 25%;">type</th>
|
210 |
+
<th align="left">default</th>
|
211 |
+
<th align="left">description</th>
|
212 |
+
</tr>
|
213 |
+
</thead>
|
214 |
+
<tbody>
|
215 |
+
<tr>
|
216 |
+
<td align="left"><code>value</code></td>
|
217 |
+
<td align="left" style="width: 25%;">
|
218 |
+
|
219 |
+
```python
|
220 |
+
dict | None
|
221 |
+
```
|
222 |
+
|
223 |
+
</td>
|
224 |
+
<td align="left"><code>None</code></td>
|
225 |
+
<td align="left">None</td>
|
226 |
+
</tr>
|
227 |
+
|
228 |
+
<tr>
|
229 |
+
<td align="left"><code>label</code></td>
|
230 |
+
<td align="left" style="width: 25%;">
|
231 |
+
|
232 |
+
```python
|
233 |
+
str | None
|
234 |
+
```
|
235 |
+
|
236 |
+
</td>
|
237 |
+
<td align="left"><code>None</code></td>
|
238 |
+
<td align="left">None</td>
|
239 |
+
</tr>
|
240 |
+
</tbody></table>
|
241 |
+
|
242 |
+
|
243 |
+
### Events
|
244 |
+
|
245 |
+
| name | description |
|
246 |
+
|:-----|:------------|
|
247 |
+
| `change` | Triggered when the value of the GradioDesigner changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input. |
|
248 |
+
| `input` | This listener is triggered when the user changes the value of the GradioDesigner. |
|
249 |
+
|
250 |
+
|
251 |
+
|
252 |
+
### User function
|
253 |
+
|
254 |
+
The impact on the users predict function varies depending on whether the component is used as an input or output for an event (or both).
|
255 |
+
|
256 |
+
- When used as an Input, the component only impacts the input signature of the user function.
|
257 |
+
- When used as an output, the component only impacts the return signature of the user function.
|
258 |
+
|
259 |
+
The code snippet below is accurate in cases where the component is used as both an input and an output.
|
260 |
+
|
261 |
+
|
262 |
+
|
263 |
+
```python
|
264 |
+
def predict(
|
265 |
+
value: dict | None
|
266 |
+
) -> dict | None:
|
267 |
+
return value
|
268 |
+
```
|
269 |
+
|
src/backend/gradio_gradiodesigner/__init__.py
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
from .gradiodesigner import GradioDesigner
|
3 |
+
|
4 |
+
__all__ = ['GradioDesigner']
|
src/backend/gradio_gradiodesigner/gradiodesigner.py
ADDED
@@ -0,0 +1,232 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
from gradio.components.base import Component
|
3 |
+
from gradio.events import Events
|
4 |
+
import json
|
5 |
+
|
6 |
+
class GradioDesigner(Component):
|
7 |
+
"""
|
8 |
+
A visual designer component for building Gradio layouts with all components
|
9 |
+
"""
|
10 |
+
|
11 |
+
EVENTS = [Events.change, Events.input]
|
12 |
+
|
13 |
+
# Complete component definitions with their properties
|
14 |
+
COMPONENT_DEFINITIONS = {
|
15 |
+
"Textbox": {
|
16 |
+
"properties": ["label", "placeholder", "lines", "max_length", "type", "value"],
|
17 |
+
"defaults": {"label": "Text Input", "placeholder": "Enter text...", "lines": 1, "value": ""},
|
18 |
+
"icon": "📝",
|
19 |
+
"category": "Input"
|
20 |
+
},
|
21 |
+
"TextArea": {
|
22 |
+
"properties": ["label", "placeholder", "lines", "max_length", "value"],
|
23 |
+
"defaults": {"label": "Text Area", "placeholder": "Enter multiple lines...", "lines": 3, "value": ""},
|
24 |
+
"icon": "📄",
|
25 |
+
"category": "Input"
|
26 |
+
},
|
27 |
+
"Button": {
|
28 |
+
"properties": ["value", "variant", "size"],
|
29 |
+
"defaults": {"value": "Click me", "variant": "secondary", "size": "sm"},
|
30 |
+
"icon": "🔘",
|
31 |
+
"category": "Action"
|
32 |
+
},
|
33 |
+
"Slider": {
|
34 |
+
"properties": ["minimum", "maximum", "step", "value", "label"],
|
35 |
+
"defaults": {"label": "Slider", "minimum": 0, "maximum": 100, "step": 1, "value": 50},
|
36 |
+
"icon": "🎚️",
|
37 |
+
"category": "Input"
|
38 |
+
},
|
39 |
+
"Number": {
|
40 |
+
"properties": ["label", "value", "precision"],
|
41 |
+
"defaults": {"label": "Number", "value": 0, "precision": 0},
|
42 |
+
"icon": "🔢",
|
43 |
+
"category": "Input"
|
44 |
+
},
|
45 |
+
"Checkbox": {
|
46 |
+
"properties": ["label", "value"],
|
47 |
+
"defaults": {"label": "Checkbox", "value": False},
|
48 |
+
"icon": "☑️",
|
49 |
+
"category": "Input"
|
50 |
+
},
|
51 |
+
"CheckboxGroup": {
|
52 |
+
"properties": ["label", "choices", "value"],
|
53 |
+
"defaults": {"label": "Checkbox Group", "choices": ["Option 1", "Option 2"], "value": []},
|
54 |
+
"icon": "☑️",
|
55 |
+
"category": "Input"
|
56 |
+
},
|
57 |
+
"Radio": {
|
58 |
+
"properties": ["label", "choices", "value"],
|
59 |
+
"defaults": {"label": "Radio", "choices": ["Option 1", "Option 2"], "value": "Option 1"},
|
60 |
+
"icon": "🔘",
|
61 |
+
"category": "Input"
|
62 |
+
},
|
63 |
+
"Dropdown": {
|
64 |
+
"properties": ["label", "choices", "value", "multiselect"],
|
65 |
+
"defaults": {"label": "Dropdown", "choices": ["Option 1", "Option 2"], "value": "Option 1", "multiselect": False},
|
66 |
+
"icon": "📋",
|
67 |
+
"category": "Input"
|
68 |
+
},
|
69 |
+
"Toggle": {
|
70 |
+
"properties": ["label", "value"],
|
71 |
+
"defaults": {"label": "Toggle", "value": False},
|
72 |
+
"icon": "🔄",
|
73 |
+
"category": "Input"
|
74 |
+
},
|
75 |
+
"ColorPicker": {
|
76 |
+
"properties": ["label", "value"],
|
77 |
+
"defaults": {"label": "Color Picker", "value": "#ff0000"},
|
78 |
+
"icon": "🎨",
|
79 |
+
"category": "Input"
|
80 |
+
},
|
81 |
+
"Date": {
|
82 |
+
"properties": ["label", "value"],
|
83 |
+
"defaults": {"label": "Date", "value": "2025-01-01"},
|
84 |
+
"icon": "📅",
|
85 |
+
"category": "Input"
|
86 |
+
},
|
87 |
+
"Time": {
|
88 |
+
"properties": ["label", "value"],
|
89 |
+
"defaults": {"label": "Time", "value": "12:00"},
|
90 |
+
"icon": "⏰",
|
91 |
+
"category": "Input"
|
92 |
+
},
|
93 |
+
"File": {
|
94 |
+
"properties": ["label", "file_types"],
|
95 |
+
"defaults": {"label": "Upload File", "file_types": [".txt", ".pdf"]},
|
96 |
+
"icon": "📁",
|
97 |
+
"category": "Input"
|
98 |
+
},
|
99 |
+
"Image": {
|
100 |
+
"properties": ["label", "type", "tool", "interactive"],
|
101 |
+
"defaults": {"label": "Image", "type": "pil", "interactive": True},
|
102 |
+
"icon": "🖼️",
|
103 |
+
"category": "Media"
|
104 |
+
},
|
105 |
+
"Video": {
|
106 |
+
"properties": ["label", "format"],
|
107 |
+
"defaults": {"label": "Video", "format": "mp4"},
|
108 |
+
"icon": "🎥",
|
109 |
+
"category": "Media"
|
110 |
+
},
|
111 |
+
"Audio": {
|
112 |
+
"properties": ["label"],
|
113 |
+
"defaults": {"label": "Audio"},
|
114 |
+
"icon": "🎵",
|
115 |
+
"category": "Media"
|
116 |
+
},
|
117 |
+
"Dataframe": {
|
118 |
+
"properties": ["headers", "datatype", "value"],
|
119 |
+
"defaults": {"headers": ["Column 1", "Column 2"], "datatype": ["str", "str"], "value": []},
|
120 |
+
"icon": "📊",
|
121 |
+
"category": "Data"
|
122 |
+
},
|
123 |
+
"JSON": {
|
124 |
+
"properties": ["value"],
|
125 |
+
"defaults": {"value": "{}"},
|
126 |
+
"icon": "📋",
|
127 |
+
"category": "Data"
|
128 |
+
},
|
129 |
+
"Markdown": {
|
130 |
+
"properties": ["value"],
|
131 |
+
"defaults": {"value": "# Markdown Text"},
|
132 |
+
"icon": "📝",
|
133 |
+
"category": "Display"
|
134 |
+
},
|
135 |
+
"HTML": {
|
136 |
+
"properties": ["value"],
|
137 |
+
"defaults": {"value": "<p>HTML Content</p>"},
|
138 |
+
"icon": "🌐",
|
139 |
+
"category": "Display"
|
140 |
+
},
|
141 |
+
"Label": {
|
142 |
+
"properties": ["value"],
|
143 |
+
"defaults": {"value": "Label Text"},
|
144 |
+
"icon": "🏷️",
|
145 |
+
"category": "Display"
|
146 |
+
},
|
147 |
+
"Progress": {
|
148 |
+
"properties": ["value"],
|
149 |
+
"defaults": {"value": 0.5},
|
150 |
+
"icon": "📈",
|
151 |
+
"category": "Display"
|
152 |
+
}
|
153 |
+
}
|
154 |
+
|
155 |
+
def __init__(
|
156 |
+
self,
|
157 |
+
value: dict | None = None,
|
158 |
+
label: str | None = None,
|
159 |
+
**kwargs,
|
160 |
+
):
|
161 |
+
self.value = value or {"components": [], "layout": "blocks"}
|
162 |
+
super().__init__(label=label, **kwargs)
|
163 |
+
|
164 |
+
def preprocess(self, payload: dict | None) -> dict | None:
|
165 |
+
"""Process the layout configuration from frontend"""
|
166 |
+
if payload is None:
|
167 |
+
return None
|
168 |
+
return payload
|
169 |
+
|
170 |
+
def postprocess(self, value: dict | None) -> dict | None:
|
171 |
+
"""Send layout configuration to frontend"""
|
172 |
+
if value is None:
|
173 |
+
return {"components": [], "layout": "blocks"}
|
174 |
+
return value
|
175 |
+
|
176 |
+
def api_info(self) -> dict[str, list[str]]:
|
177 |
+
"""API info for the component"""
|
178 |
+
return {
|
179 |
+
"info": {
|
180 |
+
"type": "object",
|
181 |
+
"properties": {
|
182 |
+
"components": {
|
183 |
+
"type": "array",
|
184 |
+
"items": {
|
185 |
+
"type": "object",
|
186 |
+
"properties": {
|
187 |
+
"id": {"type": "string"},
|
188 |
+
"type": {"type": "string"},
|
189 |
+
"position": {
|
190 |
+
"type": "object",
|
191 |
+
"properties": {
|
192 |
+
"x": {"type": "number"},
|
193 |
+
"y": {"type": "number"}
|
194 |
+
}
|
195 |
+
},
|
196 |
+
"size": {
|
197 |
+
"type": "object",
|
198 |
+
"properties": {
|
199 |
+
"width": {"type": "number"},
|
200 |
+
"height": {"type": "number"}
|
201 |
+
}
|
202 |
+
},
|
203 |
+
"props": {"type": "object"}
|
204 |
+
}
|
205 |
+
}
|
206 |
+
},
|
207 |
+
"layout": {"type": "string"}
|
208 |
+
}
|
209 |
+
},
|
210 |
+
"serialized_info": False
|
211 |
+
}
|
212 |
+
|
213 |
+
def get_component_definitions(self):
|
214 |
+
"""Get all component definitions for frontend"""
|
215 |
+
return self.COMPONENT_DEFINITIONS
|
216 |
+
|
217 |
+
def example_payload(self) -> dict:
|
218 |
+
return {
|
219 |
+
"components": [
|
220 |
+
{
|
221 |
+
"id": "textbox_1",
|
222 |
+
"type": "Textbox",
|
223 |
+
"position": {"x": 100, "y": 50},
|
224 |
+
"size": {"width": 200, "height": 100},
|
225 |
+
"props": {"label": "Input", "placeholder": "Enter text..."}
|
226 |
+
}
|
227 |
+
],
|
228 |
+
"layout": "blocks"
|
229 |
+
}
|
230 |
+
|
231 |
+
def example_value(self) -> dict:
|
232 |
+
return self.example_payload()
|
src/backend/gradio_gradiodesigner/templates/component/index.js
ADDED
@@ -0,0 +1,1450 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const {
|
2 |
+
SvelteComponent: Ze,
|
3 |
+
add_render_callback: $e,
|
4 |
+
append_hydration: f,
|
5 |
+
attr: h,
|
6 |
+
binding_callbacks: et,
|
7 |
+
children: j,
|
8 |
+
claim_element: k,
|
9 |
+
claim_space: C,
|
10 |
+
claim_text: oe,
|
11 |
+
destroy_block: tt,
|
12 |
+
destroy_each: Ae,
|
13 |
+
detach: b,
|
14 |
+
element: m,
|
15 |
+
empty: Se,
|
16 |
+
ensure_array_like: Le,
|
17 |
+
get_svelte_dataset: R,
|
18 |
+
init: lt,
|
19 |
+
insert_hydration: O,
|
20 |
+
listen: x,
|
21 |
+
noop: Ie,
|
22 |
+
run_all: je,
|
23 |
+
safe_not_equal: st,
|
24 |
+
select_option: xe,
|
25 |
+
select_value: nt,
|
26 |
+
set_data: Te,
|
27 |
+
set_input_value: Pe,
|
28 |
+
set_style: we,
|
29 |
+
space: y,
|
30 |
+
stop_propagation: it,
|
31 |
+
text: re,
|
32 |
+
toggle_class: Ue,
|
33 |
+
update_keyed_each: at
|
34 |
+
} = window.__gradio__svelte__internal, { onMount: ot } = window.__gradio__svelte__internal;
|
35 |
+
function Be(n, e, l) {
|
36 |
+
const i = n.slice();
|
37 |
+
return i[50] = e[l], i;
|
38 |
+
}
|
39 |
+
function Me(n, e, l) {
|
40 |
+
const i = n.slice();
|
41 |
+
return i[50] = e[l], i;
|
42 |
+
}
|
43 |
+
function Ve(n, e, l) {
|
44 |
+
const i = n.slice();
|
45 |
+
return i[55] = e[l], i;
|
46 |
+
}
|
47 |
+
function Re(n) {
|
48 |
+
let e, l = (
|
49 |
+
/*category*/
|
50 |
+
n[55] + ""
|
51 |
+
), i;
|
52 |
+
return {
|
53 |
+
c() {
|
54 |
+
e = m("option"), i = re(l), this.h();
|
55 |
+
},
|
56 |
+
l(t) {
|
57 |
+
e = k(t, "OPTION", {});
|
58 |
+
var r = j(e);
|
59 |
+
i = oe(r, l), r.forEach(b), this.h();
|
60 |
+
},
|
61 |
+
h() {
|
62 |
+
e.__value = /*category*/
|
63 |
+
n[55], Pe(e, e.__value);
|
64 |
+
},
|
65 |
+
m(t, r) {
|
66 |
+
O(t, e, r), f(e, i);
|
67 |
+
},
|
68 |
+
p: Ie,
|
69 |
+
d(t) {
|
70 |
+
t && b(e);
|
71 |
+
}
|
72 |
+
};
|
73 |
+
}
|
74 |
+
function He(n) {
|
75 |
+
let e, l, i;
|
76 |
+
function t(v, s) {
|
77 |
+
return s[0] & /*searchFilter*/
|
78 |
+
4 && (l = null), l == null && (l = !!/*searchFilter*/
|
79 |
+
v[2].trim()), l ? ut : rt;
|
80 |
+
}
|
81 |
+
let r = t(n, [-1, -1]), p = r(n);
|
82 |
+
return {
|
83 |
+
c() {
|
84 |
+
e = m("div"), p.c(), i = y(), this.h();
|
85 |
+
},
|
86 |
+
l(v) {
|
87 |
+
e = k(v, "DIV", { class: !0 });
|
88 |
+
var s = j(e);
|
89 |
+
p.l(s), i = C(s), s.forEach(b), this.h();
|
90 |
+
},
|
91 |
+
h() {
|
92 |
+
h(e, "class", "no-components svelte-zk15k");
|
93 |
+
},
|
94 |
+
m(v, s) {
|
95 |
+
O(v, e, s), p.m(e, null), f(e, i);
|
96 |
+
},
|
97 |
+
p(v, s) {
|
98 |
+
r === (r = t(v, s)) && p ? p.p(v, s) : (p.d(1), p = r(v), p && (p.c(), p.m(e, i)));
|
99 |
+
},
|
100 |
+
d(v) {
|
101 |
+
v && b(e), p.d();
|
102 |
+
}
|
103 |
+
};
|
104 |
+
}
|
105 |
+
function rt(n) {
|
106 |
+
let e;
|
107 |
+
return {
|
108 |
+
c() {
|
109 |
+
e = re("Loading components...");
|
110 |
+
},
|
111 |
+
l(l) {
|
112 |
+
e = oe(l, "Loading components...");
|
113 |
+
},
|
114 |
+
m(l, i) {
|
115 |
+
O(l, e, i);
|
116 |
+
},
|
117 |
+
p: Ie,
|
118 |
+
d(l) {
|
119 |
+
l && b(e);
|
120 |
+
}
|
121 |
+
};
|
122 |
+
}
|
123 |
+
function ut(n) {
|
124 |
+
let e, l, i;
|
125 |
+
return {
|
126 |
+
c() {
|
127 |
+
e = re('No components match "'), l = re(
|
128 |
+
/*searchFilter*/
|
129 |
+
n[2]
|
130 |
+
), i = re('"');
|
131 |
+
},
|
132 |
+
l(t) {
|
133 |
+
e = oe(t, 'No components match "'), l = oe(
|
134 |
+
t,
|
135 |
+
/*searchFilter*/
|
136 |
+
n[2]
|
137 |
+
), i = oe(t, '"');
|
138 |
+
},
|
139 |
+
m(t, r) {
|
140 |
+
O(t, e, r), O(t, l, r), O(t, i, r);
|
141 |
+
},
|
142 |
+
p(t, r) {
|
143 |
+
r[0] & /*searchFilter*/
|
144 |
+
4 && Te(
|
145 |
+
l,
|
146 |
+
/*searchFilter*/
|
147 |
+
t[2]
|
148 |
+
);
|
149 |
+
},
|
150 |
+
d(t) {
|
151 |
+
t && (b(e), b(l), b(i));
|
152 |
+
}
|
153 |
+
};
|
154 |
+
}
|
155 |
+
function Fe(n) {
|
156 |
+
let e, l, i = (
|
157 |
+
/*component*/
|
158 |
+
n[50].icon + ""
|
159 |
+
), t, r, p, v = (
|
160 |
+
/*component*/
|
161 |
+
n[50].label + ""
|
162 |
+
), s, c, ee, q;
|
163 |
+
function S(...D) {
|
164 |
+
return (
|
165 |
+
/*dragstart_handler*/
|
166 |
+
n[29](
|
167 |
+
/*component*/
|
168 |
+
n[50],
|
169 |
+
...D
|
170 |
+
)
|
171 |
+
);
|
172 |
+
}
|
173 |
+
return {
|
174 |
+
c() {
|
175 |
+
e = m("div"), l = m("span"), t = re(i), r = y(), p = m("span"), s = re(v), c = y(), this.h();
|
176 |
+
},
|
177 |
+
l(D) {
|
178 |
+
e = k(D, "DIV", { class: !0, draggable: !0 });
|
179 |
+
var N = j(e);
|
180 |
+
l = k(N, "SPAN", { class: !0 });
|
181 |
+
var M = j(l);
|
182 |
+
t = oe(M, i), M.forEach(b), r = C(N), p = k(N, "SPAN", { class: !0 });
|
183 |
+
var g = j(p);
|
184 |
+
s = oe(g, v), g.forEach(b), c = C(N), N.forEach(b), this.h();
|
185 |
+
},
|
186 |
+
h() {
|
187 |
+
h(l, "class", "icon svelte-zk15k"), h(p, "class", "label svelte-zk15k"), h(e, "class", "palette-item svelte-zk15k"), h(e, "draggable", "true");
|
188 |
+
},
|
189 |
+
m(D, N) {
|
190 |
+
O(D, e, N), f(e, l), f(l, t), f(e, r), f(e, p), f(p, s), f(e, c), ee || (q = x(e, "dragstart", S), ee = !0);
|
191 |
+
},
|
192 |
+
p(D, N) {
|
193 |
+
n = D, N[0] & /*displayComponents*/
|
194 |
+
64 && i !== (i = /*component*/
|
195 |
+
n[50].icon + "") && Te(t, i), N[0] & /*displayComponents*/
|
196 |
+
64 && v !== (v = /*component*/
|
197 |
+
n[50].label + "") && Te(s, v);
|
198 |
+
},
|
199 |
+
d(D) {
|
200 |
+
D && b(e), ee = !1, q();
|
201 |
+
}
|
202 |
+
};
|
203 |
+
}
|
204 |
+
function Ge(n, e) {
|
205 |
+
let l, i, t, r, p = (
|
206 |
+
/*component*/
|
207 |
+
e[50].type + ""
|
208 |
+
), v, s, c, ee = "❌", q, S, D = (
|
209 |
+
/*component*/
|
210 |
+
(e[50].props.label || /*component*/
|
211 |
+
e[50].props.value || "Component") + ""
|
212 |
+
), N, M, g, G;
|
213 |
+
function te() {
|
214 |
+
return (
|
215 |
+
/*click_handler*/
|
216 |
+
e[30](
|
217 |
+
/*component*/
|
218 |
+
e[50]
|
219 |
+
)
|
220 |
+
);
|
221 |
+
}
|
222 |
+
function J() {
|
223 |
+
return (
|
224 |
+
/*click_handler_1*/
|
225 |
+
e[31](
|
226 |
+
/*component*/
|
227 |
+
e[50]
|
228 |
+
)
|
229 |
+
);
|
230 |
+
}
|
231 |
+
function Z(...I) {
|
232 |
+
return (
|
233 |
+
/*mousedown_handler*/
|
234 |
+
e[32](
|
235 |
+
/*component*/
|
236 |
+
e[50],
|
237 |
+
...I
|
238 |
+
)
|
239 |
+
);
|
240 |
+
}
|
241 |
+
return {
|
242 |
+
key: n,
|
243 |
+
first: null,
|
244 |
+
c() {
|
245 |
+
l = m("div"), i = m("div"), t = m("div"), r = m("span"), v = re(p), s = y(), c = m("button"), c.textContent = ee, q = y(), S = m("span"), N = re(D), M = y(), this.h();
|
246 |
+
},
|
247 |
+
l(I) {
|
248 |
+
l = k(I, "DIV", { class: !0, style: !0 });
|
249 |
+
var T = j(l);
|
250 |
+
i = k(T, "DIV", { class: !0 });
|
251 |
+
var U = j(i);
|
252 |
+
t = k(U, "DIV", { class: !0 });
|
253 |
+
var X = j(t);
|
254 |
+
r = k(X, "SPAN", { class: !0 });
|
255 |
+
var W = j(r);
|
256 |
+
v = oe(W, p), W.forEach(b), s = C(X), c = k(X, "BUTTON", {
|
257 |
+
class: !0,
|
258 |
+
type: !0,
|
259 |
+
"data-svelte-h": !0
|
260 |
+
}), R(c) !== "svelte-1dvzppr" && (c.textContent = ee), X.forEach(b), q = C(U), S = k(U, "SPAN", { class: !0 });
|
261 |
+
var pe = j(S);
|
262 |
+
N = oe(pe, D), pe.forEach(b), U.forEach(b), M = C(T), T.forEach(b), this.h();
|
263 |
+
},
|
264 |
+
h() {
|
265 |
+
var I;
|
266 |
+
h(r, "class", "type svelte-zk15k"), h(c, "class", "delete-btn svelte-zk15k"), h(c, "type", "button"), h(t, "class", "component-header svelte-zk15k"), h(S, "class", "label svelte-zk15k"), h(i, "class", "component-preview svelte-zk15k"), h(l, "class", "canvas-component svelte-zk15k"), we(
|
267 |
+
l,
|
268 |
+
"left",
|
269 |
+
/*component*/
|
270 |
+
e[50].position.x + "px"
|
271 |
+
), we(
|
272 |
+
l,
|
273 |
+
"top",
|
274 |
+
/*component*/
|
275 |
+
e[50].position.y + "px"
|
276 |
+
), we(
|
277 |
+
l,
|
278 |
+
"width",
|
279 |
+
/*component*/
|
280 |
+
e[50].size.width + "px"
|
281 |
+
), we(
|
282 |
+
l,
|
283 |
+
"height",
|
284 |
+
/*component*/
|
285 |
+
e[50].size.height + "px"
|
286 |
+
), Ue(
|
287 |
+
l,
|
288 |
+
"selected",
|
289 |
+
/*selectedComponent*/
|
290 |
+
((I = e[5]) == null ? void 0 : I.id) === /*component*/
|
291 |
+
e[50].id
|
292 |
+
), this.first = l;
|
293 |
+
},
|
294 |
+
m(I, T) {
|
295 |
+
O(I, l, T), f(l, i), f(i, t), f(t, r), f(r, v), f(t, s), f(t, c), f(i, q), f(i, S), f(S, N), f(l, M), g || (G = [
|
296 |
+
x(c, "click", it(te)),
|
297 |
+
x(l, "click", J),
|
298 |
+
x(l, "mousedown", Z)
|
299 |
+
], g = !0);
|
300 |
+
},
|
301 |
+
p(I, T) {
|
302 |
+
var U;
|
303 |
+
e = I, T[0] & /*value*/
|
304 |
+
1 && p !== (p = /*component*/
|
305 |
+
e[50].type + "") && Te(v, p), T[0] & /*value*/
|
306 |
+
1 && D !== (D = /*component*/
|
307 |
+
(e[50].props.label || /*component*/
|
308 |
+
e[50].props.value || "Component") + "") && Te(N, D), T[0] & /*value*/
|
309 |
+
1 && we(
|
310 |
+
l,
|
311 |
+
"left",
|
312 |
+
/*component*/
|
313 |
+
e[50].position.x + "px"
|
314 |
+
), T[0] & /*value*/
|
315 |
+
1 && we(
|
316 |
+
l,
|
317 |
+
"top",
|
318 |
+
/*component*/
|
319 |
+
e[50].position.y + "px"
|
320 |
+
), T[0] & /*value*/
|
321 |
+
1 && we(
|
322 |
+
l,
|
323 |
+
"width",
|
324 |
+
/*component*/
|
325 |
+
e[50].size.width + "px"
|
326 |
+
), T[0] & /*value*/
|
327 |
+
1 && we(
|
328 |
+
l,
|
329 |
+
"height",
|
330 |
+
/*component*/
|
331 |
+
e[50].size.height + "px"
|
332 |
+
), T[0] & /*selectedComponent, value*/
|
333 |
+
33 && Ue(
|
334 |
+
l,
|
335 |
+
"selected",
|
336 |
+
/*selectedComponent*/
|
337 |
+
((U = e[5]) == null ? void 0 : U.id) === /*component*/
|
338 |
+
e[50].id
|
339 |
+
);
|
340 |
+
},
|
341 |
+
d(I) {
|
342 |
+
I && b(l), g = !1, je(G);
|
343 |
+
}
|
344 |
+
};
|
345 |
+
}
|
346 |
+
function pt(n) {
|
347 |
+
let e, l = "Select a component to edit properties", i, t, r = '<strong>How to use:</strong> <ul class="svelte-zk15k"><li class="svelte-zk15k">Drag components from the palette to the canvas</li> <li class="svelte-zk15k">Click components to select and edit them</li> <li class="svelte-zk15k">Drag components around the canvas to reposition</li> <li class="svelte-zk15k">Use the properties panel to customize</li></ul>';
|
348 |
+
return {
|
349 |
+
c() {
|
350 |
+
e = m("p"), e.textContent = l, i = y(), t = m("div"), t.innerHTML = r, this.h();
|
351 |
+
},
|
352 |
+
l(p) {
|
353 |
+
e = k(p, "P", { "data-svelte-h": !0 }), R(e) !== "svelte-ilodow" && (e.textContent = l), i = C(p), t = k(p, "DIV", { class: !0, "data-svelte-h": !0 }), R(t) !== "svelte-15cgtbi" && (t.innerHTML = r), this.h();
|
354 |
+
},
|
355 |
+
h() {
|
356 |
+
h(t, "class", "help-text svelte-zk15k");
|
357 |
+
},
|
358 |
+
m(p, v) {
|
359 |
+
O(p, e, v), O(p, i, v), O(p, t, v);
|
360 |
+
},
|
361 |
+
p: Ie,
|
362 |
+
d(p) {
|
363 |
+
p && (b(e), b(i), b(t));
|
364 |
+
}
|
365 |
+
};
|
366 |
+
}
|
367 |
+
function ct(n) {
|
368 |
+
let e, l, i, t = "Type:", r, p = (
|
369 |
+
/*selectedComponent*/
|
370 |
+
n[5].type + ""
|
371 |
+
), v, s, c, ee, q, S, D = (
|
372 |
+
/*selectedComponent*/
|
373 |
+
n[5].id + ""
|
374 |
+
), N, M, g, G, te, J, Z, I, T, U, X, W = "Size & Position", pe, L, H, _e = "Width:", ke, F, fe, K, le, Ce = "Height:", Q, ie, he, se, $, Oe = "X Position:", ge, ne, me, ce, A, ae = "Y Position:", B, P, de, ye, De, o = (
|
375 |
+
/*selectedComponent*/
|
376 |
+
n[5].props.label !== void 0 && Je(n)
|
377 |
+
), d = (
|
378 |
+
/*selectedComponent*/
|
379 |
+
n[5].props.placeholder !== void 0 && Xe(n)
|
380 |
+
), u = (
|
381 |
+
/*selectedComponent*/
|
382 |
+
n[5].props.value !== void 0 && Ye(n)
|
383 |
+
), _ = (
|
384 |
+
/*selectedComponent*/
|
385 |
+
n[5].props.choices !== void 0 && qe(n)
|
386 |
+
), a = (
|
387 |
+
/*selectedComponent*/
|
388 |
+
n[5].props.minimum !== void 0 && We(n)
|
389 |
+
), E = (
|
390 |
+
/*selectedComponent*/
|
391 |
+
n[5].props.maximum !== void 0 && Ke(n)
|
392 |
+
), V = (
|
393 |
+
/*selectedComponent*/
|
394 |
+
n[5].props.step !== void 0 && Qe(n)
|
395 |
+
);
|
396 |
+
return {
|
397 |
+
c() {
|
398 |
+
e = m("div"), l = m("div"), i = m("strong"), i.textContent = t, r = y(), v = re(p), s = y(), c = m("br"), ee = y(), q = m("small"), S = re("ID: "), N = re(D), M = y(), o && o.c(), g = y(), d && d.c(), G = y(), u && u.c(), te = y(), _ && _.c(), J = y(), a && a.c(), Z = y(), E && E.c(), I = y(), V && V.c(), T = y(), U = m("div"), X = m("h5"), X.textContent = W, pe = y(), L = m("div"), H = m("label"), H.textContent = _e, ke = y(), F = m("input"), K = y(), le = m("label"), le.textContent = Ce, Q = y(), ie = m("input"), se = y(), $ = m("label"), $.textContent = Oe, ge = y(), ne = m("input"), ce = y(), A = m("label"), A.textContent = ae, B = y(), P = m("input"), this.h();
|
399 |
+
},
|
400 |
+
l(w) {
|
401 |
+
e = k(w, "DIV", { class: !0 });
|
402 |
+
var z = j(e);
|
403 |
+
l = k(z, "DIV", { class: !0 });
|
404 |
+
var ue = j(l);
|
405 |
+
i = k(ue, "STRONG", { "data-svelte-h": !0 }), R(i) !== "svelte-1y9dw9w" && (i.textContent = t), r = C(ue), v = oe(ue, p), s = C(ue), c = k(ue, "BR", {}), ee = C(ue), q = k(ue, "SMALL", {});
|
406 |
+
var be = j(q);
|
407 |
+
S = oe(be, "ID: "), N = oe(be, D), be.forEach(b), ue.forEach(b), M = C(z), o && o.l(z), g = C(z), d && d.l(z), G = C(z), u && u.l(z), te = C(z), _ && _.l(z), J = C(z), a && a.l(z), Z = C(z), E && E.l(z), I = C(z), V && V.l(z), T = C(z), U = k(z, "DIV", { class: !0 });
|
408 |
+
var ze = j(U);
|
409 |
+
X = k(ze, "H5", { class: !0, "data-svelte-h": !0 }), R(X) !== "svelte-u9anyo" && (X.textContent = W), pe = C(ze), L = k(ze, "DIV", { class: !0 });
|
410 |
+
var Y = j(L);
|
411 |
+
H = k(Y, "LABEL", { class: !0, "data-svelte-h": !0 }), R(H) !== "svelte-19lukby" && (H.textContent = _e), ke = C(Y), F = k(Y, "INPUT", { type: !0, class: !0 }), K = C(Y), le = k(Y, "LABEL", { class: !0, "data-svelte-h": !0 }), R(le) !== "svelte-1ls0h4v" && (le.textContent = Ce), Q = C(Y), ie = k(Y, "INPUT", { type: !0, class: !0 }), se = C(Y), $ = k(Y, "LABEL", { class: !0, "data-svelte-h": !0 }), R($) !== "svelte-1wkby0j" && ($.textContent = Oe), ge = C(Y), ne = k(Y, "INPUT", { type: !0, class: !0 }), ce = C(Y), A = k(Y, "LABEL", { class: !0, "data-svelte-h": !0 }), R(A) !== "svelte-t7u7hk" && (A.textContent = ae), B = C(Y), P = k(Y, "INPUT", { type: !0, class: !0 }), Y.forEach(b), ze.forEach(b), z.forEach(b), this.h();
|
412 |
+
},
|
413 |
+
h() {
|
414 |
+
h(l, "class", "property-header svelte-zk15k"), h(X, "class", "svelte-zk15k"), h(H, "class", "svelte-zk15k"), h(F, "type", "number"), F.value = fe = /*selectedComponent*/
|
415 |
+
n[5].size.width, h(F, "class", "svelte-zk15k"), h(le, "class", "svelte-zk15k"), h(ie, "type", "number"), ie.value = he = /*selectedComponent*/
|
416 |
+
n[5].size.height, h(ie, "class", "svelte-zk15k"), h($, "class", "svelte-zk15k"), h(ne, "type", "number"), ne.value = me = /*selectedComponent*/
|
417 |
+
n[5].position.x, h(ne, "class", "svelte-zk15k"), h(A, "class", "svelte-zk15k"), h(P, "type", "number"), P.value = de = /*selectedComponent*/
|
418 |
+
n[5].position.y, h(P, "class", "svelte-zk15k"), h(L, "class", "size-controls svelte-zk15k"), h(U, "class", "size-section svelte-zk15k"), h(e, "class", "property-group svelte-zk15k");
|
419 |
+
},
|
420 |
+
m(w, z) {
|
421 |
+
O(w, e, z), f(e, l), f(l, i), f(l, r), f(l, v), f(l, s), f(l, c), f(l, ee), f(l, q), f(q, S), f(q, N), f(e, M), o && o.m(e, null), f(e, g), d && d.m(e, null), f(e, G), u && u.m(e, null), f(e, te), _ && _.m(e, null), f(e, J), a && a.m(e, null), f(e, Z), E && E.m(e, null), f(e, I), V && V.m(e, null), f(e, T), f(e, U), f(U, X), f(U, pe), f(U, L), f(L, H), f(L, ke), f(L, F), f(L, K), f(L, le), f(L, Q), f(L, ie), f(L, se), f(L, $), f(L, ge), f(L, ne), f(L, ce), f(L, A), f(L, B), f(L, P), ye || (De = [
|
422 |
+
x(
|
423 |
+
F,
|
424 |
+
"input",
|
425 |
+
/*input_handler_8*/
|
426 |
+
n[43]
|
427 |
+
),
|
428 |
+
x(
|
429 |
+
ie,
|
430 |
+
"input",
|
431 |
+
/*input_handler_9*/
|
432 |
+
n[44]
|
433 |
+
),
|
434 |
+
x(
|
435 |
+
ne,
|
436 |
+
"input",
|
437 |
+
/*input_handler_10*/
|
438 |
+
n[45]
|
439 |
+
),
|
440 |
+
x(
|
441 |
+
P,
|
442 |
+
"input",
|
443 |
+
/*input_handler_11*/
|
444 |
+
n[46]
|
445 |
+
)
|
446 |
+
], ye = !0);
|
447 |
+
},
|
448 |
+
p(w, z) {
|
449 |
+
z[0] & /*selectedComponent*/
|
450 |
+
32 && p !== (p = /*selectedComponent*/
|
451 |
+
w[5].type + "") && Te(v, p), z[0] & /*selectedComponent*/
|
452 |
+
32 && D !== (D = /*selectedComponent*/
|
453 |
+
w[5].id + "") && Te(N, D), /*selectedComponent*/
|
454 |
+
w[5].props.label !== void 0 ? o ? o.p(w, z) : (o = Je(w), o.c(), o.m(e, g)) : o && (o.d(1), o = null), /*selectedComponent*/
|
455 |
+
w[5].props.placeholder !== void 0 ? d ? d.p(w, z) : (d = Xe(w), d.c(), d.m(e, G)) : d && (d.d(1), d = null), /*selectedComponent*/
|
456 |
+
w[5].props.value !== void 0 ? u ? u.p(w, z) : (u = Ye(w), u.c(), u.m(e, te)) : u && (u.d(1), u = null), /*selectedComponent*/
|
457 |
+
w[5].props.choices !== void 0 ? _ ? _.p(w, z) : (_ = qe(w), _.c(), _.m(e, J)) : _ && (_.d(1), _ = null), /*selectedComponent*/
|
458 |
+
w[5].props.minimum !== void 0 ? a ? a.p(w, z) : (a = We(w), a.c(), a.m(e, Z)) : a && (a.d(1), a = null), /*selectedComponent*/
|
459 |
+
w[5].props.maximum !== void 0 ? E ? E.p(w, z) : (E = Ke(w), E.c(), E.m(e, I)) : E && (E.d(1), E = null), /*selectedComponent*/
|
460 |
+
w[5].props.step !== void 0 ? V ? V.p(w, z) : (V = Qe(w), V.c(), V.m(e, T)) : V && (V.d(1), V = null), z[0] & /*selectedComponent*/
|
461 |
+
32 && fe !== (fe = /*selectedComponent*/
|
462 |
+
w[5].size.width) && F.value !== fe && (F.value = fe), z[0] & /*selectedComponent*/
|
463 |
+
32 && he !== (he = /*selectedComponent*/
|
464 |
+
w[5].size.height) && ie.value !== he && (ie.value = he), z[0] & /*selectedComponent*/
|
465 |
+
32 && me !== (me = /*selectedComponent*/
|
466 |
+
w[5].position.x) && ne.value !== me && (ne.value = me), z[0] & /*selectedComponent*/
|
467 |
+
32 && de !== (de = /*selectedComponent*/
|
468 |
+
w[5].position.y) && P.value !== de && (P.value = de);
|
469 |
+
},
|
470 |
+
d(w) {
|
471 |
+
w && b(e), o && o.d(), d && d.d(), u && u.d(), _ && _.d(), a && a.d(), E && E.d(), V && V.d(), ye = !1, je(De);
|
472 |
+
}
|
473 |
+
};
|
474 |
+
}
|
475 |
+
function Je(n) {
|
476 |
+
let e, l = "Label:", i, t, r, p, v;
|
477 |
+
return {
|
478 |
+
c() {
|
479 |
+
e = m("label"), e.textContent = l, i = y(), t = m("input"), this.h();
|
480 |
+
},
|
481 |
+
l(s) {
|
482 |
+
e = k(s, "LABEL", { class: !0, "data-svelte-h": !0 }), R(e) !== "svelte-1mvyv0k" && (e.textContent = l), i = C(s), t = k(s, "INPUT", {
|
483 |
+
type: !0,
|
484 |
+
placeholder: !0,
|
485 |
+
class: !0
|
486 |
+
}), this.h();
|
487 |
+
},
|
488 |
+
h() {
|
489 |
+
h(e, "class", "svelte-zk15k"), h(t, "type", "text"), h(t, "placeholder", "Label"), t.value = r = /*selectedComponent*/
|
490 |
+
n[5].props.label, h(t, "class", "svelte-zk15k");
|
491 |
+
},
|
492 |
+
m(s, c) {
|
493 |
+
O(s, e, c), O(s, i, c), O(s, t, c), p || (v = x(
|
494 |
+
t,
|
495 |
+
"input",
|
496 |
+
/*input_handler*/
|
497 |
+
n[34]
|
498 |
+
), p = !0);
|
499 |
+
},
|
500 |
+
p(s, c) {
|
501 |
+
c[0] & /*selectedComponent*/
|
502 |
+
32 && r !== (r = /*selectedComponent*/
|
503 |
+
s[5].props.label) && t.value !== r && (t.value = r);
|
504 |
+
},
|
505 |
+
d(s) {
|
506 |
+
s && (b(e), b(i), b(t)), p = !1, v();
|
507 |
+
}
|
508 |
+
};
|
509 |
+
}
|
510 |
+
function Xe(n) {
|
511 |
+
let e, l = "Placeholder:", i, t, r, p, v;
|
512 |
+
return {
|
513 |
+
c() {
|
514 |
+
e = m("label"), e.textContent = l, i = y(), t = m("input"), this.h();
|
515 |
+
},
|
516 |
+
l(s) {
|
517 |
+
e = k(s, "LABEL", { class: !0, "data-svelte-h": !0 }), R(e) !== "svelte-s3gzvr" && (e.textContent = l), i = C(s), t = k(s, "INPUT", {
|
518 |
+
type: !0,
|
519 |
+
placeholder: !0,
|
520 |
+
class: !0
|
521 |
+
}), this.h();
|
522 |
+
},
|
523 |
+
h() {
|
524 |
+
h(e, "class", "svelte-zk15k"), h(t, "type", "text"), h(t, "placeholder", "Placeholder"), t.value = r = /*selectedComponent*/
|
525 |
+
n[5].props.placeholder, h(t, "class", "svelte-zk15k");
|
526 |
+
},
|
527 |
+
m(s, c) {
|
528 |
+
O(s, e, c), O(s, i, c), O(s, t, c), p || (v = x(
|
529 |
+
t,
|
530 |
+
"input",
|
531 |
+
/*input_handler_1*/
|
532 |
+
n[35]
|
533 |
+
), p = !0);
|
534 |
+
},
|
535 |
+
p(s, c) {
|
536 |
+
c[0] & /*selectedComponent*/
|
537 |
+
32 && r !== (r = /*selectedComponent*/
|
538 |
+
s[5].props.placeholder) && t.value !== r && (t.value = r);
|
539 |
+
},
|
540 |
+
d(s) {
|
541 |
+
s && (b(e), b(i), b(t)), p = !1, v();
|
542 |
+
}
|
543 |
+
};
|
544 |
+
}
|
545 |
+
function Ye(n) {
|
546 |
+
let e, l = "Value:", i, t;
|
547 |
+
function r(s, c) {
|
548 |
+
return typeof /*selectedComponent*/
|
549 |
+
s[5].props.value == "boolean" ? ht : typeof /*selectedComponent*/
|
550 |
+
s[5].props.value == "number" ? ft : dt;
|
551 |
+
}
|
552 |
+
let p = r(n), v = p(n);
|
553 |
+
return {
|
554 |
+
c() {
|
555 |
+
e = m("label"), e.textContent = l, i = y(), v.c(), t = Se(), this.h();
|
556 |
+
},
|
557 |
+
l(s) {
|
558 |
+
e = k(s, "LABEL", { class: !0, "data-svelte-h": !0 }), R(e) !== "svelte-1m0lw4v" && (e.textContent = l), i = C(s), v.l(s), t = Se(), this.h();
|
559 |
+
},
|
560 |
+
h() {
|
561 |
+
h(e, "class", "svelte-zk15k");
|
562 |
+
},
|
563 |
+
m(s, c) {
|
564 |
+
O(s, e, c), O(s, i, c), v.m(s, c), O(s, t, c);
|
565 |
+
},
|
566 |
+
p(s, c) {
|
567 |
+
p === (p = r(s)) && v ? v.p(s, c) : (v.d(1), v = p(s), v && (v.c(), v.m(t.parentNode, t)));
|
568 |
+
},
|
569 |
+
d(s) {
|
570 |
+
s && (b(e), b(i), b(t)), v.d(s);
|
571 |
+
}
|
572 |
+
};
|
573 |
+
}
|
574 |
+
function dt(n) {
|
575 |
+
let e, l, i, t;
|
576 |
+
return {
|
577 |
+
c() {
|
578 |
+
e = m("input"), this.h();
|
579 |
+
},
|
580 |
+
l(r) {
|
581 |
+
e = k(r, "INPUT", {
|
582 |
+
type: !0,
|
583 |
+
placeholder: !0,
|
584 |
+
class: !0
|
585 |
+
}), this.h();
|
586 |
+
},
|
587 |
+
h() {
|
588 |
+
h(e, "type", "text"), h(e, "placeholder", "Value"), e.value = l = /*selectedComponent*/
|
589 |
+
n[5].props.value, h(e, "class", "svelte-zk15k");
|
590 |
+
},
|
591 |
+
m(r, p) {
|
592 |
+
O(r, e, p), i || (t = x(
|
593 |
+
e,
|
594 |
+
"input",
|
595 |
+
/*input_handler_3*/
|
596 |
+
n[38]
|
597 |
+
), i = !0);
|
598 |
+
},
|
599 |
+
p(r, p) {
|
600 |
+
p[0] & /*selectedComponent*/
|
601 |
+
32 && l !== (l = /*selectedComponent*/
|
602 |
+
r[5].props.value) && e.value !== l && (e.value = l);
|
603 |
+
},
|
604 |
+
d(r) {
|
605 |
+
r && b(e), i = !1, t();
|
606 |
+
}
|
607 |
+
};
|
608 |
+
}
|
609 |
+
function ft(n) {
|
610 |
+
let e, l, i, t;
|
611 |
+
return {
|
612 |
+
c() {
|
613 |
+
e = m("input"), this.h();
|
614 |
+
},
|
615 |
+
l(r) {
|
616 |
+
e = k(r, "INPUT", { type: !0, class: !0 }), this.h();
|
617 |
+
},
|
618 |
+
h() {
|
619 |
+
h(e, "type", "number"), e.value = l = /*selectedComponent*/
|
620 |
+
n[5].props.value, h(e, "class", "svelte-zk15k");
|
621 |
+
},
|
622 |
+
m(r, p) {
|
623 |
+
O(r, e, p), i || (t = x(
|
624 |
+
e,
|
625 |
+
"input",
|
626 |
+
/*input_handler_2*/
|
627 |
+
n[37]
|
628 |
+
), i = !0);
|
629 |
+
},
|
630 |
+
p(r, p) {
|
631 |
+
p[0] & /*selectedComponent*/
|
632 |
+
32 && l !== (l = /*selectedComponent*/
|
633 |
+
r[5].props.value) && e.value !== l && (e.value = l);
|
634 |
+
},
|
635 |
+
d(r) {
|
636 |
+
r && b(e), i = !1, t();
|
637 |
+
}
|
638 |
+
};
|
639 |
+
}
|
640 |
+
function ht(n) {
|
641 |
+
let e, l, i, t;
|
642 |
+
return {
|
643 |
+
c() {
|
644 |
+
e = m("input"), this.h();
|
645 |
+
},
|
646 |
+
l(r) {
|
647 |
+
e = k(r, "INPUT", { type: !0, class: !0 }), this.h();
|
648 |
+
},
|
649 |
+
h() {
|
650 |
+
h(e, "type", "checkbox"), e.checked = l = /*selectedComponent*/
|
651 |
+
n[5].props.value, h(e, "class", "svelte-zk15k");
|
652 |
+
},
|
653 |
+
m(r, p) {
|
654 |
+
O(r, e, p), i || (t = x(
|
655 |
+
e,
|
656 |
+
"change",
|
657 |
+
/*change_handler*/
|
658 |
+
n[36]
|
659 |
+
), i = !0);
|
660 |
+
},
|
661 |
+
p(r, p) {
|
662 |
+
p[0] & /*selectedComponent*/
|
663 |
+
32 && l !== (l = /*selectedComponent*/
|
664 |
+
r[5].props.value) && (e.checked = l);
|
665 |
+
},
|
666 |
+
d(r) {
|
667 |
+
r && b(e), i = !1, t();
|
668 |
+
}
|
669 |
+
};
|
670 |
+
}
|
671 |
+
function qe(n) {
|
672 |
+
let e, l = "Choices (comma-separated):", i, t, r, p, v;
|
673 |
+
return {
|
674 |
+
c() {
|
675 |
+
e = m("label"), e.textContent = l, i = y(), t = m("input"), this.h();
|
676 |
+
},
|
677 |
+
l(s) {
|
678 |
+
e = k(s, "LABEL", { class: !0, "data-svelte-h": !0 }), R(e) !== "svelte-s5zbc2" && (e.textContent = l), i = C(s), t = k(s, "INPUT", {
|
679 |
+
type: !0,
|
680 |
+
placeholder: !0,
|
681 |
+
class: !0
|
682 |
+
}), this.h();
|
683 |
+
},
|
684 |
+
h() {
|
685 |
+
h(e, "class", "svelte-zk15k"), h(t, "type", "text"), h(t, "placeholder", "Option 1, Option 2, Option 3"), t.value = r = Array.isArray(
|
686 |
+
/*selectedComponent*/
|
687 |
+
n[5].props.choices
|
688 |
+
) ? (
|
689 |
+
/*selectedComponent*/
|
690 |
+
n[5].props.choices.join(", ")
|
691 |
+
) : (
|
692 |
+
/*selectedComponent*/
|
693 |
+
n[5].props.choices
|
694 |
+
), h(t, "class", "svelte-zk15k");
|
695 |
+
},
|
696 |
+
m(s, c) {
|
697 |
+
O(s, e, c), O(s, i, c), O(s, t, c), p || (v = x(
|
698 |
+
t,
|
699 |
+
"input",
|
700 |
+
/*input_handler_4*/
|
701 |
+
n[39]
|
702 |
+
), p = !0);
|
703 |
+
},
|
704 |
+
p(s, c) {
|
705 |
+
c[0] & /*selectedComponent*/
|
706 |
+
32 && r !== (r = Array.isArray(
|
707 |
+
/*selectedComponent*/
|
708 |
+
s[5].props.choices
|
709 |
+
) ? (
|
710 |
+
/*selectedComponent*/
|
711 |
+
s[5].props.choices.join(", ")
|
712 |
+
) : (
|
713 |
+
/*selectedComponent*/
|
714 |
+
s[5].props.choices
|
715 |
+
)) && t.value !== r && (t.value = r);
|
716 |
+
},
|
717 |
+
d(s) {
|
718 |
+
s && (b(e), b(i), b(t)), p = !1, v();
|
719 |
+
}
|
720 |
+
};
|
721 |
+
}
|
722 |
+
function We(n) {
|
723 |
+
let e, l = "Minimum:", i, t, r, p, v;
|
724 |
+
return {
|
725 |
+
c() {
|
726 |
+
e = m("label"), e.textContent = l, i = y(), t = m("input"), this.h();
|
727 |
+
},
|
728 |
+
l(s) {
|
729 |
+
e = k(s, "LABEL", { class: !0, "data-svelte-h": !0 }), R(e) !== "svelte-v7nxz2" && (e.textContent = l), i = C(s), t = k(s, "INPUT", { type: !0, class: !0 }), this.h();
|
730 |
+
},
|
731 |
+
h() {
|
732 |
+
h(e, "class", "svelte-zk15k"), h(t, "type", "number"), t.value = r = /*selectedComponent*/
|
733 |
+
n[5].props.minimum, h(t, "class", "svelte-zk15k");
|
734 |
+
},
|
735 |
+
m(s, c) {
|
736 |
+
O(s, e, c), O(s, i, c), O(s, t, c), p || (v = x(
|
737 |
+
t,
|
738 |
+
"input",
|
739 |
+
/*input_handler_5*/
|
740 |
+
n[40]
|
741 |
+
), p = !0);
|
742 |
+
},
|
743 |
+
p(s, c) {
|
744 |
+
c[0] & /*selectedComponent*/
|
745 |
+
32 && r !== (r = /*selectedComponent*/
|
746 |
+
s[5].props.minimum) && t.value !== r && (t.value = r);
|
747 |
+
},
|
748 |
+
d(s) {
|
749 |
+
s && (b(e), b(i), b(t)), p = !1, v();
|
750 |
+
}
|
751 |
+
};
|
752 |
+
}
|
753 |
+
function Ke(n) {
|
754 |
+
let e, l = "Maximum:", i, t, r, p, v;
|
755 |
+
return {
|
756 |
+
c() {
|
757 |
+
e = m("label"), e.textContent = l, i = y(), t = m("input"), this.h();
|
758 |
+
},
|
759 |
+
l(s) {
|
760 |
+
e = k(s, "LABEL", { class: !0, "data-svelte-h": !0 }), R(e) !== "svelte-elhw0w" && (e.textContent = l), i = C(s), t = k(s, "INPUT", { type: !0, class: !0 }), this.h();
|
761 |
+
},
|
762 |
+
h() {
|
763 |
+
h(e, "class", "svelte-zk15k"), h(t, "type", "number"), t.value = r = /*selectedComponent*/
|
764 |
+
n[5].props.maximum, h(t, "class", "svelte-zk15k");
|
765 |
+
},
|
766 |
+
m(s, c) {
|
767 |
+
O(s, e, c), O(s, i, c), O(s, t, c), p || (v = x(
|
768 |
+
t,
|
769 |
+
"input",
|
770 |
+
/*input_handler_6*/
|
771 |
+
n[41]
|
772 |
+
), p = !0);
|
773 |
+
},
|
774 |
+
p(s, c) {
|
775 |
+
c[0] & /*selectedComponent*/
|
776 |
+
32 && r !== (r = /*selectedComponent*/
|
777 |
+
s[5].props.maximum) && t.value !== r && (t.value = r);
|
778 |
+
},
|
779 |
+
d(s) {
|
780 |
+
s && (b(e), b(i), b(t)), p = !1, v();
|
781 |
+
}
|
782 |
+
};
|
783 |
+
}
|
784 |
+
function Qe(n) {
|
785 |
+
let e, l = "Step:", i, t, r, p, v;
|
786 |
+
return {
|
787 |
+
c() {
|
788 |
+
e = m("label"), e.textContent = l, i = y(), t = m("input"), this.h();
|
789 |
+
},
|
790 |
+
l(s) {
|
791 |
+
e = k(s, "LABEL", { class: !0, "data-svelte-h": !0 }), R(e) !== "svelte-rqjdj4" && (e.textContent = l), i = C(s), t = k(s, "INPUT", { type: !0, class: !0 }), this.h();
|
792 |
+
},
|
793 |
+
h() {
|
794 |
+
h(e, "class", "svelte-zk15k"), h(t, "type", "number"), t.value = r = /*selectedComponent*/
|
795 |
+
n[5].props.step, h(t, "class", "svelte-zk15k");
|
796 |
+
},
|
797 |
+
m(s, c) {
|
798 |
+
O(s, e, c), O(s, i, c), O(s, t, c), p || (v = x(
|
799 |
+
t,
|
800 |
+
"input",
|
801 |
+
/*input_handler_7*/
|
802 |
+
n[42]
|
803 |
+
), p = !0);
|
804 |
+
},
|
805 |
+
p(s, c) {
|
806 |
+
c[0] & /*selectedComponent*/
|
807 |
+
32 && r !== (r = /*selectedComponent*/
|
808 |
+
s[5].props.step) && t.value !== r && (t.value = r);
|
809 |
+
},
|
810 |
+
d(s) {
|
811 |
+
s && (b(e), b(i), b(t)), p = !1, v();
|
812 |
+
}
|
813 |
+
};
|
814 |
+
}
|
815 |
+
function vt(n) {
|
816 |
+
let e, l, i, t, r = "🎨 Gradio Designer", p, v, s = (
|
817 |
+
/*value*/
|
818 |
+
n[0].components.length + ""
|
819 |
+
), c, ee, q, S, D, N = "📄 Export JSON", M, g, G = "🖼️ Export PNG", te, J, Z, I, T, U = "Components", X, W, pe, L, H, _e = "All Categories", ke, F, fe, K, le, Ce, Q = [], ie = /* @__PURE__ */ new Map(), he, se, $, Oe = "Properties", ge, ne, me, ce = Le(Object.keys(
|
820 |
+
/*componentsByCategory*/
|
821 |
+
n[7]
|
822 |
+
)), A = [];
|
823 |
+
for (let u = 0; u < ce.length; u += 1)
|
824 |
+
A[u] = Re(Ve(n, ce, u));
|
825 |
+
let ae = Le(
|
826 |
+
/*displayComponents*/
|
827 |
+
n[6]
|
828 |
+
), B = [];
|
829 |
+
for (let u = 0; u < ae.length; u += 1)
|
830 |
+
B[u] = Fe(Me(n, ae, u));
|
831 |
+
let P = null;
|
832 |
+
ae.length || (P = He(n));
|
833 |
+
let de = Le(
|
834 |
+
/*value*/
|
835 |
+
n[0].components
|
836 |
+
);
|
837 |
+
const ye = (u) => (
|
838 |
+
/*component*/
|
839 |
+
u[50].id
|
840 |
+
);
|
841 |
+
for (let u = 0; u < de.length; u += 1) {
|
842 |
+
let _ = Be(n, de, u), a = ye(_);
|
843 |
+
ie.set(a, Q[u] = Ge(a, _));
|
844 |
+
}
|
845 |
+
function De(u, _) {
|
846 |
+
return (
|
847 |
+
/*selectedComponent*/
|
848 |
+
u[5] ? ct : pt
|
849 |
+
);
|
850 |
+
}
|
851 |
+
let o = De(n), d = o(n);
|
852 |
+
return {
|
853 |
+
c() {
|
854 |
+
e = m("div"), l = m("div"), i = m("div"), t = m("h3"), t.textContent = r, p = y(), v = m("span"), c = re(s), ee = re(" components"), q = y(), S = m("div"), D = m("button"), D.textContent = N, M = y(), g = m("button"), g.textContent = G, te = y(), J = m("div"), Z = m("div"), I = m("div"), T = m("h4"), T.textContent = U, X = y(), W = m("input"), pe = y(), L = m("select"), H = m("option"), H.textContent = _e;
|
855 |
+
for (let u = 0; u < A.length; u += 1)
|
856 |
+
A[u].c();
|
857 |
+
ke = y(), F = m("div");
|
858 |
+
for (let u = 0; u < B.length; u += 1)
|
859 |
+
B[u].c();
|
860 |
+
P && P.c(), fe = y(), K = m("div"), le = m("div"), Ce = y();
|
861 |
+
for (let u = 0; u < Q.length; u += 1)
|
862 |
+
Q[u].c();
|
863 |
+
he = y(), se = m("div"), $ = m("h4"), $.textContent = Oe, ge = y(), d.c(), this.h();
|
864 |
+
},
|
865 |
+
l(u) {
|
866 |
+
e = k(u, "DIV", { class: !0, id: !0 });
|
867 |
+
var _ = j(e);
|
868 |
+
l = k(_, "DIV", { class: !0 });
|
869 |
+
var a = j(l);
|
870 |
+
i = k(a, "DIV", { class: !0 });
|
871 |
+
var E = j(i);
|
872 |
+
t = k(E, "H3", { class: !0, "data-svelte-h": !0 }), R(t) !== "svelte-1dsn5ql" && (t.textContent = r), p = C(E), v = k(E, "SPAN", { class: !0 });
|
873 |
+
var V = j(v);
|
874 |
+
c = oe(V, s), ee = oe(V, " components"), V.forEach(b), E.forEach(b), q = C(a), S = k(a, "DIV", { class: !0 });
|
875 |
+
var w = j(S);
|
876 |
+
D = k(w, "BUTTON", {
|
877 |
+
class: !0,
|
878 |
+
type: !0,
|
879 |
+
"data-svelte-h": !0
|
880 |
+
}), R(D) !== "svelte-1n26als" && (D.textContent = N), M = C(w), g = k(w, "BUTTON", {
|
881 |
+
class: !0,
|
882 |
+
type: !0,
|
883 |
+
"data-svelte-h": !0
|
884 |
+
}), R(g) !== "svelte-1yzlvvh" && (g.textContent = G), w.forEach(b), a.forEach(b), te = C(_), J = k(_, "DIV", { class: !0 });
|
885 |
+
var z = j(J);
|
886 |
+
Z = k(z, "DIV", { class: !0 });
|
887 |
+
var ue = j(Z);
|
888 |
+
I = k(ue, "DIV", { class: !0 });
|
889 |
+
var be = j(I);
|
890 |
+
T = k(be, "H4", { class: !0, "data-svelte-h": !0 }), R(T) !== "svelte-6fxyga" && (T.textContent = U), X = C(be), W = k(be, "INPUT", {
|
891 |
+
type: !0,
|
892 |
+
placeholder: !0,
|
893 |
+
class: !0
|
894 |
+
}), pe = C(be), L = k(be, "SELECT", { class: !0 });
|
895 |
+
var ze = j(L);
|
896 |
+
H = k(ze, "OPTION", { "data-svelte-h": !0 }), R(H) !== "svelte-1dzjcyu" && (H.textContent = _e);
|
897 |
+
for (let ve = 0; ve < A.length; ve += 1)
|
898 |
+
A[ve].l(ze);
|
899 |
+
ze.forEach(b), be.forEach(b), ke = C(ue), F = k(ue, "DIV", { class: !0 });
|
900 |
+
var Y = j(F);
|
901 |
+
for (let ve = 0; ve < B.length; ve += 1)
|
902 |
+
B[ve].l(Y);
|
903 |
+
P && P.l(Y), Y.forEach(b), ue.forEach(b), fe = C(z), K = k(z, "DIV", { class: !0 });
|
904 |
+
var Ee = j(K);
|
905 |
+
le = k(Ee, "DIV", { class: !0 }), j(le).forEach(b), Ce = C(Ee);
|
906 |
+
for (let ve = 0; ve < Q.length; ve += 1)
|
907 |
+
Q[ve].l(Ee);
|
908 |
+
Ee.forEach(b), he = C(z), se = k(z, "DIV", { class: !0 });
|
909 |
+
var Ne = j(se);
|
910 |
+
$ = k(Ne, "H4", { class: !0, "data-svelte-h": !0 }), R($) !== "svelte-100vz0b" && ($.textContent = Oe), ge = C(Ne), d.l(Ne), Ne.forEach(b), z.forEach(b), _.forEach(b), this.h();
|
911 |
+
},
|
912 |
+
h() {
|
913 |
+
h(t, "class", "svelte-zk15k"), h(v, "class", "component-count svelte-zk15k"), h(i, "class", "toolbar-left svelte-zk15k"), h(D, "class", "export-btn svelte-zk15k"), h(D, "type", "button"), h(g, "class", "export-btn svelte-zk15k"), h(g, "type", "button"), h(S, "class", "toolbar-right svelte-zk15k"), h(l, "class", "toolbar svelte-zk15k"), h(T, "class", "svelte-zk15k"), h(W, "type", "text"), h(W, "placeholder", "Search components..."), h(W, "class", "search-input svelte-zk15k"), H.__value = "All", Pe(H, H.__value), h(L, "class", "category-select svelte-zk15k"), /*selectedCategory*/
|
914 |
+
n[3] === void 0 && $e(() => (
|
915 |
+
/*select_change_handler*/
|
916 |
+
n[28].call(L)
|
917 |
+
)), h(I, "class", "palette-header svelte-zk15k"), h(F, "class", "palette-content svelte-zk15k"), h(Z, "class", "palette svelte-zk15k"), h(le, "class", "canvas-grid svelte-zk15k"), h(K, "class", "canvas svelte-zk15k"), h($, "class", "svelte-zk15k"), h(se, "class", "properties svelte-zk15k"), h(J, "class", "designer-content svelte-zk15k"), h(e, "class", "designer-container svelte-zk15k"), h(
|
918 |
+
e,
|
919 |
+
"id",
|
920 |
+
/*elem_id*/
|
921 |
+
n[1]
|
922 |
+
);
|
923 |
+
},
|
924 |
+
m(u, _) {
|
925 |
+
O(u, e, _), f(e, l), f(l, i), f(i, t), f(i, p), f(i, v), f(v, c), f(v, ee), f(l, q), f(l, S), f(S, D), f(S, M), f(S, g), f(e, te), f(e, J), f(J, Z), f(Z, I), f(I, T), f(I, X), f(I, W), Pe(
|
926 |
+
W,
|
927 |
+
/*searchFilter*/
|
928 |
+
n[2]
|
929 |
+
), f(I, pe), f(I, L), f(L, H);
|
930 |
+
for (let a = 0; a < A.length; a += 1)
|
931 |
+
A[a] && A[a].m(L, null);
|
932 |
+
xe(
|
933 |
+
L,
|
934 |
+
/*selectedCategory*/
|
935 |
+
n[3],
|
936 |
+
!0
|
937 |
+
), f(Z, ke), f(Z, F);
|
938 |
+
for (let a = 0; a < B.length; a += 1)
|
939 |
+
B[a] && B[a].m(F, null);
|
940 |
+
P && P.m(F, null), f(J, fe), f(J, K), f(K, le), f(K, Ce);
|
941 |
+
for (let a = 0; a < Q.length; a += 1)
|
942 |
+
Q[a] && Q[a].m(K, null);
|
943 |
+
n[33](K), f(J, he), f(J, se), f(se, $), f(se, ge), d.m(se, null), ne || (me = [
|
944 |
+
x(
|
945 |
+
window,
|
946 |
+
"mousemove",
|
947 |
+
/*onCanvasMouseMove*/
|
948 |
+
n[18]
|
949 |
+
),
|
950 |
+
x(
|
951 |
+
window,
|
952 |
+
"mouseup",
|
953 |
+
/*onCanvasMouseUp*/
|
954 |
+
n[19]
|
955 |
+
),
|
956 |
+
x(
|
957 |
+
D,
|
958 |
+
"click",
|
959 |
+
/*exportAsJSON*/
|
960 |
+
n[15]
|
961 |
+
),
|
962 |
+
x(
|
963 |
+
g,
|
964 |
+
"click",
|
965 |
+
/*exportAsPNG*/
|
966 |
+
n[16]
|
967 |
+
),
|
968 |
+
x(
|
969 |
+
W,
|
970 |
+
"input",
|
971 |
+
/*input_input_handler*/
|
972 |
+
n[27]
|
973 |
+
),
|
974 |
+
x(
|
975 |
+
L,
|
976 |
+
"change",
|
977 |
+
/*select_change_handler*/
|
978 |
+
n[28]
|
979 |
+
),
|
980 |
+
x(K, "dragover", _t),
|
981 |
+
x(
|
982 |
+
K,
|
983 |
+
"drop",
|
984 |
+
/*onDrop*/
|
985 |
+
n[9]
|
986 |
+
)
|
987 |
+
], ne = !0);
|
988 |
+
},
|
989 |
+
p(u, _) {
|
990 |
+
if (_[0] & /*value*/
|
991 |
+
1 && s !== (s = /*value*/
|
992 |
+
u[0].components.length + "") && Te(c, s), _[0] & /*searchFilter*/
|
993 |
+
4 && W.value !== /*searchFilter*/
|
994 |
+
u[2] && Pe(
|
995 |
+
W,
|
996 |
+
/*searchFilter*/
|
997 |
+
u[2]
|
998 |
+
), _[0] & /*componentsByCategory*/
|
999 |
+
128) {
|
1000 |
+
ce = Le(Object.keys(
|
1001 |
+
/*componentsByCategory*/
|
1002 |
+
u[7]
|
1003 |
+
));
|
1004 |
+
let a;
|
1005 |
+
for (a = 0; a < ce.length; a += 1) {
|
1006 |
+
const E = Ve(u, ce, a);
|
1007 |
+
A[a] ? A[a].p(E, _) : (A[a] = Re(E), A[a].c(), A[a].m(L, null));
|
1008 |
+
}
|
1009 |
+
for (; a < A.length; a += 1)
|
1010 |
+
A[a].d(1);
|
1011 |
+
A.length = ce.length;
|
1012 |
+
}
|
1013 |
+
if (_[0] & /*selectedCategory, componentsByCategory*/
|
1014 |
+
136 && xe(
|
1015 |
+
L,
|
1016 |
+
/*selectedCategory*/
|
1017 |
+
u[3]
|
1018 |
+
), _[0] & /*onDragStart, displayComponents, searchFilter*/
|
1019 |
+
324) {
|
1020 |
+
ae = Le(
|
1021 |
+
/*displayComponents*/
|
1022 |
+
u[6]
|
1023 |
+
);
|
1024 |
+
let a;
|
1025 |
+
for (a = 0; a < ae.length; a += 1) {
|
1026 |
+
const E = Me(u, ae, a);
|
1027 |
+
B[a] ? B[a].p(E, _) : (B[a] = Fe(E), B[a].c(), B[a].m(F, null));
|
1028 |
+
}
|
1029 |
+
for (; a < B.length; a += 1)
|
1030 |
+
B[a].d(1);
|
1031 |
+
B.length = ae.length, !ae.length && P ? P.p(u, _) : ae.length ? P && (P.d(1), P = null) : (P = He(u), P.c(), P.m(F, null));
|
1032 |
+
}
|
1033 |
+
_[0] & /*value, selectedComponent, selectComponent, onComponentMouseDown, deleteComponent*/
|
1034 |
+
148513 && (de = Le(
|
1035 |
+
/*value*/
|
1036 |
+
u[0].components
|
1037 |
+
), Q = at(Q, _, ye, 1, u, de, ie, K, tt, Ge, null, Be)), o === (o = De(u)) && d ? d.p(u, _) : (d.d(1), d = o(u), d && (d.c(), d.m(se, null))), _[0] & /*elem_id*/
|
1038 |
+
2 && h(
|
1039 |
+
e,
|
1040 |
+
"id",
|
1041 |
+
/*elem_id*/
|
1042 |
+
u[1]
|
1043 |
+
);
|
1044 |
+
},
|
1045 |
+
i: Ie,
|
1046 |
+
o: Ie,
|
1047 |
+
d(u) {
|
1048 |
+
u && b(e), Ae(A, u), Ae(B, u), P && P.d();
|
1049 |
+
for (let _ = 0; _ < Q.length; _ += 1)
|
1050 |
+
Q[_].d();
|
1051 |
+
n[33](null), d.d(), ne = !1, je(me);
|
1052 |
+
}
|
1053 |
+
};
|
1054 |
+
}
|
1055 |
+
function _t(n) {
|
1056 |
+
n.preventDefault(), n.dataTransfer && (n.dataTransfer.dropEffect = "copy");
|
1057 |
+
}
|
1058 |
+
function kt(n) {
|
1059 |
+
return {
|
1060 |
+
Textbox: {
|
1061 |
+
label: "Text Input",
|
1062 |
+
placeholder: "Enter text...",
|
1063 |
+
value: ""
|
1064 |
+
},
|
1065 |
+
TextArea: {
|
1066 |
+
label: "Text Area",
|
1067 |
+
placeholder: "Enter multiple lines...",
|
1068 |
+
lines: 3,
|
1069 |
+
value: ""
|
1070 |
+
},
|
1071 |
+
Button: {
|
1072 |
+
value: "Click me",
|
1073 |
+
variant: "secondary",
|
1074 |
+
size: "sm"
|
1075 |
+
},
|
1076 |
+
Slider: {
|
1077 |
+
label: "Slider",
|
1078 |
+
minimum: 0,
|
1079 |
+
maximum: 100,
|
1080 |
+
step: 1,
|
1081 |
+
value: 50
|
1082 |
+
},
|
1083 |
+
Number: { label: "Number", value: 0, precision: 0 },
|
1084 |
+
Checkbox: { label: "Checkbox", value: !1 },
|
1085 |
+
CheckboxGroup: {
|
1086 |
+
label: "Checkbox Group",
|
1087 |
+
choices: ["Option 1", "Option 2"],
|
1088 |
+
value: []
|
1089 |
+
},
|
1090 |
+
Radio: {
|
1091 |
+
label: "Radio",
|
1092 |
+
choices: ["Option 1", "Option 2"],
|
1093 |
+
value: "Option 1"
|
1094 |
+
},
|
1095 |
+
Dropdown: {
|
1096 |
+
label: "Dropdown",
|
1097 |
+
choices: ["Option 1", "Option 2"],
|
1098 |
+
value: "Option 1",
|
1099 |
+
multiselect: !1
|
1100 |
+
},
|
1101 |
+
Toggle: { label: "Toggle", value: !1 },
|
1102 |
+
ColorPicker: { label: "Color Picker", value: "#ff0000" },
|
1103 |
+
Date: { label: "Date", value: "2025-01-01" },
|
1104 |
+
Time: { label: "Time", value: "12:00" },
|
1105 |
+
File: {
|
1106 |
+
label: "Upload File",
|
1107 |
+
file_types: [".txt", ".pdf"]
|
1108 |
+
},
|
1109 |
+
Image: {
|
1110 |
+
label: "Image",
|
1111 |
+
type: "pil",
|
1112 |
+
interactive: !0
|
1113 |
+
},
|
1114 |
+
Video: { label: "Video", format: "mp4" },
|
1115 |
+
Audio: { label: "Audio" },
|
1116 |
+
Dataframe: {
|
1117 |
+
headers: ["Column 1", "Column 2"],
|
1118 |
+
datatype: ["str", "str"],
|
1119 |
+
value: []
|
1120 |
+
},
|
1121 |
+
JSON: { value: "{}" },
|
1122 |
+
Markdown: { value: "# Markdown Text" },
|
1123 |
+
HTML: { value: "<p>HTML Content</p>" },
|
1124 |
+
Label: { value: "Label Text" },
|
1125 |
+
Progress: { value: 0.5 }
|
1126 |
+
}[n] || {};
|
1127 |
+
}
|
1128 |
+
function mt(n, e, l) {
|
1129 |
+
let i, t, r, { gradio: p } = e, { elem_id: v = "" } = e;
|
1130 |
+
const s = [];
|
1131 |
+
let { value: c = { components: [], layout: "blocks" } } = e;
|
1132 |
+
const ee = void 0, q = "interactive", S = {
|
1133 |
+
Input: [
|
1134 |
+
{
|
1135 |
+
type: "Textbox",
|
1136 |
+
label: "Text Input",
|
1137 |
+
icon: "📝"
|
1138 |
+
},
|
1139 |
+
{
|
1140 |
+
type: "TextArea",
|
1141 |
+
label: "Text Area",
|
1142 |
+
icon: "📄"
|
1143 |
+
},
|
1144 |
+
{
|
1145 |
+
type: "Number",
|
1146 |
+
label: "Number",
|
1147 |
+
icon: "🔢"
|
1148 |
+
},
|
1149 |
+
{
|
1150 |
+
type: "Slider",
|
1151 |
+
label: "Slider",
|
1152 |
+
icon: "🎚️"
|
1153 |
+
},
|
1154 |
+
{
|
1155 |
+
type: "Checkbox",
|
1156 |
+
label: "Checkbox",
|
1157 |
+
icon: "☑️"
|
1158 |
+
},
|
1159 |
+
{
|
1160 |
+
type: "CheckboxGroup",
|
1161 |
+
label: "Checkbox Group",
|
1162 |
+
icon: "☑️"
|
1163 |
+
},
|
1164 |
+
{
|
1165 |
+
type: "Radio",
|
1166 |
+
label: "Radio",
|
1167 |
+
icon: "🔘"
|
1168 |
+
},
|
1169 |
+
{
|
1170 |
+
type: "Dropdown",
|
1171 |
+
label: "Dropdown",
|
1172 |
+
icon: "📋"
|
1173 |
+
},
|
1174 |
+
{
|
1175 |
+
type: "Toggle",
|
1176 |
+
label: "Toggle",
|
1177 |
+
icon: "🔄"
|
1178 |
+
},
|
1179 |
+
{
|
1180 |
+
type: "ColorPicker",
|
1181 |
+
label: "Color Picker",
|
1182 |
+
icon: "🎨"
|
1183 |
+
},
|
1184 |
+
{ type: "Date", label: "Date", icon: "📅" },
|
1185 |
+
{ type: "Time", label: "Time", icon: "⏰" },
|
1186 |
+
{
|
1187 |
+
type: "File",
|
1188 |
+
label: "File Upload",
|
1189 |
+
icon: "📁"
|
1190 |
+
}
|
1191 |
+
],
|
1192 |
+
Action: [
|
1193 |
+
{
|
1194 |
+
type: "Button",
|
1195 |
+
label: "Button",
|
1196 |
+
icon: "🔘"
|
1197 |
+
}
|
1198 |
+
],
|
1199 |
+
Media: [
|
1200 |
+
{
|
1201 |
+
type: "Image",
|
1202 |
+
label: "Image",
|
1203 |
+
icon: "🖼️"
|
1204 |
+
},
|
1205 |
+
{
|
1206 |
+
type: "Video",
|
1207 |
+
label: "Video",
|
1208 |
+
icon: "🎥"
|
1209 |
+
},
|
1210 |
+
{
|
1211 |
+
type: "Audio",
|
1212 |
+
label: "Audio",
|
1213 |
+
icon: "🎵"
|
1214 |
+
}
|
1215 |
+
],
|
1216 |
+
Data: [
|
1217 |
+
{
|
1218 |
+
type: "Dataframe",
|
1219 |
+
label: "Dataframe",
|
1220 |
+
icon: "📊"
|
1221 |
+
},
|
1222 |
+
{ type: "JSON", label: "JSON", icon: "📋" }
|
1223 |
+
],
|
1224 |
+
Display: [
|
1225 |
+
{
|
1226 |
+
type: "Markdown",
|
1227 |
+
label: "Markdown",
|
1228 |
+
icon: "📝"
|
1229 |
+
},
|
1230 |
+
{ type: "HTML", label: "HTML", icon: "🌐" },
|
1231 |
+
{
|
1232 |
+
type: "Label",
|
1233 |
+
label: "Label",
|
1234 |
+
icon: "🏷️"
|
1235 |
+
},
|
1236 |
+
{
|
1237 |
+
type: "Progress",
|
1238 |
+
label: "Progress",
|
1239 |
+
icon: "📈"
|
1240 |
+
}
|
1241 |
+
]
|
1242 |
+
};
|
1243 |
+
let D = !1;
|
1244 |
+
ot(() => {
|
1245 |
+
l(24, D = !0);
|
1246 |
+
});
|
1247 |
+
let N = null, M, g = null, G = "", te = "All";
|
1248 |
+
function J(o, d) {
|
1249 |
+
N = d, o.dataTransfer && (o.dataTransfer.effectAllowed = "copy");
|
1250 |
+
}
|
1251 |
+
function Z(o) {
|
1252 |
+
if (o.preventDefault(), !N) return;
|
1253 |
+
const d = M.getBoundingClientRect(), u = o.clientX - d.left, _ = o.clientY - d.top, a = {
|
1254 |
+
id: `${N.type.toLowerCase()}_${Date.now()}`,
|
1255 |
+
type: N.type,
|
1256 |
+
position: { x: u, y: _ },
|
1257 |
+
size: { width: 200, height: 100 },
|
1258 |
+
props: kt(N.type)
|
1259 |
+
};
|
1260 |
+
l(0, c = Object.assign(Object.assign({}, c), {
|
1261 |
+
components: [...c.components, a]
|
1262 |
+
})), p.dispatch("change", c), N = null;
|
1263 |
+
}
|
1264 |
+
function I(o) {
|
1265 |
+
l(5, g = o);
|
1266 |
+
}
|
1267 |
+
function T(o, d) {
|
1268 |
+
if (!g) return;
|
1269 |
+
o === "choices" && typeof d == "string" ? d = d.split(",").map((_) => _.trim()).filter((_) => _) : o === "file_types" && typeof d == "string" && (d = d.split(",").map((_) => _.trim()).filter((_) => _));
|
1270 |
+
const u = c.components.map((_) => _.id === g.id ? Object.assign(Object.assign({}, _), {
|
1271 |
+
props: Object.assign(Object.assign({}, _.props), { [o]: d })
|
1272 |
+
}) : _);
|
1273 |
+
l(5, g = Object.assign(Object.assign({}, g), {
|
1274 |
+
props: Object.assign(Object.assign({}, g.props), { [o]: d })
|
1275 |
+
})), l(0, c = Object.assign(Object.assign({}, c), { components: u })), p.dispatch("change", c);
|
1276 |
+
}
|
1277 |
+
function U(o, d, u) {
|
1278 |
+
const _ = c.components.map((a) => a.id === o.id ? Object.assign(Object.assign({}, a), { position: { x: d, y: u } }) : a);
|
1279 |
+
l(0, c = Object.assign(Object.assign({}, c), { components: _ })), p.dispatch("change", c);
|
1280 |
+
}
|
1281 |
+
function X(o, d, u) {
|
1282 |
+
const _ = c.components.map((a) => a.id === o.id ? Object.assign(Object.assign({}, a), {
|
1283 |
+
size: { width: d, height: u }
|
1284 |
+
}) : a);
|
1285 |
+
(g == null ? void 0 : g.id) === o.id && l(5, g = Object.assign(Object.assign({}, g), {
|
1286 |
+
size: { width: d, height: u }
|
1287 |
+
})), l(0, c = Object.assign(Object.assign({}, c), { components: _ })), p.dispatch("change", c);
|
1288 |
+
}
|
1289 |
+
function W(o) {
|
1290 |
+
const d = c.components.filter((u) => u.id !== o);
|
1291 |
+
l(0, c = Object.assign(Object.assign({}, c), { components: d })), l(5, g = null), p.dispatch("change", c);
|
1292 |
+
}
|
1293 |
+
function pe() {
|
1294 |
+
const o = Object.assign(Object.assign({}, c), {
|
1295 |
+
metadata: {
|
1296 |
+
version: "1.0",
|
1297 |
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
1298 |
+
app_type: "gradio_interface",
|
1299 |
+
component_count: c.components.length
|
1300 |
+
}
|
1301 |
+
}), d = JSON.stringify(o, null, 2), u = new Blob([d], { type: "application/json" }), _ = URL.createObjectURL(u), a = document.createElement("a");
|
1302 |
+
a.href = _, a.download = "gradio-design.json", a.click(), URL.revokeObjectURL(_);
|
1303 |
+
}
|
1304 |
+
function L() {
|
1305 |
+
try {
|
1306 |
+
const o = document.createElement("canvas"), d = o.getContext("2d"), u = M.getBoundingClientRect();
|
1307 |
+
o.width = u.width * 2, o.height = u.height * 2, d.scale(2, 2), d.fillStyle = "#ffffff", d.fillRect(0, 0, u.width, u.height), d.strokeStyle = "rgba(0,0,0,0.1)", d.lineWidth = 1;
|
1308 |
+
for (let a = 0; a <= u.width; a += 20)
|
1309 |
+
d.moveTo(a, 0), d.lineTo(a, u.height);
|
1310 |
+
for (let a = 0; a <= u.height; a += 20)
|
1311 |
+
d.moveTo(0, a), d.lineTo(u.width, a);
|
1312 |
+
d.stroke(), c.components.forEach((a) => {
|
1313 |
+
const E = i.find((V) => V.type === a.type);
|
1314 |
+
d.fillStyle = "#ffffff", d.strokeStyle = "#ddd", d.lineWidth = 2, d.fillRect(a.position.x, a.position.y, a.size.width, a.size.height), d.strokeRect(a.position.x, a.position.y, a.size.width, a.size.height), d.fillStyle = "#333", d.font = "16px Arial", d.textAlign = "center", d.fillText(
|
1315 |
+
(E == null ? void 0 : E.icon) || "📦",
|
1316 |
+
a.position.x + a.size.width / 2,
|
1317 |
+
a.position.y + 25
|
1318 |
+
), d.font = "12px Arial", d.fillText(a.type, a.position.x + a.size.width / 2, a.position.y + a.size.height / 2), d.fillText(a.props.label || a.props.value || "", a.position.x + a.size.width / 2, a.position.y + a.size.height / 2 + 15);
|
1319 |
+
});
|
1320 |
+
const _ = document.createElement("a");
|
1321 |
+
_.download = "gradio-design.png", _.href = o.toDataURL("image/png"), _.click();
|
1322 |
+
} catch (o) {
|
1323 |
+
console.error("Canvas export failed:", o), alert("PNG export failed. Check console for details.");
|
1324 |
+
}
|
1325 |
+
}
|
1326 |
+
let H = !1, _e = { x: 0, y: 0 };
|
1327 |
+
function ke(o, d) {
|
1328 |
+
if (o.button !== 0) return;
|
1329 |
+
H = !0, l(5, g = d);
|
1330 |
+
const u = M.getBoundingClientRect();
|
1331 |
+
_e.x = o.clientX - u.left - d.position.x, _e.y = o.clientY - u.top - d.position.y, o.preventDefault();
|
1332 |
+
}
|
1333 |
+
function F(o) {
|
1334 |
+
if (!H || !g) return;
|
1335 |
+
const d = M.getBoundingClientRect(), u = o.clientX - d.left - _e.x, _ = o.clientY - d.top - _e.y;
|
1336 |
+
U(g, Math.max(0, u), Math.max(0, _));
|
1337 |
+
}
|
1338 |
+
function fe() {
|
1339 |
+
H = !1;
|
1340 |
+
}
|
1341 |
+
function K() {
|
1342 |
+
G = this.value, l(2, G);
|
1343 |
+
}
|
1344 |
+
function le() {
|
1345 |
+
te = nt(this), l(3, te), l(7, S);
|
1346 |
+
}
|
1347 |
+
const Ce = (o, d) => J(d, o), Q = (o) => W(o.id), ie = (o) => I(o), he = (o, d) => ke(d, o);
|
1348 |
+
function se(o) {
|
1349 |
+
et[o ? "unshift" : "push"](() => {
|
1350 |
+
M = o, l(4, M);
|
1351 |
+
});
|
1352 |
+
}
|
1353 |
+
const $ = (o) => T("label", o.target.value), Oe = (o) => T("placeholder", o.target.value), ge = (o) => T("value", o.target.checked), ne = (o) => T("value", parseFloat(o.target.value) || 0), me = (o) => T("value", o.target.value), ce = (o) => T("choices", o.target.value), A = (o) => T("minimum", parseFloat(o.target.value) || 0), ae = (o) => T("maximum", parseFloat(o.target.value) || 100), B = (o) => T("step", parseFloat(o.target.value) || 1), P = (o) => X(g, parseInt(o.target.value) || 200, g.size.height), de = (o) => X(g, g.size.width, parseInt(o.target.value) || 100), ye = (o) => U(g, parseInt(o.target.value) || 0, g.position.y), De = (o) => U(g, g.position.x, parseInt(o.target.value) || 0);
|
1354 |
+
return n.$$set = (o) => {
|
1355 |
+
"gradio" in o && l(20, p = o.gradio), "elem_id" in o && l(1, v = o.elem_id), "value" in o && l(0, c = o.value);
|
1356 |
+
}, n.$$.update = () => {
|
1357 |
+
n.$$.dirty[0] & /*selectedCategory, allComponents, searchFilter*/
|
1358 |
+
33554444 && l(26, t = (() => {
|
1359 |
+
if (te === "All") {
|
1360 |
+
let o = i;
|
1361 |
+
return G.trim() ? o.filter((d) => d.type.toLowerCase().includes(G.toLowerCase()) || d.label.toLowerCase().includes(G.toLowerCase())) : o;
|
1362 |
+
} else {
|
1363 |
+
let o = S[te] || [];
|
1364 |
+
return G.trim() ? o.filter((d) => d.type.toLowerCase().includes(G.toLowerCase()) || d.label.toLowerCase().includes(G.toLowerCase())) : o;
|
1365 |
+
}
|
1366 |
+
})()), n.$$.dirty[0] & /*mounted, filteredComponents, allComponents*/
|
1367 |
+
117440512 && l(6, r = D ? t : i);
|
1368 |
+
}, l(25, i = Object.values(S).flat()), [
|
1369 |
+
c,
|
1370 |
+
v,
|
1371 |
+
G,
|
1372 |
+
te,
|
1373 |
+
M,
|
1374 |
+
g,
|
1375 |
+
r,
|
1376 |
+
S,
|
1377 |
+
J,
|
1378 |
+
Z,
|
1379 |
+
I,
|
1380 |
+
T,
|
1381 |
+
U,
|
1382 |
+
X,
|
1383 |
+
W,
|
1384 |
+
pe,
|
1385 |
+
L,
|
1386 |
+
ke,
|
1387 |
+
F,
|
1388 |
+
fe,
|
1389 |
+
p,
|
1390 |
+
s,
|
1391 |
+
ee,
|
1392 |
+
q,
|
1393 |
+
D,
|
1394 |
+
i,
|
1395 |
+
t,
|
1396 |
+
K,
|
1397 |
+
le,
|
1398 |
+
Ce,
|
1399 |
+
Q,
|
1400 |
+
ie,
|
1401 |
+
he,
|
1402 |
+
se,
|
1403 |
+
$,
|
1404 |
+
Oe,
|
1405 |
+
ge,
|
1406 |
+
ne,
|
1407 |
+
me,
|
1408 |
+
ce,
|
1409 |
+
A,
|
1410 |
+
ae,
|
1411 |
+
B,
|
1412 |
+
P,
|
1413 |
+
de,
|
1414 |
+
ye,
|
1415 |
+
De
|
1416 |
+
];
|
1417 |
+
}
|
1418 |
+
class bt extends Ze {
|
1419 |
+
constructor(e) {
|
1420 |
+
super(), lt(
|
1421 |
+
this,
|
1422 |
+
e,
|
1423 |
+
mt,
|
1424 |
+
vt,
|
1425 |
+
st,
|
1426 |
+
{
|
1427 |
+
gradio: 20,
|
1428 |
+
elem_id: 1,
|
1429 |
+
elem_classes: 21,
|
1430 |
+
value: 0,
|
1431 |
+
loading_status: 22,
|
1432 |
+
mode: 23
|
1433 |
+
},
|
1434 |
+
null,
|
1435 |
+
[-1, -1]
|
1436 |
+
);
|
1437 |
+
}
|
1438 |
+
get elem_classes() {
|
1439 |
+
return this.$$.ctx[21];
|
1440 |
+
}
|
1441 |
+
get loading_status() {
|
1442 |
+
return this.$$.ctx[22];
|
1443 |
+
}
|
1444 |
+
get mode() {
|
1445 |
+
return this.$$.ctx[23];
|
1446 |
+
}
|
1447 |
+
}
|
1448 |
+
export {
|
1449 |
+
bt as default
|
1450 |
+
};
|
src/backend/gradio_gradiodesigner/templates/component/style.css
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
.designer-container.svelte-zk15k.svelte-zk15k{display:flex;flex-direction:column;height:700px;border:1px solid #ddd;border-radius:8px;overflow:hidden;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.toolbar.svelte-zk15k.svelte-zk15k{display:flex;justify-content:space-between;align-items:center;padding:12px 16px;background:#f8f9fa;border-bottom:1px solid #ddd}.toolbar-left.svelte-zk15k.svelte-zk15k{display:flex;align-items:center;gap:12px}.toolbar.svelte-zk15k h3.svelte-zk15k{margin:0;font-size:16px;font-weight:600}.component-count.svelte-zk15k.svelte-zk15k{background:#e9ecef;padding:2px 8px;border-radius:12px;font-size:12px;color:#495057}.toolbar-right.svelte-zk15k.svelte-zk15k{display:flex;gap:8px}.export-btn.svelte-zk15k.svelte-zk15k{padding:6px 12px;background:#007bff;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:12px}.export-btn.svelte-zk15k.svelte-zk15k:hover{background:#0056b3}.designer-content.svelte-zk15k.svelte-zk15k{display:grid!important;grid-template-columns:250px 1fr 280px!important;grid-template-areas:"palette canvas properties"!important;flex:1;height:100%;min-height:0}.palette.svelte-zk15k.svelte-zk15k{grid-area:palette!important;background:#f8f9fa;border-right:1px solid #ddd;display:flex;flex-direction:column;overflow:hidden}.canvas.svelte-zk15k.svelte-zk15k{grid-area:canvas!important;position:relative;background:#fff;overflow:hidden;-webkit-user-select:none;user-select:none}.properties.svelte-zk15k.svelte-zk15k{grid-area:properties!important;background:#f8f9fa;padding:16px;border-left:1px solid #ddd;overflow-y:auto}.palette-header.svelte-zk15k.svelte-zk15k{padding:12px 16px;border-bottom:1px solid #ddd;background:#fff;flex-shrink:0;min-height:120px;max-height:120px;overflow:hidden}.palette.svelte-zk15k h4.svelte-zk15k{margin:0 0 8px;font-size:14px;font-weight:600}.search-input.svelte-zk15k.svelte-zk15k,.category-select.svelte-zk15k.svelte-zk15k{width:100%;padding:6px 8px;border:1px solid #ddd;border-radius:4px;font-size:12px;margin-bottom:6px;box-sizing:border-box}.palette-content.svelte-zk15k.svelte-zk15k{flex:1;overflow-y:auto;padding:8px;min-height:0;background:#f8f9fa}.palette-item.svelte-zk15k.svelte-zk15k{display:flex;align-items:center;padding:8px;margin-bottom:4px;background:#fff;border:1px solid #e1e5e9;border-radius:4px;cursor:grab;-webkit-user-select:none;user-select:none}.palette-item.svelte-zk15k.svelte-zk15k:hover{background:#f0f0f0}.no-components.svelte-zk15k.svelte-zk15k{padding:20px;text-align:center;color:#666;font-size:12px;background:#fff;border-radius:4px;border:1px solid #e1e5e9}.icon.svelte-zk15k.svelte-zk15k{margin-right:8px;font-size:16px}.label.svelte-zk15k.svelte-zk15k{font-size:12px}.canvas-grid.svelte-zk15k.svelte-zk15k{position:absolute;top:0;left:0;right:0;bottom:0;background-image:linear-gradient(rgba(0,0,0,.1) 1px,transparent 1px),linear-gradient(90deg,rgba(0,0,0,.1) 1px,transparent 1px);background-size:20px 20px;opacity:.3}.canvas-component.svelte-zk15k.svelte-zk15k{position:absolute;border:2px solid #ddd;border-radius:4px;background:#fff;cursor:move;padding:8px;box-sizing:border-box}.canvas-component.svelte-zk15k.svelte-zk15k:hover{border-color:#007bff}.canvas-component.selected.svelte-zk15k.svelte-zk15k{border-color:#ff6b6b;box-shadow:0 0 0 2px #ff6b6b4d}.component-preview.svelte-zk15k.svelte-zk15k{display:flex;flex-direction:column;height:100%;text-align:center;pointer-events:none}.component-header.svelte-zk15k.svelte-zk15k{display:flex;justify-content:space-between;align-items:center;margin-bottom:4px}.type.svelte-zk15k.svelte-zk15k{font-weight:700;font-size:12px;color:#666}.delete-btn.svelte-zk15k.svelte-zk15k{background:none;border:none;cursor:pointer;font-size:10px;padding:2px;opacity:.7;pointer-events:auto}.delete-btn.svelte-zk15k.svelte-zk15k:hover{opacity:1}.properties.svelte-zk15k h4.svelte-zk15k{margin:0 0 16px;font-size:14px;font-weight:600}.property-group.svelte-zk15k.svelte-zk15k{display:flex;flex-direction:column;gap:8px}.property-header.svelte-zk15k.svelte-zk15k{padding:12px;background:#fff;border-radius:4px;border:1px solid #e1e5e9;margin-bottom:12px}.size-section.svelte-zk15k.svelte-zk15k{margin-top:16px;padding-top:16px;border-top:1px solid #ddd}.size-section.svelte-zk15k h5.svelte-zk15k{margin:0 0 8px;font-size:12px;font-weight:600}.size-controls.svelte-zk15k.svelte-zk15k{display:grid;grid-template-columns:1fr 1fr;gap:8px}.property-group.svelte-zk15k label.svelte-zk15k{font-size:12px;font-weight:500;color:#333}.property-group.svelte-zk15k input.svelte-zk15k{padding:6px 8px;border:1px solid #ddd;border-radius:4px;font-size:12px}.help-text.svelte-zk15k.svelte-zk15k{margin-top:20px;padding:12px;background:#fff;border-radius:4px;border:1px solid #e1e5e9}.help-text.svelte-zk15k ul.svelte-zk15k{margin:8px 0 0;padding-left:16px}.help-text.svelte-zk15k li.svelte-zk15k{font-size:11px;margin-bottom:4px}
|
src/backend/gradio_gradiodesigner/templates/example/index.js
ADDED
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
const {
|
2 |
+
SvelteComponent: h,
|
3 |
+
add_iframe_resize_listener: g,
|
4 |
+
add_render_callback: v,
|
5 |
+
append_hydration: y,
|
6 |
+
attr: b,
|
7 |
+
binding_callbacks: m,
|
8 |
+
children: w,
|
9 |
+
claim_element: z,
|
10 |
+
claim_text: k,
|
11 |
+
detach: c,
|
12 |
+
element: p,
|
13 |
+
init: E,
|
14 |
+
insert_hydration: S,
|
15 |
+
noop: o,
|
16 |
+
safe_not_equal: q,
|
17 |
+
set_data: C,
|
18 |
+
text: D,
|
19 |
+
toggle_class: _
|
20 |
+
} = window.__gradio__svelte__internal, { onMount: I } = window.__gradio__svelte__internal;
|
21 |
+
function M(t) {
|
22 |
+
let e, i = (
|
23 |
+
/*value*/
|
24 |
+
(t[0] ? (
|
25 |
+
/*value*/
|
26 |
+
t[0]
|
27 |
+
) : "") + ""
|
28 |
+
), s, d;
|
29 |
+
return {
|
30 |
+
c() {
|
31 |
+
e = p("div"), s = D(i), this.h();
|
32 |
+
},
|
33 |
+
l(l) {
|
34 |
+
e = z(l, "DIV", { class: !0 });
|
35 |
+
var n = w(e);
|
36 |
+
s = k(n, i), n.forEach(c), this.h();
|
37 |
+
},
|
38 |
+
h() {
|
39 |
+
b(e, "class", "svelte-84cxb8"), v(() => (
|
40 |
+
/*div_elementresize_handler*/
|
41 |
+
t[5].call(e)
|
42 |
+
)), _(
|
43 |
+
e,
|
44 |
+
"table",
|
45 |
+
/*type*/
|
46 |
+
t[1] === "table"
|
47 |
+
), _(
|
48 |
+
e,
|
49 |
+
"gallery",
|
50 |
+
/*type*/
|
51 |
+
t[1] === "gallery"
|
52 |
+
), _(
|
53 |
+
e,
|
54 |
+
"selected",
|
55 |
+
/*selected*/
|
56 |
+
t[2]
|
57 |
+
);
|
58 |
+
},
|
59 |
+
m(l, n) {
|
60 |
+
S(l, e, n), y(e, s), d = g(
|
61 |
+
e,
|
62 |
+
/*div_elementresize_handler*/
|
63 |
+
t[5].bind(e)
|
64 |
+
), t[6](e);
|
65 |
+
},
|
66 |
+
p(l, [n]) {
|
67 |
+
n & /*value*/
|
68 |
+
1 && i !== (i = /*value*/
|
69 |
+
(l[0] ? (
|
70 |
+
/*value*/
|
71 |
+
l[0]
|
72 |
+
) : "") + "") && C(s, i), n & /*type*/
|
73 |
+
2 && _(
|
74 |
+
e,
|
75 |
+
"table",
|
76 |
+
/*type*/
|
77 |
+
l[1] === "table"
|
78 |
+
), n & /*type*/
|
79 |
+
2 && _(
|
80 |
+
e,
|
81 |
+
"gallery",
|
82 |
+
/*type*/
|
83 |
+
l[1] === "gallery"
|
84 |
+
), n & /*selected*/
|
85 |
+
4 && _(
|
86 |
+
e,
|
87 |
+
"selected",
|
88 |
+
/*selected*/
|
89 |
+
l[2]
|
90 |
+
);
|
91 |
+
},
|
92 |
+
i: o,
|
93 |
+
o,
|
94 |
+
d(l) {
|
95 |
+
l && c(e), d(), t[6](null);
|
96 |
+
}
|
97 |
+
};
|
98 |
+
}
|
99 |
+
function P(t, e) {
|
100 |
+
t.style.setProperty("--local-text-width", `${e && e < 150 ? e : 200}px`), t.style.whiteSpace = "unset";
|
101 |
+
}
|
102 |
+
function V(t, e, i) {
|
103 |
+
let { value: s } = e, { type: d } = e, { selected: l = !1 } = e, n, r;
|
104 |
+
I(() => {
|
105 |
+
P(r, n);
|
106 |
+
});
|
107 |
+
function u() {
|
108 |
+
n = this.clientWidth, i(3, n);
|
109 |
+
}
|
110 |
+
function f(a) {
|
111 |
+
m[a ? "unshift" : "push"](() => {
|
112 |
+
r = a, i(4, r);
|
113 |
+
});
|
114 |
+
}
|
115 |
+
return t.$$set = (a) => {
|
116 |
+
"value" in a && i(0, s = a.value), "type" in a && i(1, d = a.type), "selected" in a && i(2, l = a.selected);
|
117 |
+
}, [s, d, l, n, r, u, f];
|
118 |
+
}
|
119 |
+
class W extends h {
|
120 |
+
constructor(e) {
|
121 |
+
super(), E(this, e, V, M, q, { value: 0, type: 1, selected: 2 });
|
122 |
+
}
|
123 |
+
}
|
124 |
+
export {
|
125 |
+
W as default
|
126 |
+
};
|
src/backend/gradio_gradiodesigner/templates/example/style.css
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
.gallery.svelte-84cxb8{padding:var(--size-1) var(--size-2)}div.svelte-84cxb8{overflow:hidden;min-width:var(--local-text-width);white-space:nowrap}
|
src/demo/__init__.py
ADDED
File without changes
|
src/demo/app.py
ADDED
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
from gradio_gradiodesigner import GradioDesigner
|
3 |
+
import json
|
4 |
+
|
5 |
+
def analyze_design(design_config):
|
6 |
+
"""Analyze the design configuration"""
|
7 |
+
if not design_config or not isinstance(design_config, dict):
|
8 |
+
return "No design configuration provided"
|
9 |
+
|
10 |
+
components = design_config.get('components', [])
|
11 |
+
|
12 |
+
# Count components by type
|
13 |
+
component_types = {}
|
14 |
+
for comp in components:
|
15 |
+
comp_type = comp.get('type', 'Unknown')
|
16 |
+
component_types[comp_type] = component_types.get(comp_type, 0) + 1
|
17 |
+
|
18 |
+
# Calculate coverage area
|
19 |
+
if components:
|
20 |
+
positions = [(comp['position']['x'], comp['position']['y']) for comp in components]
|
21 |
+
min_x, min_y = min(pos[0] for pos in positions), min(pos[1] for pos in positions)
|
22 |
+
max_x, max_y = max(pos[0] for pos in positions), max(pos[1] for pos in positions)
|
23 |
+
coverage = f"{max_x - min_x} x {max_y - min_y} pixels"
|
24 |
+
else:
|
25 |
+
coverage = "No components"
|
26 |
+
|
27 |
+
analysis = f"""📊 **Design Analysis**
|
28 |
+
|
29 |
+
**Component Summary:**
|
30 |
+
• Total components: {len(components)}
|
31 |
+
• Component types: {dict(component_types)}
|
32 |
+
• Canvas coverage: {coverage}
|
33 |
+
|
34 |
+
**Component Details:**
|
35 |
+
"""
|
36 |
+
|
37 |
+
for i, comp in enumerate(components, 1):
|
38 |
+
analysis += f"\n{i}. **{comp['type']}** (`{comp['id']}`)"
|
39 |
+
analysis += f"\n - Position: ({comp['position']['x']}, {comp['position']['y']})"
|
40 |
+
analysis += f"\n - Size: {comp['size']['width']}×{comp['size']['height']}"
|
41 |
+
if comp.get('props', {}).get('label'):
|
42 |
+
analysis += f"\n - Label: \"{comp['props']['label']}\""
|
43 |
+
|
44 |
+
return analysis
|
45 |
+
|
46 |
+
def generate_gradio_code(design_config):
|
47 |
+
"""Generate complete Gradio code from design"""
|
48 |
+
if not design_config or not isinstance(design_config, dict):
|
49 |
+
return "# No design to generate code from"
|
50 |
+
|
51 |
+
components = design_config.get('components', [])
|
52 |
+
|
53 |
+
code = '''import gradio as gr
|
54 |
+
|
55 |
+
def process_input(*args):
|
56 |
+
"""Process the inputs from your app"""
|
57 |
+
return "Hello from your generated app!"
|
58 |
+
|
59 |
+
with gr.Blocks(title="Generated Gradio App") as demo:
|
60 |
+
gr.Markdown("# 🚀 Generated Gradio App")
|
61 |
+
gr.Markdown("This app was generated from your visual design!")
|
62 |
+
|
63 |
+
'''
|
64 |
+
|
65 |
+
# Sort components by position (top to bottom, left to right)
|
66 |
+
sorted_components = sorted(components, key=lambda c: (c['position']['y'], c['position']['x']))
|
67 |
+
|
68 |
+
component_vars = []
|
69 |
+
|
70 |
+
for comp in sorted_components:
|
71 |
+
comp_type = comp.get('type', 'Textbox')
|
72 |
+
comp_id = comp.get('id', 'component')
|
73 |
+
props = comp.get('props', {})
|
74 |
+
|
75 |
+
# Build component declaration
|
76 |
+
prop_parts = []
|
77 |
+
for key, value in props.items():
|
78 |
+
if key in ['label', 'placeholder', 'value'] and isinstance(value, str):
|
79 |
+
prop_parts.append(f'{key}="{value}"')
|
80 |
+
elif key in ['minimum', 'maximum', 'step', 'lines', 'max_length', 'precision'] and isinstance(value, (int, float)):
|
81 |
+
prop_parts.append(f'{key}={value}')
|
82 |
+
elif key == 'choices' and isinstance(value, list):
|
83 |
+
prop_parts.append(f'{key}={value}')
|
84 |
+
elif isinstance(value, bool):
|
85 |
+
prop_parts.append(f'{key}={value}')
|
86 |
+
|
87 |
+
prop_string = ", ".join(prop_parts) if prop_parts else ""
|
88 |
+
|
89 |
+
code += f" {comp_id} = gr.{comp_type}({prop_string})\n"
|
90 |
+
component_vars.append(comp_id)
|
91 |
+
|
92 |
+
# Add a simple interaction if there are components
|
93 |
+
if component_vars:
|
94 |
+
inputs = [var for var in component_vars if not var.startswith('button')]
|
95 |
+
outputs = [var for var in component_vars if var.startswith('button')]
|
96 |
+
|
97 |
+
if not outputs:
|
98 |
+
outputs = inputs[:1] # Use first input as output if no buttons
|
99 |
+
|
100 |
+
if inputs and outputs:
|
101 |
+
code += f"\n # Add interactions\n"
|
102 |
+
code += f" # Example: connect inputs to outputs\n"
|
103 |
+
code += f" # {outputs[0]}.click(process_input, inputs=[{', '.join(inputs)}], outputs=[{outputs[0]}])\n"
|
104 |
+
|
105 |
+
code += '''
|
106 |
+
if __name__ == "__main__":
|
107 |
+
demo.launch()
|
108 |
+
'''
|
109 |
+
|
110 |
+
return code
|
111 |
+
|
112 |
+
with gr.Blocks(title="Gradio Visual Designer Pro", theme=gr.themes.Soft()) as demo:
|
113 |
+
gr.Markdown("""
|
114 |
+
# 🎨 Gradio Visual Designer Pro
|
115 |
+
|
116 |
+
**Build your Gradio apps visually!** Drag and drop components, customize properties, and generate production-ready code.
|
117 |
+
|
118 |
+
**Features:** 25+ Gradio components • Real-time editing • Code generation • Export options
|
119 |
+
""")
|
120 |
+
|
121 |
+
with gr.Row():
|
122 |
+
designer = GradioDesigner(
|
123 |
+
label="Visual App Designer",
|
124 |
+
value={"components": [], "layout": "blocks"}
|
125 |
+
)
|
126 |
+
|
127 |
+
with gr.Row():
|
128 |
+
with gr.Column(scale=1):
|
129 |
+
analysis_output = gr.Markdown(
|
130 |
+
value="Design analysis will appear here...",
|
131 |
+
label="Design Analysis"
|
132 |
+
)
|
133 |
+
|
134 |
+
with gr.Column(scale=1):
|
135 |
+
code_output = gr.Code(
|
136 |
+
label="Generated Gradio Code",
|
137 |
+
language="python",
|
138 |
+
value="# Design your app above to see generated code",
|
139 |
+
lines=20
|
140 |
+
)
|
141 |
+
|
142 |
+
with gr.Row():
|
143 |
+
analyze_btn = gr.Button("📊 Analyze Design", variant="secondary")
|
144 |
+
generate_btn = gr.Button("🚀 Generate Code", variant="primary")
|
145 |
+
clear_btn = gr.Button("🗑️ Clear All", variant="stop")
|
146 |
+
|
147 |
+
# Event handlers
|
148 |
+
designer.change(
|
149 |
+
fn=analyze_design,
|
150 |
+
inputs=[designer],
|
151 |
+
outputs=[analysis_output]
|
152 |
+
)
|
153 |
+
|
154 |
+
analyze_btn.click(
|
155 |
+
fn=analyze_design,
|
156 |
+
inputs=[designer],
|
157 |
+
outputs=[analysis_output]
|
158 |
+
)
|
159 |
+
|
160 |
+
generate_btn.click(
|
161 |
+
fn=generate_gradio_code,
|
162 |
+
inputs=[designer],
|
163 |
+
outputs=[code_output]
|
164 |
+
)
|
165 |
+
|
166 |
+
clear_btn.click(
|
167 |
+
fn=lambda: {"components": [], "layout": "blocks"},
|
168 |
+
outputs=[designer]
|
169 |
+
)
|
170 |
+
|
171 |
+
if __name__ == "__main__":
|
172 |
+
demo.launch()
|
src/demo/css.css
ADDED
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
html {
|
2 |
+
font-family: Inter;
|
3 |
+
font-size: 16px;
|
4 |
+
font-weight: 400;
|
5 |
+
line-height: 1.5;
|
6 |
+
-webkit-text-size-adjust: 100%;
|
7 |
+
background: #fff;
|
8 |
+
color: #323232;
|
9 |
+
-webkit-font-smoothing: antialiased;
|
10 |
+
-moz-osx-font-smoothing: grayscale;
|
11 |
+
text-rendering: optimizeLegibility;
|
12 |
+
}
|
13 |
+
|
14 |
+
:root {
|
15 |
+
--space: 1;
|
16 |
+
--vspace: calc(var(--space) * 1rem);
|
17 |
+
--vspace-0: calc(3 * var(--space) * 1rem);
|
18 |
+
--vspace-1: calc(2 * var(--space) * 1rem);
|
19 |
+
--vspace-2: calc(1.5 * var(--space) * 1rem);
|
20 |
+
--vspace-3: calc(0.5 * var(--space) * 1rem);
|
21 |
+
}
|
22 |
+
|
23 |
+
.app {
|
24 |
+
max-width: 748px !important;
|
25 |
+
}
|
26 |
+
|
27 |
+
.prose p {
|
28 |
+
margin: var(--vspace) 0;
|
29 |
+
line-height: var(--vspace * 2);
|
30 |
+
font-size: 1rem;
|
31 |
+
}
|
32 |
+
|
33 |
+
code {
|
34 |
+
font-family: "Inconsolata", sans-serif;
|
35 |
+
font-size: 16px;
|
36 |
+
}
|
37 |
+
|
38 |
+
h1,
|
39 |
+
h1 code {
|
40 |
+
font-weight: 400;
|
41 |
+
line-height: calc(2.5 / var(--space) * var(--vspace));
|
42 |
+
}
|
43 |
+
|
44 |
+
h1 code {
|
45 |
+
background: none;
|
46 |
+
border: none;
|
47 |
+
letter-spacing: 0.05em;
|
48 |
+
padding-bottom: 5px;
|
49 |
+
position: relative;
|
50 |
+
padding: 0;
|
51 |
+
}
|
52 |
+
|
53 |
+
h2 {
|
54 |
+
margin: var(--vspace-1) 0 var(--vspace-2) 0;
|
55 |
+
line-height: 1em;
|
56 |
+
}
|
57 |
+
|
58 |
+
h3,
|
59 |
+
h3 code {
|
60 |
+
margin: var(--vspace-1) 0 var(--vspace-2) 0;
|
61 |
+
line-height: 1em;
|
62 |
+
}
|
63 |
+
|
64 |
+
h4,
|
65 |
+
h5,
|
66 |
+
h6 {
|
67 |
+
margin: var(--vspace-3) 0 var(--vspace-3) 0;
|
68 |
+
line-height: var(--vspace);
|
69 |
+
}
|
70 |
+
|
71 |
+
.bigtitle,
|
72 |
+
h1,
|
73 |
+
h1 code {
|
74 |
+
font-size: calc(8px * 4.5);
|
75 |
+
word-break: break-word;
|
76 |
+
}
|
77 |
+
|
78 |
+
.title,
|
79 |
+
h2,
|
80 |
+
h2 code {
|
81 |
+
font-size: calc(8px * 3.375);
|
82 |
+
font-weight: lighter;
|
83 |
+
word-break: break-word;
|
84 |
+
border: none;
|
85 |
+
background: none;
|
86 |
+
}
|
87 |
+
|
88 |
+
.subheading1,
|
89 |
+
h3,
|
90 |
+
h3 code {
|
91 |
+
font-size: calc(8px * 1.8);
|
92 |
+
font-weight: 600;
|
93 |
+
border: none;
|
94 |
+
background: none;
|
95 |
+
letter-spacing: 0.1em;
|
96 |
+
text-transform: uppercase;
|
97 |
+
}
|
98 |
+
|
99 |
+
h2 code {
|
100 |
+
padding: 0;
|
101 |
+
position: relative;
|
102 |
+
letter-spacing: 0.05em;
|
103 |
+
}
|
104 |
+
|
105 |
+
blockquote {
|
106 |
+
font-size: calc(8px * 1.1667);
|
107 |
+
font-style: italic;
|
108 |
+
line-height: calc(1.1667 * var(--vspace));
|
109 |
+
margin: var(--vspace-2) var(--vspace-2);
|
110 |
+
}
|
111 |
+
|
112 |
+
.subheading2,
|
113 |
+
h4 {
|
114 |
+
font-size: calc(8px * 1.4292);
|
115 |
+
text-transform: uppercase;
|
116 |
+
font-weight: 600;
|
117 |
+
}
|
118 |
+
|
119 |
+
.subheading3,
|
120 |
+
h5 {
|
121 |
+
font-size: calc(8px * 1.2917);
|
122 |
+
line-height: calc(1.2917 * var(--vspace));
|
123 |
+
|
124 |
+
font-weight: lighter;
|
125 |
+
text-transform: uppercase;
|
126 |
+
letter-spacing: 0.15em;
|
127 |
+
}
|
128 |
+
|
129 |
+
h6 {
|
130 |
+
font-size: calc(8px * 1.1667);
|
131 |
+
font-size: 1.1667em;
|
132 |
+
font-weight: normal;
|
133 |
+
font-style: italic;
|
134 |
+
font-family: "le-monde-livre-classic-byol", serif !important;
|
135 |
+
letter-spacing: 0px !important;
|
136 |
+
}
|
137 |
+
|
138 |
+
#start .md > *:first-child {
|
139 |
+
margin-top: 0;
|
140 |
+
}
|
141 |
+
|
142 |
+
h2 + h3 {
|
143 |
+
margin-top: 0;
|
144 |
+
}
|
145 |
+
|
146 |
+
.md hr {
|
147 |
+
border: none;
|
148 |
+
border-top: 1px solid var(--block-border-color);
|
149 |
+
margin: var(--vspace-2) 0 var(--vspace-2) 0;
|
150 |
+
}
|
151 |
+
.prose ul {
|
152 |
+
margin: var(--vspace-2) 0 var(--vspace-1) 0;
|
153 |
+
}
|
154 |
+
|
155 |
+
.gap {
|
156 |
+
gap: 0;
|
157 |
+
}
|
src/demo/requirements.txt
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
gradio_gradiodesigner
|
src/demo/space.py
ADDED
@@ -0,0 +1,293 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
import gradio as gr
|
3 |
+
from app import demo as app
|
4 |
+
import os
|
5 |
+
|
6 |
+
_docs = {'GradioDesigner': {'description': 'A visual designer component for building Gradio layouts with all components', 'members': {'__init__': {'value': {'type': 'dict | None', 'default': 'None', 'description': None}, 'label': {'type': 'str | None', 'default': 'None', 'description': None}}, 'postprocess': {'value': {'type': 'dict | None', 'description': None}}, 'preprocess': {'return': {'type': 'dict | None', 'description': None}, 'value': None}}, 'events': {'change': {'type': None, 'default': None, 'description': 'Triggered when the value of the GradioDesigner changes either because of user input (e.g. a user types in a textbox) OR because of a function update (e.g. an image receives a value from the output of an event trigger). See `.input()` for a listener that is only triggered by user input.'}, 'input': {'type': None, 'default': None, 'description': 'This listener is triggered when the user changes the value of the GradioDesigner.'}}}, '__meta__': {'additional_interfaces': {}, 'user_fn_refs': {'GradioDesigner': []}}}
|
7 |
+
|
8 |
+
abs_path = os.path.join(os.path.dirname(__file__), "css.css")
|
9 |
+
|
10 |
+
with gr.Blocks(
|
11 |
+
css=abs_path,
|
12 |
+
theme=gr.themes.Default(
|
13 |
+
font_mono=[
|
14 |
+
gr.themes.GoogleFont("Inconsolata"),
|
15 |
+
"monospace",
|
16 |
+
],
|
17 |
+
),
|
18 |
+
) as demo:
|
19 |
+
gr.Markdown(
|
20 |
+
"""
|
21 |
+
# `gradio_gradiodesigner`
|
22 |
+
|
23 |
+
<div style="display: flex; gap: 7px;">
|
24 |
+
<img alt="Static Badge" src="https://img.shields.io/badge/version%20-%200.0.1%20-%20orange">
|
25 |
+
</div>
|
26 |
+
|
27 |
+
gradio designer
|
28 |
+
""", elem_classes=["md-custom"], header_links=True)
|
29 |
+
app.render()
|
30 |
+
gr.Markdown(
|
31 |
+
"""
|
32 |
+
## Installation
|
33 |
+
|
34 |
+
```bash
|
35 |
+
pip install gradio_gradiodesigner
|
36 |
+
```
|
37 |
+
|
38 |
+
## Usage
|
39 |
+
|
40 |
+
```python
|
41 |
+
import gradio as gr
|
42 |
+
from gradio_gradiodesigner import GradioDesigner
|
43 |
+
import json
|
44 |
+
|
45 |
+
def analyze_design(design_config):
|
46 |
+
\"\"\"Analyze the design configuration\"\"\"
|
47 |
+
if not design_config or not isinstance(design_config, dict):
|
48 |
+
return "No design configuration provided"
|
49 |
+
|
50 |
+
components = design_config.get('components', [])
|
51 |
+
|
52 |
+
# Count components by type
|
53 |
+
component_types = {}
|
54 |
+
for comp in components:
|
55 |
+
comp_type = comp.get('type', 'Unknown')
|
56 |
+
component_types[comp_type] = component_types.get(comp_type, 0) + 1
|
57 |
+
|
58 |
+
# Calculate coverage area
|
59 |
+
if components:
|
60 |
+
positions = [(comp['position']['x'], comp['position']['y']) for comp in components]
|
61 |
+
min_x, min_y = min(pos[0] for pos in positions), min(pos[1] for pos in positions)
|
62 |
+
max_x, max_y = max(pos[0] for pos in positions), max(pos[1] for pos in positions)
|
63 |
+
coverage = f"{max_x - min_x} x {max_y - min_y} pixels"
|
64 |
+
else:
|
65 |
+
coverage = "No components"
|
66 |
+
|
67 |
+
analysis = f\"\"\"📊 **Design Analysis**
|
68 |
+
|
69 |
+
**Component Summary:**
|
70 |
+
• Total components: {len(components)}
|
71 |
+
• Component types: {dict(component_types)}
|
72 |
+
• Canvas coverage: {coverage}
|
73 |
+
|
74 |
+
**Component Details:**
|
75 |
+
\"\"\"
|
76 |
+
|
77 |
+
for i, comp in enumerate(components, 1):
|
78 |
+
analysis += f"\n{i}. **{comp['type']}** (`{comp['id']}`)"
|
79 |
+
analysis += f"\n - Position: ({comp['position']['x']}, {comp['position']['y']})"
|
80 |
+
analysis += f"\n - Size: {comp['size']['width']}×{comp['size']['height']}"
|
81 |
+
if comp.get('props', {}).get('label'):
|
82 |
+
analysis += f"\n - Label: \"{comp['props']['label']}\""
|
83 |
+
|
84 |
+
return analysis
|
85 |
+
|
86 |
+
def generate_gradio_code(design_config):
|
87 |
+
\"\"\"Generate complete Gradio code from design\"\"\"
|
88 |
+
if not design_config or not isinstance(design_config, dict):
|
89 |
+
return "# No design to generate code from"
|
90 |
+
|
91 |
+
components = design_config.get('components', [])
|
92 |
+
|
93 |
+
code = '''import gradio as gr
|
94 |
+
|
95 |
+
def process_input(*args):
|
96 |
+
\"\"\"Process the inputs from your app\"\"\"
|
97 |
+
return "Hello from your generated app!"
|
98 |
+
|
99 |
+
with gr.Blocks(title="Generated Gradio App") as demo:
|
100 |
+
gr.Markdown("# 🚀 Generated Gradio App")
|
101 |
+
gr.Markdown("This app was generated from your visual design!")
|
102 |
+
|
103 |
+
'''
|
104 |
+
|
105 |
+
# Sort components by position (top to bottom, left to right)
|
106 |
+
sorted_components = sorted(components, key=lambda c: (c['position']['y'], c['position']['x']))
|
107 |
+
|
108 |
+
component_vars = []
|
109 |
+
|
110 |
+
for comp in sorted_components:
|
111 |
+
comp_type = comp.get('type', 'Textbox')
|
112 |
+
comp_id = comp.get('id', 'component')
|
113 |
+
props = comp.get('props', {})
|
114 |
+
|
115 |
+
# Build component declaration
|
116 |
+
prop_parts = []
|
117 |
+
for key, value in props.items():
|
118 |
+
if key in ['label', 'placeholder', 'value'] and isinstance(value, str):
|
119 |
+
prop_parts.append(f'{key}="{value}"')
|
120 |
+
elif key in ['minimum', 'maximum', 'step', 'lines', 'max_length', 'precision'] and isinstance(value, (int, float)):
|
121 |
+
prop_parts.append(f'{key}={value}')
|
122 |
+
elif key == 'choices' and isinstance(value, list):
|
123 |
+
prop_parts.append(f'{key}={value}')
|
124 |
+
elif isinstance(value, bool):
|
125 |
+
prop_parts.append(f'{key}={value}')
|
126 |
+
|
127 |
+
prop_string = ", ".join(prop_parts) if prop_parts else ""
|
128 |
+
|
129 |
+
code += f" {comp_id} = gr.{comp_type}({prop_string})\n"
|
130 |
+
component_vars.append(comp_id)
|
131 |
+
|
132 |
+
# Add a simple interaction if there are components
|
133 |
+
if component_vars:
|
134 |
+
inputs = [var for var in component_vars if not var.startswith('button')]
|
135 |
+
outputs = [var for var in component_vars if var.startswith('button')]
|
136 |
+
|
137 |
+
if not outputs:
|
138 |
+
outputs = inputs[:1] # Use first input as output if no buttons
|
139 |
+
|
140 |
+
if inputs and outputs:
|
141 |
+
code += f"\n # Add interactions\n"
|
142 |
+
code += f" # Example: connect inputs to outputs\n"
|
143 |
+
code += f" # {outputs[0]}.click(process_input, inputs=[{', '.join(inputs)}], outputs=[{outputs[0]}])\n"
|
144 |
+
|
145 |
+
code += '''
|
146 |
+
if __name__ == "__main__":
|
147 |
+
demo.launch()
|
148 |
+
'''
|
149 |
+
|
150 |
+
return code
|
151 |
+
|
152 |
+
with gr.Blocks(title="Gradio Visual Designer Pro", theme=gr.themes.Soft()) as demo:
|
153 |
+
gr.Markdown(\"\"\"
|
154 |
+
# 🎨 Gradio Visual Designer Pro
|
155 |
+
|
156 |
+
**Build your Gradio apps visually!** Drag and drop components, customize properties, and generate production-ready code.
|
157 |
+
|
158 |
+
**Features:** 25+ Gradio components • Real-time editing • Code generation • Export options
|
159 |
+
\"\"\")
|
160 |
+
|
161 |
+
with gr.Row():
|
162 |
+
designer = GradioDesigner(
|
163 |
+
label="Visual App Designer",
|
164 |
+
value={"components": [], "layout": "blocks"}
|
165 |
+
)
|
166 |
+
|
167 |
+
with gr.Row():
|
168 |
+
with gr.Column(scale=1):
|
169 |
+
analysis_output = gr.Markdown(
|
170 |
+
value="Design analysis will appear here...",
|
171 |
+
label="Design Analysis"
|
172 |
+
)
|
173 |
+
|
174 |
+
with gr.Column(scale=1):
|
175 |
+
code_output = gr.Code(
|
176 |
+
label="Generated Gradio Code",
|
177 |
+
language="python",
|
178 |
+
value="# Design your app above to see generated code",
|
179 |
+
lines=20
|
180 |
+
)
|
181 |
+
|
182 |
+
with gr.Row():
|
183 |
+
analyze_btn = gr.Button("📊 Analyze Design", variant="secondary")
|
184 |
+
generate_btn = gr.Button("🚀 Generate Code", variant="primary")
|
185 |
+
clear_btn = gr.Button("🗑️ Clear All", variant="stop")
|
186 |
+
|
187 |
+
# Event handlers
|
188 |
+
designer.change(
|
189 |
+
fn=analyze_design,
|
190 |
+
inputs=[designer],
|
191 |
+
outputs=[analysis_output]
|
192 |
+
)
|
193 |
+
|
194 |
+
analyze_btn.click(
|
195 |
+
fn=analyze_design,
|
196 |
+
inputs=[designer],
|
197 |
+
outputs=[analysis_output]
|
198 |
+
)
|
199 |
+
|
200 |
+
generate_btn.click(
|
201 |
+
fn=generate_gradio_code,
|
202 |
+
inputs=[designer],
|
203 |
+
outputs=[code_output]
|
204 |
+
)
|
205 |
+
|
206 |
+
clear_btn.click(
|
207 |
+
fn=lambda: {"components": [], "layout": "blocks"},
|
208 |
+
outputs=[designer]
|
209 |
+
)
|
210 |
+
|
211 |
+
if __name__ == "__main__":
|
212 |
+
demo.launch()
|
213 |
+
|
214 |
+
```
|
215 |
+
""", elem_classes=["md-custom"], header_links=True)
|
216 |
+
|
217 |
+
|
218 |
+
gr.Markdown("""
|
219 |
+
## `GradioDesigner`
|
220 |
+
|
221 |
+
### Initialization
|
222 |
+
""", elem_classes=["md-custom"], header_links=True)
|
223 |
+
|
224 |
+
gr.ParamViewer(value=_docs["GradioDesigner"]["members"]["__init__"], linkify=[])
|
225 |
+
|
226 |
+
|
227 |
+
gr.Markdown("### Events")
|
228 |
+
gr.ParamViewer(value=_docs["GradioDesigner"]["events"], linkify=['Event'])
|
229 |
+
|
230 |
+
|
231 |
+
|
232 |
+
|
233 |
+
gr.Markdown("""
|
234 |
+
|
235 |
+
### User function
|
236 |
+
|
237 |
+
The impact on the users predict function varies depending on whether the component is used as an input or output for an event (or both).
|
238 |
+
|
239 |
+
- When used as an Input, the component only impacts the input signature of the user function.
|
240 |
+
- When used as an output, the component only impacts the return signature of the user function.
|
241 |
+
|
242 |
+
The code snippet below is accurate in cases where the component is used as both an input and an output.
|
243 |
+
|
244 |
+
|
245 |
+
|
246 |
+
```python
|
247 |
+
def predict(
|
248 |
+
value: dict | None
|
249 |
+
) -> dict | None:
|
250 |
+
return value
|
251 |
+
```
|
252 |
+
""", elem_classes=["md-custom", "GradioDesigner-user-fn"], header_links=True)
|
253 |
+
|
254 |
+
|
255 |
+
|
256 |
+
|
257 |
+
demo.load(None, js=r"""function() {
|
258 |
+
const refs = {};
|
259 |
+
const user_fn_refs = {
|
260 |
+
GradioDesigner: [], };
|
261 |
+
requestAnimationFrame(() => {
|
262 |
+
|
263 |
+
Object.entries(user_fn_refs).forEach(([key, refs]) => {
|
264 |
+
if (refs.length > 0) {
|
265 |
+
const el = document.querySelector(`.${key}-user-fn`);
|
266 |
+
if (!el) return;
|
267 |
+
refs.forEach(ref => {
|
268 |
+
el.innerHTML = el.innerHTML.replace(
|
269 |
+
new RegExp("\\b"+ref+"\\b", "g"),
|
270 |
+
`<a href="#h-${ref.toLowerCase()}">${ref}</a>`
|
271 |
+
);
|
272 |
+
})
|
273 |
+
}
|
274 |
+
})
|
275 |
+
|
276 |
+
Object.entries(refs).forEach(([key, refs]) => {
|
277 |
+
if (refs.length > 0) {
|
278 |
+
const el = document.querySelector(`.${key}`);
|
279 |
+
if (!el) return;
|
280 |
+
refs.forEach(ref => {
|
281 |
+
el.innerHTML = el.innerHTML.replace(
|
282 |
+
new RegExp("\\b"+ref+"\\b", "g"),
|
283 |
+
`<a href="#h-${ref.toLowerCase()}">${ref}</a>`
|
284 |
+
);
|
285 |
+
})
|
286 |
+
}
|
287 |
+
})
|
288 |
+
})
|
289 |
+
}
|
290 |
+
|
291 |
+
""")
|
292 |
+
|
293 |
+
demo.launch()
|
src/frontend/Example.svelte
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import { onMount } from "svelte";
|
3 |
+
|
4 |
+
export let value: string | null;
|
5 |
+
export let type: "gallery" | "table";
|
6 |
+
export let selected = false;
|
7 |
+
|
8 |
+
let size: number;
|
9 |
+
let el: HTMLDivElement;
|
10 |
+
|
11 |
+
function set_styles(element: HTMLElement, el_width: number): void {
|
12 |
+
element.style.setProperty(
|
13 |
+
"--local-text-width",
|
14 |
+
`${el_width && el_width < 150 ? el_width : 200}px`
|
15 |
+
);
|
16 |
+
element.style.whiteSpace = "unset";
|
17 |
+
}
|
18 |
+
|
19 |
+
onMount(() => {
|
20 |
+
set_styles(el, size);
|
21 |
+
});
|
22 |
+
</script>
|
23 |
+
|
24 |
+
<div
|
25 |
+
bind:clientWidth={size}
|
26 |
+
bind:this={el}
|
27 |
+
class:table={type === "table"}
|
28 |
+
class:gallery={type === "gallery"}
|
29 |
+
class:selected
|
30 |
+
>
|
31 |
+
{value ? value : ""}
|
32 |
+
</div>
|
33 |
+
|
34 |
+
<style>
|
35 |
+
.gallery {
|
36 |
+
padding: var(--size-1) var(--size-2);
|
37 |
+
}
|
38 |
+
|
39 |
+
div {
|
40 |
+
overflow: hidden;
|
41 |
+
min-width: var(--local-text-width);
|
42 |
+
|
43 |
+
white-space: nowrap;
|
44 |
+
}
|
45 |
+
</style>
|
src/frontend/Index.svelte
ADDED
@@ -0,0 +1,890 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<script lang="ts">
|
2 |
+
import type { LoadingStatus } from "@gradio/statustracker";
|
3 |
+
import type { Gradio } from "@gradio/utils";
|
4 |
+
import { onMount } from 'svelte';
|
5 |
+
|
6 |
+
export let gradio: Gradio<{
|
7 |
+
change: never;
|
8 |
+
input: never;
|
9 |
+
}>;
|
10 |
+
export let elem_id = "";
|
11 |
+
export const elem_classes: string[] = [];
|
12 |
+
export let value: any = { components: [], layout: "blocks" };
|
13 |
+
export const loading_status: LoadingStatus | undefined = undefined;
|
14 |
+
export const mode: "static" | "interactive" = "interactive";
|
15 |
+
|
16 |
+
// Complete component definitions organized by category
|
17 |
+
const componentsByCategory = {
|
18 |
+
"Input": [
|
19 |
+
{ type: "Textbox", label: "Text Input", icon: "📝" },
|
20 |
+
{ type: "TextArea", label: "Text Area", icon: "📄" },
|
21 |
+
{ type: "Number", label: "Number", icon: "🔢" },
|
22 |
+
{ type: "Slider", label: "Slider", icon: "🎚️" },
|
23 |
+
{ type: "Checkbox", label: "Checkbox", icon: "☑️" },
|
24 |
+
{ type: "CheckboxGroup", label: "Checkbox Group", icon: "☑️" },
|
25 |
+
{ type: "Radio", label: "Radio", icon: "🔘" },
|
26 |
+
{ type: "Dropdown", label: "Dropdown", icon: "📋" },
|
27 |
+
{ type: "Toggle", label: "Toggle", icon: "🔄" },
|
28 |
+
{ type: "ColorPicker", label: "Color Picker", icon: "🎨" },
|
29 |
+
{ type: "Date", label: "Date", icon: "📅" },
|
30 |
+
{ type: "Time", label: "Time", icon: "⏰" },
|
31 |
+
{ type: "File", label: "File Upload", icon: "📁" }
|
32 |
+
],
|
33 |
+
"Action": [
|
34 |
+
{ type: "Button", label: "Button", icon: "🔘" }
|
35 |
+
],
|
36 |
+
"Media": [
|
37 |
+
{ type: "Image", label: "Image", icon: "🖼️" },
|
38 |
+
{ type: "Video", label: "Video", icon: "🎥" },
|
39 |
+
{ type: "Audio", label: "Audio", icon: "🎵" }
|
40 |
+
],
|
41 |
+
"Data": [
|
42 |
+
{ type: "Dataframe", label: "Dataframe", icon: "📊" },
|
43 |
+
{ type: "JSON", label: "JSON", icon: "📋" }
|
44 |
+
],
|
45 |
+
"Display": [
|
46 |
+
{ type: "Markdown", label: "Markdown", icon: "📝" },
|
47 |
+
{ type: "HTML", label: "HTML", icon: "🌐" },
|
48 |
+
{ type: "Label", label: "Label", icon: "🏷️" },
|
49 |
+
{ type: "Progress", label: "Progress", icon: "📈" }
|
50 |
+
]
|
51 |
+
};
|
52 |
+
|
53 |
+
// Force components to show immediately on mount
|
54 |
+
let mounted = false;
|
55 |
+
onMount(() => {
|
56 |
+
mounted = true;
|
57 |
+
});
|
58 |
+
|
59 |
+
let draggedComponent: any = null;
|
60 |
+
let canvasRef: HTMLElement;
|
61 |
+
let selectedComponent: any = null;
|
62 |
+
let searchFilter = "";
|
63 |
+
let selectedCategory = "All";
|
64 |
+
|
65 |
+
// Ensure components are always available
|
66 |
+
$: allComponents = Object.values(componentsByCategory).flat();
|
67 |
+
|
68 |
+
$: filteredComponents = (() => {
|
69 |
+
if (selectedCategory === "All") {
|
70 |
+
let components = allComponents;
|
71 |
+
|
72 |
+
if (searchFilter.trim()) {
|
73 |
+
return components.filter(comp =>
|
74 |
+
comp.type.toLowerCase().includes(searchFilter.toLowerCase()) ||
|
75 |
+
comp.label.toLowerCase().includes(searchFilter.toLowerCase())
|
76 |
+
);
|
77 |
+
}
|
78 |
+
|
79 |
+
return components;
|
80 |
+
} else {
|
81 |
+
let components = componentsByCategory[selectedCategory] || [];
|
82 |
+
|
83 |
+
if (searchFilter.trim()) {
|
84 |
+
return components.filter(comp =>
|
85 |
+
comp.type.toLowerCase().includes(searchFilter.toLowerCase()) ||
|
86 |
+
comp.label.toLowerCase().includes(searchFilter.toLowerCase())
|
87 |
+
);
|
88 |
+
}
|
89 |
+
|
90 |
+
return components;
|
91 |
+
}
|
92 |
+
})();
|
93 |
+
|
94 |
+
// Use this to display components on initial load
|
95 |
+
$: displayComponents = mounted ? filteredComponents : allComponents;
|
96 |
+
|
97 |
+
function onDragStart(event: DragEvent, componentType: any) {
|
98 |
+
draggedComponent = componentType;
|
99 |
+
if (event.dataTransfer) {
|
100 |
+
event.dataTransfer.effectAllowed = "copy";
|
101 |
+
}
|
102 |
+
}
|
103 |
+
|
104 |
+
function onDragOver(event: DragEvent) {
|
105 |
+
event.preventDefault();
|
106 |
+
if (event.dataTransfer) {
|
107 |
+
event.dataTransfer.dropEffect = "copy";
|
108 |
+
}
|
109 |
+
}
|
110 |
+
|
111 |
+
function onDrop(event: DragEvent) {
|
112 |
+
event.preventDefault();
|
113 |
+
if (!draggedComponent) return;
|
114 |
+
|
115 |
+
const rect = canvasRef.getBoundingClientRect();
|
116 |
+
const x = event.clientX - rect.left;
|
117 |
+
const y = event.clientY - rect.top;
|
118 |
+
|
119 |
+
const newComponent = {
|
120 |
+
id: `${draggedComponent.type.toLowerCase()}_${Date.now()}`,
|
121 |
+
type: draggedComponent.type,
|
122 |
+
position: { x, y },
|
123 |
+
size: { width: 200, height: 100 },
|
124 |
+
props: getDefaultProps(draggedComponent.type)
|
125 |
+
};
|
126 |
+
|
127 |
+
value = {
|
128 |
+
...value,
|
129 |
+
components: [...value.components, newComponent]
|
130 |
+
};
|
131 |
+
|
132 |
+
gradio.dispatch("change", value);
|
133 |
+
draggedComponent = null;
|
134 |
+
}
|
135 |
+
|
136 |
+
function getDefaultProps(type: string) {
|
137 |
+
const defaults = {
|
138 |
+
Textbox: { label: "Text Input", placeholder: "Enter text...", value: "" },
|
139 |
+
TextArea: { label: "Text Area", placeholder: "Enter multiple lines...", lines: 3, value: "" },
|
140 |
+
Button: { value: "Click me", variant: "secondary", size: "sm" },
|
141 |
+
Slider: { label: "Slider", minimum: 0, maximum: 100, step: 1, value: 50 },
|
142 |
+
Number: { label: "Number", value: 0, precision: 0 },
|
143 |
+
Checkbox: { label: "Checkbox", value: false },
|
144 |
+
CheckboxGroup: { label: "Checkbox Group", choices: ["Option 1", "Option 2"], value: [] },
|
145 |
+
Radio: { label: "Radio", choices: ["Option 1", "Option 2"], value: "Option 1" },
|
146 |
+
Dropdown: { label: "Dropdown", choices: ["Option 1", "Option 2"], value: "Option 1", multiselect: false },
|
147 |
+
Toggle: { label: "Toggle", value: false },
|
148 |
+
ColorPicker: { label: "Color Picker", value: "#ff0000" },
|
149 |
+
Date: { label: "Date", value: "2025-01-01" },
|
150 |
+
Time: { label: "Time", value: "12:00" },
|
151 |
+
File: { label: "Upload File", file_types: [".txt", ".pdf"] },
|
152 |
+
Image: { label: "Image", type: "pil", interactive: true },
|
153 |
+
Video: { label: "Video", format: "mp4" },
|
154 |
+
Audio: { label: "Audio" },
|
155 |
+
Dataframe: { headers: ["Column 1", "Column 2"], datatype: ["str", "str"], value: [] },
|
156 |
+
JSON: { value: "{}" },
|
157 |
+
Markdown: { value: "# Markdown Text" },
|
158 |
+
HTML: { value: "<p>HTML Content</p>" },
|
159 |
+
Label: { value: "Label Text" },
|
160 |
+
Progress: { value: 0.5 }
|
161 |
+
};
|
162 |
+
return defaults[type] || {};
|
163 |
+
}
|
164 |
+
|
165 |
+
function selectComponent(component: any) {
|
166 |
+
selectedComponent = component;
|
167 |
+
}
|
168 |
+
|
169 |
+
function updateComponentProp(prop: string, newValue: any) {
|
170 |
+
if (!selectedComponent) return;
|
171 |
+
|
172 |
+
// Handle special input types
|
173 |
+
if (prop === "choices" && typeof newValue === "string") {
|
174 |
+
newValue = newValue.split(",").map(s => s.trim()).filter(s => s);
|
175 |
+
} else if (prop === "file_types" && typeof newValue === "string") {
|
176 |
+
newValue = newValue.split(",").map(s => s.trim()).filter(s => s);
|
177 |
+
}
|
178 |
+
|
179 |
+
const updatedComponents = value.components.map(comp =>
|
180 |
+
comp.id === selectedComponent.id
|
181 |
+
? { ...comp, props: { ...comp.props, [prop]: newValue }}
|
182 |
+
: comp
|
183 |
+
);
|
184 |
+
|
185 |
+
selectedComponent = { ...selectedComponent, props: { ...selectedComponent.props, [prop]: newValue }};
|
186 |
+
value = { ...value, components: updatedComponents };
|
187 |
+
gradio.dispatch("change", value);
|
188 |
+
}
|
189 |
+
|
190 |
+
function updateComponentPosition(component: any, newX: number, newY: number) {
|
191 |
+
const updatedComponents = value.components.map(comp =>
|
192 |
+
comp.id === component.id
|
193 |
+
? { ...comp, position: { x: newX, y: newY }}
|
194 |
+
: comp
|
195 |
+
);
|
196 |
+
|
197 |
+
value = { ...value, components: updatedComponents };
|
198 |
+
gradio.dispatch("change", value);
|
199 |
+
}
|
200 |
+
|
201 |
+
function updateComponentSize(component: any, newWidth: number, newHeight: number) {
|
202 |
+
const updatedComponents = value.components.map(comp =>
|
203 |
+
comp.id === component.id
|
204 |
+
? { ...comp, size: { width: newWidth, height: newHeight }}
|
205 |
+
: comp
|
206 |
+
);
|
207 |
+
|
208 |
+
if (selectedComponent?.id === component.id) {
|
209 |
+
selectedComponent = { ...selectedComponent, size: { width: newWidth, height: newHeight }};
|
210 |
+
}
|
211 |
+
|
212 |
+
value = { ...value, components: updatedComponents };
|
213 |
+
gradio.dispatch("change", value);
|
214 |
+
}
|
215 |
+
|
216 |
+
function deleteComponent(componentId: string) {
|
217 |
+
const updatedComponents = value.components.filter(comp => comp.id !== componentId);
|
218 |
+
value = { ...value, components: updatedComponents };
|
219 |
+
selectedComponent = null;
|
220 |
+
gradio.dispatch("change", value);
|
221 |
+
}
|
222 |
+
|
223 |
+
function exportAsJSON() {
|
224 |
+
const exportData = {
|
225 |
+
...value,
|
226 |
+
metadata: {
|
227 |
+
version: "1.0",
|
228 |
+
created_at: new Date().toISOString(),
|
229 |
+
app_type: "gradio_interface",
|
230 |
+
component_count: value.components.length
|
231 |
+
}
|
232 |
+
};
|
233 |
+
|
234 |
+
const jsonString = JSON.stringify(exportData, null, 2);
|
235 |
+
const blob = new Blob([jsonString], { type: 'application/json' });
|
236 |
+
const url = URL.createObjectURL(blob);
|
237 |
+
const a = document.createElement('a');
|
238 |
+
a.href = url;
|
239 |
+
a.download = 'gradio-design.json';
|
240 |
+
a.click();
|
241 |
+
URL.revokeObjectURL(url);
|
242 |
+
}
|
243 |
+
|
244 |
+
function exportAsPNG() {
|
245 |
+
try {
|
246 |
+
const canvas = document.createElement('canvas');
|
247 |
+
const ctx = canvas.getContext('2d');
|
248 |
+
|
249 |
+
const rect = canvasRef.getBoundingClientRect();
|
250 |
+
canvas.width = rect.width * 2;
|
251 |
+
canvas.height = rect.height * 2;
|
252 |
+
|
253 |
+
ctx.scale(2, 2);
|
254 |
+
|
255 |
+
// White background
|
256 |
+
ctx.fillStyle = '#ffffff';
|
257 |
+
ctx.fillRect(0, 0, rect.width, rect.height);
|
258 |
+
|
259 |
+
// Draw grid
|
260 |
+
ctx.strokeStyle = 'rgba(0,0,0,0.1)';
|
261 |
+
ctx.lineWidth = 1;
|
262 |
+
for (let x = 0; x <= rect.width; x += 20) {
|
263 |
+
ctx.moveTo(x, 0);
|
264 |
+
ctx.lineTo(x, rect.height);
|
265 |
+
}
|
266 |
+
for (let y = 0; y <= rect.height; y += 20) {
|
267 |
+
ctx.moveTo(0, y);
|
268 |
+
ctx.lineTo(rect.width, y);
|
269 |
+
}
|
270 |
+
ctx.stroke();
|
271 |
+
|
272 |
+
// Draw components
|
273 |
+
value.components.forEach(component => {
|
274 |
+
const componentDef = allComponents.find(c => c.type === component.type);
|
275 |
+
|
276 |
+
ctx.fillStyle = '#ffffff';
|
277 |
+
ctx.strokeStyle = '#ddd';
|
278 |
+
ctx.lineWidth = 2;
|
279 |
+
|
280 |
+
ctx.fillRect(component.position.x, component.position.y, component.size.width, component.size.height);
|
281 |
+
ctx.strokeRect(component.position.x, component.position.y, component.size.width, component.size.height);
|
282 |
+
|
283 |
+
// Component icon and text
|
284 |
+
ctx.fillStyle = '#333';
|
285 |
+
ctx.font = '16px Arial';
|
286 |
+
ctx.textAlign = 'center';
|
287 |
+
ctx.fillText(
|
288 |
+
componentDef?.icon || '📦',
|
289 |
+
component.position.x + component.size.width/2,
|
290 |
+
component.position.y + 25
|
291 |
+
);
|
292 |
+
|
293 |
+
ctx.font = '12px Arial';
|
294 |
+
ctx.fillText(
|
295 |
+
component.type,
|
296 |
+
component.position.x + component.size.width/2,
|
297 |
+
component.position.y + component.size.height/2
|
298 |
+
);
|
299 |
+
|
300 |
+
ctx.fillText(
|
301 |
+
component.props.label || component.props.value || '',
|
302 |
+
component.position.x + component.size.width/2,
|
303 |
+
component.position.y + component.size.height/2 + 15
|
304 |
+
);
|
305 |
+
});
|
306 |
+
|
307 |
+
const link = document.createElement('a');
|
308 |
+
link.download = 'gradio-design.png';
|
309 |
+
link.href = canvas.toDataURL('image/png');
|
310 |
+
link.click();
|
311 |
+
|
312 |
+
} catch (error) {
|
313 |
+
console.error('Canvas export failed:', error);
|
314 |
+
alert('PNG export failed. Check console for details.');
|
315 |
+
}
|
316 |
+
}
|
317 |
+
|
318 |
+
// Make components draggable within canvas
|
319 |
+
let isDragging = false;
|
320 |
+
let dragOffset = { x: 0, y: 0 };
|
321 |
+
|
322 |
+
function onComponentMouseDown(event: MouseEvent, component: any) {
|
323 |
+
if (event.button !== 0) return; // Only left click
|
324 |
+
|
325 |
+
isDragging = true;
|
326 |
+
selectedComponent = component;
|
327 |
+
|
328 |
+
const rect = canvasRef.getBoundingClientRect();
|
329 |
+
dragOffset.x = event.clientX - rect.left - component.position.x;
|
330 |
+
dragOffset.y = event.clientY - rect.top - component.position.y;
|
331 |
+
|
332 |
+
event.preventDefault();
|
333 |
+
}
|
334 |
+
|
335 |
+
function onCanvasMouseMove(event: MouseEvent) {
|
336 |
+
if (!isDragging || !selectedComponent) return;
|
337 |
+
|
338 |
+
const rect = canvasRef.getBoundingClientRect();
|
339 |
+
const newX = event.clientX - rect.left - dragOffset.x;
|
340 |
+
const newY = event.clientY - rect.top - dragOffset.y;
|
341 |
+
|
342 |
+
updateComponentPosition(selectedComponent, Math.max(0, newX), Math.max(0, newY));
|
343 |
+
}
|
344 |
+
|
345 |
+
function onCanvasMouseUp() {
|
346 |
+
isDragging = false;
|
347 |
+
}
|
348 |
+
</script>
|
349 |
+
|
350 |
+
<svelte:window on:mousemove={onCanvasMouseMove} on:mouseup={onCanvasMouseUp} />
|
351 |
+
|
352 |
+
<div class="designer-container" id={elem_id}>
|
353 |
+
<!-- Top Toolbar -->
|
354 |
+
<div class="toolbar">
|
355 |
+
<div class="toolbar-left">
|
356 |
+
<h3>🎨 Gradio Designer</h3>
|
357 |
+
<span class="component-count">{value.components.length} components</span>
|
358 |
+
</div>
|
359 |
+
<div class="toolbar-right">
|
360 |
+
<button class="export-btn" on:click={exportAsJSON} type="button">
|
361 |
+
📄 Export JSON
|
362 |
+
</button>
|
363 |
+
<button class="export-btn" on:click={exportAsPNG} type="button">
|
364 |
+
🖼️ Export PNG
|
365 |
+
</button>
|
366 |
+
</div>
|
367 |
+
</div>
|
368 |
+
|
369 |
+
<div class="designer-content">
|
370 |
+
<!-- Component Palette - Always on the left -->
|
371 |
+
<div class="palette">
|
372 |
+
<div class="palette-header">
|
373 |
+
<h4>Components</h4>
|
374 |
+
<input
|
375 |
+
type="text"
|
376 |
+
placeholder="Search components..."
|
377 |
+
bind:value={searchFilter}
|
378 |
+
class="search-input"
|
379 |
+
/>
|
380 |
+
<select bind:value={selectedCategory} class="category-select">
|
381 |
+
<option value="All">All Categories</option>
|
382 |
+
{#each Object.keys(componentsByCategory) as category}
|
383 |
+
<option value={category}>{category}</option>
|
384 |
+
{/each}
|
385 |
+
</select>
|
386 |
+
</div>
|
387 |
+
|
388 |
+
<div class="palette-content">
|
389 |
+
{#each displayComponents as component}
|
390 |
+
<div
|
391 |
+
class="palette-item"
|
392 |
+
draggable="true"
|
393 |
+
on:dragstart={(e) => onDragStart(e, component)}
|
394 |
+
>
|
395 |
+
<span class="icon">{component.icon}</span>
|
396 |
+
<span class="label">{component.label}</span>
|
397 |
+
</div>
|
398 |
+
{:else}
|
399 |
+
<div class="no-components">
|
400 |
+
{#if searchFilter.trim()}
|
401 |
+
No components match "{searchFilter}"
|
402 |
+
{:else}
|
403 |
+
Loading components...
|
404 |
+
{/if}
|
405 |
+
</div>
|
406 |
+
{/each}
|
407 |
+
</div>
|
408 |
+
</div>
|
409 |
+
|
410 |
+
<!-- Design Canvas -->
|
411 |
+
<div
|
412 |
+
class="canvas"
|
413 |
+
bind:this={canvasRef}
|
414 |
+
on:dragover={onDragOver}
|
415 |
+
on:drop={onDrop}
|
416 |
+
>
|
417 |
+
<div class="canvas-grid"></div>
|
418 |
+
{#each value.components as component (component.id)}
|
419 |
+
<div
|
420 |
+
class="canvas-component"
|
421 |
+
class:selected={selectedComponent?.id === component.id}
|
422 |
+
style="
|
423 |
+
left: {component.position.x}px;
|
424 |
+
top: {component.position.y}px;
|
425 |
+
width: {component.size.width}px;
|
426 |
+
height: {component.size.height}px;
|
427 |
+
"
|
428 |
+
on:click={() => selectComponent(component)}
|
429 |
+
on:mousedown={(e) => onComponentMouseDown(e, component)}
|
430 |
+
>
|
431 |
+
<div class="component-preview">
|
432 |
+
<div class="component-header">
|
433 |
+
<span class="type">{component.type}</span>
|
434 |
+
<button
|
435 |
+
class="delete-btn"
|
436 |
+
on:click|stopPropagation={() => deleteComponent(component.id)}
|
437 |
+
type="button"
|
438 |
+
>
|
439 |
+
❌
|
440 |
+
</button>
|
441 |
+
</div>
|
442 |
+
<span class="label">{component.props.label || component.props.value || 'Component'}</span>
|
443 |
+
</div>
|
444 |
+
</div>
|
445 |
+
{/each}
|
446 |
+
</div>
|
447 |
+
|
448 |
+
<!-- Properties Panel -->
|
449 |
+
<div class="properties">
|
450 |
+
<h4>Properties</h4>
|
451 |
+
{#if selectedComponent}
|
452 |
+
<div class="property-group">
|
453 |
+
<div class="property-header">
|
454 |
+
<strong>Type:</strong> {selectedComponent.type}
|
455 |
+
<br>
|
456 |
+
<small>ID: {selectedComponent.id}</small>
|
457 |
+
</div>
|
458 |
+
|
459 |
+
<!-- Component Properties -->
|
460 |
+
{#if selectedComponent.props.label !== undefined}
|
461 |
+
<label>Label:</label>
|
462 |
+
<input
|
463 |
+
type="text"
|
464 |
+
placeholder="Label"
|
465 |
+
value={selectedComponent.props.label}
|
466 |
+
on:input={(e) => updateComponentProp('label', e.target.value)}
|
467 |
+
/>
|
468 |
+
{/if}
|
469 |
+
|
470 |
+
{#if selectedComponent.props.placeholder !== undefined}
|
471 |
+
<label>Placeholder:</label>
|
472 |
+
<input
|
473 |
+
type="text"
|
474 |
+
placeholder="Placeholder"
|
475 |
+
value={selectedComponent.props.placeholder}
|
476 |
+
on:input={(e) => updateComponentProp('placeholder', e.target.value)}
|
477 |
+
/>
|
478 |
+
{/if}
|
479 |
+
|
480 |
+
{#if selectedComponent.props.value !== undefined}
|
481 |
+
<label>Value:</label>
|
482 |
+
{#if typeof selectedComponent.props.value === 'boolean'}
|
483 |
+
<input
|
484 |
+
type="checkbox"
|
485 |
+
checked={selectedComponent.props.value}
|
486 |
+
on:change={(e) => updateComponentProp('value', e.target.checked)}
|
487 |
+
/>
|
488 |
+
{:else if typeof selectedComponent.props.value === 'number'}
|
489 |
+
<input
|
490 |
+
type="number"
|
491 |
+
value={selectedComponent.props.value}
|
492 |
+
on:input={(e) => updateComponentProp('value', parseFloat(e.target.value) || 0)}
|
493 |
+
/>
|
494 |
+
{:else}
|
495 |
+
<input
|
496 |
+
type="text"
|
497 |
+
placeholder="Value"
|
498 |
+
value={selectedComponent.props.value}
|
499 |
+
on:input={(e) => updateComponentProp('value', e.target.value)}
|
500 |
+
/>
|
501 |
+
{/if}
|
502 |
+
{/if}
|
503 |
+
|
504 |
+
{#if selectedComponent.props.choices !== undefined}
|
505 |
+
<label>Choices (comma-separated):</label>
|
506 |
+
<input
|
507 |
+
type="text"
|
508 |
+
placeholder="Option 1, Option 2, Option 3"
|
509 |
+
value={Array.isArray(selectedComponent.props.choices) ? selectedComponent.props.choices.join(", ") : selectedComponent.props.choices}
|
510 |
+
on:input={(e) => updateComponentProp('choices', e.target.value)}
|
511 |
+
/>
|
512 |
+
{/if}
|
513 |
+
|
514 |
+
{#if selectedComponent.props.minimum !== undefined}
|
515 |
+
<label>Minimum:</label>
|
516 |
+
<input
|
517 |
+
type="number"
|
518 |
+
value={selectedComponent.props.minimum}
|
519 |
+
on:input={(e) => updateComponentProp('minimum', parseFloat(e.target.value) || 0)}
|
520 |
+
/>
|
521 |
+
{/if}
|
522 |
+
|
523 |
+
{#if selectedComponent.props.maximum !== undefined}
|
524 |
+
<label>Maximum:</label>
|
525 |
+
<input
|
526 |
+
type="number"
|
527 |
+
value={selectedComponent.props.maximum}
|
528 |
+
on:input={(e) => updateComponentProp('maximum', parseFloat(e.target.value) || 100)}
|
529 |
+
/>
|
530 |
+
{/if}
|
531 |
+
|
532 |
+
{#if selectedComponent.props.step !== undefined}
|
533 |
+
<label>Step:</label>
|
534 |
+
<input
|
535 |
+
type="number"
|
536 |
+
value={selectedComponent.props.step}
|
537 |
+
on:input={(e) => updateComponentProp('step', parseFloat(e.target.value) || 1)}
|
538 |
+
/>
|
539 |
+
{/if}
|
540 |
+
|
541 |
+
<!-- Size Controls -->
|
542 |
+
<div class="size-section">
|
543 |
+
<h5>Size & Position</h5>
|
544 |
+
<div class="size-controls">
|
545 |
+
<label>Width:</label>
|
546 |
+
<input
|
547 |
+
type="number"
|
548 |
+
value={selectedComponent.size.width}
|
549 |
+
on:input={(e) => updateComponentSize(selectedComponent, parseInt(e.target.value) || 200, selectedComponent.size.height)}
|
550 |
+
/>
|
551 |
+
|
552 |
+
<label>Height:</label>
|
553 |
+
<input
|
554 |
+
type="number"
|
555 |
+
value={selectedComponent.size.height}
|
556 |
+
on:input={(e) => updateComponentSize(selectedComponent, selectedComponent.size.width, parseInt(e.target.value) || 100)}
|
557 |
+
/>
|
558 |
+
|
559 |
+
<label>X Position:</label>
|
560 |
+
<input
|
561 |
+
type="number"
|
562 |
+
value={selectedComponent.position.x}
|
563 |
+
on:input={(e) => updateComponentPosition(selectedComponent, parseInt(e.target.value) || 0, selectedComponent.position.y)}
|
564 |
+
/>
|
565 |
+
|
566 |
+
<label>Y Position:</label>
|
567 |
+
<input
|
568 |
+
type="number"
|
569 |
+
value={selectedComponent.position.y}
|
570 |
+
on:input={(e) => updateComponentPosition(selectedComponent, selectedComponent.position.x, parseInt(e.target.value) || 0)}
|
571 |
+
/>
|
572 |
+
</div>
|
573 |
+
</div>
|
574 |
+
</div>
|
575 |
+
{:else}
|
576 |
+
<p>Select a component to edit properties</p>
|
577 |
+
<div class="help-text">
|
578 |
+
<strong>How to use:</strong>
|
579 |
+
<ul>
|
580 |
+
<li>Drag components from the palette to the canvas</li>
|
581 |
+
<li>Click components to select and edit them</li>
|
582 |
+
<li>Drag components around the canvas to reposition</li>
|
583 |
+
<li>Use the properties panel to customize</li>
|
584 |
+
</ul>
|
585 |
+
</div>
|
586 |
+
{/if}
|
587 |
+
</div>
|
588 |
+
</div>
|
589 |
+
</div>
|
590 |
+
|
591 |
+
<style>
|
592 |
+
.designer-container {
|
593 |
+
display: flex;
|
594 |
+
flex-direction: column;
|
595 |
+
height: 700px;
|
596 |
+
border: 1px solid #ddd;
|
597 |
+
border-radius: 8px;
|
598 |
+
overflow: hidden;
|
599 |
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
600 |
+
}
|
601 |
+
|
602 |
+
.toolbar {
|
603 |
+
display: flex;
|
604 |
+
justify-content: space-between;
|
605 |
+
align-items: center;
|
606 |
+
padding: 12px 16px;
|
607 |
+
background: #f8f9fa;
|
608 |
+
border-bottom: 1px solid #ddd;
|
609 |
+
}
|
610 |
+
|
611 |
+
.toolbar-left {
|
612 |
+
display: flex;
|
613 |
+
align-items: center;
|
614 |
+
gap: 12px;
|
615 |
+
}
|
616 |
+
|
617 |
+
.toolbar h3 {
|
618 |
+
margin: 0;
|
619 |
+
font-size: 16px;
|
620 |
+
font-weight: 600;
|
621 |
+
}
|
622 |
+
|
623 |
+
.component-count {
|
624 |
+
background: #e9ecef;
|
625 |
+
padding: 2px 8px;
|
626 |
+
border-radius: 12px;
|
627 |
+
font-size: 12px;
|
628 |
+
color: #495057;
|
629 |
+
}
|
630 |
+
|
631 |
+
.toolbar-right {
|
632 |
+
display: flex;
|
633 |
+
gap: 8px;
|
634 |
+
}
|
635 |
+
|
636 |
+
.export-btn {
|
637 |
+
padding: 6px 12px;
|
638 |
+
background: #007bff;
|
639 |
+
color: white;
|
640 |
+
border: none;
|
641 |
+
border-radius: 4px;
|
642 |
+
cursor: pointer;
|
643 |
+
font-size: 12px;
|
644 |
+
}
|
645 |
+
|
646 |
+
.export-btn:hover {
|
647 |
+
background: #0056b3;
|
648 |
+
}
|
649 |
+
|
650 |
+
/* CRITICAL FIX: Force grid layout with !important to ensure initial render is correct */
|
651 |
+
.designer-content {
|
652 |
+
display: grid !important;
|
653 |
+
grid-template-columns: 250px 1fr 280px !important;
|
654 |
+
grid-template-areas: "palette canvas properties" !important;
|
655 |
+
flex: 1;
|
656 |
+
height: 100%;
|
657 |
+
min-height: 0; /* Force grid to work immediately */
|
658 |
+
}
|
659 |
+
|
660 |
+
/* CRITICAL FIX: Use grid-area with !important to lock positions */
|
661 |
+
.palette {
|
662 |
+
grid-area: palette !important;
|
663 |
+
background: #f8f9fa;
|
664 |
+
border-right: 1px solid #ddd;
|
665 |
+
display: flex;
|
666 |
+
flex-direction: column;
|
667 |
+
overflow: hidden;
|
668 |
+
}
|
669 |
+
|
670 |
+
.canvas {
|
671 |
+
grid-area: canvas !important;
|
672 |
+
position: relative;
|
673 |
+
background: white;
|
674 |
+
overflow: hidden;
|
675 |
+
user-select: none;
|
676 |
+
}
|
677 |
+
|
678 |
+
.properties {
|
679 |
+
grid-area: properties !important;
|
680 |
+
background: #f8f9fa;
|
681 |
+
padding: 16px;
|
682 |
+
border-left: 1px solid #ddd;
|
683 |
+
overflow-y: auto;
|
684 |
+
}
|
685 |
+
|
686 |
+
.palette-header {
|
687 |
+
padding: 12px 16px;
|
688 |
+
border-bottom: 1px solid #ddd;
|
689 |
+
background: white;
|
690 |
+
flex-shrink: 0;
|
691 |
+
min-height: 120px;
|
692 |
+
max-height: 120px;
|
693 |
+
overflow: hidden;
|
694 |
+
}
|
695 |
+
|
696 |
+
.palette h4 {
|
697 |
+
margin: 0 0 8px 0;
|
698 |
+
font-size: 14px;
|
699 |
+
font-weight: 600;
|
700 |
+
}
|
701 |
+
|
702 |
+
.search-input, .category-select {
|
703 |
+
width: 100%;
|
704 |
+
padding: 6px 8px;
|
705 |
+
border: 1px solid #ddd;
|
706 |
+
border-radius: 4px;
|
707 |
+
font-size: 12px;
|
708 |
+
margin-bottom: 6px;
|
709 |
+
box-sizing: border-box;
|
710 |
+
}
|
711 |
+
|
712 |
+
.palette-content {
|
713 |
+
flex: 1;
|
714 |
+
overflow-y: auto;
|
715 |
+
padding: 8px;
|
716 |
+
min-height: 0;
|
717 |
+
background: #f8f9fa;
|
718 |
+
}
|
719 |
+
|
720 |
+
.palette-item {
|
721 |
+
display: flex;
|
722 |
+
align-items: center;
|
723 |
+
padding: 8px;
|
724 |
+
margin-bottom: 4px;
|
725 |
+
background: white;
|
726 |
+
border: 1px solid #e1e5e9;
|
727 |
+
border-radius: 4px;
|
728 |
+
cursor: grab;
|
729 |
+
user-select: none;
|
730 |
+
}
|
731 |
+
|
732 |
+
.palette-item:hover {
|
733 |
+
background: #f0f0f0;
|
734 |
+
}
|
735 |
+
|
736 |
+
.no-components {
|
737 |
+
padding: 20px;
|
738 |
+
text-align: center;
|
739 |
+
color: #666;
|
740 |
+
font-size: 12px;
|
741 |
+
background: white;
|
742 |
+
border-radius: 4px;
|
743 |
+
border: 1px solid #e1e5e9;
|
744 |
+
}
|
745 |
+
|
746 |
+
.icon {
|
747 |
+
margin-right: 8px;
|
748 |
+
font-size: 16px;
|
749 |
+
}
|
750 |
+
|
751 |
+
.label {
|
752 |
+
font-size: 12px;
|
753 |
+
}
|
754 |
+
|
755 |
+
.canvas-grid {
|
756 |
+
position: absolute;
|
757 |
+
top: 0;
|
758 |
+
left: 0;
|
759 |
+
right: 0;
|
760 |
+
bottom: 0;
|
761 |
+
background-image:
|
762 |
+
linear-gradient(rgba(0,0,0,0.1) 1px, transparent 1px),
|
763 |
+
linear-gradient(90deg, rgba(0,0,0,0.1) 1px, transparent 1px);
|
764 |
+
background-size: 20px 20px;
|
765 |
+
opacity: 0.3;
|
766 |
+
}
|
767 |
+
|
768 |
+
.canvas-component {
|
769 |
+
position: absolute;
|
770 |
+
border: 2px solid #ddd;
|
771 |
+
border-radius: 4px;
|
772 |
+
background: white;
|
773 |
+
cursor: move;
|
774 |
+
padding: 8px;
|
775 |
+
box-sizing: border-box;
|
776 |
+
}
|
777 |
+
|
778 |
+
.canvas-component:hover {
|
779 |
+
border-color: #007bff;
|
780 |
+
}
|
781 |
+
|
782 |
+
.canvas-component.selected {
|
783 |
+
border-color: #ff6b6b;
|
784 |
+
box-shadow: 0 0 0 2px rgba(255, 107, 107, 0.3);
|
785 |
+
}
|
786 |
+
|
787 |
+
.component-preview {
|
788 |
+
display: flex;
|
789 |
+
flex-direction: column;
|
790 |
+
height: 100%;
|
791 |
+
text-align: center;
|
792 |
+
pointer-events: none;
|
793 |
+
}
|
794 |
+
|
795 |
+
.component-header {
|
796 |
+
display: flex;
|
797 |
+
justify-content: space-between;
|
798 |
+
align-items: center;
|
799 |
+
margin-bottom: 4px;
|
800 |
+
}
|
801 |
+
|
802 |
+
.type {
|
803 |
+
font-weight: bold;
|
804 |
+
font-size: 12px;
|
805 |
+
color: #666;
|
806 |
+
}
|
807 |
+
|
808 |
+
.delete-btn {
|
809 |
+
background: none;
|
810 |
+
border: none;
|
811 |
+
cursor: pointer;
|
812 |
+
font-size: 10px;
|
813 |
+
padding: 2px;
|
814 |
+
opacity: 0.7;
|
815 |
+
pointer-events: auto;
|
816 |
+
}
|
817 |
+
|
818 |
+
.delete-btn:hover {
|
819 |
+
opacity: 1;
|
820 |
+
}
|
821 |
+
|
822 |
+
.properties h4 {
|
823 |
+
margin: 0 0 16px 0;
|
824 |
+
font-size: 14px;
|
825 |
+
font-weight: 600;
|
826 |
+
}
|
827 |
+
|
828 |
+
.property-group {
|
829 |
+
display: flex;
|
830 |
+
flex-direction: column;
|
831 |
+
gap: 8px;
|
832 |
+
}
|
833 |
+
|
834 |
+
.property-header {
|
835 |
+
padding: 12px;
|
836 |
+
background: white;
|
837 |
+
border-radius: 4px;
|
838 |
+
border: 1px solid #e1e5e9;
|
839 |
+
margin-bottom: 12px;
|
840 |
+
}
|
841 |
+
|
842 |
+
.size-section {
|
843 |
+
margin-top: 16px;
|
844 |
+
padding-top: 16px;
|
845 |
+
border-top: 1px solid #ddd;
|
846 |
+
}
|
847 |
+
|
848 |
+
.size-section h5 {
|
849 |
+
margin: 0 0 8px 0;
|
850 |
+
font-size: 12px;
|
851 |
+
font-weight: 600;
|
852 |
+
}
|
853 |
+
|
854 |
+
.size-controls {
|
855 |
+
display: grid;
|
856 |
+
grid-template-columns: 1fr 1fr;
|
857 |
+
gap: 8px;
|
858 |
+
}
|
859 |
+
|
860 |
+
.property-group label {
|
861 |
+
font-size: 12px;
|
862 |
+
font-weight: 500;
|
863 |
+
color: #333;
|
864 |
+
}
|
865 |
+
|
866 |
+
.property-group input, .property-group select {
|
867 |
+
padding: 6px 8px;
|
868 |
+
border: 1px solid #ddd;
|
869 |
+
border-radius: 4px;
|
870 |
+
font-size: 12px;
|
871 |
+
}
|
872 |
+
|
873 |
+
.help-text {
|
874 |
+
margin-top: 20px;
|
875 |
+
padding: 12px;
|
876 |
+
background: white;
|
877 |
+
border-radius: 4px;
|
878 |
+
border: 1px solid #e1e5e9;
|
879 |
+
}
|
880 |
+
|
881 |
+
.help-text ul {
|
882 |
+
margin: 8px 0 0 0;
|
883 |
+
padding-left: 16px;
|
884 |
+
}
|
885 |
+
|
886 |
+
.help-text li {
|
887 |
+
font-size: 11px;
|
888 |
+
margin-bottom: 4px;
|
889 |
+
}
|
890 |
+
</style>
|
src/frontend/gradio.config.js
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export default {
|
2 |
+
plugins: [],
|
3 |
+
svelte: {
|
4 |
+
preprocess: [],
|
5 |
+
},
|
6 |
+
build: {
|
7 |
+
target: "modules",
|
8 |
+
},
|
9 |
+
};
|
src/frontend/package-lock.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
src/frontend/package.json
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"name": "gradio_gradiodesigner",
|
3 |
+
"version": "0.3.22",
|
4 |
+
"description": "Gradio UI packages",
|
5 |
+
"type": "module",
|
6 |
+
"author": "",
|
7 |
+
"license": "ISC",
|
8 |
+
"private": false,
|
9 |
+
"main_changeset": true,
|
10 |
+
"exports": {
|
11 |
+
".": {
|
12 |
+
"gradio": "./Index.svelte",
|
13 |
+
"svelte": "./dist/Index.svelte",
|
14 |
+
"types": "./dist/Index.svelte.d.ts"
|
15 |
+
},
|
16 |
+
"./example": {
|
17 |
+
"gradio": "./Example.svelte",
|
18 |
+
"svelte": "./dist/Example.svelte",
|
19 |
+
"types": "./dist/Example.svelte.d.ts"
|
20 |
+
},
|
21 |
+
"./package.json": "./package.json"
|
22 |
+
},
|
23 |
+
"dependencies": {
|
24 |
+
"@gradio/atoms": "0.16.1",
|
25 |
+
"@gradio/icons": "0.12.0",
|
26 |
+
"@gradio/statustracker": "0.10.12",
|
27 |
+
"@gradio/utils": "0.10.2",
|
28 |
+
"svelte-moveable": "^0.45.0",
|
29 |
+
"html-to-image": "^1.9.0"
|
30 |
+
},
|
31 |
+
"devDependencies": {
|
32 |
+
"@gradio/preview": "0.13.1"
|
33 |
+
},
|
34 |
+
"peerDependencies": {
|
35 |
+
"svelte": "^4.0.0"
|
36 |
+
},
|
37 |
+
"repository": {
|
38 |
+
"type": "git",
|
39 |
+
"url": "git+https://github.com/gradio-app/gradio.git",
|
40 |
+
"directory": "js/simpletextbox"
|
41 |
+
}
|
42 |
+
}
|
src/frontend/tsconfig.json
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"compilerOptions": {
|
3 |
+
"allowJs": true,
|
4 |
+
"checkJs": true,
|
5 |
+
"esModuleInterop": true,
|
6 |
+
"forceConsistentCasingInFileNames": true,
|
7 |
+
"resolveJsonModule": true,
|
8 |
+
"skipLibCheck": true,
|
9 |
+
"sourceMap": true,
|
10 |
+
"strict": true,
|
11 |
+
"verbatimModuleSyntax": true
|
12 |
+
},
|
13 |
+
"exclude": ["node_modules", "dist", "./gradio.config.js"]
|
14 |
+
}
|
src/pyproject.toml
ADDED
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[build-system]
|
2 |
+
requires = [
|
3 |
+
"hatchling",
|
4 |
+
"hatch-requirements-txt",
|
5 |
+
"hatch-fancy-pypi-readme>=22.5.0",
|
6 |
+
]
|
7 |
+
build-backend = "hatchling.build"
|
8 |
+
|
9 |
+
[project]
|
10 |
+
name = "gradio_gradiodesigner"
|
11 |
+
version = "0.0.1"
|
12 |
+
description = "gradio designer"
|
13 |
+
readme = "README.md"
|
14 |
+
license = "apache-2.0"
|
15 |
+
requires-python = ">=3.10"
|
16 |
+
authors = [{ name = "YOUR NAME", email = "[email protected]" }]
|
17 |
+
keywords = ["gradio-custom-component", "gradio-template-SimpleTextbox", "designer", "drag and drop", "custom designs"]
|
18 |
+
# Add dependencies here
|
19 |
+
dependencies = ["gradio>=4.0,<6.0"]
|
20 |
+
classifiers = [
|
21 |
+
'Development Status :: 3 - Alpha',
|
22 |
+
'Operating System :: OS Independent',
|
23 |
+
'Programming Language :: Python :: 3',
|
24 |
+
'Programming Language :: Python :: 3 :: Only',
|
25 |
+
'Programming Language :: Python :: 3.8',
|
26 |
+
'Programming Language :: Python :: 3.9',
|
27 |
+
'Programming Language :: Python :: 3.10',
|
28 |
+
'Programming Language :: Python :: 3.11',
|
29 |
+
'Topic :: Scientific/Engineering',
|
30 |
+
'Topic :: Scientific/Engineering :: Artificial Intelligence',
|
31 |
+
'Topic :: Scientific/Engineering :: Visualization',
|
32 |
+
]
|
33 |
+
|
34 |
+
# The repository and space URLs are optional, but recommended.
|
35 |
+
# Adding a repository URL will create a badge in the auto-generated README that links to the repository.
|
36 |
+
# Adding a space URL will create a badge in the auto-generated README that links to the space.
|
37 |
+
# This will make it easy for people to find your deployed demo or source code when they
|
38 |
+
# encounter your project in the wild.
|
39 |
+
|
40 |
+
# [project.urls]
|
41 |
+
# repository = "your github repository"
|
42 |
+
# space = "your space url"
|
43 |
+
|
44 |
+
[project.optional-dependencies]
|
45 |
+
dev = ["build", "twine"]
|
46 |
+
|
47 |
+
[tool.hatch.build]
|
48 |
+
artifacts = ["/backend/gradio_gradiodesigner/templates", "*.pyi"]
|
49 |
+
|
50 |
+
[tool.hatch.build.targets.wheel]
|
51 |
+
packages = ["/backend/gradio_gradiodesigner"]
|