Yukkkop commited on
Commit
a413231
·
verified ·
1 Parent(s): 1dacea4
Files changed (5) hide show
  1. README.md +8 -5
  2. components/navbar.js +64 -0
  3. index.html +324 -18
  4. script.js +489 -0
  5. style.css +253 -18
README.md CHANGED
@@ -1,10 +1,13 @@
1
  ---
2
- title: Pixelforge Studio
3
- emoji: 🔥
4
- colorFrom: blue
5
- colorTo: yellow
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: PixelForge Studio 🎨
3
+ colorFrom: purple
4
+ colorTo: blue
5
+ emoji: 🐳
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite-v3
10
  ---
11
 
12
+ # Welcome to your new DeepSite project!
13
+ This project was created with [DeepSite](https://huggingface.co/deepsite).
components/navbar.js ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Navigation Bar Component
2
+ class CustomNavbar extends HTMLElement {
3
+ connectedCallback() {
4
+ this.attachShadow({ mode: 'open' });
5
+ this.shadowRoot.innerHTML = `
6
+ <style>
7
+ .navbar {
8
+ background: #1f2937;
9
+ padding: 1rem 2rem;
10
+ display: flex;
11
+ justify-content: space-between;
12
+ align-items: center;
13
+ border-bottom: 1px solid #374151;
14
+ }
15
+
16
+ .navbar-brand {
17
+ font-size: 1.5rem;
18
+ font-weight: bold;
19
+ color: #fff;
20
+ text-decoration: none;
21
+ display: flex;
22
+ align-items: center;
23
+ gap: 0.5rem;
24
+ }
25
+
26
+ .navbar-menu {
27
+ display: flex;
28
+ gap: 1rem;
29
+ list-style: none;
30
+ margin: 0;
31
+ padding: 0;
32
+ }
33
+
34
+ .navbar-menu a {
35
+ color: #9ca3af;
36
+ text-decoration: none;
37
+ padding: 0.5rem 1rem;
38
+ border-radius: 0.375rem;
39
+ transition: all 0.2s;
40
+ }
41
+
42
+ .navbar-menu a:hover {
43
+ background: #374151;
44
+ color: #fff;
45
+ }
46
+ </style>
47
+ <nav class="navbar">
48
+ <a href="#" class="navbar-brand">
49
+ 🎨 PixelForge Studio
50
+ </a>
51
+ <ul class="navbar-menu">
52
+ <li><a href="#file">File</a></li>
53
+ <li><a href="#edit">Edit</a></li>
54
+ <li><a href="#image">Image</a></li>
55
+ <li><a href="#layer">Layer</a></li>
56
+ <li><a href="#filter">Filter</a></li>
57
+ <li><a href="#view">View</a></li>
58
+ </ul>
59
+ </nav>
60
+ `;
61
+ }
62
+ }
63
+
64
+ customElements.define('custom-navbar', CustomNavbar);
index.html CHANGED
@@ -1,19 +1,325 @@
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>PixelForge Studio</title>
7
+ <link rel="stylesheet" href="style.css">
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ </head>
10
+ <body class="bg-gray-900 text-white overflow-hidden">
11
+ <div class="flex flex-col h-screen">
12
+ <header class="bg-gray-800 border-b border-gray-700">
13
+ <div class="flex items-center justify-between px-2 py-1">
14
+ <div class="flex items-center space-x-4">
15
+ <div class="relative menu-dropdown">
16
+ <button class="px-3 py-1 text-sm hover:bg-gray-700 rounded flex items-center space-x-1">
17
+ <span>File</span>
18
+ <i data-feather="chevron-down" class="w-3 h-3"></i>
19
+ </button>
20
+ <div class="absolute top-full left-0 bg-gray-800 border border-gray-700 rounded shadow-lg hidden mt-1 z-50 min-w-[200px]">
21
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">New</a>
22
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Open</a>
23
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Save</a>
24
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Save As</a>
25
+ <div class="border-t border-gray-700"></div>
26
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Export</a>
27
+ </div>
28
+ </div>
29
+ <div class="relative menu-dropdown">
30
+ <button class="px-3 py-1 text-sm hover:bg-gray-700 rounded flex items-center space-x-1">
31
+ <span>Edit</span>
32
+ <i data-feather="chevron-down" class="w-3 h-3"></i>
33
+ </button>
34
+ <div class="absolute top-full left-0 bg-gray-800 border border-gray-700 rounded shadow-lg hidden mt-1 z-50 min-w-[200px]">
35
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Undo</a>
36
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Redo</a>
37
+ <div class="border-t border-gray-700"></div>
38
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Cut</a>
39
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Copy</a>
40
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Paste</a>
41
+ </div>
42
+ </div>
43
+ <div class="relative menu-dropdown">
44
+ <button class="px-3 py-1 text-sm hover:bg-gray-700 rounded flex items-center space-x-1">
45
+ <span>Image</span>
46
+ <i data-feather="chevron-down" class="w-3 h-3"></i>
47
+ </button>
48
+ <div class="absolute top-full left-0 bg-gray-800 border border-gray-700 rounded shadow-lg hidden mt-1 z-50 min-w-[200px]">
49
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Adjustments</a>
50
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Image Size</a>
51
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Canvas Size</a>
52
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Rotate</a>
53
+ </div>
54
+ </div>
55
+ <div class="relative menu-dropdown">
56
+ <button class="px-3 py-1 text-sm hover:bg-gray-700 rounded flex items-center space-x-1">
57
+ <span>Layer</span>
58
+ <i data-feather="chevron-down" class="w-3 h-3"></i>
59
+ </button>
60
+ <div class="absolute top-full left-0 bg-gray-800 border border-gray-700 rounded shadow-lg hidden mt-1 z-50 min-w-[200px]">
61
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">New Layer</a>
62
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Duplicate Layer</a>
63
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Delete Layer</a>
64
+ <div class="border-t border-gray-700"></div>
65
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Merge Down</a>
66
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Flatten Image</a>
67
+ </div>
68
+ </div>
69
+ <div class="relative menu-dropdown">
70
+ <button class="px-3 py-1 text-sm hover:bg-gray-700 rounded flex items-center space-x-1">
71
+ <span>Filter</span>
72
+ <i data-feather="chevron-down" class="w-3 h-3"></i>
73
+ </button>
74
+ <div class="absolute top-full left-0 bg-gray-800 border border-gray-700 rounded shadow-lg hidden mt-1 z-50 min-w-[200px]">
75
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Blur</a>
76
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Sharpen</a>
77
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Noise</a>
78
+ <div class="border-t border-gray-700"></div>
79
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Pixelate</a>
80
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Distort</a>
81
+ </div>
82
+ </div>
83
+ <div class="relative menu-dropdown">
84
+ <button class="px-3 py-1 text-sm hover:bg-gray-700 rounded flex items-center space-x-1">
85
+ <span>View</span>
86
+ <i data-feather="chevron-down" class="w-3 h-3"></i>
87
+ </button>
88
+ <div class="absolute top-full left-0 bg-gray-800 border border-gray-700 rounded shadow-lg hidden mt-1 z-50 min-w-[200px]">
89
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Zoom In</a>
90
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Zoom Out</a>
91
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Fit to Screen</a>
92
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Actual Size</a>
93
+ </div>
94
+ </div>
95
+ <div class="relative menu-dropdown">
96
+ <button class="px-3 py-1 text-sm hover:bg-gray-700 rounded flex items-center space-x-1">
97
+ <span>Window</span>
98
+ <i data-feather="chevron-down" class="w-3 h-3"></i>
99
+ </button>
100
+ <div class="absolute top-full left-0 bg-gray-800 border border-gray-700 rounded shadow-lg hidden mt-1 z-50 min-w-[200px]">
101
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Layers</a>
102
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">History</a>
103
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Properties</a>
104
+ <a href="#" class="block px-4 py-2 hover:bg-gray-700 text-sm">Tools</a>
105
+ </div>
106
+ </div>
107
+ </div>
108
+ <div class="flex items-center space-x-4">
109
+ <span class="text-sm text-gray-400">Untitled-1.psd @ 100%</span>
110
+ <div class="flex items-center space-x-2">
111
+ <button class="p-1 hover:bg-gray-700 rounded">
112
+ <i data-feather="minimize-2" class="w-4 h-4"></i>
113
+ </button>
114
+ <button class="p-1 hover:bg-gray-700 rounded">
115
+ <i data-feather="square" class="w-4 h-4"></i>
116
+ </button>
117
+ <button class="p-1 hover:bg-gray-700 rounded">
118
+ <i data-feather="x" class="w-4 h-4"></i>
119
+ </button>
120
+ </div>
121
+ </div>
122
+ </div>
123
+ </header>
124
+ <!-- Main Editor Area -->
125
+ <div class="flex flex-1 overflow-hidden">
126
+ <!-- Left Toolbar -->
127
+ <aside class="w-16 bg-gray-800 border-r border-gray-700 flex flex-col items-center py-2 space-y-1">
128
+ <button class="tool-btn p-3 hover:bg-gray-700 rounded" data-tool="move" title="Move Tool">
129
+ <i data-feather="move" class="w-5 h-5"></i>
130
+ </button>
131
+ <button class="tool-btn p-3 hover:bg-gray-700 rounded" data-tool="select" title="Marquee Select">
132
+ <i data-feather="square" class="w-5 h-5"></i>
133
+ </button>
134
+ <button class="tool-btn p-3 hover:bg-gray-700 rounded" data-tool="lasso" title="Lasso Tool">
135
+ <i data-feather="edit-3" class="w-5 h-5"></i>
136
+ </button>
137
+ <button class="tool-btn p-3 hover:bg-gray-700 rounded" data-tool="wand" title="Magic Wand">
138
+ <i data-feather="zap" class="w-5 h-5"></i>
139
+ </button>
140
+ <button class="tool-btn p-3 hover:bg-gray-700 rounded" data-tool="crop" title="Crop Tool">
141
+ <i data-feather="crop" class="w-5 h-5"></i>
142
+ </button>
143
+ <button class="tool-btn p-3 hover:bg-gray-700 rounded" data-tool="eyedropper" title="Eyedropper">
144
+ <i data-feather="eye" class="w-5 h-5"></i>
145
+ </button>
146
+ <button class="tool-btn p-3 hover:bg-gray-700 rounded" data-tool="brush" title="Brush Tool">
147
+ <i data-feather="edit-2" class="w-5 h-5"></i>
148
+ </button>
149
+ <button class="tool-btn p-3 hover:bg-gray-700 rounded" data-tool="eraser" title="Eraser">
150
+ <i data-feather="delete" class="w-5 h-5"></i>
151
+ </button>
152
+ <button class="tool-btn p-3 hover:bg-gray-700 rounded" data-tool="gradient" title="Gradient">
153
+ <i data-feather="trending-up" class="w-5 h-5"></i>
154
+ </button>
155
+ <button class="tool-btn p-3 hover:bg-gray-700 rounded" data-tool="text" title="Text Tool">
156
+ <i data-feather="type" class="w-5 h-5"></i>
157
+ </button>
158
+ <button class="tool-btn p-3 hover:bg-gray-700 rounded" data-tool="shape" title="Shape Tool">
159
+ <i data-feather="triangle" class="w-5 h-5"></i>
160
+ </button>
161
+ <button class="tool-btn p-3 hover:bg-gray-700 rounded" data-tool="hand" title="Hand Tool">
162
+ <i data-feather="move" class="w-5 h-5"></i>
163
+ </button>
164
+ <button class="tool-btn p-3 hover:bg-gray-700 rounded" data-tool="zoom" title="Zoom Tool">
165
+ <i data-feather="search" class="w-5 h-5"></i>
166
+ </button>
167
+ </aside>
168
+ <main class="flex-1 bg-gray-600 relative overflow-hidden" id="canvas-container">
169
+ <div class="absolute inset-0 flex items-center justify-center">
170
+ <div class="bg-white shadow-2xl" id="main-canvas" style="width: 800px; height: 600px;">
171
+ <canvas id="photo-canvas" width="800" height="600" class="block"></canvas>
172
+ </div>
173
+ </div>
174
+ <div class="absolute bottom-4 right-4 bg-gray-800 rounded-lg px-3 py-2 flex items-center space-x-2">
175
+ <button class="p-1 hover:bg-gray-700 rounded" id="zoom-out">
176
+ <i data-feather="minus" class="w-4 h-4"></i>
177
+ </button>
178
+ <span class="text-sm w-12 text-center" id="zoom-level">100%</span>
179
+ <button class="p-1 hover:bg-gray-700 rounded" id="zoom-in">
180
+ <i data-feather="plus" class="w-4 h-4"></i>
181
+ </button>
182
+ </div>
183
+ </main>
184
+ <!-- Right Panels -->
185
+ <div class="w-80 bg-gray-800 border-l border-gray-700 flex flex-col">
186
+ <div class="p-4 border-b border-gray-700">
187
+ <h3 class="text-sm font-semibold mb-3">Color</h3>
188
+ <div class="flex space-x-2">
189
+ <div class="relative">
190
+ <div class="w-16 h-16 bg-black rounded cursor-pointer border-2 border-gray-600" id="fg-color"></div>
191
+ <div class="absolute -bottom-1 -right-1 w-8 h-8 bg-white rounded border-2 border-gray-600 cursor-pointer" id="bg-color"></div>
192
+ </div>
193
+ <div class="flex-1 space-y-2">
194
+ <div class="flex items-center space-x-2">
195
+ <span class="text-xs text-gray-400 w-12">R:</span>
196
+ <input type="range" min="0" max="255" class="flex-1" id="color-r">
197
+ <span class="text-xs w-8 text-right" id="r-val">0</span>
198
+ </div>
199
+ <div class="flex items-center space-x-2">
200
+ <span class="text-xs text-gray-400 w-12">G:</span>
201
+ <input type="range" min="0" max="255" class="flex-1" id="color-g">
202
+ <span class="text-xs w-8 text-right" id="g-val">0</span>
203
+ </div>
204
+ <div class="flex items-center space-x-2">
205
+ <span class="text-xs text-gray-400 w-12">B:</span>
206
+ <input type="range" min="0" max="255" class="flex-1" id="color-b">
207
+ <span class="text-xs w-8 text-right" id="b-val">0</span>
208
+ </div>
209
+ </div>
210
+ </div>
211
+ </div>
212
+ <div class="flex-1 flex flex-col overflow-hidden">
213
+ <div class="p-4 border-b border-gray-700 flex items-center justify-between">
214
+ <h3 class="text-sm font-semibold">Layers</h3>
215
+ <div class="flex space-x-1">
216
+ <button class="p-1 hover:bg-gray-700 rounded" title="New Layer">
217
+ <i data-feather="plus" class="w-4 h-4"></i>
218
+ </button>
219
+ <button class="p-1 hover:bg-gray-700 rounded" title="Delete Layer">
220
+ <i data-feather="trash-2" class="w-4 h-4"></i>
221
+ </button>
222
+ <button class="p-1 hover:bg-gray-700 rounded" title="Duplicate Layer">
223
+ <i data-feather="copy" class="w-4 h-4"></i>
224
+ </button>
225
+ </div>
226
+ </div>
227
+ <div class="flex-1 overflow-y-auto p-2" id="layers-list">
228
+ <div class="layer-item bg-gray-700 rounded p-2 mb-2 flex items-center space-x-2 cursor-pointer">
229
+ <i data-feather="eye" class="w-4 h-4"></i>
230
+ <i data-feather="lock" class="w-4 h-4"></i>
231
+ <div class="w-8 h-8 bg-white rounded"></div>
232
+ <span class="flex-1 text-sm">Background</span>
233
+ <span class="text-xs text-gray-400">100%</span>
234
+ </div>
235
+ </div>
236
+ </div>
237
+ <div class="p-4 border-t border-gray-700 max-h-64 overflow-y-auto">
238
+ <h3 class="text-sm font-semibold mb-3">Properties</h3>
239
+ <div class="space-y-3">
240
+ <div>
241
+ <label class="text-xs text-gray-400">Opacity</label>
242
+ <div class="flex items-center space-x-2">
243
+ <input type="range" min="0" max="100" value="100" class="flex-1" id="opacity">
244
+ <span class="text-xs w-10 text-right" id="opacity-val">100%</span>
245
+ </div>
246
+ </div>
247
+ <div>
248
+ <label class="text-xs text-gray-400">Fill</label>
249
+ <div class="flex items-center space-x-2">
250
+ <input type="range" min="0" max="100" value="100" class="flex-1" id="fill">
251
+ <span class="text-xs w-10 text-right" id="fill-val">100%</span>
252
+ </div>
253
+ </div>
254
+ <div>
255
+ <label class="text-xs text-gray-400">Blend Mode</label>
256
+ <select class="w-full bg-gray-700 rounded px-2 py-1 text-sm">
257
+ <option>Normal</option>
258
+ <option>Multiply</option>
259
+ <option>Screen</option>
260
+ <option>Overlay</option>
261
+ <option>Soft Light</option>
262
+ <option>Hard Light</option>
263
+ </select>
264
+ </div>
265
+ </div>
266
+ </div>
267
+ </div>
268
+ </div>
269
+ <footer class="bg-gray-800 border-t border-gray-700 px-4 py-1 flex items-center justify-between text-xs text-gray-400">
270
+ <div class="flex items-center space-x-4">
271
+ <span>800px × 600px</span>
272
+ <span>RGB/8</span>
273
+ <span id="cursor-position">X: 400, Y: 300</span>
274
+ </div>
275
+ <div class="flex items-center space-x-2">
276
+ <button class="px-2 py-1 hover:bg-gray-700 rounded">8-bit</button>
277
+ <button class="px-2 py-1 hover:bg-gray-700 rounded">Proof Colors</button>
278
+ <button class="px-2 py-1 hover:bg-gray-700 rounded">Pixel Aspect Ratio</button>
279
+ </div>
280
+ </footer>
281
+ </div>
282
+
283
+ <!-- Modal for new document -->
284
+ <div id="new-doc-modal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden z-50">
285
+ <div class="bg-gray-800 rounded-lg p-6 w-96">
286
+ <h2 class="text-xl font-semibold mb-4">New Document</h2>
287
+ <div class="space-y-4">
288
+ <div>
289
+ <label class="text-sm text-gray-400">Name</label>
290
+ <input type="text" class="w-full bg-gray-700 rounded px-3 py-2" value="Untitled-1">
291
+ </div>
292
+ <div class="grid grid-cols-2 gap-4">
293
+ <div>
294
+ <label class="text-sm text-gray-400">Width</label>
295
+ <input type="number" class="w-full bg-gray-700 rounded px-3 py-2" value="800">
296
+ </div>
297
+ <div>
298
+ <label class="text-sm text-gray-400">Height</label>
299
+ <input type="number" class="w-full bg-gray-700 rounded px-3 py-2" value="600">
300
+ </div>
301
+ </div>
302
+ <div>
303
+ <label class="text-sm text-gray-400">Resolution</label>
304
+ <input type="number" class="w-full bg-gray-700 rounded px-3 py-2" value="72">
305
+ </div>
306
+ <div>
307
+ <label class="text-sm text-gray-400">Color Mode</label>
308
+ <select class="w-full bg-gray-700 rounded px-3 py-2">
309
+ <option>RGB Color</option>
310
+ <option>CMYK Color</option>
311
+ <option>Grayscale</option>
312
+ </select>
313
+ </div>
314
+ </div>
315
+ <div class="flex justify-end space-x-2 mt-6">
316
+ <button class="px-4 py-2 bg-gray-700 rounded hover:bg-gray-600" onclick="closeModal()">Cancel</button>
317
+ <button class="px-4 py-2 bg-blue-600 rounded hover:bg-blue-500">Create</button>
318
+ </div>
319
+ </div>
320
+ </div>
321
+ <script src="script.js"></script>
322
+ <script>feather.replace();</script>
323
+ <script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
324
+ </body>
325
  </html>
script.js ADDED
@@ -0,0 +1,489 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // PixelForge Studio - Main JavaScript
2
+
3
+ // Canvas and context
4
+ let canvas = document.getElementById('photo-canvas');
5
+ let ctx = canvas.getContext('2d');
6
+ let isDrawing = false;
7
+ let currentTool = 'brush';
8
+ let currentColor = '#000000';
9
+ let brushSize = 5;
10
+ let zoomLevel = 1;
11
+ let history = [];
12
+ let historyStep = -1;
13
+ let layers = [];
14
+ let activeLayer = 0;
15
+
16
+ // Initialize canvas with white background
17
+ function initCanvas() {
18
+ ctx.fillStyle = 'white';
19
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
20
+ saveHistory();
21
+ }
22
+
23
+ // Tool selection
24
+ document.querySelectorAll('.tool-btn').forEach(btn => {
25
+ btn.addEventListener('click', function() {
26
+ document.querySelectorAll('.tool-btn').forEach(b => b.classList.remove('active'));
27
+ this.classList.add('active');
28
+ currentTool = this.dataset.tool;
29
+ updateCursor();
30
+ });
31
+ });
32
+
33
+ // Update cursor based on tool
34
+ function updateCursor() {
35
+ switch(currentTool) {
36
+ case 'brush':
37
+ case 'eraser':
38
+ canvas.style.cursor = 'crosshair';
39
+ break;
40
+ case 'move':
41
+ canvas.style.cursor = 'move';
42
+ break;
43
+ case 'eyedropper':
44
+ canvas.style.cursor = 'copy';
45
+ break;
46
+ case 'text':
47
+ canvas.style.cursor = 'text';
48
+ break;
49
+ case 'zoom':
50
+ canvas.style.cursor = 'zoom-in';
51
+ break;
52
+ default:
53
+ canvas.style.cursor = 'default';
54
+ }
55
+ }
56
+
57
+ // Drawing functions
58
+ canvas.addEventListener('mousedown', startDrawing);
59
+ canvas.addEventListener('mousemove', draw);
60
+ canvas.addEventListener('mouseup', stopDrawing);
61
+ canvas.addEventListener('mouseout', stopDrawing);
62
+
63
+ function startDrawing(e) {
64
+ if (currentTool === 'brush' || currentTool === 'eraser') {
65
+ isDrawing = true;
66
+ const rect = canvas.getBoundingClientRect();
67
+ const x = e.clientX - rect.left;
68
+ const y = e.clientY - rect.top;
69
+
70
+ ctx.beginPath();
71
+ ctx.moveTo(x, y);
72
+ }
73
+ }
74
+
75
+ function draw(e) {
76
+ if (!isDrawing) return;
77
+
78
+ const rect = canvas.getBoundingClientRect();
79
+ const x = e.clientX - rect.left;
80
+ const y = e.clientY - rect.top;
81
+
82
+ if (currentTool === 'brush') {
83
+ ctx.globalCompositeOperation = 'source-over';
84
+ ctx.strokeStyle = currentColor;
85
+ ctx.lineWidth = brushSize;
86
+ ctx.lineCap = 'round';
87
+ ctx.lineJoin = 'round';
88
+ ctx.lineTo(x, y);
89
+ ctx.stroke();
90
+ ctx.beginPath();
91
+ ctx.moveTo(x, y);
92
+ } else if (currentTool === 'eraser') {
93
+ ctx.globalCompositeOperation = 'destination-out';
94
+ ctx.lineWidth = brushSize * 2;
95
+ ctx.lineCap = 'round';
96
+ ctx.lineJoin = 'round';
97
+ ctx.lineTo(x, y);
98
+ ctx.stroke();
99
+ ctx.beginPath();
100
+ ctx.moveTo(x, y);
101
+ }
102
+
103
+ updateCursorPosition(e);
104
+ }
105
+
106
+ function stopDrawing() {
107
+ if (isDrawing) {
108
+ isDrawing = false;
109
+ ctx.beginPath();
110
+ saveHistory();
111
+ }
112
+ }
113
+
114
+ // Color picker functionality
115
+ let rSlider = document.getElementById('color-r');
116
+ let gSlider = document.getElementById('color-g');
117
+ let bSlider = document.getElementById('color-b');
118
+ let rVal = document.getElementById('r-val');
119
+ let gVal = document.getElementById('g-val');
120
+ let bVal = document.getElementById('b-val');
121
+ let fgColor = document.getElementById('fg-color');
122
+
123
+ function updateColor() {
124
+ const r = rSlider.value;
125
+ const g = gSlider.value;
126
+ const b = bSlider.value;
127
+ currentColor = `rgb(${r}, ${g}, ${b})`;
128
+ fgColor.style.backgroundColor = currentColor;
129
+ rVal.textContent = r;
130
+ gVal.textContent = g;
131
+ bVal.textContent = b;
132
+ }
133
+
134
+ rSlider.addEventListener('input', updateColor);
135
+ gSlider.addEventListener('input', updateColor);
136
+ bSlider.addEventListener('input', updateColor);
137
+
138
+ // Opacity control
139
+ let opacitySlider = document.getElementById('opacity');
140
+ let opacityVal = document.getElementById('opacity-val');
141
+
142
+ opacitySlider.addEventListener('input', function() {
143
+ ctx.globalAlpha = this.value / 100;
144
+ opacityVal.textContent = this.value + '%';
145
+ });
146
+
147
+ // Zoom controls
148
+ document.getElementById('zoom-in').addEventListener('click', function() {
149
+ if (zoomLevel < 3) {
150
+ zoomLevel += 0.25;
151
+ updateZoom();
152
+ }
153
+ });
154
+
155
+ document.getElementById('zoom-out').addEventListener('click', function() {
156
+ if (zoomLevel > 0.25) {
157
+ zoomLevel -= 0.25;
158
+ updateZoom();
159
+ }
160
+ });
161
+
162
+ function updateZoom() {
163
+ let mainCanvas = document.getElementById('main-canvas');
164
+ mainCanvas.style.transform = `scale(${zoomLevel})`;
165
+ document.getElementById('zoom-level').textContent = Math.round(zoomLevel * 100) + '%';
166
+ }
167
+
168
+ // History management
169
+ function saveHistory() {
170
+ historyStep++;
171
+ if (historyStep < history.length) {
172
+ history.length = historyStep;
173
+ }
174
+ history.push(canvas.toDataURL());
175
+ }
176
+
177
+ function undo() {
178
+ if (historyStep > 0) {
179
+ historyStep--;
180
+ restoreCanvas();
181
+ }
182
+ }
183
+
184
+ function redo() {
185
+ if (historyStep < history.length - 1) {
186
+ historyStep++;
187
+ restoreCanvas();
188
+ }
189
+ }
190
+
191
+ function restoreCanvas() {
192
+ let img = new Image();
193
+ img.src = history[historyStep];
194
+ img.onload = function() {
195
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
196
+ ctx.drawImage(img, 0, 0);
197
+ };
198
+ }
199
+
200
+ // Keyboard shortcuts
201
+ document.addEventListener('keydown', function(e) {
202
+ if (e.ctrlKey || e.metaKey) {
203
+ switch(e.key) {
204
+ case 'z':
205
+ e.preventDefault();
206
+ undo();
207
+ break;
208
+ case 'y':
209
+ e.preventDefault();
210
+ redo();
211
+ break;
212
+ case 's':
213
+ e.preventDefault();
214
+ saveImage();
215
+ break;
216
+ case 'o':
217
+ e.preventDefault();
218
+ openImage();
219
+ break;
220
+ case 'n':
221
+ e.preventDefault();
222
+ document.getElementById('new-doc-modal').classList.remove('hidden');
223
+ break;
224
+ }
225
+ }
226
+
227
+ // Tool shortcuts
228
+ switch(e.key) {
229
+ case 'b':
230
+ document.querySelector('[data-tool="brush"]').click();
231
+ break;
232
+ case 'e':
233
+ document.querySelector('[data-tool="eraser"]').click();
234
+ break;
235
+ case 'm':
236
+ document.querySelector('[data-tool="move"]').click();
237
+ break;
238
+ case 't':
239
+ document.querySelector('[data-tool="text"]').click();
240
+ break;
241
+ case 'c':
242
+ document.querySelector('[data-tool="crop"]').click();
243
+ break;
244
+ case 'i':
245
+ document.querySelector('[data-tool="eyedropper"]').click();
246
+ break;
247
+ case 'w':
248
+ document.querySelector('[data-tool="wand"]').click();
249
+ break;
250
+ case 'g':
251
+ document.querySelector('[data-tool="gradient"]').click();
252
+ break;
253
+ case 'z':
254
+ if (!e.ctrlKey && !e.metaKey) {
255
+ document.querySelector('[data-tool="zoom"]').click();
256
+ }
257
+ break;
258
+ }
259
+ });
260
+
261
+ // Image save and load
262
+ function saveImage() {
263
+ const link = document.createElement('a');
264
+ link.download = 'pixelforge-image.png';
265
+ link.href = canvas.toDataURL();
266
+ link.click();
267
+ }
268
+
269
+ function openImage() {
270
+ const input = document.createElement('input');
271
+ input.type = 'file';
272
+ input.accept = 'image/*';
273
+ input.onchange = function(e) {
274
+ const file = e.target.files[0];
275
+ const reader = new FileReader();
276
+ reader.onload = function(event) {
277
+ const img = new Image();
278
+ img.onload = function() {
279
+ canvas.width = img.width;
280
+ canvas.height = img.height;
281
+ ctx.drawImage(img, 0, 0);
282
+ saveHistory();
283
+ };
284
+ img.src = event.target.result;
285
+ };
286
+ reader.readAsDataURL(file);
287
+ };
288
+ input.click();
289
+ }
290
+
291
+ // Update cursor position
292
+ function updateCursorPosition(e) {
293
+ const rect = canvas.getBoundingClientRect();
294
+ const x = Math.round(e.clientX - rect.left);
295
+ const y = Math.round(e.clientY - rect.top);
296
+ document.getElementById('cursor-position').textContent = `X: ${x}, Y: ${y}`;
297
+ }
298
+
299
+ canvas.addEventListener('mousemove', updateCursorPosition);
300
+
301
+ // Layer management
302
+ function addLayer() {
303
+ const layersList = document.getElementById('layers-list');
304
+ const layerCount = layersList.children.length;
305
+ const layerItem = document.createElement('div');
306
+ layerItem.className = 'layer-item bg-gray-700 rounded p-2 mb-2 flex items-center space-x-2 cursor-pointer';
307
+ layerItem.innerHTML = `
308
+ <i data-feather="eye" class="w-4 h-4"></i>
309
+ <i data-feather="unlock" class="w-4 h-4"></i>
310
+ <div class="w-8 h-8 bg-gray-600 rounded"></div>
311
+ <span class="flex-1 text-sm">Layer ${layerCount}</span>
312
+ <span class="text-xs text-gray-400">100%</span>
313
+ `;
314
+ layersList.insertBefore(layerItem, layersList.firstChild);
315
+ feather.replace();
316
+
317
+ // Add click handler for layer selection
318
+ layerItem.addEventListener('click', function() {
319
+ document.querySelectorAll('.layer-item').forEach(item => {
320
+ item.classList.remove('active');
321
+ });
322
+ this.classList.add('active');
323
+ activeLayer = layerCount;
324
+ });
325
+ }
326
+
327
+ // Modal functions
328
+ function closeModal() {
329
+ document.getElementById('new-doc-modal').classList.add('hidden');
330
+ }
331
+
332
+ // Fill slider
333
+ document.getElementById('fill').addEventListener('input', function() {
334
+ document.getElementById('fill-val').textContent = this.value + '%';
335
+ });
336
+
337
+ // Eyedropper tool
338
+ canvas.addEventListener('click', function(e) {
339
+ if (currentTool === 'eyedropper') {
340
+ const rect = canvas.getBoundingClientRect();
341
+ const x = e.clientX - rect.left;
342
+ const y = e.clientY - rect.top;
343
+ const pixel = ctx.getImageData(x, y, 1, 1).data;
344
+
345
+ rSlider.value = pixel[0];
346
+ gSlider.value = pixel[1];
347
+ bSlider.value = pixel[2];
348
+ updateColor();
349
+ }
350
+ });
351
+
352
+ // Text tool
353
+ canvas.addEventListener('click', function(e) {
354
+ if (currentTool === 'text') {
355
+ const rect = canvas.getBoundingClientRect();
356
+ const x = e.clientX - rect.left;
357
+ const y = e.clientY - rect.top;
358
+
359
+ const text = prompt('Enter text:');
360
+ if (text) {
361
+ ctx.font = '20px Arial';
362
+ ctx.fillStyle = currentColor;
363
+ ctx.fillText(text, x, y);
364
+ saveHistory();
365
+ }
366
+ }
367
+ });
368
+
369
+ // Initialize
370
+ initCanvas();
371
+ document.querySelector('[data-tool="brush"]').classList.add('active');
372
+
373
+ // Add initial layer
374
+ layers.push({ name: 'Background', visible: true, opacity: 1 });
375
+
376
+ // Drag and drop support
377
+ document.body.addEventListener('dragover', function(e) {
378
+ e.preventDefault();
379
+ document.body.classList.add('dragover');
380
+ });
381
+
382
+ document.body.addEventListener('dragleave', function() {
383
+ document.body.classList.remove('dragover');
384
+ });
385
+
386
+ document.body.addEventListener('drop', function(e) {
387
+ e.preventDefault();
388
+ document.body.classList.remove('dragover');
389
+
390
+ const file = e.dataTransfer.files[0];
391
+ if (file && file.type.startsWith('image/')) {
392
+ const reader = new FileReader();
393
+ reader.onload = function(event) {
394
+ const img = new Image();
395
+ img.onload = function() {
396
+ canvas.width = img.width;
397
+ canvas.height = img.height;
398
+ ctx.drawImage(img, 0, 0);
399
+ saveHistory();
400
+ };
401
+ img.src = event.target.result;
402
+ };
403
+ reader.readAsDataURL(file);
404
+ }
405
+ });
406
+
407
+ // Filter functions
408
+ function applyBlur() {
409
+ ctx.filter = 'blur(5px)';
410
+ const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
411
+ ctx.putImageData(imageData, 0, 0);
412
+ ctx.filter = 'none';
413
+ saveHistory();
414
+ }
415
+
416
+ function applyGrayscale() {
417
+ const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
418
+ const data = imageData.data;
419
+
420
+ for (let i = 0; i < data.length; i += 4) {
421
+ const gray = data[i] * 0.299 + data[i + 1] * 0.587 + data[i + 2] * 0.114;
422
+ data[i] = gray;
423
+ data[i + 1] = gray;
424
+ data[i + 2] = gray;
425
+ }
426
+
427
+ ctx.putImageData(imageData, 0, 0);
428
+ saveHistory();
429
+ }
430
+
431
+ function applyInvert() {
432
+ const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
433
+ const data = imageData.data;
434
+
435
+ for (let i = 0; i < data.length; i += 4) {
436
+ data[i] = 255 - data[i];
437
+ data[i + 1] = 255 - data[i + 1];
438
+ data[i + 2] = 255 - data[i + 2];
439
+ }
440
+
441
+ ctx.putImageData(imageData, 0, 0);
442
+ saveHistory();
443
+ }
444
+
445
+ // Brush size control (mouse wheel)
446
+ canvas.addEventListener('wheel', function(e) {
447
+ if (e.ctrlKey) {
448
+ e.preventDefault();
449
+ if (e.deltaY < 0) {
450
+ brushSize = Math.min(brushSize + 1, 50);
451
+ } else {
452
+ brushSize = Math.max(brushSize - 1, 1);
453
+ }
454
+ console.log('Brush size:', brushSize);
455
+ }
456
+ });
457
+
458
+ // Touch support for mobile devices
459
+ let touchDrawing = false;
460
+
461
+ canvas.addEventListener('touchstart', function(e) {
462
+ if (e.touches.length === 1) {
463
+ const touch = e.touches[0];
464
+ const mouseEvent = new MouseEvent('mousedown', {
465
+ clientX: touch.clientX,
466
+ clientY: touch.clientY
467
+ });
468
+ canvas.dispatchEvent(mouseEvent);
469
+ touchDrawing = true;
470
+ }
471
+ });
472
+
473
+ canvas.addEventListener('touchmove', function(e) {
474
+ if (touchDrawing && e.touches.length === 1) {
475
+ e.preventDefault();
476
+ const touch = e.touches[0];
477
+ const mouseEvent = new MouseEvent('mousemove', {
478
+ clientX: touch.clientX,
479
+ clientY: touch.clientY
480
+ });
481
+ canvas.dispatchEvent(mouseEvent);
482
+ }
483
+ });
484
+
485
+ canvas.addEventListener('touchend', function(e) {
486
+ const mouseEvent = new MouseEvent('mouseup', {});
487
+ canvas.dispatchEvent(mouseEvent);
488
+ touchDrawing = false;
489
+ });
style.css CHANGED
@@ -1,28 +1,263 @@
 
 
 
 
 
 
 
 
1
  body {
2
- padding: 2rem;
3
- font-family: -apple-system, BlinkMacSystemFont, "Arial", sans-serif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  }
5
 
6
- h1 {
7
- font-size: 16px;
8
- margin-top: 0;
 
 
 
 
9
  }
10
 
11
- p {
12
- color: rgb(107, 114, 128);
13
- font-size: 15px;
14
- margin-bottom: 10px;
15
- margin-top: 5px;
 
 
 
16
  }
17
 
18
- .card {
19
- max-width: 620px;
20
- margin: 0 auto;
21
- padding: 16px;
22
- border: 1px solid lightgray;
23
- border-radius: 16px;
24
  }
25
 
26
- .card p:last-child {
27
- margin-bottom: 0;
 
28
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Custom styles for PixelForge Studio */
2
+
3
+ * {
4
+ margin: 0;
5
+ padding: 0;
6
+ box-sizing: border-box;
7
+ }
8
+
9
  body {
10
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
11
+ user-select: none;
12
+ }
13
+
14
+ /* Dropdown menu styles */
15
+ .menu-dropdown:hover .absolute {
16
+ display: block !important;
17
+ }
18
+
19
+ /* Canvas styles */
20
+ #photo-canvas {
21
+ cursor: crosshair;
22
+ }
23
+
24
+ #main-canvas {
25
+ transform-origin: center center;
26
+ transition: transform 0.3s ease;
27
+ }
28
+
29
+ /* Tool button active state */
30
+ .tool-btn.active {
31
+ background-color: #3b82f6;
32
+ color: white;
33
+ }
34
+
35
+ /* Layer item styles */
36
+ .layer-item.active {
37
+ background-color: #3b82f6;
38
+ }
39
+
40
+ .layer-item:hover {
41
+ background-color: #374151;
42
+ }
43
+
44
+ /* Custom scrollbar */
45
+ ::-webkit-scrollbar {
46
+ width: 8px;
47
+ height: 8px;
48
+ }
49
+
50
+ ::-webkit-scrollbar-track {
51
+ background: #1f2937;
52
+ }
53
+
54
+ ::-webkit-scrollbar-thumb {
55
+ background: #4b5563;
56
+ border-radius: 4px;
57
+ }
58
+
59
+ ::-webkit-scrollbar-thumb:hover {
60
+ background: #6b7280;
61
+ }
62
+
63
+ /* Color picker styles */
64
+ #fg-color {
65
+ position: relative;
66
+ z-index: 2;
67
+ }
68
+
69
+ #bg-color {
70
+ position: absolute;
71
+ bottom: -8px;
72
+ right: -8px;
73
+ z-index: 1;
74
+ }
75
+
76
+ /* Panel transitions */
77
+ .panel {
78
+ transition: all 0.3s ease;
79
+ }
80
+
81
+ /* Tooltips */
82
+ [title] {
83
+ position: relative;
84
+ }
85
+
86
+ [title]:hover::after {
87
+ content: attr(title);
88
+ position: absolute;
89
+ bottom: 100%;
90
+ left: 50%;
91
+ transform: translateX(-50%);
92
+ background-color: #1f2937;
93
+ color: white;
94
+ padding: 4px 8px;
95
+ border-radius: 4px;
96
+ font-size: 12px;
97
+ white-space: nowrap;
98
+ z-index: 1000;
99
+ pointer-events: none;
100
+ margin-bottom: 4px;
101
+ }
102
+
103
+ /* Zoom controls */
104
+ #zoom-controls button {
105
+ transition: all 0.2s ease;
106
+ }
107
+
108
+ #zoom-controls button:hover {
109
+ transform: scale(1.1);
110
  }
