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 = "YOUREMAIL@domain.com" }]
|
| 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"]
|