senangwebs-photobooth 1.0.1 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +219 -235
  2. package/dist/swp.css +884 -344
  3. package/dist/swp.js +1 -1
  4. package/examples/data-attribute.html +69 -0
  5. package/examples/index.html +56 -51
  6. package/examples/studio.html +83 -0
  7. package/package.json +12 -5
  8. package/src/css/swp.css +884 -344
  9. package/src/js/core/Canvas.js +398 -0
  10. package/src/js/core/EventEmitter.js +188 -0
  11. package/src/js/core/History.js +250 -0
  12. package/src/js/core/Keyboard.js +323 -0
  13. package/src/js/filters/FilterManager.js +248 -0
  14. package/src/js/index.js +48 -0
  15. package/src/js/io/Clipboard.js +52 -0
  16. package/src/js/io/FileManager.js +150 -0
  17. package/src/js/layers/BlendModes.js +342 -0
  18. package/src/js/layers/Layer.js +415 -0
  19. package/src/js/layers/LayerManager.js +459 -0
  20. package/src/js/selection/Selection.js +167 -0
  21. package/src/js/swp.js +297 -709
  22. package/src/js/tools/BaseTool.js +264 -0
  23. package/src/js/tools/BrushTool.js +314 -0
  24. package/src/js/tools/CropTool.js +400 -0
  25. package/src/js/tools/EraserTool.js +155 -0
  26. package/src/js/tools/EyedropperTool.js +184 -0
  27. package/src/js/tools/FillTool.js +109 -0
  28. package/src/js/tools/GradientTool.js +141 -0
  29. package/src/js/tools/HandTool.js +51 -0
  30. package/src/js/tools/MarqueeTool.js +103 -0
  31. package/src/js/tools/MoveTool.js +465 -0
  32. package/src/js/tools/ShapeTool.js +285 -0
  33. package/src/js/tools/TextTool.js +253 -0
  34. package/src/js/tools/ToolManager.js +277 -0
  35. package/src/js/tools/ZoomTool.js +68 -0
  36. package/src/js/ui/ColorManager.js +71 -0
  37. package/src/js/ui/UI.js +1211 -0
  38. package/swp_preview1.png +0 -0
  39. package/swp_preview2.png +0 -0
  40. package/webpack.config.js +4 -11
  41. package/dist/styles.js +0 -1
  42. package/examples/customization.html +0 -360
  43. package/spec.md +0 -239
  44. package/swp_preview.png +0 -0
package/src/css/swp.css CHANGED
@@ -1,447 +1,987 @@
1
1
  /**
2
- * SenangWebs Photobooth (SWP) - Styles
3
- * @version 1.0.0
2
+ * SenangWebs Photobooth (SWP) - TOAST UI Style
3
+ * Simple & Clean Image Editor UI
4
+ * @version 3.0.0
4
5
  */
5
6
 