111
 
112
+ /* Canvas grid */
113
+ .canvas-grid {
114
+ background-image:
115
+ linear-gradient(rgba(255,255,255,0.1) 1px, transparent 1px),
116
+ linear-gradient(90deg, rgba(255,255,255,0.1) 1px, transparent 1px);
117
+ background-size: 20px 20px;
118
+ background-position: -1px -1px;
119
  }
120
 
121
+ /* Loading spinner */
122
+ .loading-spinner {
123
+ border: 3px solid #1f2937;
124
+ border-top: 3px solid #3b82f6;
125
+ border-radius: 50%;
126
+ width: 40px;
127
+ height: 40px;
128
+ animation: spin 1s linear infinite;
129
  }
130
 
131
+ @keyframes spin {
132
+ 0% { transform: rotate(0deg); }
133
+ 100% { transform: rotate(360deg); }
 
 
 
134
  }
135
 
136
+ /* Modal backdrop */
137
+ .modal-backdrop {
138
+ backdrop-filter: blur(4px);
139
  }
140
+
141
+ /* Layer thumbnail */
142
+ .layer-thumbnail {
143
+ image-rendering: pixelated;
144
+ image-rendering: -moz-crisp-edges;
145
+ image-rendering: crisp-edges;
146
+ }
147
+
148
+ /* Selection box */
149
+ .selection-box {
150
+ border: 1px dashed #3b82f6;
151
+ background-color: rgba(59, 130, 246, 0.1);
152
+ position: absolute;
153
+ pointer-events: none;
154
+ }
155
+
156
+ /* Transform handles */
157
+ .transform-handle {
158
+ width: 8px;
159
+ height: 8px;
160
+ background-color: white;
161
+ border: 1px solid #3b82f6;
162
+ position: absolute;
163
+ }
164
+
165
+ /* Responsive adjustments */
166
+ @media (max-width: 1024px) {
167
+ .w-80 {
168
+ width: 16rem;
169
+ }
170
+ }
171
+
172
+ @media (max-width: 768px) {
173
+ .w-80 {
174
+ display: none;
175
+ }
176
+ }
177
+
178
+ /* File upload area */
179
+ .file-upload-area {
180
+ border: 2px dashed #4b5563;
181
+ border-radius: 8px;
182
+ padding: 2rem;
183
+ text-align: center;
184
+ transition: all 0.3s ease;
185
+ }
186
+
187
+ .file-upload-area.dragover {
188
+ border-color: #3b82f6;
189
+ background-color: rgba(59, 130, 246, 0.1);
190
+ }
191
+
192
+ /* History panel */
193
+ .history-item {
194
+ padding: 0.5rem;
195
+ cursor: pointer;
196
+ border-radius: 4px;
197
+ transition: background-color 0.2s ease;
198
+ }
199
+
200
+ .history-item:hover {
201
+ background-color: #374151;
202
+ }
203
+
204
+ .history-item.active {
205
+ background-color: #3b82f6;
206
+ }
207
+
208
+ /* Filter preview */
209
+ .filter-preview {
210
+ width: 60px;
211
+ height: 60px;
212
+ border-radius: 4px;
213
+ overflow: hidden;
214
+ cursor: pointer;
215
+ transition: transform 0.2s ease;
216
+ }
217
+
218
+ .filter-preview:hover {
219
+ transform: scale(1.1);
220
+ }
221
+
222
+ /* Tool options panel */
223
+ .tool-options {
224
+ background-color: #1f2937;
225
+ border-radius: 4px;
226
+ padding: 1rem;
227
+ margin-top: 1rem;
228
+ }
229
+
230
+ /* Brush preview */
231
+ .brush-preview {
232
+ width: 40px;
233
+ height: 40px;
234
+ border: 1px solid #4b5563;
235
+ border-radius: 4px;
236
+ display: flex;
237
+ align-items: center;
238
+ justify-content: center;
239
+ }
240
+
241
+ .brush-preview-circle {
242
+ border-radius: 50%;
243
+ background-color: currentColor;
244
+ }
245
+
246
+ /* Animation classes */
247
+ .fade-in {
248
+ animation: fadeIn 0.3s ease-in;
249
+ }
250
+
251
+ @keyframes fadeIn {
252
+ from { opacity: 0; }
253
+ to { opacity: 1; }
254
+ }
255
+
256
+ .slide-in {
257
+ animation: slideIn 0.3s ease-out;
258
+ }
259
+
260
+ @keyframes slideIn {
261
+ from { transform: translateY(-10px); opacity: 0; }
262
+ to { transform: translateY(0); opacity: 1; }
263
+ }