windowpp 0.1.1
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.
- package/bin/windowpp.js +86 -0
- package/cmake/embed_assets.py +144 -0
- package/framework/CMakeLists.txt +176 -0
- package/framework/include/windowpp/windowpp.h +704 -0
- package/framework/src/AppData/API/AppData.ts +137 -0
- package/framework/src/AppData/appdata_bridge.h +138 -0
- package/framework/src/AppData/appdata_manager.cpp +126 -0
- package/framework/src/AppData/appdata_manager.h +3 -0
- package/framework/src/FileSystem/API/FileSystem.ts +389 -0
- package/framework/src/FileSystem/Linux/filesearch.cpp +148 -0
- package/framework/src/FileSystem/Linux/readfile.cpp +79 -0
- package/framework/src/FileSystem/Linux/savefile.cpp +333 -0
- package/framework/src/FileSystem/MacOS/filesearch.cpp +149 -0
- package/framework/src/FileSystem/MacOS/readfile.cpp +80 -0
- package/framework/src/FileSystem/MacOS/savefile.cpp +264 -0
- package/framework/src/FileSystem/Windows/filesearch.cpp +195 -0
- package/framework/src/FileSystem/Windows/readfile.cpp +122 -0
- package/framework/src/FileSystem/Windows/savefile.cpp +290 -0
- package/framework/src/FileSystem/file_index_service.cpp +262 -0
- package/framework/src/FileSystem/file_index_service.h +55 -0
- package/framework/src/FileSystem/filesystem_bridge.h +243 -0
- package/framework/src/FileSystem/filesystem_handler.h +93 -0
- package/framework/src/FileSystem/filesystem_json.h +241 -0
- package/framework/src/FileSystem/filesystem_search_service.cpp +414 -0
- package/framework/src/FileSystem/filesystem_search_service.h +94 -0
- package/framework/src/Input/API/Input.ts +161 -0
- package/framework/src/Input/Linux/linux_key_utils.h +135 -0
- package/framework/src/Input/MacOS/macos_key_utils.h +137 -0
- package/framework/src/Input/Windows/win32_key_utils.h +199 -0
- package/framework/src/Input/input_bridge.h +192 -0
- package/framework/src/Input/input_service.cpp +584 -0
- package/framework/src/Input/input_service.h +21 -0
- package/framework/src/application.cpp +29 -0
- package/framework/src/common/hit_test.cpp +40 -0
- package/framework/src/common/image_loader.cpp +24 -0
- package/framework/src/common/paths.cpp +75 -0
- package/framework/src/filedrop/filedrop.cpp +316 -0
- package/framework/src/filedrop/filedrop.css +421 -0
- package/framework/src/filedrop/filedrop.hpp +92 -0
- package/framework/src/filedrop/filedrop.ts +183 -0
- package/framework/src/platform/API/App.ts +156 -0
- package/framework/src/platform/API/Window.ts +249 -0
- package/framework/src/platform/linux/app_linux.cpp +256 -0
- package/framework/src/platform/linux/app_linux.h +64 -0
- package/framework/src/platform/linux/linux_helpers.cpp +26 -0
- package/framework/src/platform/linux/linux_helpers.h +19 -0
- package/framework/src/platform/linux/tray_linux.cpp +21 -0
- package/framework/src/platform/linux/tray_linux.h +26 -0
- package/framework/src/platform/linux/window_linux.cpp +256 -0
- package/framework/src/platform/linux/window_linux.h +70 -0
- package/framework/src/platform/macos/app_macos.h +59 -0
- package/framework/src/platform/macos/app_macos.mm +223 -0
- package/framework/src/platform/macos/macos_helpers.h +21 -0
- package/framework/src/platform/macos/tray_macos.h +22 -0
- package/framework/src/platform/macos/tray_macos.mm +53 -0
- package/framework/src/platform/macos/window_macos.h +74 -0
- package/framework/src/platform/macos/window_macos.mm +318 -0
- package/framework/src/platform/platform_bridge.h +514 -0
- package/framework/src/platform/platform_factory.cpp +33 -0
- package/framework/src/platform/platform_factory.h +19 -0
- package/framework/src/platform/win32/app_win32.cpp +572 -0
- package/framework/src/platform/win32/app_win32.h +83 -0
- package/framework/src/platform/win32/tray_win32.cpp +57 -0
- package/framework/src/platform/win32/tray_win32.h +30 -0
- package/framework/src/platform/win32/win32_helpers.h +61 -0
- package/framework/src/platform/win32/window_win32.cpp +267 -0
- package/framework/src/platform/win32/window_win32.h +79 -0
- package/framework/src/renderer/webgpu.h +128 -0
- package/framework/src/renderer/webview/include/WebView2.h +48014 -0
- package/framework/src/renderer/webview/include/WebView2EnvironmentOptions.h +342 -0
- package/framework/src/renderer/webview/webview.h +13 -0
- package/framework/src/renderer/webview/webview_linux.cpp +392 -0
- package/framework/src/renderer/webview/webview_macos.mm +388 -0
- package/framework/src/renderer/webview/webview_win32.cpp +688 -0
- package/framework/src/renderer/webview/x64/WebView2Loader.dll +0 -0
- package/framework/src/renderer/webview/x64/WebView2Loader.lib +0 -0
- package/framework/src/renderer/webview/x64/WebView2LoaderStatic.lib +0 -0
- package/lib/build.js +112 -0
- package/lib/create.js +283 -0
- package/lib/dev.js +155 -0
- package/package.json +24 -0
- package/scripts/publish.js +67 -0
- package/scripts/sync-framework.js +73 -0
- package/templates/solid/CMakeLists.txt +56 -0
- package/templates/solid/frontend/package.json +22 -0
- package/templates/solid/frontend/vite.config.ts +25 -0
- package/templates/solid/main.cpp +72 -0
- package/templates/solid/package.json +12 -0
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FileDrop Styles - Drop zone styling for drag & drop functionality
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* <div class="filedrop-zone">
|
|
6
|
+
* Drop files here
|
|
7
|
+
* </div>
|
|
8
|
+
*
|
|
9
|
+
* States automatically applied via JavaScript:
|
|
10
|
+
* - .wpp-dropzone-active: When drag enters the zone
|
|
11
|
+
* - .wpp-dropzone-disabled: When file drop is disabled
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/* ============================================================================
|
|
15
|
+
* BASE DROP ZONE STYLES
|
|
16
|
+
* ============================================================================ */
|
|
17
|
+
|
|
18
|
+
.wpp-dropzone {
|
|
19
|
+
position: relative;
|
|
20
|
+
display: flex;
|
|
21
|
+
flex-direction: column;
|
|
22
|
+
align-items: center;
|
|
23
|
+
justify-content: center;
|
|
24
|
+
min-height: 200px;
|
|
25
|
+
padding: 2rem;
|
|
26
|
+
border: 2px dashed #cbd5e1;
|
|
27
|
+
border-radius: 0.75rem;
|
|
28
|
+
background-color: #f8fafc;
|
|
29
|
+
transition: all 0.2s ease-in-out;
|
|
30
|
+
cursor: pointer;
|
|
31
|
+
user-select: none;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.wpp-dropzone:hover {
|
|
35
|
+
border-color: #94a3b8;
|
|
36
|
+
background-color: #f1f5f9;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* ============================================================================
|
|
40
|
+
* ACTIVE STATE (Drag Over)
|
|
41
|
+
* ============================================================================ */
|
|
42
|
+
|
|
43
|
+
.wpp-dropzone.wpp-dropzone-active {
|
|
44
|
+
border-color: #3b82f6;
|
|
45
|
+
background-color: #eff6ff;
|
|
46
|
+
border-width: 3px;
|
|
47
|
+
transform: scale(1.02);
|
|
48
|
+
box-shadow: 0 0 0 4px rgba(59, 130, 246, 0.1);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.wpp-dropzone.wpp-dropzone-active::before {
|
|
52
|
+
content: '';
|
|
53
|
+
position: absolute;
|
|
54
|
+
inset: 0;
|
|
55
|
+
border-radius: 0.5rem;
|
|
56
|
+
background: linear-gradient(135deg, rgba(59, 130, 246, 0.05), rgba(147, 51, 234, 0.05));
|
|
57
|
+
pointer-events: none;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/* ============================================================================
|
|
61
|
+
* DISABLED STATE
|
|
62
|
+
* ============================================================================ */
|
|
63
|
+
|
|
64
|
+
.wpp-dropzone.wpp-dropzone-disabled {
|
|
65
|
+
opacity: 0.5;
|
|
66
|
+
cursor: not-allowed;
|
|
67
|
+
border-color: #e2e8f0;
|
|
68
|
+
background-color: #f8fafc;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.wpp-dropzone.wpp-dropzone-disabled:hover {
|
|
72
|
+
border-color: #e2e8f0;
|
|
73
|
+
background-color: #f8fafc;
|
|
74
|
+
transform: none;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/* ============================================================================
|
|
78
|
+
* DROP ZONE CONTENT
|
|
79
|
+
* ============================================================================ */
|
|
80
|
+
|
|
81
|
+
.wpp-dropzone-content {
|
|
82
|
+
display: flex;
|
|
83
|
+
flex-direction: column;
|
|
84
|
+
align-items: center;
|
|
85
|
+
gap: 1rem;
|
|
86
|
+
text-align: center;
|
|
87
|
+
pointer-events: none;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.wpp-dropzone-icon {
|
|
91
|
+
width: 3rem;
|
|
92
|
+
height: 3rem;
|
|
93
|
+
color: #94a3b8;
|
|
94
|
+
transition: all 0.2s ease-in-out;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.wpp-dropzone.wpp-dropzone-active .wpp-dropzone-icon {
|
|
98
|
+
color: #3b82f6;
|
|
99
|
+
transform: scale(1.2);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.wpp-dropzone.wpp-dropzone-disabled .wpp-dropzone-icon {
|
|
103
|
+
color: #cbd5e1;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.wpp-dropzone-text {
|
|
107
|
+
font-size: 1rem;
|
|
108
|
+
font-weight: 500;
|
|
109
|
+
color: #475569;
|
|
110
|
+
transition: color 0.2s ease-in-out;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.wpp-dropzone.wpp-dropzone-active .wpp-dropzone-text {
|
|
114
|
+
color: #3b82f6;
|
|
115
|
+
font-weight: 600;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.wpp-dropzone.wpp-dropzone-disabled .wpp-dropzone-text {
|
|
119
|
+
color: #cbd5e1;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.wpp-dropzone-hint {
|
|
123
|
+
font-size: 0.875rem;
|
|
124
|
+
color: #94a3b8;
|
|
125
|
+
transition: color 0.2s ease-in-out;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.wpp-dropzone.wpp-dropzone-active .wpp-dropzone-hint {
|
|
129
|
+
color: #60a5fa;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.wpp-dropzone.wpp-dropzone-disabled .wpp-dropzone-hint {
|
|
133
|
+
color: #cbd5e1;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/* ============================================================================
|
|
137
|
+
* COMPACT VARIANT
|
|
138
|
+
* ============================================================================ */
|
|
139
|
+
|
|
140
|
+
.wpp-dropzone.wpp-dropzone-compact {
|
|
141
|
+
min-height: 120px;
|
|
142
|
+
padding: 1.5rem;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.wpp-dropzone.wpp-dropzone-compact .wpp-dropzone-icon {
|
|
146
|
+
width: 2rem;
|
|
147
|
+
height: 2rem;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.wpp-dropzone.wpp-dropzone-compact .wpp-dropzone-text {
|
|
151
|
+
font-size: 0.875rem;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.wpp-dropzone.wpp-dropzone-compact .wpp-dropzone-hint {
|
|
155
|
+
font-size: 0.75rem;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/* ============================================================================
|
|
159
|
+
* INLINE VARIANT (Full Width)
|
|
160
|
+
* ============================================================================ */
|
|
161
|
+
|
|
162
|
+
.wpp-dropzone.wpp-dropzone-inline {
|
|
163
|
+
min-height: 80px;
|
|
164
|
+
padding: 1rem;
|
|
165
|
+
flex-direction: row;
|
|
166
|
+
justify-content: flex-start;
|
|
167
|
+
gap: 1rem;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.wpp-dropzone.wpp-dropzone-inline .wpp-dropzone-content {
|
|
171
|
+
flex-direction: row;
|
|
172
|
+
align-items: center;
|
|
173
|
+
text-align: left;
|
|
174
|
+
gap: 0.75rem;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.wpp-dropzone.wpp-dropzone-inline .wpp-dropzone-icon {
|
|
178
|
+
width: 2rem;
|
|
179
|
+
height: 2rem;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/* ============================================================================
|
|
183
|
+
* FILE LIST DISPLAY
|
|
184
|
+
* ============================================================================ */
|
|
185
|
+
|
|
186
|
+
.wpp-dropzone-files {
|
|
187
|
+
margin-top: 1rem;
|
|
188
|
+
width: 100%;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.wpp-dropzone-file-item {
|
|
192
|
+
display: flex;
|
|
193
|
+
align-items: center;
|
|
194
|
+
gap: 0.75rem;
|
|
195
|
+
padding: 0.75rem;
|
|
196
|
+
background-color: white;
|
|
197
|
+
border: 1px solid #e2e8f0;
|
|
198
|
+
border-radius: 0.5rem;
|
|
199
|
+
margin-bottom: 0.5rem;
|
|
200
|
+
transition: all 0.2s ease-in-out;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.wpp-dropzone-file-item:hover {
|
|
204
|
+
border-color: #cbd5e1;
|
|
205
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.wpp-dropzone-file-icon {
|
|
209
|
+
width: 2rem;
|
|
210
|
+
height: 2rem;
|
|
211
|
+
flex-shrink: 0;
|
|
212
|
+
display: flex;
|
|
213
|
+
align-items: center;
|
|
214
|
+
justify-content: center;
|
|
215
|
+
background-color: #f1f5f9;
|
|
216
|
+
border-radius: 0.375rem;
|
|
217
|
+
color: #64748b;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.wpp-dropzone-file-info {
|
|
221
|
+
flex: 1;
|
|
222
|
+
min-width: 0;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.wpp-dropzone-file-name {
|
|
226
|
+
font-size: 0.875rem;
|
|
227
|
+
font-weight: 500;
|
|
228
|
+
color: #334155;
|
|
229
|
+
white-space: nowrap;
|
|
230
|
+
overflow: hidden;
|
|
231
|
+
text-overflow: ellipsis;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.wpp-dropzone-file-meta {
|
|
235
|
+
font-size: 0.75rem;
|
|
236
|
+
color: #94a3b8;
|
|
237
|
+
margin-top: 0.125rem;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.wpp-dropzone-file-remove {
|
|
241
|
+
flex-shrink: 0;
|
|
242
|
+
width: 1.5rem;
|
|
243
|
+
height: 1.5rem;
|
|
244
|
+
display: flex;
|
|
245
|
+
align-items: center;
|
|
246
|
+
justify-content: center;
|
|
247
|
+
border-radius: 0.25rem;
|
|
248
|
+
color: #94a3b8;
|
|
249
|
+
cursor: pointer;
|
|
250
|
+
transition: all 0.2s ease-in-out;
|
|
251
|
+
pointer-events: auto;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.wpp-dropzone-file-remove:hover {
|
|
255
|
+
background-color: #fee2e2;
|
|
256
|
+
color: #ef4444;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/* ============================================================================
|
|
260
|
+
* DARK MODE SUPPORT
|
|
261
|
+
* ============================================================================ */
|
|
262
|
+
|
|
263
|
+
@media (prefers-color-scheme: dark) {
|
|
264
|
+
.wpp-dropzone {
|
|
265
|
+
border-color: #475569;
|
|
266
|
+
background-color: #1e293b;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.wpp-dropzone:hover {
|
|
270
|
+
border-color: #64748b;
|
|
271
|
+
background-color: #334155;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.wpp-dropzone.wpp-dropzone-active {
|
|
275
|
+
border-color: #60a5fa;
|
|
276
|
+
background-color: #1e3a8a;
|
|
277
|
+
box-shadow: 0 0 0 4px rgba(96, 165, 250, 0.1);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
.wpp-dropzone.wpp-dropzone-active::before {
|
|
281
|
+
background: linear-gradient(135deg, rgba(96, 165, 250, 0.1), rgba(168, 85, 247, 0.1));
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.wpp-dropzone.wpp-dropzone-disabled {
|
|
285
|
+
border-color: #334155;
|
|
286
|
+
background-color: #1e293b;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.wpp-dropzone-icon {
|
|
290
|
+
color: #64748b;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.wpp-dropzone.wpp-dropzone-active .wpp-dropzone-icon {
|
|
294
|
+
color: #60a5fa;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.wpp-dropzone.wpp-dropzone-disabled .wpp-dropzone-icon {
|
|
298
|
+
color: #475569;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
.wpp-dropzone-text {
|
|
302
|
+
color: #cbd5e1;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.wpp-dropzone.wpp-dropzone-active .wpp-dropzone-text {
|
|
306
|
+
color: #93c5fd;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.wpp-dropzone.wpp-dropzone-disabled .wpp-dropzone-text {
|
|
310
|
+
color: #64748b;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.wpp-dropzone-hint {
|
|
314
|
+
color: #64748b;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.wpp-dropzone.wpp-dropzone-active .wpp-dropzone-hint {
|
|
318
|
+
color: #93c5fd;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.wpp-dropzone-file-item {
|
|
322
|
+
background-color: #334155;
|
|
323
|
+
border-color: #475569;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.wpp-dropzone-file-item:hover {
|
|
327
|
+
border-color: #64748b;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
.wpp-dropzone-file-icon {
|
|
331
|
+
background-color: #1e293b;
|
|
332
|
+
color: #94a3b8;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.wpp-dropzone-file-name {
|
|
336
|
+
color: #e2e8f0;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
.wpp-dropzone-file-meta {
|
|
340
|
+
color: #64748b;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.wpp-dropzone-file-remove:hover {
|
|
344
|
+
background-color: #7f1d1d;
|
|
345
|
+
color: #fca5a5;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/* ============================================================================
|
|
350
|
+
* ANIMATION UTILITIES
|
|
351
|
+
* ============================================================================ */
|
|
352
|
+
|
|
353
|
+
@keyframes filedrop-pulse {
|
|
354
|
+
0%, 100% {
|
|
355
|
+
opacity: 1;
|
|
356
|
+
}
|
|
357
|
+
50% {
|
|
358
|
+
opacity: 0.7;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
.wpp-dropzone.wpp-dropzone-processing {
|
|
363
|
+
animation: filedrop-pulse 1.5s ease-in-out infinite;
|
|
364
|
+
pointer-events: none;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
@keyframes filedrop-shake {
|
|
368
|
+
0%, 100% {
|
|
369
|
+
transform: translateX(0);
|
|
370
|
+
}
|
|
371
|
+
25% {
|
|
372
|
+
transform: translateX(-4px);
|
|
373
|
+
}
|
|
374
|
+
75% {
|
|
375
|
+
transform: translateX(4px);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.wpp-dropzone.wpp-dropzone-error {
|
|
380
|
+
border-color: #ef4444;
|
|
381
|
+
background-color: #fee2e2;
|
|
382
|
+
animation: filedrop-shake 0.3s ease-in-out;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
@media (prefers-color-scheme: dark) {
|
|
386
|
+
.wpp-dropzone.wpp-dropzone-error {
|
|
387
|
+
border-color: #f87171;
|
|
388
|
+
background-color: #7f1d1d;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/* ============================================================================
|
|
393
|
+
* CUSTOM VARIANTS
|
|
394
|
+
* ============================================================================ */
|
|
395
|
+
|
|
396
|
+
/* Minimal variant - subtle styling */
|
|
397
|
+
.wpp-dropzone.wpp-dropzone-minimal {
|
|
398
|
+
border-style: solid;
|
|
399
|
+
border-width: 1px;
|
|
400
|
+
background-color: transparent;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.wpp-dropzone.wpp-dropzone-minimal:hover {
|
|
404
|
+
background-color: rgba(0, 0, 0, 0.02);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
@media (prefers-color-scheme: dark) {
|
|
408
|
+
.wpp-dropzone.wpp-dropzone-minimal:hover {
|
|
409
|
+
background-color: rgba(255, 255, 255, 0.02);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/* Bold variant - prominent styling */
|
|
414
|
+
.wpp-dropzone.wpp-dropzone-bold {
|
|
415
|
+
border-width: 3px;
|
|
416
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.wpp-dropzone.wpp-dropzone-bold.wpp-dropzone-active {
|
|
420
|
+
box-shadow: 0 8px 16px rgba(59, 130, 246, 0.2);
|
|
421
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <cstdint>
|
|
4
|
+
#include <string>
|
|
5
|
+
#include <vector>
|
|
6
|
+
#include <functional>
|
|
7
|
+
|
|
8
|
+
namespace pw {
|
|
9
|
+
class Window;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
namespace pw {
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* FileInfo - Represents a dropped file
|
|
16
|
+
*/
|
|
17
|
+
struct FileInfo {
|
|
18
|
+
std::string path; // Full path to the file
|
|
19
|
+
std::string name; // File name with extension
|
|
20
|
+
std::string type; // MIME type (e.g., "image/png", "text/plain")
|
|
21
|
+
std::uint64_t size; // File size in bytes
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* FileDrop - Cross-platform drag & drop file handling
|
|
26
|
+
*
|
|
27
|
+
* Enables dragging files into the webview window and from the window to the desktop.
|
|
28
|
+
* Supports all file types cross-platform (Windows, macOS, Linux).
|
|
29
|
+
*/
|
|
30
|
+
class FileDrop {
|
|
31
|
+
public:
|
|
32
|
+
FileDrop();
|
|
33
|
+
~FileDrop();
|
|
34
|
+
|
|
35
|
+
static FileDrop& instance() {
|
|
36
|
+
static FileDrop instance;
|
|
37
|
+
return instance;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Attach FileDrop handlers to a Window
|
|
42
|
+
*/
|
|
43
|
+
void attach(void* nativeWindowHandle);
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Enable or disable file drop into window
|
|
47
|
+
* @param enabled - true to allow files to be dropped into the window
|
|
48
|
+
*/
|
|
49
|
+
void setEnabled(bool enabled);
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Check if file drop is currently enabled
|
|
53
|
+
* @return true if file drop is enabled
|
|
54
|
+
*/
|
|
55
|
+
bool isEnabled() const;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Set callback for when files are dropped into the window
|
|
59
|
+
* @param callback - Function called with array of dropped files
|
|
60
|
+
*/
|
|
61
|
+
void onFilesDropped(std::function<void(const std::vector<FileInfo>&)> callback);
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Set callback for when a drag operation enters the window
|
|
65
|
+
* @param callback - Function called when drag enters
|
|
66
|
+
*/
|
|
67
|
+
void onDragEnter(std::function<void()> callback);
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Set callback for when a drag operation leaves the window
|
|
71
|
+
* @param callback - Function called when drag leaves
|
|
72
|
+
*/
|
|
73
|
+
void onDragLeave(std::function<void()> callback);
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Start a drag operation to drag files out of the window
|
|
77
|
+
* @param filePaths - Paths to files to be dragged
|
|
78
|
+
* @return true if drag operation started successfully
|
|
79
|
+
*/
|
|
80
|
+
bool startDrag(const std::vector<std::string>& filePaths);
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Clear all callbacks
|
|
84
|
+
*/
|
|
85
|
+
void clearCallbacks();
|
|
86
|
+
|
|
87
|
+
private:
|
|
88
|
+
struct Impl;
|
|
89
|
+
Impl* pImpl;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
} // namespace pw
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WindowPP FileDrop API
|
|
3
|
+
*
|
|
4
|
+
* Simple API for handling OS file drops in your app.
|
|
5
|
+
* Enable in config: .fileDrop(true)
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* import windowpp from 'windowpp';
|
|
9
|
+
*
|
|
10
|
+
* // Listen for file drops on a zone
|
|
11
|
+
* windowpp.fileDrop.onFiles('myZone', (files) => {
|
|
12
|
+
* console.log('Dropped:', files.map(f => f.name));
|
|
13
|
+
* });
|
|
14
|
+
*
|
|
15
|
+
* // Or use data-dropzone attribute
|
|
16
|
+
* // <div data-dropzone="upload"></div>
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
export interface FileInfo {
|
|
20
|
+
path: string;
|
|
21
|
+
name: string;
|
|
22
|
+
type: string;
|
|
23
|
+
size: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface DropZone {
|
|
27
|
+
name: string;
|
|
28
|
+
onFiles(callback: (files: FileInfo[]) => void): () => void;
|
|
29
|
+
onDragEnter(callback: () => void): () => void;
|
|
30
|
+
onDragLeave(callback: () => void): () => void;
|
|
31
|
+
element: HTMLElement | null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface PendingCall {
|
|
35
|
+
resolve: (v: any) => void;
|
|
36
|
+
reject: (e: any) => void;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let callId = 0;
|
|
40
|
+
const pending = new Map<string, PendingCall>();
|
|
41
|
+
const zones = new Map<string, DropZone>();
|
|
42
|
+
|
|
43
|
+
function getGlobal(): any {
|
|
44
|
+
if (typeof window !== 'undefined') return window;
|
|
45
|
+
if (typeof globalThis !== 'undefined') return globalThis;
|
|
46
|
+
return {};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const g = getGlobal();
|
|
50
|
+
const previousResponse = g.__response__;
|
|
51
|
+
|
|
52
|
+
g.__response__ = function(id: string, result: any, error?: any) {
|
|
53
|
+
const p = pending.get(id);
|
|
54
|
+
if (p) {
|
|
55
|
+
pending.delete(id);
|
|
56
|
+
error ? p.reject(new Error(error)) : p.resolve(result);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (previousResponse) {
|
|
61
|
+
previousResponse(id, result, error);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
g.__wpp_fileDrop__ = function(zoneName: string, files: FileInfo[]) {
|
|
66
|
+
const zone = zones.get(zoneName);
|
|
67
|
+
if (zone) {
|
|
68
|
+
const cb = (zone as any).__onFiles;
|
|
69
|
+
if (cb) cb(files);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
async function invoke<T>(method: string, params: any[] = []): Promise<T> {
|
|
74
|
+
return new Promise((resolve, reject) => {
|
|
75
|
+
const id = String(++callId);
|
|
76
|
+
pending.set(id, { resolve, reject });
|
|
77
|
+
const payload = JSON.stringify({ id, method, params });
|
|
78
|
+
|
|
79
|
+
if (g.__native_invoke__) {
|
|
80
|
+
g.__native_invoke__(payload);
|
|
81
|
+
} else if (g.chrome && g.chrome.webview && g.chrome.webview.postMessage) {
|
|
82
|
+
g.chrome.webview.postMessage(payload);
|
|
83
|
+
} else {
|
|
84
|
+
pending.delete(id);
|
|
85
|
+
console.warn('[WindowPP] Native bridge not ready');
|
|
86
|
+
resolve(null as T);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function createDropZone(name: string, element?: HTMLElement | null): DropZone {
|
|
92
|
+
const el = element || document.querySelector(`[data-dropzone="${name}"]`) as HTMLElement;
|
|
93
|
+
|
|
94
|
+
if (el) {
|
|
95
|
+
el.setAttribute('data-dropzone', name);
|
|
96
|
+
el.classList.add('wpp-dropzone');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const zone: DropZone = {
|
|
100
|
+
name,
|
|
101
|
+
element: el,
|
|
102
|
+
onFiles: (callback: (files: FileInfo[]) => void) => {
|
|
103
|
+
(zone as any).__onFiles = callback;
|
|
104
|
+
zones.set(name, zone);
|
|
105
|
+
return () => {
|
|
106
|
+
(zone as any).__onFiles = undefined;
|
|
107
|
+
zones.delete(name);
|
|
108
|
+
};
|
|
109
|
+
},
|
|
110
|
+
onDragEnter: (callback: () => void) => {
|
|
111
|
+
(zone as any).__onDragEnter = callback;
|
|
112
|
+
return () => { (zone as any).__onDragEnter = undefined; };
|
|
113
|
+
},
|
|
114
|
+
onDragLeave: (callback: () => void) => {
|
|
115
|
+
(zone as any).__onDragLeave = callback;
|
|
116
|
+
return () => { (zone as any).__onDragLeave = undefined; };
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
zones.set(name, zone);
|
|
121
|
+
return zone;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export const fileDrop = {
|
|
125
|
+
createDropZone,
|
|
126
|
+
|
|
127
|
+
onFiles: (name: string, callback: (files: FileInfo[]) => void): (() => void) => {
|
|
128
|
+
const zone = zones.get(name);
|
|
129
|
+
if (zone) {
|
|
130
|
+
return zone.onFiles(callback);
|
|
131
|
+
}
|
|
132
|
+
const newZone = createDropZone(name);
|
|
133
|
+
return newZone.onFiles(callback);
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
setEnabled: (enabled: boolean): Promise<void> =>
|
|
137
|
+
invoke<void>('wpp.fileDrop.setEnabled', [enabled]),
|
|
138
|
+
|
|
139
|
+
isEnabled: (): Promise<boolean> =>
|
|
140
|
+
invoke<boolean>('wpp.fileDrop.isEnabled'),
|
|
141
|
+
|
|
142
|
+
startDrag: (filePaths: string[]): Promise<void> =>
|
|
143
|
+
invoke<void>('wpp.fileDrop.startDrag', [filePaths]),
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
export function formatFileSize(bytes: number): string {
|
|
147
|
+
if (bytes === 0) return '0 B';
|
|
148
|
+
const k = 1024;
|
|
149
|
+
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
150
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
151
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function filterFilesByExtension(files: FileInfo[], extensions: string[]): FileInfo[] {
|
|
155
|
+
const exts = extensions.map(e => e.toLowerCase().replace(/^\./, ''));
|
|
156
|
+
return files.filter(f => {
|
|
157
|
+
const ext = f.name.split('.').pop()?.toLowerCase() || '';
|
|
158
|
+
return exts.includes(ext);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export function filterFilesByMimeType(files: FileInfo[], mimeTypes: string[]): FileInfo[] {
|
|
163
|
+
return files.filter(f => mimeTypes.includes(f.type));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export function isImageFile(file: FileInfo): boolean {
|
|
167
|
+
return file.type.startsWith('image/');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function isVideoFile(file: FileInfo): boolean {
|
|
171
|
+
return file.type.startsWith('video/');
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function isAudioFile(file: FileInfo): boolean {
|
|
175
|
+
return file.type.startsWith('audio/');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export function isTextFile(file: FileInfo): boolean {
|
|
179
|
+
return file.type.startsWith('text/') || file.name.endsWith('.txt') ||
|
|
180
|
+
file.name.endsWith('.md') || file.name.endsWith('.json');
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export default fileDrop;
|