plusui-native 0.2.62 → 0.2.65
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "plusui-native",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.65",
|
|
4
4
|
"description": "PlusUI CLI - Build C++ desktop apps modern UI ",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
"semver": "^7.6.0",
|
|
28
28
|
"which": "^4.0.0",
|
|
29
29
|
"execa": "^8.0.1",
|
|
30
|
-
"plusui-native-builder": "^0.1.
|
|
31
|
-
"plusui-native-connect": "^0.1.
|
|
30
|
+
"plusui-native-builder": "^0.1.64",
|
|
31
|
+
"plusui-native-connect": "^0.1.64"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
|
-
"plusui-native-connect": "^0.1.
|
|
34
|
+
"plusui-native-connect": "^0.1.64"
|
|
35
35
|
},
|
|
36
36
|
"publishConfig": {
|
|
37
37
|
"access": "public"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useState, useEffect } from 'react';
|
|
2
|
-
import plusui
|
|
3
|
-
//
|
|
4
|
-
|
|
2
|
+
import plusui from 'plusui';
|
|
3
|
+
// Generated by `plusui connect` — channel objects auto-created from name.on / name.emit usage:
|
|
4
|
+
import { customFileDrop } from '../Connections/connections.gen';
|
|
5
5
|
|
|
6
6
|
// Define routes for your app (optional - for SPA routing)
|
|
7
7
|
const routes = {
|
|
@@ -17,11 +17,10 @@ function App() {
|
|
|
17
17
|
const [canGoBack, setCanGoBack] = useState(false);
|
|
18
18
|
const [canGoForward, setCanGoForward] = useState(false);
|
|
19
19
|
|
|
20
|
-
//
|
|
21
|
-
const [files, setFiles] = useState<FileInfo[]>([]);
|
|
20
|
+
// customFileDrop connect channel state
|
|
22
21
|
const [isDragging, setIsDragging] = useState(false);
|
|
23
|
-
const [
|
|
24
|
-
const [
|
|
22
|
+
const [droppedFiles, setDroppedFiles] = useState<{ name: string; size: number; type: string }[]>([]);
|
|
23
|
+
const [backendMsg, setBackendMsg] = useState<string | null>(null);
|
|
25
24
|
|
|
26
25
|
useEffect(() => {
|
|
27
26
|
plusui.win.show().catch(() => {
|
|
@@ -38,21 +37,11 @@ function App() {
|
|
|
38
37
|
plusui.browser.canGoForward().then(setCanGoForward);
|
|
39
38
|
});
|
|
40
39
|
|
|
41
|
-
//
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
setFiles(prev => [...prev, ...droppedFiles]);
|
|
45
|
-
setIsDragging(false);
|
|
40
|
+
// Listen for responses emitted from C++ via ch.customFileDrop.emit(...) in main.cpp
|
|
41
|
+
const unsubChannel = customFileDrop.on((data: any) => {
|
|
42
|
+
setBackendMsg(data?.message ?? JSON.stringify(data));
|
|
46
43
|
});
|
|
47
|
-
|
|
48
|
-
const unsubEnter = plusui.fileDrop.onDragEnter(() => {
|
|
49
|
-
setIsDragging(true);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
const unsubLeave = plusui.fileDrop.onDragLeave(() => {
|
|
53
|
-
setIsDragging(false);
|
|
54
|
-
});
|
|
55
|
-
|
|
44
|
+
|
|
56
45
|
// Get initial state
|
|
57
46
|
plusui.browser.getUrl().then(setCurrentUrl);
|
|
58
47
|
plusui.browser.canGoBack().then(setCanGoBack);
|
|
@@ -60,9 +49,7 @@ function App() {
|
|
|
60
49
|
|
|
61
50
|
return () => {
|
|
62
51
|
unsub();
|
|
63
|
-
|
|
64
|
-
unsubEnter();
|
|
65
|
-
unsubLeave();
|
|
52
|
+
unsubChannel();
|
|
66
53
|
};
|
|
67
54
|
}, []);
|
|
68
55
|
|
|
@@ -90,6 +77,22 @@ function App() {
|
|
|
90
77
|
// App control
|
|
91
78
|
const handleQuit = async () => await plusui.app.quit();
|
|
92
79
|
|
|
80
|
+
// customFileDrop drag handlers — use HTML5 drag events to collect files, then
|
|
81
|
+
// emit them to the C++ backend via the connect channel
|
|
82
|
+
const handleDragOver = (e: React.DragEvent) => { e.preventDefault(); setIsDragging(true); };
|
|
83
|
+
const handleDragLeave = (e: React.DragEvent) => { e.preventDefault(); setIsDragging(false); };
|
|
84
|
+
const handleDrop = (e: React.DragEvent) => {
|
|
85
|
+
e.preventDefault();
|
|
86
|
+
setIsDragging(false);
|
|
87
|
+
const items = Array.from(e.dataTransfer.files).map(f => ({
|
|
88
|
+
name: f.name, size: f.size, type: f.type || 'unknown',
|
|
89
|
+
}));
|
|
90
|
+
setDroppedFiles(items);
|
|
91
|
+
setBackendMsg(null);
|
|
92
|
+
// Emit to C++ — ch.customFileDrop.on() in main.cpp receives this
|
|
93
|
+
customFileDrop.emit({ files: items });
|
|
94
|
+
};
|
|
95
|
+
|
|
93
96
|
return (
|
|
94
97
|
<div className="app">
|
|
95
98
|
<header className="app-header">
|
|
@@ -154,67 +157,57 @@ function App() {
|
|
|
154
157
|
</div>
|
|
155
158
|
|
|
156
159
|
<div className="card">
|
|
157
|
-
<h2>
|
|
160
|
+
<h2>Custom Channel — File Drop</h2>
|
|
158
161
|
<p style={{ fontSize: '0.85em', color: '#aaa', marginBottom: '1rem' }}>
|
|
159
|
-
|
|
160
|
-
to
|
|
162
|
+
Drop files below. The frontend calls <code>customFileDrop.emit()</code> to send file
|
|
163
|
+
info to C++. The C++ handler calls <code>ch.customFileDrop.emit()</code> to reply.
|
|
164
|
+
The frontend receives the reply via <code>customFileDrop.on()</code>. Run{' '}
|
|
165
|
+
<code>plusui connect</code> to regenerate the channel bindings from both sides.
|
|
161
166
|
</p>
|
|
162
167
|
|
|
163
|
-
<div className="filedrop-control-row">
|
|
164
|
-
<label className="filedrop-control-label">Style:</label>
|
|
165
|
-
<select
|
|
166
|
-
value={dropZoneStyle}
|
|
167
|
-
onChange={(e) => setDropZoneStyle(e.target.value)}
|
|
168
|
-
className="filedrop-control-select"
|
|
169
|
-
>
|
|
170
|
-
<option value="">Default</option>
|
|
171
|
-
<option value="filedrop-compact">Compact</option>
|
|
172
|
-
<option value="filedrop-inline">Inline</option>
|
|
173
|
-
<option value="filedrop-minimal">Minimal</option>
|
|
174
|
-
<option value="filedrop-bold">Bold</option>
|
|
175
|
-
</select>
|
|
176
|
-
</div>
|
|
177
|
-
|
|
178
168
|
<div
|
|
179
|
-
className={`filedrop-zone ${
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
169
|
+
className={`filedrop-zone ${isDragging ? 'filedrop-active' : ''}`}
|
|
170
|
+
onDragOver={handleDragOver}
|
|
171
|
+
onDragEnter={handleDragOver}
|
|
172
|
+
onDragLeave={handleDragLeave}
|
|
173
|
+
onDrop={handleDrop}
|
|
184
174
|
>
|
|
185
175
|
<div className="filedrop-content">
|
|
186
176
|
<svg className="filedrop-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
187
|
-
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2}
|
|
177
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2}
|
|
188
178
|
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" />
|
|
189
179
|
</svg>
|
|
190
180
|
<div className="filedrop-text">
|
|
191
|
-
{isDragging ? 'Drop files here' : 'Drag & drop files'}
|
|
181
|
+
{isDragging ? 'Drop files here' : 'Drag & drop files to send to C++'}
|
|
192
182
|
</div>
|
|
193
|
-
<div className="filedrop-hint">All file types supported</div>
|
|
194
183
|
</div>
|
|
195
184
|
</div>
|
|
196
185
|
|
|
197
|
-
{
|
|
198
|
-
<div className="filedrop-files">
|
|
199
|
-
{
|
|
186
|
+
{droppedFiles.length > 0 && (
|
|
187
|
+
<div className="filedrop-files" style={{ marginTop: '1rem' }}>
|
|
188
|
+
<p style={{ fontSize: '0.8em', color: '#888', marginBottom: '0.5rem' }}>
|
|
189
|
+
Sent to C++ via <code>customFileDrop.emit()</code>:
|
|
190
|
+
</p>
|
|
191
|
+
{droppedFiles.map((file, i) => (
|
|
200
192
|
<div key={i} className="filedrop-file-item">
|
|
201
193
|
<div className="filedrop-file-icon">📄</div>
|
|
202
194
|
<div className="filedrop-file-info">
|
|
203
195
|
<div className="filedrop-file-name">{file.name}</div>
|
|
204
|
-
<div className="filedrop-file-meta">
|
|
205
|
-
{plusui.formatFileSize(file.size)} • {file.type}
|
|
206
|
-
</div>
|
|
196
|
+
<div className="filedrop-file-meta">{plusui.formatFileSize(file.size)} • {file.type}</div>
|
|
207
197
|
</div>
|
|
208
|
-
<button
|
|
209
|
-
className="filedrop-file-remove"
|
|
210
|
-
onClick={() => setFiles(files.filter((_, idx) => idx !== i))}
|
|
211
|
-
>
|
|
212
|
-
✕
|
|
213
|
-
</button>
|
|
214
198
|
</div>
|
|
215
199
|
))}
|
|
216
200
|
</div>
|
|
217
201
|
)}
|
|
202
|
+
|
|
203
|
+
{backendMsg !== null && (
|
|
204
|
+
<div style={{ marginTop: '1rem', padding: '0.75rem 1rem', background: '#1a2e1a', border: '1px solid #2d5a2d', borderRadius: '6px' }}>
|
|
205
|
+
<p style={{ fontSize: '0.8em', color: '#4caf50', margin: 0 }}>
|
|
206
|
+
✓ C++ replied via <code>ch.customFileDrop.emit()</code>:
|
|
207
|
+
</p>
|
|
208
|
+
<p style={{ fontSize: '0.9em', color: '#e0e0e0', margin: '0.4rem 0 0' }}>{backendMsg}</p>
|
|
209
|
+
</div>
|
|
210
|
+
)}
|
|
218
211
|
</div>
|
|
219
212
|
|
|
220
213
|
<div className="info">
|
|
@@ -184,14 +184,25 @@ int main() {
|
|
|
184
184
|
Connections ch(connect); // use ch.name.on() / ch.name.emit()
|
|
185
185
|
|
|
186
186
|
// ========================================
|
|
187
|
-
// FILE DROP
|
|
187
|
+
// CUSTOM FILE DROP CHANNEL
|
|
188
188
|
// ========================================
|
|
189
|
-
//
|
|
190
|
-
// Frontend
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
189
|
+
// customFileDrop is a connect channel detected by `plusui connect`.
|
|
190
|
+
// Frontend drops files → emits via customFileDrop.emit({ files: [...] })
|
|
191
|
+
// C++ receives here, processes, then emits back to the frontend.
|
|
192
|
+
// Frontend receives the reply via customFileDrop.on() in App.tsx.
|
|
193
|
+
ch.customFileDrop.on([&ch](const json& payload) {
|
|
194
|
+
auto files = payload.value("files", json::array());
|
|
195
|
+
int count = static_cast<int>(files.size());
|
|
196
|
+
std::cout << "customFileDrop: received " << count << " file(s) from frontend" << std::endl;
|
|
197
|
+
for (const auto& f : files) {
|
|
198
|
+
std::cout << " - " << f.value("name", "?") << " (" << f.value("size", 0) << " bytes)" << std::endl;
|
|
199
|
+
}
|
|
200
|
+
// Reply back to frontend — received by customFileDrop.on() in App.tsx
|
|
201
|
+
ch.customFileDrop.emit({
|
|
202
|
+
{"processed", true},
|
|
203
|
+
{"count", count},
|
|
204
|
+
{"message", "C++ received " + std::to_string(count) + " file(s)"}
|
|
205
|
+
});
|
|
195
206
|
});
|
|
196
207
|
|
|
197
208
|
// ========================================
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createSignal, onMount, onCleanup, Show, For } from 'solid-js';
|
|
2
|
-
import plusui
|
|
3
|
-
//
|
|
4
|
-
|
|
2
|
+
import plusui from 'plusui';
|
|
3
|
+
// Generated by `plusui connect` — channel objects auto-created from name.on / name.emit usage:
|
|
4
|
+
import { customFileDrop } from '../Connections/connections.gen';
|
|
5
5
|
|
|
6
6
|
// Define routes for your app (optional - for SPA routing)
|
|
7
7
|
const routes = {
|
|
@@ -17,11 +17,10 @@ function App() {
|
|
|
17
17
|
const [canGoBack, setCanGoBack] = createSignal(false);
|
|
18
18
|
const [canGoForward, setCanGoForward] = createSignal(false);
|
|
19
19
|
|
|
20
|
-
//
|
|
21
|
-
const [files, setFiles] = createSignal<FileInfo[]>([]);
|
|
20
|
+
// customFileDrop connect channel state
|
|
22
21
|
const [isDragging, setIsDragging] = createSignal(false);
|
|
23
|
-
const [
|
|
24
|
-
const [
|
|
22
|
+
const [droppedFiles, setDroppedFiles] = createSignal<{ name: string; size: number; type: string }[]>([]);
|
|
23
|
+
const [backendMsg, setBackendMsg] = createSignal<string | null>(null);
|
|
25
24
|
|
|
26
25
|
onMount(() => {
|
|
27
26
|
// Setup routes
|
|
@@ -39,26 +38,11 @@ function App() {
|
|
|
39
38
|
plusui.browser.canGoBack().then(setCanGoBack);
|
|
40
39
|
plusui.browser.canGoForward().then(setCanGoForward);
|
|
41
40
|
|
|
42
|
-
//
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
setFiles(prev => [...prev, ...droppedFiles]);
|
|
46
|
-
setIsDragging(false);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
const unsubEnter = plusui.fileDrop.onDragEnter(() => {
|
|
50
|
-
setIsDragging(true);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
const unsubLeave = plusui.fileDrop.onDragLeave(() => {
|
|
54
|
-
setIsDragging(false);
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
onCleanup(() => {
|
|
58
|
-
unsubDrop();
|
|
59
|
-
unsubEnter();
|
|
60
|
-
unsubLeave();
|
|
41
|
+
// Listen for responses emitted from C++ via ch.customFileDrop.emit(...) in main.cpp
|
|
42
|
+
const unsub = customFileDrop.on((data: any) => {
|
|
43
|
+
setBackendMsg(data?.message ?? JSON.stringify(data));
|
|
61
44
|
});
|
|
45
|
+
onCleanup(() => unsub());
|
|
62
46
|
});
|
|
63
47
|
|
|
64
48
|
const handleMinimize = async () => await plusui.win.minimize();
|
|
@@ -85,6 +69,22 @@ function App() {
|
|
|
85
69
|
// App control
|
|
86
70
|
const handleQuit = async () => await plusui.app.quit();
|
|
87
71
|
|
|
72
|
+
// customFileDrop drag handlers — use HTML5 drag events to collect files, then
|
|
73
|
+
// emit them to the C++ backend via the connect channel
|
|
74
|
+
const handleDragOver = (e: DragEvent) => { e.preventDefault(); setIsDragging(true); };
|
|
75
|
+
const handleDragLeave = (e: DragEvent) => { e.preventDefault(); setIsDragging(false); };
|
|
76
|
+
const handleDrop = (e: DragEvent) => {
|
|
77
|
+
e.preventDefault();
|
|
78
|
+
setIsDragging(false);
|
|
79
|
+
const items = Array.from(e.dataTransfer?.files ?? []).map(f => ({
|
|
80
|
+
name: f.name, size: f.size, type: f.type || 'unknown',
|
|
81
|
+
}));
|
|
82
|
+
setDroppedFiles(items);
|
|
83
|
+
setBackendMsg(null);
|
|
84
|
+
// Emit to C++ — ch.customFileDrop.on() in main.cpp receives this
|
|
85
|
+
customFileDrop.emit({ files: items });
|
|
86
|
+
};
|
|
87
|
+
|
|
88
88
|
return (
|
|
89
89
|
<div class="app">
|
|
90
90
|
<header class="app-header">
|
|
@@ -149,69 +149,59 @@ function App() {
|
|
|
149
149
|
</div>
|
|
150
150
|
|
|
151
151
|
<div class="card">
|
|
152
|
-
<h2>
|
|
152
|
+
<h2>Custom Channel — File Drop</h2>
|
|
153
153
|
<p style={{ 'font-size': '0.85em', color: '#aaa', 'margin-bottom': '1rem' }}>
|
|
154
|
-
|
|
155
|
-
to
|
|
154
|
+
Drop files below. The frontend calls <code>customFileDrop.emit()</code> to send file
|
|
155
|
+
info to C++. The C++ handler calls <code>ch.customFileDrop.emit()</code> to reply.
|
|
156
|
+
The frontend receives the reply via <code>customFileDrop.on()</code>. Run{' '}
|
|
157
|
+
<code>plusui connect</code> to regenerate the channel bindings from both sides.
|
|
156
158
|
</p>
|
|
157
159
|
|
|
158
|
-
<div class="filedrop-control-row">
|
|
159
|
-
<label class="filedrop-control-label">Style:</label>
|
|
160
|
-
<select
|
|
161
|
-
value={dropZoneStyle()}
|
|
162
|
-
onChange={(e) => setDropZoneStyle(e.target.value)}
|
|
163
|
-
class="filedrop-control-select"
|
|
164
|
-
>
|
|
165
|
-
<option value="">Default</option>
|
|
166
|
-
<option value="filedrop-compact">Compact</option>
|
|
167
|
-
<option value="filedrop-inline">Inline</option>
|
|
168
|
-
<option value="filedrop-minimal">Minimal</option>
|
|
169
|
-
<option value="filedrop-bold">Bold</option>
|
|
170
|
-
</select>
|
|
171
|
-
</div>
|
|
172
|
-
|
|
173
160
|
<div
|
|
174
|
-
class={`filedrop-zone ${
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
161
|
+
class={`filedrop-zone ${isDragging() ? 'filedrop-active' : ''}`}
|
|
162
|
+
onDragOver={handleDragOver}
|
|
163
|
+
onDragEnter={handleDragOver}
|
|
164
|
+
onDragLeave={handleDragLeave}
|
|
165
|
+
onDrop={handleDrop}
|
|
179
166
|
>
|
|
180
167
|
<div class="filedrop-content">
|
|
181
168
|
<svg class="filedrop-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
182
|
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width={2}
|
|
169
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width={2}
|
|
183
170
|
d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12" />
|
|
184
171
|
</svg>
|
|
185
172
|
<div class="filedrop-text">
|
|
186
|
-
{isDragging() ? 'Drop files here' : 'Drag & drop files'}
|
|
173
|
+
{isDragging() ? 'Drop files here' : 'Drag & drop files to send to C++'}
|
|
187
174
|
</div>
|
|
188
|
-
<div class="filedrop-hint">All file types supported</div>
|
|
189
175
|
</div>
|
|
190
176
|
</div>
|
|
191
177
|
|
|
192
|
-
<Show when={
|
|
193
|
-
<div class="filedrop-files">
|
|
194
|
-
<
|
|
195
|
-
|
|
178
|
+
<Show when={droppedFiles().length > 0}>
|
|
179
|
+
<div class="filedrop-files" style={{ 'margin-top': '1rem' }}>
|
|
180
|
+
<p style={{ 'font-size': '0.8em', color: '#888', 'margin-bottom': '0.5rem' }}>
|
|
181
|
+
Sent to C++ via <code>customFileDrop.emit()</code>:
|
|
182
|
+
</p>
|
|
183
|
+
<For each={droppedFiles()}>
|
|
184
|
+
{(file) => (
|
|
196
185
|
<div class="filedrop-file-item">
|
|
197
186
|
<div class="filedrop-file-icon">📄</div>
|
|
198
187
|
<div class="filedrop-file-info">
|
|
199
188
|
<div class="filedrop-file-name">{file.name}</div>
|
|
200
|
-
<div class="filedrop-file-meta">
|
|
201
|
-
{plusui.formatFileSize(file.size)} • {file.type}
|
|
202
|
-
</div>
|
|
189
|
+
<div class="filedrop-file-meta">{plusui.formatFileSize(file.size)} • {file.type}</div>
|
|
203
190
|
</div>
|
|
204
|
-
<button
|
|
205
|
-
class="filedrop-file-remove"
|
|
206
|
-
onClick={() => setFiles(files().filter((_, idx) => idx !== i()))}
|
|
207
|
-
>
|
|
208
|
-
✕
|
|
209
|
-
</button>
|
|
210
191
|
</div>
|
|
211
192
|
)}
|
|
212
193
|
</For>
|
|
213
194
|
</div>
|
|
214
195
|
</Show>
|
|
196
|
+
|
|
197
|
+
<Show when={backendMsg() !== null}>
|
|
198
|
+
<div style={{ 'margin-top': '1rem', padding: '0.75rem 1rem', background: '#1a2e1a', border: '1px solid #2d5a2d', 'border-radius': '6px' }}>
|
|
199
|
+
<p style={{ 'font-size': '0.8em', color: '#4caf50', margin: '0' }}>
|
|
200
|
+
✓ C++ replied via <code>ch.customFileDrop.emit()</code>:
|
|
201
|
+
</p>
|
|
202
|
+
<p style={{ 'font-size': '0.9em', color: '#e0e0e0', margin: '0.4rem 0 0' }}>{backendMsg()}</p>
|
|
203
|
+
</div>
|
|
204
|
+
</Show>
|
|
215
205
|
</div>
|
|
216
206
|
|
|
217
207
|
<div class="info">
|
|
@@ -178,14 +178,25 @@ int main() {
|
|
|
178
178
|
Connections ch(connect); // use ch.name.on() / ch.name.emit()
|
|
179
179
|
|
|
180
180
|
// ========================================
|
|
181
|
-
// FILE DROP
|
|
181
|
+
// CUSTOM FILE DROP CHANNEL
|
|
182
182
|
// ========================================
|
|
183
|
-
//
|
|
184
|
-
// Frontend
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
183
|
+
// customFileDrop is a connect channel detected by `plusui connect`.
|
|
184
|
+
// Frontend drops files → emits via customFileDrop.emit({ files: [...] })
|
|
185
|
+
// C++ receives here, processes, then emits back to the frontend.
|
|
186
|
+
// Frontend receives the reply via customFileDrop.on() in App.tsx.
|
|
187
|
+
ch.customFileDrop.on([&ch](const json& payload) {
|
|
188
|
+
auto files = payload.value("files", json::array());
|
|
189
|
+
int count = static_cast<int>(files.size());
|
|
190
|
+
std::cout << "customFileDrop: received " << count << " file(s) from frontend" << std::endl;
|
|
191
|
+
for (const auto& f : files) {
|
|
192
|
+
std::cout << " - " << f.value("name", "?") << " (" << f.value("size", 0) << " bytes)" << std::endl;
|
|
193
|
+
}
|
|
194
|
+
// Reply back to frontend — received by customFileDrop.on() in App.tsx
|
|
195
|
+
ch.customFileDrop.emit({
|
|
196
|
+
{"processed", true},
|
|
197
|
+
{"count", count},
|
|
198
|
+
{"message", "C++ received " + std::to_string(count) + " file(s)"}
|
|
199
|
+
});
|
|
189
200
|
});
|
|
190
201
|
|
|
191
202
|
// ========================================
|