basheer1414 commited on
Commit
472d17b
·
verified ·
1 Parent(s): 0b6a8c8

Okay do one thing let's remove the sidebar we don't want I think so because you can create like the toolbar on the left side also see you know the photoshop left side told bar excited like that I need and that water input card IV and section everything over there as a small small buttons again I don't small buttons I don't want waste any Canvas face okay and make the Canvas fill every balance and you didn't remove that position and size settings from the toolbar that of top under rotation I don't want that on the toolbox action I want its on any and I went what I am going to add any element on the Canvas I am and able to 100% customisation for that element you understand from the Canvas I am I need to enable the moving ragging I want I need enable is icing I need I want you to made make enable like the corner curving and that's adding distance of the shadow whatever I want and customisation of the element like 100% customisation on the canvas - Initial Deployment

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +1500 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Ui Creater
3
- emoji: 🌖
4
- colorFrom: purple
5
- colorTo: gray
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: ui-creater
3
+ emoji: 🐳
4
+ colorFrom: gray
5
+ colorTo: green
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,1500 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Enhanced UI Customization Tool</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <link rel="stylesheet" href="https://uiverse.io/galaxy/style.min.css">
10
+ <style>
11
+ /* Custom CSS for enhanced UI */
12
+ .sidebar {
13
+ transition: all 0.3s ease;
14
+ }
15
+ .sidebar.collapsed {
16
+ transform: translateX(-90%);
17
+ }
18
+ .sidebar.collapsed:hover {
19
+ transform: translateX(0);
20
+ }
21
+ #toggleSidebar {
22
+ transition: transform 0.3s ease;
23
+ position: relative;
24
+ z-index: 10;
25
+ }
26
+ .color-picker {
27
+ width: 30px;
28
+ height: 30px;
29
+ border-radius: 50%;
30
+ cursor: pointer;
31
+ transition: transform 0.2s;
32
+ }
33
+ .color-picker:hover {
34
+ transform: scale(1.2);
35
+ }
36
+ .gradient-preview {
37
+ width: 100%;
38
+ height: 60px;
39
+ border-radius: 8px;
40
+ margin-top: 10px;
41
+ }
42
+ .modal {
43
+ display: none;
44
+ position: fixed;
45
+ z-index: 100;
46
+ left: 0;
47
+ top: 0;
48
+ width: 100%;
49
+ height: 100%;
50
+ background-color: rgba(0,0,0,0.5);
51
+ }
52
+ .modal-content {
53
+ background-color: #f8fafc;
54
+ margin: 5% auto;
55
+ padding: 20px;
56
+ border-radius: 10px;
57
+ width: 80%;
58
+ max-width: 700px;
59
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
60
+ }
61
+ .code-editor {
62
+ width: 100%;
63
+ height: 300px;
64
+ font-family: 'Courier New', monospace;
65
+ padding: 10px;
66
+ border-radius: 5px;
67
+ border: 1px solid #cbd5e1;
68
+ resize: none;
69
+ }
70
+ .canvas-container {
71
+ position: relative;
72
+ border: 2px dashed #94a3b8;
73
+ background-color: #f1f5f9;
74
+ overflow: auto;
75
+ background-image:
76
+ linear-gradient(rgba(0, 0, 0, 0.05) 1px, transparent 1px),
77
+ linear-gradient(90deg, rgba(0, 0, 0, 0.05) 1px, transparent 1px);
78
+ background-size: 20px 20px;
79
+ }
80
+ .resize-handle {
81
+ position: absolute;
82
+ width: 12px;
83
+ height: 12px;
84
+ background-color: #3b82f6;
85
+ border-radius: 50%;
86
+ z-index: 10;
87
+ border: 2px solid white;
88
+ box-shadow: 0 0 2px rgba(0,0,0,0.5);
89
+ }
90
+ .resize-handle.nw { top: -6px; left: -6px; cursor: nw-resize; }
91
+ .resize-handle.ne { top: -6px; right: -6px; cursor: ne-resize; }
92
+ .resize-handle.sw { bottom: -6px; left: -6px; cursor: sw-resize; }
93
+ .resize-handle.se { bottom: -6px; right: -6px; cursor: se-resize; }
94
+ .toolbar {
95
+ transition: all 0.3s ease;
96
+ height: 32px;
97
+ }
98
+ .toolbar input[type="number"],
99
+ .toolbar input[type="text"],
100
+ .toolbar input[type="range"] {
101
+ height: 20px;
102
+ }
103
+ .toolbar button {
104
+ min-width: 24px;
105
+ }
106
+ .element-controls {
107
+ position: absolute;
108
+ top: -40px;
109
+ left: 0;
110
+ background-color: white;
111
+ padding: 5px;
112
+ border-radius: 5px;
113
+ box-shadow: 0 2px 5px rgba(0,0,0,0.2);
114
+ display: none;
115
+ }
116
+ .canvas-element:hover .element-controls {
117
+ display: block;
118
+ }
119
+ .tab-button {
120
+ transition: all 0.2s ease;
121
+ }
122
+ .tab-button.active {
123
+ background-color: #3b82f6;
124
+ color: white;
125
+ }
126
+ .uiverse-modal {
127
+ max-height: 80vh;
128
+ overflow-y: auto;
129
+ }
130
+
131
+ /* Galaxy component preview sizing */
132
+ .uiverse-element .button-galaxy {
133
+ transform: scale(0.8);
134
+ }
135
+
136
+ .uiverse-element .input-galaxy {
137
+ width: 200px;
138
+ }
139
+
140
+ .uiverse-element .card-galaxy {
141
+ transform: scale(0.8);
142
+ }
143
+
144
+ .uiverse-element .checkbox-galaxy {
145
+ transform: scale(0.8);
146
+ }
147
+
148
+ /* Make sure Galaxy components are visible on canvas */
149
+ .canvas-element .button-galaxy,
150
+ .canvas-element .input-galaxy,
151
+ .canvas-element .card-galaxy,
152
+ .canvas-element .checkbox-galaxy {
153
+ transform: scale(1);
154
+ }
155
+
156
+ /* Selection styles */
157
+ .canvas-element.selected {
158
+ outline: 2px solid #3b82f6;
159
+ outline-offset: 2px;
160
+ }
161
+
162
+ /* Rotation handle */
163
+ .rotation-handle {
164
+ position: absolute;
165
+ width: 20px;
166
+ height: 20px;
167
+ top: -30px;
168
+ left: 50%;
169
+ transform: translateX(-50%);
170
+ cursor: grab;
171
+ background-color: #3b82f6;
172
+ border-radius: 50%;
173
+ display: flex;
174
+ align-items: center;
175
+ justify-content: center;
176
+ color: white;
177
+ font-size: 10px;
178
+ z-index: 10;
179
+ }
180
+
181
+ /* Element ghost */
182
+ .element-ghost {
183
+ position: absolute;
184
+ opacity: 0.5;
185
+ pointer-events: none;
186
+ z-index: 100;
187
+ }
188
+
189
+ /* Grid toggle */
190
+ .grid-toggle {
191
+ position: absolute;
192
+ bottom: 10px;
193
+ right: 10px;
194
+ background: white;
195
+ padding: 5px 10px;
196
+ border-radius: 4px;
197
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
198
+ cursor: pointer;
199
+ z-index: 10;
200
+ }
201
+ </style>
202
+ </head>
203
+ <body class="bg-gray-100 h-screen flex flex-col">
204
+ <!-- Top Navigation -->
205
+ <header class="bg-white shadow-sm py-2 px-4 flex justify-between items-center">
206
+ <h1 class="text-xl font-bold text-gray-800">Enhanced UI Customization Tool</h1>
207
+ <div class="flex space-x-2">
208
+ <button id="htmlBtn" class="bg-blue-500 hover:bg-blue-600 text-white px-2 py-1 rounded text-xs">
209
+ <i class="fas fa-code mr-1"></i>HTML
210
+ </button>
211
+ <button id="cssBtn" class="bg-purple-500 hover:bg-purple-600 text-white px-2 py-1 rounded text-xs">
212
+ <i class="fab fa-css3-alt mr-1"></i>CSS
213
+ </button>
214
+ <button id="saveBtn" class="bg-green-500 hover:bg-green-600 text-white px-2 py-1 rounded text-xs">
215
+ <i class="fas fa-save mr-1"></i>Save
216
+ </button>
217
+ <button id="resetBtn" class="bg-red-500 hover:bg-red-600 text-white px-2 py-1 rounded text-xs">
218
+ <i class="fas fa-trash-alt mr-1"></i>Reset
219
+ </button>
220
+ </div>
221
+ </header>
222
+
223
+ <div class="flex flex-1 overflow-hidden">
224
+ <!-- Sidebar -->
225
+ <div id="sidebar" class="sidebar w-64 bg-gray-800 text-white h-full flex flex-col transition-all duration-300">
226
+ <div class="p-4 flex justify-between items-center bg-gray-900">
227
+ <h2 class="text-lg font-semibold">Elements</h2>
228
+ <button id="toggleSidebar" class="text-gray-400 hover:text-white">
229
+ <i class="fas fa-chevron-left"></i>
230
+ </button>
231
+ </div>
232
+ <div class="flex-1 overflow-y-auto p-4">
233
+ <div class="mb-6">
234
+ <h3 class="text-sm uppercase font-medium text-gray-400 mb-2">Basic Elements</h3>
235
+ <div class="space-y-2">
236
+ <button class="element-btn w-full text-left px-3 py-2 bg-gray-700 hover:bg-gray-600 rounded flex items-center" data-type="button">
237
+ <i class="fas fa-square mr-2"></i> Button
238
+ </button>
239
+ <button class="element-btn w-full text-left px-3 py-2 bg-gray-700 hover:bg-gray-600 rounded flex items-center" data-type="input">
240
+ <i class="fas fa-font mr-2"></i> Input
241
+ </button>
242
+ <button class="element-btn w-full text-left px-3 py-2 bg-gray-700 hover:bg-gray-600 rounded flex items-center" data-type="card">
243
+ <i class="fas fa-id-card mr-2"></i> Card
244
+ </button>
245
+ </div>
246
+ </div>
247
+ <div class="mb-6">
248
+ <h3 class="text-sm uppercase font-medium text-gray-400 mb-2">Containers</h3>
249
+ <div class="space-y-2">
250
+ <button class="element-btn w-full text-left px-3 py-2 bg-gray-700 hover:bg-gray-600 rounded flex items-center" data-type="div">
251
+ <i class="fas fa-square-full mr-2"></i> Div
252
+ </button>
253
+ <button class="element-btn w-full text-left px-3 py-2 bg-gray-700 hover:bg-gray-600 rounded flex items-center" data-type="section">
254
+ <i class="fas fa-border-all mr-2"></i> Section
255
+ </button>
256
+ </div>
257
+ </div>
258
+ <div class="mb-6">
259
+ <h3 class="text-sm uppercase font-medium text-gray-400 mb-2">Advanced</h3>
260
+ <div class="space-y-2">
261
+ <button id="uiverseBtn" class="w-full text-left px-3 py-2 bg-indigo-700 hover:bg-indigo-600 rounded flex items-center">
262
+ <i class="fas fa-magic mr-2"></i> Uiverse.io
263
+ </button>
264
+ <button class="element-btn w-full text-left px-3 py-2 bg-gray-700 hover:bg-gray-600 rounded flex items-center" data-type="custom">
265
+ <i class="fas fa-code mr-2"></i> Custom HTML
266
+ </button>
267
+ </div>
268
+ </div>
269
+ </div>
270
+ </div>
271
+
272
+ <!-- Main Content -->
273
+ <div class="flex-1 flex flex-col overflow-hidden">
274
+ <!-- Toolbar -->
275
+ <div class="toolbar bg-white border-b p-1 flex items-center space-x-2 overflow-x-auto text-xs">
276
+ <div class="flex items-center space-x-1">
277
+ <span>Pos:</span>
278
+ <input type="number" id="posX" placeholder="X" class="w-10 px-1 py-0.5 border rounded text-xs">
279
+ <input type="number" id="posY" placeholder="Y" class="w-10 px-1 py-0.5 border rounded text-xs">
280
+ </div>
281
+ <div class="flex items-center space-x-1">
282
+ <span>Size:</span>
283
+ <input type="number" id="width" placeholder="W" class="w-10 px-1 py-0.5 border rounded text-xs">
284
+ <input type="number" id="height" placeholder="H" class="w-10 px-1 py-0.5 border rounded text-xs">
285
+ </div>
286
+ <div class="flex items-center space-x-1">
287
+ <span>Rot:</span>
288
+ <input type="number" id="rotation" placeholder="deg" class="w-12 px-1 py-0.5 border rounded text-xs">
289
+ </div>
290
+ <div class="flex items-center space-x-1">
291
+ <span>Color:</span>
292
+ <input type="color" id="colorPicker" class="w-6 h-6 cursor-pointer">
293
+ </div>
294
+ <div class="flex items-center space-x-1">
295
+ <span>BG:</span>
296
+ <input type="color" id="bgColorPicker" class="w-6 h-6 cursor-pointer">
297
+ </div>
298
+ <div class="flex items-center space-x-1">
299
+ <button id="gradientBtn" class="px-1 py-0.5 bg-gray-200 rounded text-xs">Grad</button>
300
+ </div>
301
+ <div class="flex items-center space-x-1">
302
+ <span>Opacity:</span>
303
+ <input type="range" id="opacity" min="0" max="100" value="100" class="w-16">
304
+ </div>
305
+ <div class="flex items-center space-x-1">
306
+ <span>Z:</span>
307
+ <input type="number" id="zIndex" value="1" class="w-10 px-1 py-0.5 border rounded text-xs">
308
+ </div>
309
+ <div class="flex items-center space-x-1">
310
+ <button id="deleteBtn" class="px-1 py-0.5 bg-red-500 text-white rounded text-xs">
311
+ <i class="fas fa-trash-alt"></i>
312
+ </button>
313
+ </div>
314
+ <div class="flex items-center space-x-1">
315
+ <button id="duplicateBtn" class="px-1 py-0.5 bg-blue-500 text-white rounded text-xs">
316
+ <i class="fas fa-copy"></i>
317
+ </button>
318
+ </div>
319
+ <div class="flex items-center space-x-1">
320
+ <button id="newWindowBtn" class="px-1 py-0.5 bg-green-500 text-white rounded text-xs">
321
+ <i class="fas fa-plus"></i>
322
+ </button>
323
+ </div>
324
+ <div class="flex items-center space-x-1">
325
+ <button id="snapToggle" class="px-1 py-0.5 bg-yellow-500 text-white rounded text-xs">
326
+ <i class="fas fa-magnet"></i>
327
+ </button>
328
+ </div>
329
+ </div>
330
+
331
+ <!-- Canvas -->
332
+ <div id="canvasContainer" class="canvas-container flex-1 m-4 bg-white relative overflow-auto">
333
+ <div id="canvas" class="relative w-full h-full min-h-[500px]">
334
+ <!-- Elements will be added here -->
335
+ </div>
336
+ <div id="gridToggle" class="grid-toggle">
337
+ <i class="fas fa-th"></i> Grid
338
+ </div>
339
+ </div>
340
+ </div>
341
+ </div>
342
+
343
+ <!-- HTML Modal -->
344
+ <div id="htmlModal" class="modal">
345
+ <div class="modal-content">
346
+ <div class="flex justify-between items-center mb-4">
347
+ <h2 class="text-xl font-bold">HTML Editor</h2>
348
+ <button id="closeHtmlModal" class="text-gray-500 hover:text-gray-700">
349
+ <i class="fas fa-times"></i>
350
+ </button>
351
+ </div>
352
+ <textarea id="htmlEditor" class="code-editor" placeholder="Paste your HTML code here..."></textarea>
353
+ <div class="flex justify-end mt-4 space-x-2">
354
+ <button id="cancelHtmlBtn" class="px-4 py-2 bg-gray-300 hover:bg-gray-400 rounded">Cancel</button>
355
+ <button id="applyHtmlBtn" class="px-4 py-2 bg-blue-500 hover:bg-blue-600 text-white rounded">Apply</button>
356
+ </div>
357
+ </div>
358
+ </div>
359
+
360
+ <!-- CSS Modal -->
361
+ <div id="cssModal" class="modal">
362
+ <div class="modal-content">
363
+ <div class="flex justify-between items-center mb-4">
364
+ <h2 class="text-xl font-bold">CSS Editor</h2>
365
+ <button id="closeCssModal" class="text-gray-500 hover:text-gray-700">
366
+ <i class="fas fa-times"></i>
367
+ </button>
368
+ </div>
369
+ <textarea id="cssEditor" class="code-editor" placeholder="Paste your CSS code here..."></textarea>
370
+ <div class="flex justify-end mt-4 space-x-2">
371
+ <button id="cancelCssBtn" class="px-4 py-2 bg-gray-300 hover:bg-gray-400 rounded">Cancel</button>
372
+ <button id="applyCssBtn" class="px-4 py-2 bg-blue-500 hover:bg-blue-600 text-white rounded">Apply</button>
373
+ </div>
374
+ </div>
375
+ </div>
376
+
377
+ <!-- Gradient Modal -->
378
+ <div id="gradientModal" class="modal">
379
+ <div class="modal-content">
380
+ <div class="flex justify-between items-center mb-4">
381
+ <h2 class="text-xl font-bold">Gradient Editor</h2>
382
+ <button id="closeGradientModal" class="text-gray-500 hover:text-gray-700">
383
+ <i class="fas fa-times"></i>
384
+ </button>
385
+ </div>
386
+ <div class="grid grid-cols-2 gap-4">
387
+ <div>
388
+ <label class="block text-sm font-medium mb-1">Gradient Type</label>
389
+ <select id="gradientType" class="w-full p-2 border rounded">
390
+ <option value="linear">Linear</option>
391
+ <option value="radial">Radial</option>
392
+ </select>
393
+ </div>
394
+ <div id="linearOptions">
395
+ <label class="block text-sm font-medium mb-1">Direction</label>
396
+ <select id="gradientDirection" class="w-full p-2 border rounded">
397
+ <option value="to right">Left to Right</option>
398
+ <option value="to bottom">Top to Bottom</option>
399
+ <option value="to bottom right">Diagonal</option>
400
+ <option value="135deg">135°</option>
401
+ </select>
402
+ </div>
403
+ </div>
404
+ <div class="mt-4">
405
+ <label class="block text-sm font-medium mb-2">Color Stops</label>
406
+ <div id="colorStops" class="space-y-2">
407
+ <div class="flex items-center space-x-2">
408
+ <input type="color" value="#3b82f6" class="color-picker">
409
+ <input type="range" min="0" max="100" value="0" class="flex-1">
410
+ <span>0%</span>
411
+ <button class="remove-stop px-2 py-1 bg-red-500 text-white rounded text-sm">
412
+ <i class="fas fa-times"></i>
413
+ </button>
414
+ </div>
415
+ <div class="flex items-center space-x-2">
416
+ <input type="color" value="#8b5cf6" class="color-picker">
417
+ <input type="range" min="0" max="100" value="100" class="flex-1">
418
+ <span>100%</span>
419
+ <button class="remove-stop px-2 py-1 bg-red-500 text-white rounded text-sm">
420
+ <i class="fas fa-times"></i>
421
+ </button>
422
+ </div>
423
+ </div>
424
+ <button id="addStopBtn" class="mt-2 px-3 py-1 bg-gray-200 hover:bg-gray-300 rounded text-sm">
425
+ <i class="fas fa-plus mr-1"></i> Add Color Stop
426
+ </button>
427
+ </div>
428
+ <div class="mt-4">
429
+ <label class="block text-sm font-medium mb-1">Preview</label>
430
+ <div id="gradientPreview" class="gradient-preview" style="background: linear-gradient(to right, #3b82f6, #8b5cf6);"></div>
431
+ </div>
432
+ <div class="flex justify-end mt-4 space-x-2">
433
+ <button id="cancelGradientBtn" class="px-4 py-2 bg-gray-300 hover:bg-gray-400 rounded">Cancel</button>
434
+ <button id="applyGradientBtn" class="px-4 py-2 bg-blue-500 hover:bg-blue-600 text-white rounded">Apply</button>
435
+ </div>
436
+ </div>
437
+ </div>
438
+
439
+ <!-- Uiverse Modal -->
440
+ <div id="uiverseModal" class="modal">
441
+ <div class="modal-content uiverse-modal">
442
+ <div class="flex justify-between items-center mb-4">
443
+ <h2 class="text-xl font-bold">Uiverse Elements</h2>
444
+ <button id="closeUiverseModal" class="text-gray-500 hover:text-gray-700">
445
+ <i class="fas fa-times"></i>
446
+ </button>
447
+ </div>
448
+ <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 p-4">
449
+ <!-- Galaxy Buttons -->
450
+ <div class="uiverse-element border rounded p-4">
451
+ <h3 class="font-medium mb-2">Galaxy Button 1</h3>
452
+ <div class="mb-3 flex justify-center">
453
+ <button class="button-galaxy">
454
+ <span class="button-galaxy__content">Hover me</span>
455
+ <span class="button-galaxy__glow"></span>
456
+ <span class="button-galaxy__stars"></span>
457
+ </button>
458
+ </div>
459
+ <div class="flex justify-between">
460
+ <button class="add-to-canvas px-2 py-1 bg-green-500 text-white rounded text-sm">
461
+ <i class="fas fa-plus mr-1"></i> Add to Canvas
462
+ </button>
463
+ </div>
464
+ </div>
465
+
466
+ <!-- Galaxy Input -->
467
+ <div class="uiverse-element border rounded p-4">
468
+ <h3 class="font-medium mb-2">Galaxy Input</h3>
469
+ <div class="mb-3 flex justify-center">
470
+ <div class="input-galaxy">
471
+ <input class="input-galaxy__field" type="text" placeholder=" " />
472
+ <label class="input-galaxy__label">Username</label>
473
+ <div class="input-galaxy__underline"></div>
474
+ </div>
475
+ </div>
476
+ <div class="flex justify-between">
477
+ <button class="add-to-canvas px-2 py-1 bg-green-500 text-white rounded text-sm">
478
+ <i class="fas fa-plus mr-1"></i> Add to Canvas
479
+ </button>
480
+ </div>
481
+ </div>
482
+
483
+ <!-- Galaxy Card -->
484
+ <div class="uiverse-element border rounded p-4">
485
+ <h3 class="font-medium mb-2">Galaxy Card</h3>
486
+ <div class="mb-3 flex justify-center">
487
+ <div class="card-galaxy">
488
+ <div class="card-galaxy__content">
489
+ <h3 class="card-galaxy__title">Galaxy Card</h3>
490
+ <p class="card-galaxy__description">Beautiful galaxy-themed card</p>
491
+ </div>
492
+ </div>
493
+ </div>
494
+ <div class="flex justify-between">
495
+ <button class="add-to-canvas px-2 py-1 bg-green-500 text-white rounded text-sm">
496
+ <i class="fas fa-plus mr-1"></i> Add to Canvas
497
+ </button>
498
+ </div>
499
+ </div>
500
+
501
+ <!-- Galaxy Checkbox -->
502
+ <div class="uiverse-element border rounded p-4">
503
+ <h3 class="font-medium mb-2">Galaxy Checkbox</h3>
504
+ <div class="mb-3 flex justify-center">
505
+ <label class="checkbox-galaxy">
506
+ <input type="checkbox" class="checkbox-galaxy__input" />
507
+ <div class="checkbox-galaxy__box"></div>
508
+ <span class="checkbox-galaxy__text">Check me</span>
509
+ </label>
510
+ </div>
511
+ <div class="flex justify-between">
512
+ <button class="add-to-canvas px-2 py-1 bg-green-500 text-white rounded text-sm">
513
+ <i class="fas fa-plus mr-1"></i> Add to Canvas
514
+ </button>
515
+ </div>
516
+ </div>
517
+ </div>
518
+ <div class="flex justify-center mt-6">
519
+ <button class="px-4 py-2 bg-gray-200 hover:bg-gray-300 rounded">
520
+ Load More
521
+ </button>
522
+ </div>
523
+ </div>
524
+ </div>
525
+
526
+ <!-- Custom Element Modal -->
527
+ <div id="customElementModal" class="modal">
528
+ <div class="modal-content">
529
+ <div class="flex justify-between items-center mb-4">
530
+ <h2 class="text-xl font-bold">Custom Element</h2>
531
+ <button id="closeCustomModal" class="text-gray-500 hover:text-gray-700">
532
+ <i class="fas fa-times"></i>
533
+ </button>
534
+ </div>
535
+ <textarea id="customElementEditor" class="code-editor" placeholder="Enter your custom HTML here..."></textarea>
536
+ <div class="flex justify-end mt-4 space-x-2">
537
+ <button id="cancelCustomBtn" class="px-4 py-2 bg-gray-300 hover:bg-gray-400 rounded">Cancel</button>
538
+ <button id="applyCustomBtn" class="px-4 py-2 bg-blue-500 hover:bg-blue-600 text-white rounded">Add to Canvas</button>
539
+ </div>
540
+ </div>
541
+ </div>
542
+
543
+ <script>
544
+ // DOM Elements
545
+ const htmlBtn = document.getElementById('htmlBtn');
546
+ const cssBtn = document.getElementById('cssBtn');
547
+ const saveBtn = document.getElementById('saveBtn');
548
+ const resetBtn = document.getElementById('resetBtn');
549
+ const htmlModal = document.getElementById('htmlModal');
550
+ const cssModal = document.getElementById('cssModal');
551
+ const gradientModal = document.getElementById('gradientModal');
552
+ const uiverseModal = document.getElementById('uiverseModal');
553
+ const customElementModal = document.getElementById('customElementModal');
554
+ const closeHtmlModal = document.getElementById('closeHtmlModal');
555
+ const closeCssModal = document.getElementById('closeCssModal');
556
+ const closeGradientModal = document.getElementById('closeGradientModal');
557
+ const closeUiverseModal = document.getElementById('closeUiverseModal');
558
+ const closeCustomModal = document.getElementById('closeCustomModal');
559
+ const cancelHtmlBtn = document.getElementById('cancelHtmlBtn');
560
+ const cancelCssBtn = document.getElementById('cancelCssBtn');
561
+ const cancelGradientBtn = document.getElementById('cancelGradientBtn');
562
+ const cancelCustomBtn = document.getElementById('cancelCustomBtn');
563
+ const applyHtmlBtn = document.getElementById('applyHtmlBtn');
564
+ const applyCssBtn = document.getElementById('applyCssBtn');
565
+ const applyGradientBtn = document.getElementById('applyGradientBtn');
566
+ const applyCustomBtn = document.getElementById('applyCustomBtn');
567
+ const htmlEditor = document.getElementById('htmlEditor');
568
+ const cssEditor = document.getElementById('cssEditor');
569
+ const customElementEditor = document.getElementById('customElementEditor');
570
+ const canvas = document.getElementById('canvas');
571
+ const gradientBtn = document.getElementById('gradientBtn');
572
+ const toggleSidebar = document.getElementById('toggleSidebar');
573
+ const sidebar = document.getElementById('sidebar');
574
+ const elementBtns = document.querySelectorAll('.element-btn');
575
+ const uiverseBtn = document.getElementById('uiverseBtn');
576
+ const deleteBtn = document.getElementById('deleteBtn');
577
+ const duplicateBtn = document.getElementById('duplicateBtn');
578
+ const newWindowBtn = document.getElementById('newWindowBtn');
579
+ const snapToggle = document.getElementById('snapToggle');
580
+ const gridToggle = document.getElementById('gridToggle');
581
+ const posX = document.getElementById('posX');
582
+ const posY = document.getElementById('posY');
583
+ const width = document.getElementById('width');
584
+ const height = document.getElementById('height');
585
+ const rotation = document.getElementById('rotation');
586
+ const colorPicker = document.getElementById('colorPicker');
587
+ const bgColorPicker = document.getElementById('bgColorPicker');
588
+ const opacity = document.getElementById('opacity');
589
+ const zIndex = document.getElementById('zIndex');
590
+ const gradientType = document.getElementById('gradientType');
591
+ const gradientDirection = document.getElementById('gradientDirection');
592
+ const colorStops = document.getElementById('colorStops');
593
+ const addStopBtn = document.getElementById('addStopBtn');
594
+ const gradientPreview = document.getElementById('gradientPreview');
595
+
596
+ // State
597
+ let selectedElement = null;
598
+ let isDragging = false;
599
+ let isResizing = false;
600
+ let isRotating = false;
601
+ let resizeHandle = null;
602
+ let startX, startY, startWidth, startHeight, startLeft, startTop;
603
+ let ghostElement = null;
604
+ let snapToGrid = true;
605
+ let gridSize = 20;
606
+
607
+ // Initialize
608
+ function init() {
609
+ // Set default color picker values
610
+ colorPicker.value = '#000000';
611
+ bgColorPicker.value = '#ffffff';
612
+
613
+ // Add event listeners
614
+ setupEventListeners();
615
+
616
+ // Load saved data if available
617
+ loadSavedData();
618
+ }
619
+
620
+ // Set up all event listeners
621
+ function setupEventListeners() {
622
+ // Modal buttons
623
+ htmlBtn.addEventListener('click', () => htmlModal.style.display = 'block');
624
+ cssBtn.addEventListener('click', () => cssModal.style.display = 'block');
625
+ saveBtn.addEventListener('click', saveDesign);
626
+ resetBtn.addEventListener('click', resetCanvas);
627
+
628
+ // Close modals
629
+ closeHtmlModal.addEventListener('click', () => htmlModal.style.display = 'none');
630
+ closeCssModal.addEventListener('click', () => cssModal.style.display = 'none');
631
+ closeGradientModal.addEventListener('click', () => gradientModal.style.display = 'none');
632
+ closeUiverseModal.addEventListener('click', () => uiverseModal.style.display = 'none');
633
+ closeCustomModal.addEventListener('click', () => customElementModal.style.display = 'none');
634
+
635
+ // Cancel buttons
636
+ cancelHtmlBtn.addEventListener('click', () => htmlModal.style.display = 'none');
637
+ cancelCssBtn.addEventListener('click', () => cssModal.style.display = 'none');
638
+ cancelGradientBtn.addEventListener('click', () => gradientModal.style.display = 'none');
639
+ cancelCustomBtn.addEventListener('click', () => customElementModal.style.display = 'none');
640
+
641
+ // Apply buttons
642
+ applyHtmlBtn.addEventListener('click', applyHtml);
643
+ applyCssBtn.addEventListener('click', applyCss);
644
+ applyGradientBtn.addEventListener('click', applyGradient);
645
+ applyCustomBtn.addEventListener('click', addCustomElement);
646
+
647
+ // Gradient editor
648
+ gradientBtn.addEventListener('click', () => gradientModal.style.display = 'block');
649
+ gradientType.addEventListener('change', updateGradientUI);
650
+ gradientDirection.addEventListener('change', updateGradientPreview);
651
+
652
+ // Color stops
653
+ addStopBtn.addEventListener('click', addColorStop);
654
+ colorStops.addEventListener('click', (e) => {
655
+ if (e.target.classList.contains('remove-stop')) {
656
+ if (colorStops.children.length > 2) {
657
+ e.target.parentElement.remove();
658
+ updateGradientPreview();
659
+ }
660
+ } else if (e.target.classList.contains('color-picker')) {
661
+ e.target.addEventListener('change', updateGradientPreview);
662
+ } else if (e.target.type === 'range') {
663
+ e.target.addEventListener('input', () => {
664
+ e.target.nextElementSibling.textContent = e.target.value + '%';
665
+ updateGradientPreview();
666
+ });
667
+ }
668
+ });
669
+
670
+ // Sidebar
671
+ toggleSidebar.addEventListener('click', toggleSidebarCollapse);
672
+
673
+ // Element buttons
674
+ elementBtns.forEach(btn => {
675
+ btn.addEventListener('click', (e) => {
676
+ const type = btn.dataset.type;
677
+ if (type === 'custom') {
678
+ customElementModal.style.display = 'block';
679
+ customElementEditor.value = '';
680
+ } else {
681
+ // Get mouse position relative to canvas
682
+ const canvasRect = canvas.getBoundingClientRect();
683
+ const x = e.clientX - canvasRect.left;
684
+ const y = e.clientY - canvasRect.top;
685
+ addElementToCanvas(type, null, x, y);
686
+ }
687
+ });
688
+ });
689
+
690
+ // Uiverse button
691
+ uiverseBtn.addEventListener('click', () => uiverseModal.style.display = 'block');
692
+
693
+ // Uiverse modal interactions
694
+ document.querySelectorAll('.add-to-canvas').forEach(btn => {
695
+ btn.addEventListener('click', (e) => {
696
+ const element = btn.closest('.uiverse-element');
697
+ const preview = element.querySelector('.button-galaxy, .input-galaxy, .card-galaxy, .checkbox-galaxy');
698
+ if (preview) {
699
+ const clone = preview.cloneNode(true);
700
+
701
+ // Make sure Galaxy components are properly initialized
702
+ if (clone.classList.contains('input-galaxy')) {
703
+ initGalaxyInput(clone);
704
+ } else if (clone.classList.contains('checkbox-galaxy')) {
705
+ initGalaxyCheckbox(clone);
706
+ }
707
+
708
+ // Get mouse position relative to canvas
709
+ const canvasRect = canvas.getBoundingClientRect();
710
+ const x = e.clientX - canvasRect.left;
711
+ const y = e.clientY - canvasRect.top;
712
+
713
+ addElementToCanvas(clone, null, x, y);
714
+ uiverseModal.style.display = 'none';
715
+ }
716
+ });
717
+ });
718
+
719
+ // Initialize Galaxy input functionality
720
+ function initGalaxyInput(input) {
721
+ const field = input.querySelector('.input-galaxy__field');
722
+ const label = input.querySelector('.input-galaxy__label');
723
+
724
+ field.addEventListener('focus', () => {
725
+ label.classList.add('input-galaxy__label--active');
726
+ });
727
+
728
+ field.addEventListener('blur', () => {
729
+ if (!field.value) {
730
+ label.classList.remove('input-galaxy__label--active');
731
+ }
732
+ });
733
+ }
734
+
735
+ // Initialize Galaxy checkbox functionality
736
+ function initGalaxyCheckbox(checkbox) {
737
+ const input = checkbox.querySelector('.checkbox-galaxy__input');
738
+ const box = checkbox.querySelector('.checkbox-galaxy__box');
739
+
740
+ input.addEventListener('change', () => {
741
+ if (input.checked) {
742
+ box.classList.add('checkbox-galaxy__box--checked');
743
+ } else {
744
+ box.classList.remove('checkbox-galaxy__box--checked');
745
+ }
746
+ });
747
+ }
748
+
749
+ // Canvas interactions
750
+ canvas.addEventListener('mousedown', startDrag);
751
+ document.addEventListener('mousemove', handleDrag);
752
+ document.addEventListener('mouseup', stopDrag);
753
+
754
+ // Toolbar controls
755
+ posX.addEventListener('change', updateElementPosition);
756
+ posY.addEventListener('change', updateElementPosition);
757
+ width.addEventListener('change', updateElementSize);
758
+ height.addEventListener('change', updateElementSize);
759
+ rotation.addEventListener('change', updateElementRotation);
760
+ colorPicker.addEventListener('change', updateElementColor);
761
+ bgColorPicker.addEventListener('change', updateElementBackground);
762
+ opacity.addEventListener('input', updateElementOpacity);
763
+ zIndex.addEventListener('change', updateElementZIndex);
764
+ deleteBtn.addEventListener('click', deleteSelectedElement);
765
+ duplicateBtn.addEventListener('click', duplicateSelectedElement);
766
+ newWindowBtn.addEventListener('click', addNewWindow);
767
+
768
+ // Snap to grid toggle
769
+ snapToggle.addEventListener('click', () => {
770
+ snapToGrid = !snapToGrid;
771
+ snapToggle.classList.toggle('bg-yellow-600', snapToGrid);
772
+ });
773
+
774
+ // Grid toggle
775
+ gridToggle.addEventListener('click', () => {
776
+ canvasContainer.classList.toggle('bg-none');
777
+ gridToggle.classList.toggle('bg-blue-200');
778
+ });
779
+ }
780
+
781
+ // Toggle sidebar collapse
782
+ function toggleSidebarCollapse() {
783
+ sidebar.classList.toggle('collapsed');
784
+ const icon = toggleSidebar.querySelector('i');
785
+ if (sidebar.classList.contains('collapsed')) {
786
+ icon.classList.remove('fa-chevron-left');
787
+ icon.classList.add('fa-chevron-right');
788
+ toggleSidebar.style.transform = 'translateX(64px)';
789
+ } else {
790
+ icon.classList.remove('fa-chevron-right');
791
+ icon.classList.add('fa-chevron-left');
792
+ toggleSidebar.style.transform = 'translateX(0)';
793
+ }
794
+ }
795
+
796
+ // Add element to canvas
797
+ function addElementToCanvas(type, html = null, x = 50, y = 50) {
798
+ let element;
799
+
800
+ if (html) {
801
+ // Create a temporary div to parse the HTML
802
+ const tempDiv = document.createElement('div');
803
+ tempDiv.innerHTML = html;
804
+ element = tempDiv.firstChild;
805
+ } else {
806
+ // Create standard elements based on type
807
+ switch (type) {
808
+ case 'button':
809
+ element = document.createElement('button');
810
+ element.textContent = 'Button';
811
+ element.className = 'px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 transition';
812
+ break;
813
+ case 'input':
814
+ element = document.createElement('input');
815
+ element.type = 'text';
816
+ element.placeholder = 'Type something...';
817
+ element.className = 'px-3 py-2 border rounded';
818
+ break;
819
+ case 'card':
820
+ element = document.createElement('div');
821
+ element.className = 'bg-white rounded-lg shadow-md p-4 w-64';
822
+ element.innerHTML = `
823
+ <h3 class="text-lg font-semibold mb-2">Card Title</h3>
824
+ <p class="text-gray-600">This is a sample card element.</p>
825
+ `;
826
+ break;
827
+ case 'div':
828
+ element = document.createElement('div');
829
+ element.className = 'bg-gray-200 border border-gray-300 p-4';
830
+ element.textContent = 'Div Container';
831
+ break;
832
+ case 'section':
833
+ element = document.createElement('section');
834
+ element.className = 'bg-white border border-gray-300 p-4';
835
+ element.textContent = 'Section Container';
836
+ break;
837
+ default:
838
+ element = document.createElement('div');
839
+ element.textContent = 'New Element';
840
+ }
841
+ }
842
+
843
+ // Set default styles for positioning
844
+ element.className += ' absolute cursor-move canvas-element';
845
+ element.style.left = `${x}px`;
846
+ element.style.top = `${y}px`;
847
+ element.style.width = 'auto';
848
+ element.style.minWidth = '100px';
849
+ element.style.minHeight = '40px';
850
+
851
+ // Add resize handles
852
+ addResizeHandles(element);
853
+
854
+ // Add rotation handle
855
+ addRotationHandle(element);
856
+
857
+ // Add element to canvas
858
+ canvas.appendChild(element);
859
+
860
+ // Select the new element
861
+ selectElement(element);
862
+ }
863
+
864
+ // Add custom element from modal
865
+ function addCustomElement() {
866
+ const html = customElementEditor.value.trim();
867
+ if (html) {
868
+ addElementToCanvas('custom', html);
869
+ customElementModal.style.display = 'none';
870
+ }
871
+ }
872
+
873
+ // Add resize handles to an element
874
+ function addResizeHandles(element) {
875
+ const positions = ['nw', 'ne', 'sw', 'se'];
876
+
877
+ positions.forEach(pos => {
878
+ const handle = document.createElement('div');
879
+ handle.className = `resize-handle ${pos}`;
880
+ handle.dataset.position = pos;
881
+ element.appendChild(handle);
882
+
883
+ // Add event listeners for resizing
884
+ handle.addEventListener('mousedown', (e) => {
885
+ e.stopPropagation();
886
+ isResizing = true;
887
+ resizeHandle = pos;
888
+ selectedElement = element;
889
+
890
+ // Store initial dimensions and position
891
+ startWidth = parseInt(getComputedStyle(element).width);
892
+ startHeight = parseInt(getComputedStyle(element).height);
893
+ startLeft = parseInt(getComputedStyle(element).left);
894
+ startTop = parseInt(getComputedStyle(element).top);
895
+
896
+ // Update toolbar inputs
897
+ updateToolbarWithElementData(element);
898
+ });
899
+ });
900
+ }
901
+
902
+ // Add rotation handle to an element
903
+ function addRotationHandle(element) {
904
+ const handle = document.createElement('div');
905
+ handle.className = 'rotation-handle';
906
+ handle.innerHTML = '<i class="fas fa-sync-alt"></i>';
907
+ element.appendChild(handle);
908
+
909
+ // Add event listeners for rotation
910
+ handle.addEventListener('mousedown', (e) => {
911
+ e.stopPropagation();
912
+ isRotating = true;
913
+ selectedElement = element;
914
+
915
+ // Store initial position
916
+ const rect = element.getBoundingClientRect();
917
+ startX = e.clientX;
918
+ startY = e.clientY;
919
+
920
+ // Get current rotation
921
+ const transform = getComputedStyle(element).transform;
922
+ let currentRotation = 0;
923
+ if (transform && transform !== 'none') {
924
+ const values = transform.match(/matrix\((.+)\)/)[1].split(', ');
925
+ const a = parseFloat(values[0]);
926
+ const b = parseFloat(values[1]);
927
+ currentRotation = Math.round(Math.atan2(b, a) * (180 / Math.PI));
928
+ }
929
+
930
+ // Update toolbar inputs
931
+ rotation.value = currentRotation;
932
+ });
933
+ }
934
+
935
+ // Start dragging an element
936
+ function startDrag(e) {
937
+ if (e.target.classList.contains('resize-handle') ||
938
+ e.target.classList.contains('rotation-handle')) {
939
+ return; // Let the resize/rotation handle handle this
940
+ }
941
+
942
+ const element = e.target.closest('.canvas-element');
943
+ if (element) {
944
+ e.preventDefault();
945
+ isDragging = true;
946
+ selectedElement = element;
947
+
948
+ // Store initial position
949
+ startX = e.clientX;
950
+ startY = e.clientY;
951
+ startLeft = parseInt(getComputedStyle(element).left);
952
+ startTop = parseInt(getComputedStyle(element).top);
953
+
954
+ // Create ghost element
955
+ createGhostElement(element);
956
+
957
+ // Update toolbar inputs
958
+ updateToolbarWithElementData(element);
959
+
960
+ // Select the element
961
+ selectElement(element);
962
+ } else {
963
+ // Clicked on canvas background: deselect
964
+ deselectElement();
965
+ }
966
+ }
967
+
968
+ // Create ghost element for dragging
969
+ function createGhostElement(element) {
970
+ ghostElement = element.cloneNode(true);
971
+ ghostElement.classList.add('element-ghost');
972
+ ghostElement.style.opacity = '0.7';
973
+ ghostElement.style.pointerEvents = 'none';
974
+
975
+ // Position ghost element
976
+ ghostElement.style.left = element.style.left;
977
+ ghostElement.style.top = element.style.top;
978
+ ghostElement.style.width = element.style.width;
979
+ ghostElement.style.height = element.style.height;
980
+ ghostElement.style.transform = element.style.transform;
981
+
982
+ canvas.appendChild(ghostElement);
983
+ }
984
+
985
+ // Handle dragging
986
+ function handleDrag(e) {
987
+ if (isDragging && selectedElement && ghostElement) {
988
+ const dx = e.clientX - startX;
989
+ const dy = e.clientY - startY;
990
+
991
+ let newLeft = startLeft + dx;
992
+ let newTop = startTop + dy;
993
+
994
+ // Snap to grid if enabled
995
+ if (snapToGrid) {
996
+ newLeft = Math.round(newLeft / gridSize) * gridSize;
997
+ newTop = Math.round(newTop / gridSize) * gridSize;
998
+ }
999
+
1000
+ ghostElement.style.left = `${newLeft}px`;
1001
+ ghostElement.style.top = `${newTop}px`;
1002
+ } else if (isResizing && selectedElement) {
1003
+ const dx = e.clientX - startX;
1004
+ const dy = e.clientY - startY;
1005
+
1006
+ let newWidth = startWidth;
1007
+ let newHeight = startHeight;
1008
+ let newLeft = startLeft;
1009
+ let newTop = startTop;
1010
+
1011
+ switch (resizeHandle) {
1012
+ case 'nw':
1013
+ newWidth = startWidth - dx;
1014
+ newHeight = startHeight - dy;
1015
+ newLeft = startLeft + dx;
1016
+ newTop = startTop + dy;
1017
+ break;
1018
+ case 'ne':
1019
+ newWidth = startWidth + dx;
1020
+ newHeight = startHeight - dy;
1021
+ newTop = startTop + dy;
1022
+ break;
1023
+ case 'sw':
1024
+ newWidth = startWidth - dx;
1025
+ newHeight = startHeight + dy;
1026
+ newLeft = startLeft + dx;
1027
+ break;
1028
+ case 'se':
1029
+ newWidth = startWidth + dx;
1030
+ newHeight = startHeight + dy;
1031
+ break;
1032
+ }
1033
+
1034
+ // Apply minimum dimensions
1035
+ newWidth = Math.max(newWidth, 30);
1036
+ newHeight = Math.max(newHeight, 30);
1037
+
1038
+ selectedElement.style.width = `${newWidth}px`;
1039
+ selectedElement.style.height = `${newHeight}px`;
1040
+ if (newLeft !== startLeft) selectedElement.style.left = `${newLeft}px`;
1041
+ if (newTop !== startTop) selectedElement.style.top = `${newTop}px`;
1042
+
1043
+ // Update size inputs
1044
+ width.value = newWidth;
1045
+ height.value = newHeight;
1046
+ if (newLeft !== startLeft) posX.value = newLeft;
1047
+ if (newTop !== startTop) posY.value = newTop;
1048
+ } else if (isRotating && selectedElement) {
1049
+ const rect = selectedElement.getBoundingClientRect();
1050
+ const centerX = rect.left + rect.width / 2;
1051
+ const centerY = rect.top + rect.height / 2;
1052
+
1053
+ const angle = Math.atan2(e.clientY - centerY, e.clientX - centerX) * 180 / Math.PI;
1054
+
1055
+ // Apply rotation
1056
+ selectedElement.style.transform = `rotate(${angle}deg)`;
1057
+
1058
+ // Update toolbar
1059
+ rotation.value = Math.round(angle);
1060
+ }
1061
+ }
1062
+
1063
+ // Stop dragging
1064
+ function stopDrag() {
1065
+ if (isDragging && selectedElement && ghostElement) {
1066
+ // Apply ghost position to actual element
1067
+ selectedElement.style.left = ghostElement.style.left;
1068
+ selectedElement.style.top = ghostElement.style.top;
1069
+
1070
+ // Update position inputs
1071
+ posX.value = parseInt(ghostElement.style.left);
1072
+ posY.value = parseInt(ghostElement.style.top);
1073
+
1074
+ // Remove ghost element
1075
+ ghostElement.remove();
1076
+ ghostElement = null;
1077
+ }
1078
+
1079
+ isDragging = false;
1080
+ isResizing = false;
1081
+ isRotating = false;
1082
+ resizeHandle = null;
1083
+ }
1084
+
1085
+ // Select an element
1086
+ function selectElement(element) {
1087
+ // Remove selection from all elements
1088
+ document.querySelectorAll('.canvas-element').forEach(el => {
1089
+ el.classList.remove('selected', 'ring-2', 'ring-blue-500');
1090
+ });
1091
+
1092
+ // Select the new element
1093
+ element.classList.add('selected', 'ring-2', 'ring-blue-500');
1094
+ selectedElement = element;
1095
+
1096
+ // Update toolbar with element data
1097
+ updateToolbarWithElementData(element);
1098
+ }
1099
+
1100
+ // Deselect element
1101
+ function deselectElement() {
1102
+ if (selectedElement) {
1103
+ selectedElement.classList.remove('selected', 'ring-2', 'ring-blue-500');
1104
+ selectedElement = null;
1105
+ clearToolbar();
1106
+ }
1107
+ }
1108
+
1109
+ // Clear toolbar inputs
1110
+ function clearToolbar() {
1111
+ posX.value = '';
1112
+ posY.value = '';
1113
+ width.value = '';
1114
+ height.value = '';
1115
+ rotation.value = '';
1116
+ colorPicker.value = '#000000';
1117
+ bgColorPicker.value = '#ffffff';
1118
+ opacity.value = '100';
1119
+ zIndex.value = '1';
1120
+ }
1121
+
1122
+ // Update toolbar inputs with element data
1123
+ function updateToolbarWithElementData(element) {
1124
+ const style = getComputedStyle(element);
1125
+
1126
+ // Position
1127
+ posX.value = parseInt(style.left) || 0;
1128
+ posY.value = parseInt(style.top) || 0;
1129
+
1130
+ // Size
1131
+ width.value = parseInt(style.width) || 0;
1132
+ height.value = parseInt(style.height) || 0;
1133
+
1134
+ // Rotation
1135
+ const transform = style.transform;
1136
+ if (transform && transform !== 'none') {
1137
+ const values = transform.match(/matrix\((.+)\)/)[1].split(', ');
1138
+ const a = parseFloat(values[0]);
1139
+ const b = parseFloat(values[1]);
1140
+ const angle = Math.round(Math.atan2(b, a) * (180 / Math.PI));
1141
+ rotation.value = angle;
1142
+ } else {
1143
+ rotation.value = 0;
1144
+ }
1145
+
1146
+ // Color
1147
+ colorPicker.value = rgbToHex(style.color);
1148
+
1149
+ // Background color
1150
+ if (style.background && style.background !== 'none' && !style.background.includes('gradient')) {
1151
+ bgColorPicker.value = rgbToHex(style.backgroundColor);
1152
+ }
1153
+
1154
+ // Opacity
1155
+ opacity.value = Math.round(parseFloat(style.opacity) * 100);
1156
+
1157
+ // Z-index
1158
+ zIndex.value = style.zIndex;
1159
+ }
1160
+
1161
+ // Convert RGB to HEX
1162
+ function rgbToHex(rgb) {
1163
+ if (!rgb) return '#000000';
1164
+
1165
+ // Check if it's already hex
1166
+ if (rgb.startsWith('#')) return rgb;
1167
+
1168
+ // Extract RGB values
1169
+ const match = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
1170
+ if (!match) return '#000000';
1171
+
1172
+ const r = parseInt(match[1]);
1173
+ const g = parseInt(match[2]);
1174
+ const b = parseInt(match[3]);
1175
+
1176
+ return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
1177
+ }
1178
+
1179
+ // Update element position from toolbar
1180
+ function updateElementPosition() {
1181
+ if (selectedElement) {
1182
+ selectedElement.style.left = `${posX.value}px`;
1183
+ selectedElement.style.top = `${posY.value}px`;
1184
+ }
1185
+ }
1186
+
1187
+ // Update element size from toolbar
1188
+ function updateElementSize() {
1189
+ if (selectedElement) {
1190
+ selectedElement.style.width = `${width.value}px`;
1191
+ selectedElement.style.height = `${height.value}px`;
1192
+ }
1193
+ }
1194
+
1195
+ // Update element rotation from toolbar
1196
+ function updateElementRotation() {
1197
+ if (selectedElement) {
1198
+ selectedElement.style.transform = `rotate(${rotation.value}deg)`;
1199
+ }
1200
+ }
1201
+
1202
+ // Update element color from toolbar
1203
+ function updateElementColor() {
1204
+ if (selectedElement) {
1205
+ selectedElement.style.color = colorPicker.value;
1206
+ }
1207
+ }
1208
+
1209
+ // Update element background from toolbar
1210
+ function updateElementBackground() {
1211
+ if (selectedElement) {
1212
+ selectedElement.style.background = bgColorPicker.value;
1213
+ }
1214
+ }
1215
+
1216
+ // Update element opacity from toolbar
1217
+ function updateElementOpacity() {
1218
+ if (selectedElement) {
1219
+ selectedElement.style.opacity = opacity.value / 100;
1220
+ }
1221
+ }
1222
+
1223
+ // Update element z-index from toolbar
1224
+ function updateElementZIndex() {
1225
+ if (selectedElement) {
1226
+ selectedElement.style.zIndex = zIndex.value;
1227
+ }
1228
+ }
1229
+
1230
+ // Delete selected element
1231
+ function deleteSelectedElement() {
1232
+ if (selectedElement) {
1233
+ selectedElement.remove();
1234
+ selectedElement = null;
1235
+ clearToolbar();
1236
+ }
1237
+ }
1238
+
1239
+ // Duplicate selected element
1240
+ function duplicateSelectedElement() {
1241
+ if (selectedElement) {
1242
+ const clone = selectedElement.cloneNode(true);
1243
+ canvas.appendChild(clone);
1244
+
1245
+ // Offset the clone slightly
1246
+ const left = parseInt(getComputedStyle(selectedElement).left) + 20;
1247
+ const top = parseInt(getComputedStyle(selectedElement).top) + 20;
1248
+ clone.style.left = `${left}px`;
1249
+ clone.style.top = `${top}px`;
1250
+
1251
+ // Add resize handles to the clone
1252
+ addResizeHandles(clone);
1253
+
1254
+ // Add rotation handle to the clone
1255
+ addRotationHandle(clone);
1256
+
1257
+ // Select the new clone
1258
+ selectElement(clone);
1259
+ }
1260
+ }
1261
+
1262
+ // Add new window
1263
+ function addNewWindow() {
1264
+ const window = document.createElement('div');
1265
+ window.className = 'absolute bg-white border border-gray-300 shadow-lg rounded-lg overflow-hidden canvas-element';
1266
+ window.style.width = '400px';
1267
+ window.style.height = '300px';
1268
+ window.style.left = '100px';
1269
+ window.style.top = '100px';
1270
+
1271
+ // Window header
1272
+ const header = document.createElement('div');
1273
+ header.className = 'bg-gray-800 text-white p-2 flex justify-between items-center';
1274
+ header.innerHTML = `
1275
+ <span>New Window</span>
1276
+ <button class="close-window text-white hover:text-gray-300">
1277
+ <i class="fas fa-times"></i>
1278
+ </button>
1279
+ `;
1280
+
1281
+ // Window content
1282
+ const content = document.createElement('div');
1283
+ content.className = 'p-4 flex-1 overflow-auto';
1284
+ content.textContent = 'Window content goes here...';
1285
+
1286
+ // Add elements to window
1287
+ window.appendChild(header);
1288
+ window.appendChild(content);
1289
+
1290
+ // Add to canvas
1291
+ canvas.appendChild(window);
1292
+
1293
+ // Add resize handles
1294
+ addResizeHandles(window);
1295
+
1296
+ // Add rotation handle
1297
+ addRotationHandle(window);
1298
+
1299
+ // Select the new window
1300
+ selectElement(window);
1301
+
1302
+ // Add close event
1303
+ header.querySelector('.close-window').addEventListener('click', () => {
1304
+ window.remove();
1305
+ });
1306
+ }
1307
+
1308
+ // Apply HTML from modal
1309
+ function applyHtml() {
1310
+ const html = htmlEditor.value.trim();
1311
+ if (html) {
1312
+ // Clear canvas
1313
+ canvas.innerHTML = '';
1314
+
1315
+ // Add the HTML to canvas
1316
+ canvas.innerHTML = html;
1317
+
1318
+ // Add canvas-element class and resize handles to all top-level children
1319
+ Array.from(canvas.children).forEach(child => {
1320
+ child.classList.add('canvas-element');
1321
+ addResizeHandles(child);
1322
+ addRotationHandle(child);
1323
+ });
1324
+
1325
+ // Close modal
1326
+ htmlModal.style.display = 'none';
1327
+ }
1328
+ }
1329
+
1330
+ // Apply CSS from modal
1331
+ function applyCss() {
1332
+ const css = cssEditor.value.trim();
1333
+ if (css) {
1334
+ // Create a style element or use existing one
1335
+ let styleElement = document.getElementById('custom-css');
1336
+ if (!styleElement) {
1337
+ styleElement = document.createElement('style');
1338
+ styleElement.id = 'custom-css';
1339
+ document.head.appendChild(styleElement);
1340
+ }
1341
+
1342
+ // Set CSS
1343
+ styleElement.textContent = css;
1344
+
1345
+ // Close modal
1346
+ cssModal.style.display = 'none';
1347
+ }
1348
+ }
1349
+
1350
+ // Add color stop to gradient editor
1351
+ function addColorStop() {
1352
+ const stopDiv = document.createElement('div');
1353
+ stopDiv.className = 'flex items-center space-x-2';
1354
+
1355
+ // Random color for new stop
1356
+ const randomColor = '#' + Math.floor(Math.random()*16777215).toString(16);
1357
+ const position = Math.floor(Math.random() * 50) + 25; // Between 25-75%
1358
+
1359
+ stopDiv.innerHTML = `
1360
+ <input type="color" value="${randomColor}" class="color-picker">
1361
+ <input type="range" min="0" max="100" value="${position}" class="flex-1">
1362
+ <span>${position}%</span>
1363
+ <button class="remove-stop px-2 py-1 bg-red-500 text-white rounded text-sm">
1364
+ <i class="fas fa-times"></i>
1365
+ </button>
1366
+ `;
1367
+
1368
+ colorStops.appendChild(stopDiv);
1369
+
1370
+ // Add event listeners
1371
+ stopDiv.querySelector('.color-picker').addEventListener('change', updateGradientPreview);
1372
+ stopDiv.querySelector('input[type="range"]').addEventListener('input', function() {
1373
+ this.nextElementSibling.textContent = this.value + '%';
1374
+ updateGradientPreview();
1375
+ });
1376
+
1377
+ updateGradientPreview();
1378
+ }
1379
+
1380
+ // Update gradient UI based on type
1381
+ function updateGradientUI() {
1382
+ const type = gradientType.value;
1383
+ if (type === 'linear') {
1384
+ document.getElementById('linearOptions').style.display = 'block';
1385
+ } else {
1386
+ document.getElementById('linearOptions').style.display = 'none';
1387
+ }
1388
+ updateGradientPreview();
1389
+ }
1390
+
1391
+ // Update gradient preview
1392
+ function updateGradientPreview() {
1393
+ const type = gradientType.value;
1394
+ const stops = Array.from(colorStops.querySelectorAll('.flex.items-center')).map(div => {
1395
+ const color = div.querySelector('.color-picker').value;
1396
+ const position = div.querySelector('input[type="range"]').value;
1397
+ return `${color} ${position}%`;
1398
+ }).join(', ');
1399
+
1400
+ if (type === 'linear') {
1401
+ const direction = gradientDirection.value;
1402
+ gradientPreview.style.background = `linear-gradient(${direction}, ${stops})`;
1403
+ } else {
1404
+ gradientPreview.style.background = `radial-gradient(circle, ${stops})`;
1405
+ }
1406
+ }
1407
+
1408
+ // Apply gradient to selected element
1409
+ function applyGradient() {
1410
+ if (selectedElement) {
1411
+ const type = gradientType.value;
1412
+ const stops = Array.from(colorStops.querySelectorAll('.flex.items-center')).map(div => {
1413
+ const color = div.querySelector('.color-picker').value;
1414
+ const position = div.querySelector('input[type="range"]').value;
1415
+ return `${color} ${position}%`;
1416
+ }).join(', ');
1417
+
1418
+ if (type === 'linear') {
1419
+ const direction = gradientDirection.value;
1420
+ selectedElement.style.background = `linear-gradient(${direction}, ${stops})`;
1421
+ } else {
1422
+ selectedElement.style.background = `radial-gradient(circle, ${stops})`;
1423
+ }
1424
+
1425
+ // Close modal
1426
+ gradientModal.style.display = 'none';
1427
+ }
1428
+ }
1429
+
1430
+ // Save design to localStorage
1431
+ function saveDesign() {
1432
+ if (canvas) {
1433
+ const html = canvas.innerHTML;
1434
+ const css = document.getElementById('custom-css')?.textContent || '';
1435
+
1436
+ localStorage.setItem('uiDesigner_html', html);
1437
+ localStorage.setItem('uiDesigner_css', css);
1438
+
1439
+ alert('Design saved successfully!');
1440
+ }
1441
+ }
1442
+
1443
+ // Load saved data from localStorage
1444
+ function loadSavedData() {
1445
+ const savedHtml = localStorage.getItem('uiDesigner_html');
1446
+ const savedCss = localStorage.getItem('uiDesigner_css');
1447
+
1448
+ if (savedHtml) {
1449
+ canvas.innerHTML = savedHtml;
1450
+
1451
+ // Add canvas-element class and resize handles to all top-level children
1452
+ Array.from(canvas.children).forEach(child => {
1453
+ child.classList.add('canvas-element');
1454
+ addResizeHandles(child);
1455
+ addRotationHandle(child);
1456
+ });
1457
+ }
1458
+
1459
+ if (savedCss) {
1460
+ let styleElement = document.getElementById('custom-css');
1461
+ if (!styleElement) {
1462
+ styleElement = document.createElement('style');
1463
+ styleElement.id = 'custom-css';
1464
+ document.head.appendChild(styleElement);
1465
+ }
1466
+ styleElement.textContent = savedCss;
1467
+
1468
+ // Update editors
1469
+ cssEditor.value = savedCss;
1470
+ }
1471
+ }
1472
+
1473
+ // Reset canvas
1474
+ function resetCanvas() {
1475
+ if (confirm('Are you sure you want to reset the canvas? This cannot be undone.')) {
1476
+ canvas.innerHTML = '';
1477
+
1478
+ // Remove custom CSS
1479
+ const styleElement = document.getElementById('custom-css');
1480
+ if (styleElement) {
1481
+ styleElement.remove();
1482
+ }
1483
+
1484
+ // Clear localStorage
1485
+ localStorage.removeItem('uiDesigner_html');
1486
+ localStorage.removeItem('uiDesigner_css');
1487
+
1488
+ // Clear editors
1489
+ htmlEditor.value = '';
1490
+ cssEditor.value = '';
1491
+
1492
+ selectedElement = null;
1493
+ }
1494
+ }
1495
+
1496
+ // Initialize the app
1497
+ init();
1498
+ </script>
1499
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=basheer1414/ui-creater" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
1500
+ </html>