6
- /* Font Awesome */
7
- @import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css');
7
+ /* CSS Variables */
8
+ :root {
9
+ --swp-bg-dark: #1e1e1e;
10
+ --swp-bg-medium: #2d2d2d;
11
+ --swp-bg-light: #3d3d3d;
12
+ --swp-bg-hover: #4a4a4a;
13
+ --swp-border: #404040;
14
+ --swp-border-light: #555555;
15
+ --swp-text: #ffffff;
16
+ --swp-text-secondary: #b0b0b0;
17
+ --swp-text-dim: #808080;
18
+ --swp-accent: #00FF99;
19
+ --swp-accent-hover: #33ffad;
20
+ --swp-accent-dim: rgba(0, 255, 153, 0.2);
21
+ --swp-accent-contrast: #000000;
22
+ --swp-success: #4ade80;
23
+ --swp-warning: #fbbf24;
24
+ --swp-error: #f87171;
25
+ --swp-canvas-bg: #151515;
26
+ --swp-header-height: 56px;
27
+ --swp-menu-height: 80px;
28
+ --swp-radius: 8px;
29
+ --swp-radius-sm: 6px;
30
+ --swp-radius-lg: 12px;
31
+ --swp-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
32
+ --swp-shadow-sm: 0 4px 12px rgba(0, 0, 0, 0.3);
33
+ --swp-transition: 0.2s ease;
34
+ }
35
+
36
+ /* Light Theme */
37
+ .swp-app.swp-theme-light {
38
+ --swp-bg-dark: #ffffff;
39
+ --swp-bg-medium: #f8f8f8;
40
+ --swp-bg-light: #ececec;
41
+ --swp-bg-hover: #e0e0e0;
42
+ --swp-border: #d4d4d4;
43
+ --swp-border-light: #c0c0c0;
44
+ --swp-text: #1a1a1a;
45
+ --swp-text-secondary: #666666;
46
+ --swp-text-dim: #999999;
47
+ --swp-accent: #2563eb;
48
+ --swp-accent-hover: #1d4ed8;
49
+ --swp-accent-dim: rgba(37, 99, 235, 0.15);
50
+ --swp-canvas-bg: #e8e8e8;
51
+ --swp-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
52
+ --swp-shadow-sm: 0 4px 12px rgba(0, 0, 0, 0.1);
53
+ }
54
+
55
+ /* Reset */
56
+ .swp-app *, .swp-app *::before, .swp-app *::after {
57
+ box-sizing: border-box;
58
+ margin: 0;
59
+ padding: 0;
60
+ }
61
+
62
+ /* Main Container */
63
+ .swp-app {
64
+ display: flex;
65
+ flex-direction: column;
66
+ width: 100%;
67
+ height: 100%;
68
+ min-height: 400px;
69
+ background: var(--swp-bg-dark);
70
+ color: var(--swp-text);
71
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
72
+ font-size: 14px;
73
+ overflow: hidden;
74
+ user-select: none;
75
+ -webkit-font-smoothing: antialiased;
76
+ }
77
+
78
+ /* ==================== HEADER ==================== */
79
+ .swp-header {
80
+ height: var(--swp-header-height);
81
+ background: var(--swp-bg-medium);
82
+ border-bottom: 1px solid var(--swp-border);
83
+ display: flex;
84
+ align-items: center;
85
+ justify-content: space-between;
86
+ padding: 0 16px;
87
+ gap: 16px;
88
+ flex-shrink: 0;
89
+ }
90
+
91
+ .swp-header-left,
92
+ .swp-header-center,
93
+ .swp-header-right {
94
+ display: flex;
95
+ align-items: center;
96
+ gap: 8px;
97
+ }
98
+
99
+ .swp-header-center {
100
+ flex: 1;
101
+ justify-content: center;
102
+ }
103
+
104
+ .swp-header-btn {
105
+ display: flex;
106
+ align-items: center;
107
+ gap: 8px;
108
+ padding: 10px 18px;
109
+ background: var(--swp-bg-light);
110
+ color: var(--swp-text);
111
+ border: 1px solid var(--swp-border);
112
+ border-radius: var(--swp-radius);
113
+ cursor: pointer;
114
+ font-size: 14px;
115
+ font-weight: 500;
116
+ transition: all var(--swp-transition);
117
+ }
118
+
119
+ .swp-header-btn:hover {
120
+ background: var(--swp-accent);
121
+ border-color: var(--swp-accent);
122
+ color: var(--swp-accent-contrast);
123
+ }
124
+
125
+ .swp-header-btn ss-icon {
126
+ font-size: 18px;
127
+ }
128
+
129
+ /* Download Dropdown */
130
+ .swp-download-dropdown {
131
+ position: relative;
132
+ }
133
+
134
+ .swp-download-dropdown .swp-header-btn {
135
+ gap: 6px;
136
+ }
137
+
138
+ .swp-dropdown-arrow {
139
+ font-size: 14px !important;
140
+ opacity: 0.7;
141
+ margin-left: 2px;
142
+ }
143
+
144
+ .swp-dropdown-menu {
145
+ position: absolute;
146
+ top: 100%;
147
+ left: 0;
148
+ margin-top: 4px;
149
+ background: var(--swp-bg-medium);
150
+ border: 1px solid var(--swp-border);
151
+ border-radius: var(--swp-radius);
152
+ box-shadow: var(--swp-shadow);
153
+ min-width: 120px;
154
+ z-index: 200;
155
+ overflow: hidden;
156
+ animation: swp-dropdown-fade 0.15s ease;
157
+ }
158
+
159
+ @keyframes swp-dropdown-fade {
160
+ from {
161
+ opacity: 0;
162
+ transform: translateY(-4px);
163
+ }
164
+ to {
165
+ opacity: 1;
166
+ transform: translateY(0);
167
+ }
168
+ }
8
169
 
9
- /* Container */
10
- .swp-container {
11
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
12
- max-width: 1200px;
13
- box-sizing: border-box;
170
+ .swp-dropdown-menu[hidden] {
171
+ display: none;
14
172
  }
15
173
 
16
- .swp-wrapper {
17
- background: #ffffff;
18
- overflow: hidden;
19
- height: 100%;
20
- display: flex;
21
- flex-direction: column;
174
+ .swp-dropdown-item {
175
+ display: block;
176
+ width: 100%;
177
+ padding: 10px 16px;
178
+ background: transparent;
179
+ color: var(--swp-text);
180
+ border: none;
181
+ font-size: 14px;
182
+ font-weight: 500;
183
+ text-align: left;
184
+ cursor: pointer;
185
+ transition: all var(--swp-transition);
22
186
  }
23
187
 
24
- /* Toolbar */
25
- .swp-toolbar {
26
- display: flex;
27
- gap: 8px;
28
- padding: 8px;
29
- background: #f8f9fa;
30
- flex-wrap: wrap;
31
- justify-content: space-between;
188
+ .swp-dropdown-item:hover {
189
+ background: var(--swp-accent);
190
+ color: var(--swp-accent-contrast);
32
191
  }
33
192
 
34
- .swp-toolbar-group {
35
- display: flex;
36
- gap: 0px;
37
- align-items: center;
38
- border: 1px solid #dee2e6;
39
- border-radius: 8px;
40
- overflow: hidden;
193
+ .swp-dropdown-item:not(:last-child) {
194
+ border-bottom: 1px solid var(--swp-border);
41
195
  }
42
196
 
43
- .swp-toolbar-group .swp-btn {
44
- display: flex;
45
- flex-direction: column;
46
- gap: 0px;
47
- height: 48px;
48
- width: 80px;
49
- min-width: 48px;
50
- align-items: center;
51
- justify-content: center;
52
- border-radius: 0px;
53
- border: none;
54
- padding: 0px;
197
+ .swp-divider {
198
+ width: 1px;
199
+ height: 24px;
200
+ background: var(--swp-border);
201
+ margin: 0 8px;
202
+ }
203
+
204
+ /* Icon Button */
205
+ .swp-icon-btn {
206
+ width: 40px;
207
+ height: 40px;
208
+ display: flex;
209
+ align-items: center;
210
+ justify-content: center;
211
+ background: transparent;
212
+ color: var(--swp-text-secondary);
213
+ border: none;
214
+ border-radius: var(--swp-radius);
215
+ cursor: pointer;
216
+ transition: all var(--swp-transition);
55
217
  }
56
218
 
57
- .swp-toolbar-group .swp-btn span {
58
- font-size: 12px;
219
+ .swp-icon-btn:hover {
220
+ background: var(--swp-bg-hover);
221
+ color: var(--swp-text);
59
222
  }
60
223
 
61
- .swp-btn {
62
- display: flex;
63
- align-items: center;
64
- justify-content: center;
65
- gap: 8px;
66
- padding: 0px 12px;
67
- border: 1px solid #dee2e6;
68
- background: #ffffff;
69
- border-radius: 6px;
70
- cursor: pointer;
71
- font-size: 14px;
72
- color: #495057;
73
- transition: all 0.2s ease;
74
- font-family: inherit;
75
- height: 40px;
224
+ .swp-icon-btn:disabled {
225
+ opacity: 0.4;
226
+ cursor: not-allowed;
76
227
  }
77
228
 
78
- .swp-btn:hover {
79
- background: #e9ecef;
80
- border-color: #adb5bd;
229
+ .swp-icon-btn ss-icon {
230
+ font-size: 20px;
81
231
  }
82
232
 
83
- .swp-btn:active {
84
- transform: scale(0.98);
233
+ /* ==================== WORKSPACE ==================== */
234
+ .swp-workspace {
235
+ flex: 1;
236
+ background: var(--swp-canvas-bg);
237
+ background-image:
238
+ linear-gradient(45deg, #202020 25%, transparent 25%),
239
+ linear-gradient(-45deg, #202020 25%, transparent 25%),
240
+ linear-gradient(45deg, transparent 75%, #202020 75%),
241
+ linear-gradient(-45deg, transparent 75%, #202020 75%);
242
+ background-size: 20px 20px;
243
+ background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
244
+ overflow: hidden;
245
+ position: relative;
246
+ }
247
+
248
+ .swp-theme-light .swp-workspace {
249
+ background-image:
250
+ linear-gradient(45deg, #d0d0d0 25%, transparent 25%),
251
+ linear-gradient(-45deg, #d0d0d0 25%, transparent 25%),
252
+ linear-gradient(45deg, transparent 75%, #d0d0d0 75%),
253
+ linear-gradient(-45deg, transparent 75%, #d0d0d0 75%);
85
254
  }
86
255
 
87
- .swp-btn-primary {
88
- background: #007bff;
89
- color: white;
90
- border-color: #007bff;
256
+ /* Viewport */
257
+ .swp-viewport {
258
+ width: 100%;
259
+ height: 100%;
260
+ overflow: hidden;
261
+ position: relative;
91
262
  }
92
263
 
93
- .swp-btn-primary:hover {
94
- background: #0056b3;
95
- border-color: #0056b3;
264
+ .swp-canvas-wrapper {
265
+ position: relative;
266
+ box-shadow: var(--swp-shadow);
96
267
  }
97
268
 
98
- .swp-btn-icon-only {
99
- padding: 0px 12px;
100
- justify-content: center;
101
- align-items: center;
102
- aspect-ratio: 1 / 1;
103
- max-width: 40px;
269
+ .swp-display-canvas,
270
+ .swp-overlay-canvas {
271
+ position: absolute;
272
+ top: 0;
273
+ left: 0;
104
274
  }
105
275
 
106
- .swp-icon {
107
- font-size: 18px;
276
+ .swp-overlay-canvas {
277
+ pointer-events: none;
108
278
  }
109
279
 
110
- .swp-layout-container {
111
- display: flex;
112
- flex-grow: 1;
280
+ /* ==================== BOTTOM MENU BAR ==================== */
281
+ .swp-menu-bar {
282
+ height: var(--swp-menu-height);
283
+ background: var(--swp-bg-medium);
284
+ border-top: 1px solid var(--swp-border);
285
+ display: flex;
286
+ align-items: center;
287
+ justify-content: center;
288
+ gap: 4px;
289
+ padding: 8px 16px;
290
+ flex-shrink: 0;
113
291
  }
114
292
 
115
- .swp-control-container {
116
- min-width: 348px;
117
- background: #f8f9fa;
118
- padding: 8px 16px;
293
+ .swp-menu-item {
294
+ display: flex;
295
+ flex-direction: column;
296
+ align-items: center;
297
+ justify-content: center;
298
+ gap: 4px;
299
+ width: 72px;
300
+ height: 64px;
301
+ padding: 8px;
302
+ background: transparent;
303
+ color: var(--swp-text-secondary);
304
+ border: none;
305
+ border-radius: var(--swp-radius);
306
+ cursor: pointer;
307
+ font-size: 12px;
308
+ font-weight: 500;
309
+ transition: all var(--swp-transition);
119
310
  }
120
311
 
121
- .swp-control-container.hidden {
122
- display: block;
312
+ .swp-menu-item:hover {
313
+ background: var(--swp-bg-hover);
314
+ color: var(--swp-text);
123
315
  }
124
316
 
125
- /* Canvas Container */
126
- .swp-canvas-container {
127
- position: relative;
128
- display: flex;
129
- align-items: center;
130
- justify-content: center;
131
- min-height: 400px;
132
- padding: 8px;
133
- border-top: 1px solid #dee2e6;
134
- border-right: 1px solid #dee2e6;
135
- border-top-right-radius: 8px;
136
- flex-grow: 1;
137
- min-width: 452px;;
317
+ .swp-menu-item.active {
318
+ background: var(--swp-accent);
319
+ color: var(--swp-accent-contrast);
138
320
  }
139
321
 
140
- .swp-canvas {
141
- max-width: 100%;
142
- height: auto;
143
- background: white;
322
+ .swp-menu-item ss-icon {
323
+ font-size: 24px;
144
324
  }
145
325
 
146
- /* Adjustments Panel */
147
- .swp-adjustments-panel,
148
- .swp-filters-panel,
149
- .swp-resize-panel {
150
- display: none;
326
+ /* ==================== SUBMENU ==================== */
327
+ .swp-submenu {
328
+ position: absolute;
329
+ bottom: calc(var(--swp-menu-height) + 16px);
330
+ left: 50%;
331
+ transform: translateX(-50%);
332
+ background: var(--swp-bg-medium);
333
+ border: 1px solid var(--swp-border);
334
+ border-radius: var(--swp-radius-lg);
335
+ box-shadow: var(--swp-shadow);
336
+ z-index: 100;
337
+ animation: swp-fade-up 0.2s ease;
151
338
  }
152
339
 
153
- .swp-adjustments-panel.active,
154
- .swp-filters-panel.active,
155
- .swp-resize-panel.active {
156
- display: block;
340
+ @keyframes swp-fade-up {
341
+ from {
342
+ opacity: 0;
343
+ transform: translateX(-50%) translateY(10px);
344
+ }
345
+ to {
346
+ opacity: 1;
347
+ transform: translateX(-50%) translateY(0);
348
+ }
157
349
  }
158
350
 
159
- .swp-adjustments-panel h3,
160
- .swp-filters-panel h3,
161
- .swp-resize-panel h3 {
162
- margin: 0 0 15px 0;
163
- font-size: 16px;
164
- font-weight: 600;
165
- color: #212529;
351
+ .swp-submenu[hidden] {
352
+ display: none;
166
353
  }
167
354
 
168
- .swp-adjustment {
169
- display: flex;
170
- align-items: center;
171
- gap: 12px;
172
- margin-bottom: 15px;
173
- width: 100%;
355
+ .swp-submenu-content {
356
+ padding: 20px 24px;
357
+ min-width: 280px;
174
358
  }
175
359
 
176
- .swp-adjustment label {
177
- min-width: 100px;
178
- font-size: 14px;
179
- color: #495057;
180
- font-weight: 500;
360
+ .swp-submenu-content.swp-submenu-wide {
361
+ min-width: 360px;
181
362
  }
182
363
 
183
- .swp-adjustment input[type="range"] {
184
- flex: 1;
185
- flex-shrink: 1;
186
- height: 6px;
187
- border-radius: 3px;
188
- background: #e9ecef;
189
- outline: none;
190
- -webkit-appearance: none;
364
+ .swp-submenu-title {
365
+ font-size: 16px;
366
+ font-weight: 600;
367
+ margin-bottom: 16px;
368
+ padding-bottom: 12px;
369
+ border-bottom: 1px solid var(--swp-border);
370
+ color: var(--swp-text);
191
371
  }
192
372
 
193
- .swp-adjustment input[type="range"]::-webkit-slider-thumb {
194
- -webkit-appearance: none;
195
- appearance: none;
196
- width: 18px;
197
- height: 18px;
198
- border-radius: 50%;
199
- background: #007bff;
200
- cursor: pointer;
201
- transition: all 0.2s ease;
373
+ .swp-submenu-group {
374
+ margin-bottom: 16px;
202
375
  }
203
376
 
204
- .swp-adjustment input[type="range"]::-webkit-slider-thumb:hover {
205
- background: #0056b3;
206
- transform: scale(1.1);
377
+ .swp-submenu-group:last-child {
378
+ margin-bottom: 0;
207
379
  }
208
380
 
209
- .swp-adjustment input[type="range"]::-moz-range-thumb {
210
- width: 18px;
211
- height: 18px;
212
- border-radius: 50%;
213
- background: #007bff;
214
- cursor: pointer;
215
- border: none;
216
- transition: all 0.2s ease;
381
+ .swp-submenu-label {
382
+ display: block;
383
+ font-size: 12px;
384
+ font-weight: 500;
385
+ color: var(--swp-text-secondary);
386
+ text-transform: uppercase;
387
+ letter-spacing: 0.5px;
388
+ margin-bottom: 8px;
217
389
  }
218
390
 
219
- .swp-adjustment input[type="range"]::-moz-range-thumb:hover {
220
- background: #0056b3;
221
- transform: scale(1.1);
391
+ /* Button Group */
392
+ .swp-btn-group {
393
+ display: flex;
394
+ gap: 6px;
222
395
  }
223
396
 
224
- .swp-value {
225
- text-align: right;
226
- font-size: 14px;
227
- color: #6c757d;
228
- font-weight: 500;
397
+ .swp-btn-group-lg .swp-submenu-btn {
398
+ flex: 1;
399
+ padding: 12px 16px;
229
400
  }
230
401
 
231
- /* Resize Panel */
232
- .swp-resize-controls {
233
- display: flex;
234
- flex-direction: column;
235
- gap: 15px;
402
+ .swp-submenu-btn {
403
+ display: flex;
404
+ align-items: center;
405
+ justify-content: center;
406
+ gap: 6px;
407
+ padding: 10px 14px;
408
+ background: var(--swp-bg-light);
409
+ color: var(--swp-text-secondary);
410
+ border: 1px solid var(--swp-border);
411
+ border-radius: var(--swp-radius-sm);
412
+ cursor: pointer;
413
+ font-size: 13px;
414
+ font-weight: 500;
415
+ transition: all var(--swp-transition);
236
416
  }
237
417
 
238
- .swp-resize-controls .swp-adjustment {
239
- display: flex;
240
- align-items: center;
241
- gap: 10px;
418
+ .swp-submenu-btn:hover {
419
+ background: var(--swp-bg-hover);
420
+ color: var(--swp-text);
421
+ border-color: var(--swp-border-light);
242
422
  }
243
423
 
244
- .swp-resize-controls input[type="number"] {
245
- flex: 1;
246
- padding: 8px 12px;
247
- border: 1px solid #dee2e6;
248
- border-radius: 6px;
249
- font-size: 14px;
250
- color: #495057;
424
+ .swp-submenu-btn.active {
425
+ background: var(--swp-accent);
426
+ color: var(--swp-accent-contrast);
427
+ border-color: var(--swp-accent);
251
428
  }
252
429
 
253
- .swp-resize-controls input[type="number"]:focus {
254
- outline: none;
255
- border-color: #007bff;
430
+ .swp-submenu-btn ss-icon {
431
+ font-size: 18px;
256
432
  }
257
433
 
258
- .swp-resize-controls input[type="checkbox"] {
259
- width: 18px;
260
- height: 18px;
261
- cursor: pointer;
434
+ /* Range Slider */
435
+ .swp-range-wrap {
436
+ display: flex;
437
+ align-items: center;
438
+ gap: 12px;
262
439
  }
263
440
 
264
- .swp-resize-controls label {
265
- display: flex;
266
- align-items: center;
267
- gap: 8px;
268
- cursor: pointer;
269
- font-size: 14px;
270
- color: #495057;
441
+ .swp-slider {
442
+ flex: 1;
443
+ -webkit-appearance: none;
444
+ appearance: none;
445
+ height: 6px;
446
+ background: var(--swp-bg-dark);
447
+ border-radius: 3px;
448
+ outline: none;
271
449
  }
272
450
 
273
- .swp-resize-controls button {
274
- margin-top: 10px;
451
+ .swp-slider::-webkit-slider-thumb {
452
+ -webkit-appearance: none;
453
+ appearance: none;
454
+ width: 18px;
455
+ height: 18px;
456
+ background: var(--swp-accent);
457
+ border-radius: 50%;
458
+ cursor: pointer;
459
+ transition: all var(--swp-transition);
460
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
275
461
  }
276
462
 
463
+ .swp-slider::-webkit-slider-thumb:hover {
464
+ transform: scale(1.15);
465
+ background: var(--swp-accent-hover);
466
+ }
467
+
468
+ .swp-slider::-moz-range-thumb {
469
+ width: 18px;
470
+ height: 18px;
471
+ background: var(--swp-accent);
472
+ border-radius: 50%;
473
+ cursor: pointer;
474
+ border: none;
475
+ }
476
+
477
+ .swp-range-value {
478
+ min-width: 48px;
479
+ font-size: 13px;
480
+ color: var(--swp-text);
481
+ text-align: right;
482
+ font-weight: 500;
483
+ }
484
+
485
+ /* Color Input */
486
+ .swp-color-input {
487
+ width: 100%;
488
+ height: 40px;
489
+ padding: 4px;
490
+ background: var(--swp-bg-dark);
491
+ border: 1px solid var(--swp-border);
492
+ border-radius: var(--swp-radius-sm);
493
+ cursor: pointer;
494
+ }
495
+
496
+ .swp-color-input::-webkit-color-swatch-wrapper {
497
+ padding: 0;
498
+ }
277
499
 
278
- /* Filters Panel */
279
- .swp-filters-grid {
280
- display: grid;
281
- grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
282
- gap: 15px;
500
+ .swp-color-input::-webkit-color-swatch {
501
+ border: none;
502
+ border-radius: 4px;
503
+ }
504
+
505
+ /* Select */
506
+ .swp-select {
507
+ width: 100%;
508
+ padding: 10px 12px;
509
+ background: var(--swp-bg-dark);
510
+ color: var(--swp-text);
511
+ border: 1px solid var(--swp-border);
512
+ border-radius: var(--swp-radius-sm);
513
+ font-size: 14px;
514
+ cursor: pointer;
515
+ outline: none;
516
+ transition: all var(--swp-transition);
517
+ }
518
+
519
+ .swp-select:focus {
520
+ border-color: var(--swp-accent);
521
+ box-shadow: 0 0 0 3px var(--swp-accent-dim);
522
+ }
523
+
524
+ /* Input Field */
525
+ .swp-input {
526
+ width: 100%;
527
+ padding: 10px 12px;
528
+ background: var(--swp-bg-dark);
529
+ color: var(--swp-text);
530
+ border: 1px solid var(--swp-border);
531
+ border-radius: var(--swp-radius-sm);
532
+ font-size: 14px;
533
+ outline: none;
534
+ transition: all var(--swp-transition);
535
+ }
536
+
537
+ .swp-input:focus {
538
+ border-color: var(--swp-accent);
539
+ box-shadow: 0 0 0 3px var(--swp-accent-dim);
540
+ }
541
+
542
+ /* Resize Inputs */
543
+ .swp-resize-inputs {
544
+ display: flex;
545
+ gap: 12px;
546
+ }
547
+
548
+ .swp-input-group {
549
+ flex: 1;
550
+ }
551
+
552
+ .swp-input-group label {
553
+ display: block;
554
+ font-size: 12px;
555
+ color: var(--swp-text-secondary);
556
+ margin-bottom: 6px;
557
+ }
558
+
559
+ /* Checkbox */
560
+ .swp-checkbox-label {
561
+ display: flex;
562
+ align-items: center;
563
+ gap: 8px;
564
+ font-size: 14px;
565
+ color: var(--swp-text);
566
+ cursor: pointer;
567
+ }
568
+
569
+ .swp-checkbox-label input[type="checkbox"] {
570
+ width: 18px;
571
+ height: 18px;
572
+ accent-color: var(--swp-accent);
573
+ cursor: pointer;
574
+ }
575
+
576
+ /* Button Group Wrap */
577
+ .swp-btn-group-wrap {
578
+ flex-wrap: wrap;
579
+ gap: 6px;
580
+ }
581
+
582
+ .swp-preset-btn {
583
+ font-size: 12px !important;
584
+ padding: 8px 12px !important;
585
+ }
586
+
587
+ /* Submenu Actions */
588
+ .swp-submenu-actions {
589
+ display: flex;
590
+ gap: 8px;
591
+ margin-top: 20px;
592
+ padding-top: 16px;
593
+ border-top: 1px solid var(--swp-border);
594
+ }
595
+
596
+ .swp-submenu-actions .swp-btn {
597
+ flex: 1;
598
+ }
599
+
600
+ /* Buttons */
601
+ .swp-btn {
602
+ padding: 10px 20px;
603
+ background: var(--swp-bg-light);
604
+ color: var(--swp-text);
605
+ border: 1px solid var(--swp-border);
606
+ border-radius: var(--swp-radius);
607
+ cursor: pointer;
608
+ font-size: 14px;
609
+ font-weight: 500;
610
+ transition: all var(--swp-transition);
611
+ }
612
+
613
+ .swp-btn:hover {
614
+ background: var(--swp-bg-hover);
615
+ border-color: var(--swp-border-light);
616
+ }
617
+
618
+ .swp-btn-primary {
619
+ background: var(--swp-accent);
620
+ color: var(--swp-accent-contrast);
621
+ border-color: var(--swp-accent);
622
+ }
623
+
624
+ .swp-btn-primary:hover {
625
+ background: var(--swp-accent-hover);
626
+ border-color: var(--swp-accent-hover);
627
+ }
628
+
629
+ /* ==================== FILTER GRID ==================== */
630
+ .swp-filter-grid {
631
+ display: grid;
632
+ grid-template-columns: repeat(4, 1fr);
633
+ gap: 8px;
283
634
  }
284
635
 
285
636
  .swp-filter-btn {
286
- display: flex;
287
- flex-direction: column;
288
- align-items: center;
289
- gap: 8px;
290
- padding: 12px;
291
- border: 2px solid #dee2e6;
292
- background: #ffffff;
293
- border-radius: 8px;
294
- cursor: pointer;
295
- font-size: 13px;
296
- color: #495057;
297
- transition: all 0.2s ease;
298
- font-family: inherit;
637
+ display: flex;
638
+ flex-direction: column;
639
+ align-items: center;
640
+ gap: 6px;
641
+ padding: 8px;
642
+ background: var(--swp-bg-light);
643
+ border: 2px solid transparent;
644
+ border-radius: var(--swp-radius-sm);
645
+ cursor: pointer;
646
+ font-size: 11px;
647
+ color: var(--swp-text-secondary);
648
+ transition: all var(--swp-transition);
299
649
  }
300
650
 
301
651
  .swp-filter-btn:hover {
302
- border-color: #007bff;
303
- background: #f8f9fa;
652
+ border-color: var(--swp-border-light);
653
+ color: var(--swp-text);
304
654
  }
305
655
 
306
656
  .swp-filter-btn.active {
307
- border-color: #007bff;
308
- background: #e7f3ff;
309
- color: #007bff;
310
- font-weight: 600;
657
+ border-color: var(--swp-accent);
658
+ color: var(--swp-text);
659
+ background: var(--swp-accent-dim);
311
660
  }
312
661
 
313
662
  .swp-filter-preview {
314
- width: 60px;
315
- height: 60px;
316
- border-radius: 6px;
317
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
318
- display: block;
663
+ width: 48px;
664
+ height: 48px;
665
+ background: linear-gradient(135deg, #ff6b6b, #4ecdc4, #45b7d1, #96c93d);
666
+ border-radius: 4px;
667
+ }
668
+
669
+ .swp-filter-grayscale .swp-filter-preview,
670
+ .swp-filter-btn[data-filter="grayscale"] .swp-filter-preview {
671
+ filter: grayscale(100%);
319
672
  }
320
673
 
321
- .swp-filter-preview[data-filter="grayscale"] {
322
- filter: grayscale(100%);
674
+ .swp-filter-sepia .swp-filter-preview,
675
+ .swp-filter-btn[data-filter="sepia"] .swp-filter-preview {
676
+ filter: sepia(100%);
323
677
  }
324
678
 
325
- .swp-filter-preview[data-filter="sepia"] {
326
- filter: sepia(100%);
679
+ .swp-filter-invert .swp-filter-preview,
680
+ .swp-filter-btn[data-filter="invert"] .swp-filter-preview {
681
+ filter: invert(100%);
327
682
  }
328
683
 
329
- .swp-filter-preview[data-filter="invert"] {
330
- filter: invert(100%);
684
+ .swp-filter-blur .swp-filter-preview,
685
+ .swp-filter-btn[data-filter="blur"] .swp-filter-preview {
686
+ filter: blur(2px);
331
687
  }
332
688
 
333
- .swp-filter-preview[data-filter="blur"] {
334
- filter: blur(3px);
689
+ .swp-filter-brightness .swp-filter-preview,
690
+ .swp-filter-btn[data-filter="brightness"] .swp-filter-preview {
691
+ filter: brightness(130%);
335
692
  }
336
693
 
337
- .swp-filter-preview[data-filter="none"] {
338
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
694
+ .swp-filter-contrast .swp-filter-preview,
695
+ .swp-filter-btn[data-filter="contrast"] .swp-filter-preview {
696
+ filter: contrast(150%);
339
697
  }
340
698
 
341
- /* Responsive Design */
699
+ .swp-filter-sharpen .swp-filter-preview,
700
+ .swp-filter-btn[data-filter="sharpen"] .swp-filter-preview {
701
+ filter: contrast(120%) saturate(110%);
702
+ }
703
+
704
+ /* ==================== TEXT INPUT ==================== */
705
+ .swp-text-input {
706
+ position: absolute;
707
+ opacity: 0;
708
+ pointer-events: none;
709
+ }
710
+
711
+ /* ==================== SCROLLBAR ==================== */
712
+ .swp-app ::-webkit-scrollbar {
713
+ width: 8px;
714
+ height: 8px;
715
+ }
716
+
717
+ .swp-app ::-webkit-scrollbar-track {
718
+ background: transparent;
719
+ }
720
+
721
+ .swp-app ::-webkit-scrollbar-thumb {
722
+ background: var(--swp-border);
723
+ border-radius: 4px;
724
+ }
725
+
726
+ .swp-app ::-webkit-scrollbar-thumb:hover {
727
+ background: var(--swp-border-light);
728
+ }
729
+
730
+ /* ==================== RESPONSIVE ==================== */
342
731
  @media (max-width: 768px) {
343
- .swp-toolbar {
344
- padding: 10px;
345
- gap: 5px;
346
- }
347
-
348
- .swp-toolbar-group {
349
- gap: 5px;
350
- }
351
-
352
- .swp-btn {
353
- padding: 6px 12px;
354
- font-size: 12px;
355
- }
356
-
357
- .swp-btn span:not(.swp-icon) {
358
- display: none;
359
- }
360
-
361
- .swp-canvas-container {
362
- min-height: 300px;
363
- padding: 10px;
364
- }
365
-
366
- .swp-adjustments-panel,
367
- .swp-filters-panel {
368
- padding: 15px;
369
- }
370
-
371
- .swp-adjustment {
372
- flex-wrap: wrap;
373
- }
374
-
375
- .swp-adjustment label {
376
- min-width: 100%;
377
- }
378
-
379
- .swp-filters-grid {
380
- grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
381
- gap: 10px;
382
- }
383
-
384
- .swp-filter-preview {
385
- width: 50px;
386
- height: 50px;
387
- }
388
- }
389
-
390
- /* Loading State */
391
- .swp-loading {
392
- position: absolute;
393
- top: 50%;
394
- left: 50%;
395
- transform: translate(-50%, -50%);
396
- font-size: 14px;
397
- color: #6c757d;
398
- }
399
-
400
- /* Empty State */
401
- .swp-empty-state {
402
- text-align: center;
403
- padding: 60px 20px;
404
- color: #6c757d;
405
- }
406
-
407
- .swp-empty-state-icon {
408
- font-size: 48px;
409
- margin-bottom: 15px;
410
- opacity: 0.5;
411
- }
412
-
413
- .swp-empty-state-text {
414
- font-size: 16px;
415
- margin-bottom: 20px;
416
- }
417
-
418
- /* Animations */
419
- @keyframes fadeIn {
420
- from {
421
- opacity: 0;
422
- transform: translateY(-10px);
423
- }
424
- to {
425
- opacity: 1;
426
- transform: translateY(0);
427
- }
428
- }
429
-
430
- .swp-adjustments-panel.active,
431
- .swp-filters-panel.active {
432
- animation: fadeIn 0.3s ease;
433
- }
434
-
435
- /* Print Styles */
436
- @media print {
437
- .swp-toolbar,
438
- .swp-adjustments-panel,
439
- .swp-filters-panel {
440
- display: none;
441
- }
442
-
443
- .swp-canvas-container {
444
- padding: 0;
445
- background: transparent;
446
- }
732
+ .swp-header {
733
+ padding: 0 12px;
734
+ }
735
+
736
+ .swp-header-btn span {
737
+ display: none;
738
+ }
739
+
740
+ .swp-header-btn {
741
+ padding: 10px 12px;
742
+ }
743
+
744
+ .swp-menu-item {
745
+ width: 56px;
746
+ height: 56px;
747
+ padding: 6px;
748
+ font-size: 10px;
749
+ }
750
+
751
+ .swp-menu-item ss-icon {
752
+ font-size: 20px;
753
+ }
754
+
755
+ .swp-menu-bar {
756
+ height: 72px;
757
+ gap: 2px;
758
+ padding: 8px;
759
+ }
760
+
761
+ .swp-submenu-content {
762
+ min-width: 260px;
763
+ padding: 16px;
764
+ }
765
+
766
+ .swp-submenu-content.swp-submenu-wide {
767
+ min-width: 300px;
768
+ }
769
+
770
+ .swp-filter-grid {
771
+ grid-template-columns: repeat(3, 1fr);
772
+ }
773
+ }
774
+
775
+ @media (max-width: 480px) {
776
+ .swp-header-left .swp-header-btn:nth-child(2) {
777
+ display: none;
778
+ }
779
+
780
+ .swp-menu-item {
781
+ width: 48px;
782
+ height: 52px;
783
+ }
784
+
785
+ .swp-menu-item span {
786
+ display: none;
787
+ }
788
+
789
+ .swp-submenu {
790
+ left: 8px;
791
+ right: 8px;
792
+ transform: none;
793
+ }
794
+
795
+ .swp-submenu-content,
796
+ .swp-submenu-content.swp-submenu-wide {
797
+ min-width: auto;
798
+ }
799
+
800
+ .swp-filter-grid {
801
+ grid-template-columns: repeat(2, 1fr);
802
+ }
803
+ }
804
+
805
+ /* ==================== SIDE PANEL ==================== */
806
+ .swp-side-panel {
807
+ position: absolute;
808
+ top: var(--swp-header-height);
809
+ right: 0;
810
+ width: 280px;
811
+ bottom: var(--swp-menu-height);
812
+ background: var(--swp-bg-medium);
813
+ border-left: 1px solid var(--swp-border);
814
+ display: flex;
815
+ flex-direction: column;
816
+ z-index: 50;
817
+ animation: swp-slide-in 0.2s ease;
818
+ }
819
+
820
+ @keyframes swp-slide-in {
821
+ from {
822
+ transform: translateX(100%);
823
+ opacity: 0;
824
+ }
825
+ to {
826
+ transform: translateX(0);
827
+ opacity: 1;
828
+ }
829
+ }
830
+
831
+ .swp-side-panel[hidden] {
832
+ display: none;
833
+ }
834
+
835
+ .swp-side-panel-header {
836
+ display: flex;
837
+ align-items: center;
838
+ justify-content: space-between;
839
+ padding: 12px 16px;
840
+ background: var(--swp-bg-light);
841
+ border-bottom: 1px solid var(--swp-border);
842
+ }
843
+
844
+ .swp-side-panel-title {
845
+ font-size: 14px;
846
+ font-weight: 600;
847
+ color: var(--swp-text);
848
+ }
849
+
850
+ .swp-side-panel-close {
851
+ width: 28px;
852
+ height: 28px;
853
+ }
854
+
855
+ .swp-side-panel-content {
856
+ flex: 1;
857
+ overflow-y: auto;
858
+ padding: 12px;
859
+ }
860
+
861
+ .swp-panel-list {
862
+ display: flex;
863
+ flex-direction: column;
864
+ gap: 4px;
865
+ }
866
+
867
+ .swp-panel-empty {
868
+ text-align: center;
869
+ color: var(--swp-text-dim);
870
+ padding: 24px;
871
+ font-size: 13px;
872
+ }
873
+
874
+ .swp-panel-item {
875
+ display: flex;
876
+ align-items: center;
877
+ gap: 10px;
878
+ padding: 10px 12px;
879
+ background: var(--swp-bg-dark);
880
+ border-radius: var(--swp-radius);
881
+ cursor: pointer;
882
+ transition: all var(--swp-transition);
883
+ border: 1px solid transparent;
884
+ font-size: 13px;
885
+ color: var(--swp-text-secondary);
886
+ }
887
+
888
+ .swp-panel-item:hover {
889
+ background: var(--swp-bg-hover);
890
+ color: var(--swp-text);
891
+ }
892
+
893
+ .swp-panel-item.active {
894
+ background: var(--swp-accent-dim);
895
+ border-color: var(--swp-accent);
896
+ color: var(--swp-text);
897
+ }
898
+
899
+ .swp-panel-item ss-icon {
900
+ font-size: 16px;
901
+ opacity: 0.7;
902
+ }
903
+
904
+ .swp-panel-item span {
905
+ flex: 1;
906
+ overflow: hidden;
907
+ text-overflow: ellipsis;
908
+ white-space: nowrap;
909
+ }
910
+
911
+ /* Layer visibility button */
912
+ .swp-layer-vis-btn {
913
+ width: 24px;
914
+ height: 24px;
915
+ border: none;
916
+ background: transparent;
917
+ cursor: pointer;
918
+ color: var(--swp-text-dim);
919
+ display: flex;
920
+ align-items: center;
921
+ justify-content: center;
922
+ border-radius: var(--swp-radius-sm);
923
+ transition: all var(--swp-transition);
924
+ }
925
+
926
+ .swp-layer-vis-btn:hover {
927
+ background: var(--swp-bg-light);
928
+ }
929
+
930
+ .swp-layer-vis-btn.visible {
931
+ color: var(--swp-accent);
932
+ }
933
+
934
+ .swp-layer-name {
935
+ flex: 1;
936
+ overflow: hidden;
937
+ text-overflow: ellipsis;
938
+ white-space: nowrap;
939
+ }
940
+
941
+ .swp-layer-opacity {
942
+ font-size: 11px;
943
+ color: var(--swp-text-dim);
944
+ background: var(--swp-bg-light);
945
+ padding: 2px 6px;
946
+ border-radius: 10px;
947
+ }
948
+
949
+ /* Panel Actions */
950
+ .swp-panel-actions {
951
+ display: flex;
952
+ gap: 8px;
953
+ padding: 8px;
954
+ border-top: 1px solid var(--swp-border);
955
+ background: var(--swp-bg-light);
956
+ justify-content: space-between;
957
+ margin-top: 12px;
958
+ border-radius: 10px;
959
+ }
960
+
961
+ .swp-btn-sm {
962
+ padding: 8px 12px;
963
+ font-size: 12px;
964
+ display: flex;
965
+ align-items: center;
966
+ gap: 6px;
967
+ }
968
+
969
+ .swp-btn-sm ss-icon {
970
+ font-size: 14px;
971
+ }
972
+
973
+ .swp-btn-danger {
974
+ color: var(--swp-error);
975
+ }
976
+
977
+ .swp-btn-danger:hover {
978
+ background: var(--swp-error);
979
+ color: white;
980
+ border-color: var(--swp-error);
981
+ }
982
+
983
+ /* Active state for header icon buttons */
984
+ .swp-icon-btn.active {
985
+ background: var(--swp-accent);
986
+ color: var(--swp-accent-contrast);
447
987
  }