@decentnetwork/beagle-ui 0.1.3 → 0.2.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/dist/beagle-ui.js +516 -421
- package/package.json +1 -1
package/dist/beagle-ui.js
CHANGED
|
@@ -1,325 +1,4 @@
|
|
|
1
|
-
export const BEAGLE_UI_VERSION = "0.1
|
|
2
|
-
// src/icons.jsx
|
|
3
|
-
var ICON_PATHS = {
|
|
4
|
-
// ---- tab bar (the four must feel like one set) ----
|
|
5
|
-
users: '<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>',
|
|
6
|
-
grid: '<rect x="3" y="3" width="7.5" height="7.5" rx="1.6"/><rect x="13.5" y="3" width="7.5" height="7.5" rx="1.6"/><rect x="13.5" y="13.5" width="7.5" height="7.5" rx="1.6"/><rect x="3" y="13.5" width="7.5" height="7.5" rx="1.6"/>',
|
|
7
|
-
wallet: '<path d="M19 7V6a2 2 0 0 0-2-2H6a3 3 0 0 0-3 3v10a3 3 0 0 0 3 3h12a2 2 0 0 0 2-2v-1"/><path d="M3 7a3 3 0 0 0 3 3h13a2 2 0 0 1 2 2v0a2 2 0 0 1-2 2h-3"/><circle cx="16.5" cy="14" r="1.15" fill="currentColor" stroke="none"/>',
|
|
8
|
-
userRound: '<circle cx="12" cy="8" r="4.5"/><path d="M20 21a8 8 0 0 0-16 0"/>',
|
|
9
|
-
// ---- actions / chrome ----
|
|
10
|
-
search: '<circle cx="11" cy="11" r="7.5"/><path d="m21 21-4.3-4.3"/>',
|
|
11
|
-
plus: '<path d="M5 12h14M12 5v14"/>',
|
|
12
|
-
chevronRight: '<path d="m9 18 6-6-6-6"/>',
|
|
13
|
-
chevronLeft: '<path d="m15 18-6-6 6-6"/>',
|
|
14
|
-
info: '<circle cx="12" cy="12" r="9.5"/><path d="M12 16.5v-5M12 7.6h.01"/>',
|
|
15
|
-
more: '<circle cx="5" cy="12" r="1.4" fill="currentColor" stroke="none"/><circle cx="12" cy="12" r="1.4" fill="currentColor" stroke="none"/><circle cx="19" cy="12" r="1.4" fill="currentColor" stroke="none"/>',
|
|
16
|
-
x: '<path d="M18 6 6 18M6 6l12 12"/>',
|
|
17
|
-
check: '<path d="M20 6 9 17l-5-5"/>',
|
|
18
|
-
checkCheck: '<path d="M18 6 7 17l-5-5"/><path d="m22 10-7.6 7.6L13 16"/>',
|
|
19
|
-
copy: '<rect x="9" y="9" width="12" height="12" rx="2.4"/><path d="M6 15H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v1"/>',
|
|
20
|
-
// Three linked nodes — an address is for passing ON to someone else, so it
|
|
21
|
-
// must not wear the same glyph as the userid's plain copy.
|
|
22
|
-
share: '<circle cx="18" cy="5" r="2.6"/><circle cx="6" cy="12" r="2.6"/><circle cx="18" cy="19" r="2.6"/><path d="M8.3 10.8l7.4-4.3M8.3 13.2l7.4 4.3"/>',
|
|
23
|
-
refresh: '<path d="M21 12a9 9 0 1 1-2.6-6.3"/><path d="M21 4v4.5h-4.5"/>',
|
|
24
|
-
clock: '<circle cx="12" cy="12" r="9.5"/><path d="M12 7.5V12l3 2"/>',
|
|
25
|
-
edit: '<path d="M11 4H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-5"/><path d="M18.5 2.5a2.12 2.12 0 0 1 3 3L12 15l-4 1 1-4Z"/>',
|
|
26
|
-
qr: '<rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><path d="M14 14h3v3M21 14v.01M14 21h.01M17 21h.01M21 17v4"/>',
|
|
27
|
-
// ---- app tiles ----
|
|
28
|
-
video: '<path d="m22 8.5-5.4 3.5 5.4 3.5V8.5Z"/><rect x="2" y="6" width="14.5" height="12" rx="3"/>',
|
|
29
|
-
monitor: '<rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/>',
|
|
30
|
-
sparkles: '<path d="M12 3.5 13.6 9 19 10.5 13.6 12 12 17.5 10.4 12 5 10.5 10.4 9 12 3.5Z"/><path d="M19 3.5v3.2M20.6 5.1h-3.2"/><path d="M5 16v2.4M6.2 17.2H3.8"/>',
|
|
31
|
-
mic: '<rect x="9" y="2.5" width="6" height="11.5" rx="3"/><path d="M5.5 11a6.5 6.5 0 0 0 13 0"/><path d="M12 17.5v3.5"/>',
|
|
32
|
-
flask: '<path d="M9.5 3v6.2L4.8 17.4A2 2 0 0 0 6.5 20.5h11a2 2 0 0 0 1.7-3.1L14.5 9.2V3"/><path d="M8.5 3h7"/><path d="M7.3 15h9.4"/>',
|
|
33
|
-
headphones: '<path d="M3.5 14v-1.5a8.5 8.5 0 0 1 17 0V14"/><path d="M3.5 14.5a2.5 2.5 0 0 1 2.5-2.5h0a1.5 1.5 0 0 1 1.5 1.5v3.5a1.5 1.5 0 0 1-1.5 1.5h0a2.5 2.5 0 0 1-2.5-2.5Z"/><path d="M20.5 14.5a2.5 2.5 0 0 0-2.5-2.5h0a1.5 1.5 0 0 0-1.5 1.5v3.5a1.5 1.5 0 0 0 1.5 1.5h0a2.5 2.5 0 0 0 2.5-2.5Z"/>',
|
|
34
|
-
globe: '<circle cx="12" cy="12" r="9.5"/><path d="M2.5 12h19"/><path d="M12 2.5a14 14 0 0 1 0 19 14 14 0 0 1 0-19Z"/>',
|
|
35
|
-
store: '<path d="M4 9.5V19a1.5 1.5 0 0 0 1.5 1.5h13A1.5 1.5 0 0 0 20 19V9.5"/><path d="M3 6.5 4.5 3.5h15L21 6.5a2.5 2.5 0 0 1-4.5 1.5 2.5 2.5 0 0 1-4.5 0 2.5 2.5 0 0 1-4.5 0A2.5 2.5 0 0 1 3 6.5Z"/>',
|
|
36
|
-
// ---- chat composer ----
|
|
37
|
-
camera: '<path d="M14.5 4.5h-5L7.2 7.2H4.5A2.5 2.5 0 0 0 2 9.7V18a2.5 2.5 0 0 0 2.5 2.5h15A2.5 2.5 0 0 0 22 18V9.7a2.5 2.5 0 0 0-2.5-2.5h-2.7L14.5 4.5Z"/><circle cx="12" cy="13.5" r="3.2"/>',
|
|
38
|
-
phone: '<path d="M16.5 21a2 2 0 0 0 2-2.2 1.9 1.9 0 0 0-.6-1.2l-2-1.7a2 2 0 0 0-2.4-.1l-.9.6a14 14 0 0 1-5-5l.6-.9a2 2 0 0 0-.1-2.4l-1.7-2a1.9 1.9 0 0 0-1.2-.6A2 2 0 0 0 3 5.5 16 16 0 0 0 16.5 21Z"/>',
|
|
39
|
-
bolt: '<path d="M13 2 4 13h7l-1 9 9-11h-7l1-9Z"/>',
|
|
40
|
-
arrowUp: '<path d="M12 20V5M6 11l6-6 6 6"/>',
|
|
41
|
-
send: '<path d="M21.5 4.5 10.5 13.5"/><path d="M21.5 4.5 14.8 21.5 11 13l-8.5-3.8 19-4.7Z"/>',
|
|
42
|
-
// ---- account ----
|
|
43
|
-
shield: '<path d="M12 21.5s7.5-3.8 7.5-9.5V5.5L12 2.8 4.5 5.5V12c0 5.7 7.5 9.5 7.5 9.5Z"/>',
|
|
44
|
-
download: '<path d="M12 3.5v11M7.5 10l4.5 4.5 4.5-4.5"/><path d="M5 20.5h14"/>',
|
|
45
|
-
// Folder with a magnifier corner — "reveal / show in file manager".
|
|
46
|
-
folderOpen: '<path d="M3 7.5a2 2 0 0 1 2-2h4l2 2.5h8a2 2 0 0 1 2 2V17a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Z"/><circle cx="12" cy="13" r="2.4"/><path d="M13.9 14.9 15.5 16.5"/>',
|
|
47
|
-
migrate: '<path d="M8 4 4 8l4 4"/><path d="M4 8h13a3 3 0 0 1 3 3v1"/><path d="m16 20 4-4-4-4"/><path d="M20 16H7a3 3 0 0 1-3-3v-1"/>',
|
|
48
|
-
starCoin: '<circle cx="12" cy="12" r="9"/><path d="m12 7.2 1.4 2.9 3.2.4-2.3 2.2.6 3.1-2.9-1.5-2.9 1.5.6-3.1L8.4 10.5l3.2-.4L12 7.2Z" fill="currentColor" stroke="none"/>',
|
|
49
|
-
link: '<path d="M10.5 13.5a4 4 0 0 0 5.7 0l2.3-2.3a4 4 0 0 0-5.7-5.7l-1 1"/><path d="M13.5 10.5a4 4 0 0 0-5.7 0l-2.3 2.3a4 4 0 0 0 5.7 5.7l1-1"/>',
|
|
50
|
-
trendingUp: '<path d="M22 7.5 13.5 16l-4.5-4.5L2 18.5"/><path d="M16.5 7.5H22v5.5"/>',
|
|
51
|
-
bell: '<path d="M18 8.5a6 6 0 0 0-12 0c0 6.5-2.5 8-2.5 8h17S18 15 18 8.5Z"/><path d="M13.7 20.5a2 2 0 0 1-3.4 0"/>',
|
|
52
|
-
bot: '<rect x="3.5" y="9" width="17" height="11" rx="3"/><path d="M12 4.5v4.5"/><circle cx="12" cy="3" r="1.4"/><path d="M8.5 14.5h.01M15.5 14.5h.01"/><path d="M2 13.5v3M22 13.5v3"/>',
|
|
53
|
-
scan: '<path d="M3 8V6a3 3 0 0 1 3-3h2"/><path d="M16 3h2a3 3 0 0 1 3 3v2"/><path d="M21 16v2a3 3 0 0 1-3 3h-2"/><path d="M8 21H6a3 3 0 0 1-3-3v-2"/><path d="M7 12h10"/>',
|
|
54
|
-
userPlus: '<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M19 8v6M22 11h-6"/>',
|
|
55
|
-
at: '<circle cx="12" cy="12" r="4"/><path d="M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-3.9 7.9"/>',
|
|
56
|
-
keyRound: '<circle cx="7.5" cy="15.5" r="5.5"/><path d="m21 2-9.6 9.6"/><path d="m15.5 7.5 3 3L22 7l-3-3"/>',
|
|
57
|
-
alert: '<path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0Z"/><path d="M12 9v4M12 17h.01"/>',
|
|
58
|
-
chevronDown: '<path d="m6 9 6 6 6-6"/>',
|
|
59
|
-
eye: '<path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7Z"/><circle cx="12" cy="12" r="3"/>',
|
|
60
|
-
book: '<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2Z"/>',
|
|
61
|
-
trash: '<path d="M3 6h18"/><path d="M8 6V4.5A1.5 1.5 0 0 1 9.5 3h5A1.5 1.5 0 0 1 16 4.5V6"/><path d="M18.5 6l-1 13.5a2 2 0 0 1-2 1.5h-7a2 2 0 0 1-2-1.5L5.5 6"/><path d="M10 10.5v6M14 10.5v6"/>',
|
|
62
|
-
arrowDown: '<path d="M12 4v15M6 13l6 6 6-6"/>',
|
|
63
|
-
shrink: '<path d="M4 14h6v6"/><path d="M20 10h-6V4"/><path d="m14 10 7-7"/><path d="m3 21 7-7"/>',
|
|
64
|
-
maximize: '<path d="M8 3H5a2 2 0 0 0-2 2v3"/><path d="M21 8V5a2 2 0 0 0-2-2h-3"/><path d="M3 16v3a2 2 0 0 0 2 2h3"/><path d="M16 21h3a2 2 0 0 0 2-2v-3"/>',
|
|
65
|
-
theater: '<rect x="2.5" y="6.5" width="19" height="11" rx="2"/>',
|
|
66
|
-
speaker: '<path d="M11 5 6 9H3v6h3l5 4V5Z"/><path d="M16 9a3 3 0 0 1 0 6"/><path d="M19 7a6 6 0 0 1 0 10"/>',
|
|
67
|
-
micFill: '<rect x="9" y="2.5" width="6" height="11.5" rx="3"/><path d="M5.5 11a6.5 6.5 0 0 0 13 0"/><path d="M12 17.5v3.5"/>'
|
|
68
|
-
};
|
|
69
|
-
function Icon({ name, size = 24, stroke = 1.75, color = "currentColor", fill = "none", style }) {
|
|
70
|
-
const d = ICON_PATHS[name];
|
|
71
|
-
if (!d)
|
|
72
|
-
return null;
|
|
73
|
-
return /* @__PURE__ */ React.createElement(
|
|
74
|
-
"svg",
|
|
75
|
-
{
|
|
76
|
-
width: size,
|
|
77
|
-
height: size,
|
|
78
|
-
viewBox: "0 0 24 24",
|
|
79
|
-
fill,
|
|
80
|
-
stroke: color,
|
|
81
|
-
strokeWidth: stroke,
|
|
82
|
-
strokeLinecap: "round",
|
|
83
|
-
strokeLinejoin: "round",
|
|
84
|
-
style: { display: "block", flexShrink: 0, ...style },
|
|
85
|
-
dangerouslySetInnerHTML: { __html: d }
|
|
86
|
-
}
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
Object.assign(window, { Icon, ICON_PATHS });
|
|
90
|
-
|
|
91
|
-
// src/rtc-signaling.jsx
|
|
92
|
-
var DK_FALLBACK_ICE_SERVERS = [
|
|
93
|
-
{ urls: "stun:stun.l.google.com:19302" },
|
|
94
|
-
{ urls: "turn:tokyo.fi.chat:3478", username: "allcom", credential: "allcompass" },
|
|
95
|
-
{ urls: "turn:tokyo.fi.chat:3478?transport=tcp", username: "allcom", credential: "allcompass" }
|
|
96
|
-
];
|
|
97
|
-
var DK_LIVE_ICE_SERVERS = [];
|
|
98
|
-
var _dkIcePromise = null;
|
|
99
|
-
var _dkIceWarmPromise = null;
|
|
100
|
-
function dkWarmCallIce(iceServers) {
|
|
101
|
-
if (_dkIceWarmPromise)
|
|
102
|
-
return _dkIceWarmPromise;
|
|
103
|
-
if (!window.RTCPeerConnection || !iceServers || !iceServers.length) {
|
|
104
|
-
_dkIceWarmPromise = Promise.resolve();
|
|
105
|
-
return _dkIceWarmPromise;
|
|
106
|
-
}
|
|
107
|
-
_dkIceWarmPromise = new Promise((resolve) => {
|
|
108
|
-
let pc;
|
|
109
|
-
let finished = false;
|
|
110
|
-
const done = (why) => {
|
|
111
|
-
if (finished)
|
|
112
|
-
return;
|
|
113
|
-
finished = true;
|
|
114
|
-
try {
|
|
115
|
-
if (pc)
|
|
116
|
-
pc.close();
|
|
117
|
-
} catch (e) {
|
|
118
|
-
}
|
|
119
|
-
console.log("[rtc] ICE warmup done (" + why + ")");
|
|
120
|
-
resolve();
|
|
121
|
-
};
|
|
122
|
-
try {
|
|
123
|
-
pc = new RTCPeerConnection({ iceServers, iceTransportPolicy: "all" });
|
|
124
|
-
const timer = setTimeout(() => done("timeout"), 5e3);
|
|
125
|
-
pc.onicecandidate = (ev) => {
|
|
126
|
-
const c = ev.candidate && ev.candidate.candidate;
|
|
127
|
-
if (c && /typ relay/.test(c)) {
|
|
128
|
-
clearTimeout(timer);
|
|
129
|
-
done("relay");
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
pc.onicegatheringstatechange = () => {
|
|
133
|
-
if (pc.iceGatheringState === "complete") {
|
|
134
|
-
clearTimeout(timer);
|
|
135
|
-
done("gather-complete");
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
pc.createDataChannel("ice-warm");
|
|
139
|
-
pc.createOffer().then((o) => pc.setLocalDescription(o)).catch(() => done("offer-fail"));
|
|
140
|
-
} catch (e) {
|
|
141
|
-
done("error");
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
return _dkIceWarmPromise;
|
|
145
|
-
}
|
|
146
|
-
function dkLoadCallIceServers() {
|
|
147
|
-
if (_dkIcePromise)
|
|
148
|
-
return _dkIcePromise;
|
|
149
|
-
_dkIcePromise = (async () => {
|
|
150
|
-
try {
|
|
151
|
-
const r = await fetch("/api/call-ice-servers", { headers: { "cache-control": "no-cache" } });
|
|
152
|
-
const d = await r.json();
|
|
153
|
-
if (d && d.ok && Array.isArray(d.iceServers) && d.iceServers.length) {
|
|
154
|
-
DK_LIVE_ICE_SERVERS.splice(0, DK_LIVE_ICE_SERVERS.length, ...d.iceServers);
|
|
155
|
-
console.log("[rtc] Carrier bootstrap ICE servers:", DK_LIVE_ICE_SERVERS.map((s) => s.urls));
|
|
156
|
-
await dkWarmCallIce(DK_LIVE_ICE_SERVERS);
|
|
157
|
-
return DK_LIVE_ICE_SERVERS;
|
|
158
|
-
}
|
|
159
|
-
console.warn("[rtc] call-ice-servers unavailable:", d && d.error);
|
|
160
|
-
} catch (e) {
|
|
161
|
-
console.warn("[rtc] call-ice-servers fetch failed", e);
|
|
162
|
-
}
|
|
163
|
-
console.warn("[rtc] falling back to tokyo TURN \u2014 web\u2194Android online ICE may fail");
|
|
164
|
-
DK_LIVE_ICE_SERVERS.splice(0, DK_LIVE_ICE_SERVERS.length, ...DK_FALLBACK_ICE_SERVERS.map((s) => ({ ...s })));
|
|
165
|
-
await dkWarmCallIce(DK_LIVE_ICE_SERVERS);
|
|
166
|
-
return DK_LIVE_ICE_SERVERS;
|
|
167
|
-
})();
|
|
168
|
-
return _dkIcePromise;
|
|
169
|
-
}
|
|
170
|
-
function dkAwaitCallIceServers(ms) {
|
|
171
|
-
const budget = typeof ms === "number" ? ms : 1e4;
|
|
172
|
-
return Promise.race([
|
|
173
|
-
dkLoadCallIceServers(),
|
|
174
|
-
new Promise((resolve) => setTimeout(() => {
|
|
175
|
-
if (!DK_LIVE_ICE_SERVERS.length) {
|
|
176
|
-
DK_LIVE_ICE_SERVERS.splice(0, DK_LIVE_ICE_SERVERS.length, ...DK_FALLBACK_ICE_SERVERS.map((s) => ({ ...s })));
|
|
177
|
-
console.warn("[rtc] ICE wait timed out \u2014 using fallback");
|
|
178
|
-
}
|
|
179
|
-
resolve(DK_LIVE_ICE_SERVERS);
|
|
180
|
-
}, budget))
|
|
181
|
-
]).then(() => DK_LIVE_ICE_SERVERS);
|
|
182
|
-
}
|
|
183
|
-
dkLoadCallIceServers();
|
|
184
|
-
function dkRtcParseEnvelope(data) {
|
|
185
|
-
const text = String(data || "").replace(/\0+$/u, "").trim();
|
|
186
|
-
if (!text)
|
|
187
|
-
return null;
|
|
188
|
-
try {
|
|
189
|
-
const obj = JSON.parse(text);
|
|
190
|
-
if (obj && obj.dkRtc === 1 && typeof obj.kind === "string")
|
|
191
|
-
return obj;
|
|
192
|
-
} catch (e) {
|
|
193
|
-
}
|
|
194
|
-
return null;
|
|
195
|
-
}
|
|
196
|
-
function dkRtcSignalBus() {
|
|
197
|
-
if (window.__dkRtcSignalBus)
|
|
198
|
-
return window.__dkRtcSignalBus;
|
|
199
|
-
const PW = window.PeerWebRTC;
|
|
200
|
-
const handlers = /* @__PURE__ */ new Map();
|
|
201
|
-
const pendingCalls = [];
|
|
202
|
-
const PENDING_CALL_CAP = 16;
|
|
203
|
-
let started = false;
|
|
204
|
-
let stopped = false;
|
|
205
|
-
function emit(kind, userid, payload) {
|
|
206
|
-
const set = handlers.get(kind);
|
|
207
|
-
if (!set || !set.size) {
|
|
208
|
-
if (kind === "call") {
|
|
209
|
-
pendingCalls.push({ userid, payload });
|
|
210
|
-
if (pendingCalls.length > PENDING_CALL_CAP)
|
|
211
|
-
pendingCalls.shift();
|
|
212
|
-
}
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
|
-
for (const h of Array.from(set)) {
|
|
216
|
-
try {
|
|
217
|
-
h(userid, payload);
|
|
218
|
-
} catch (e) {
|
|
219
|
-
console.warn("[rtc] signal handler failed", e);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
async function pollLoop() {
|
|
224
|
-
let cursor = null;
|
|
225
|
-
while (!stopped) {
|
|
226
|
-
let signals = [];
|
|
227
|
-
try {
|
|
228
|
-
const u = cursor == null ? "/api/call-poll" : "/api/call-poll?since=" + cursor;
|
|
229
|
-
const r = await fetch(u, { headers: { "cache-control": "no-cache" } });
|
|
230
|
-
const d = await r.json();
|
|
231
|
-
signals = d && d.signals || [];
|
|
232
|
-
if (d && typeof d.cursor === "number")
|
|
233
|
-
cursor = d.cursor;
|
|
234
|
-
} catch (e) {
|
|
235
|
-
await new Promise((res) => setTimeout(res, 1e3));
|
|
236
|
-
continue;
|
|
237
|
-
}
|
|
238
|
-
for (const s of signals) {
|
|
239
|
-
const env = dkRtcParseEnvelope(s.data);
|
|
240
|
-
if (env) {
|
|
241
|
-
emit(env.kind, s.userid, env);
|
|
242
|
-
continue;
|
|
243
|
-
}
|
|
244
|
-
if (PW) {
|
|
245
|
-
try {
|
|
246
|
-
emit("call", s.userid, PW.decodeSignal(s.data));
|
|
247
|
-
} catch (e) {
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
const bus = {
|
|
254
|
-
start() {
|
|
255
|
-
if (started)
|
|
256
|
-
return;
|
|
257
|
-
started = true;
|
|
258
|
-
stopped = false;
|
|
259
|
-
pollLoop();
|
|
260
|
-
},
|
|
261
|
-
on(kind, cb) {
|
|
262
|
-
if (!handlers.has(kind))
|
|
263
|
-
handlers.set(kind, /* @__PURE__ */ new Set());
|
|
264
|
-
handlers.get(kind).add(cb);
|
|
265
|
-
this.start();
|
|
266
|
-
if (kind === "call" && pendingCalls.length) {
|
|
267
|
-
const queued = pendingCalls.splice(0);
|
|
268
|
-
console.log("[rtc] flushing " + queued.length + " buffered call signal(s)");
|
|
269
|
-
for (const q of queued) {
|
|
270
|
-
try {
|
|
271
|
-
cb(q.userid, q.payload);
|
|
272
|
-
} catch (e) {
|
|
273
|
-
console.warn("[rtc] buffered call handler failed", e);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
return () => {
|
|
278
|
-
var _a;
|
|
279
|
-
return (_a = handlers.get(kind)) == null ? void 0 : _a.delete(cb);
|
|
280
|
-
};
|
|
281
|
-
},
|
|
282
|
-
async send(userid, data) {
|
|
283
|
-
const body = JSON.stringify({ userid, data: typeof data === "string" ? data : JSON.stringify(data) });
|
|
284
|
-
const r = await fetch("/api/call-signal", {
|
|
285
|
-
method: "POST",
|
|
286
|
-
headers: { "content-type": "application/json" },
|
|
287
|
-
body
|
|
288
|
-
});
|
|
289
|
-
const d = await r.json().catch(() => ({ ok: r.ok }));
|
|
290
|
-
if (!d.ok)
|
|
291
|
-
throw new Error(d.error || "call-signal send failed");
|
|
292
|
-
},
|
|
293
|
-
stop() {
|
|
294
|
-
stopped = true;
|
|
295
|
-
}
|
|
296
|
-
};
|
|
297
|
-
window.__dkRtcSignalBus = bus;
|
|
298
|
-
return bus;
|
|
299
|
-
}
|
|
300
|
-
function makeDaemonSignaling() {
|
|
301
|
-
const PW = window.PeerWebRTC;
|
|
302
|
-
const bus = dkRtcSignalBus();
|
|
303
|
-
let off = null;
|
|
304
|
-
return {
|
|
305
|
-
async send(peerId, signal) {
|
|
306
|
-
await bus.send(peerId, PW.encodeSignal(signal));
|
|
307
|
-
},
|
|
308
|
-
onSignal(cb) {
|
|
309
|
-
if (off)
|
|
310
|
-
off();
|
|
311
|
-
off = bus.on("call", cb);
|
|
312
|
-
},
|
|
313
|
-
stop() {
|
|
314
|
-
if (off) {
|
|
315
|
-
off();
|
|
316
|
-
off = null;
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
Object.assign(window, { dkRtcSignalBus, makeDaemonSignaling });
|
|
322
|
-
|
|
1
|
+
export const BEAGLE_UI_VERSION = "0.2.1";
|
|
323
2
|
// src/ui-host.jsx
|
|
324
3
|
var H = {};
|
|
325
4
|
var hostNeedsWelcome = false;
|
|
@@ -629,19 +308,108 @@ function useDaemonData() {
|
|
|
629
308
|
setThreads((t) => Object.assign({}, t, { [peerId]: withDay }));
|
|
630
309
|
} catch (e) {
|
|
631
310
|
}
|
|
632
|
-
}, []);
|
|
633
|
-
return Object.assign({}, snap, { threads, refresh, loadThread });
|
|
311
|
+
}, []);
|
|
312
|
+
return Object.assign({}, snap, { threads, refresh, loadThread });
|
|
313
|
+
}
|
|
314
|
+
Object.assign(window, {
|
|
315
|
+
dkHash,
|
|
316
|
+
dkIdenticon,
|
|
317
|
+
dkClock,
|
|
318
|
+
dkDayLabel,
|
|
319
|
+
dkApi,
|
|
320
|
+
useDaemonData,
|
|
321
|
+
DK_ME_FALLBACK,
|
|
322
|
+
dkCopy
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
// src/icons.jsx
|
|
326
|
+
var ICON_PATHS = {
|
|
327
|
+
// ---- tab bar (the four must feel like one set) ----
|
|
328
|
+
users: '<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>',
|
|
329
|
+
grid: '<rect x="3" y="3" width="7.5" height="7.5" rx="1.6"/><rect x="13.5" y="3" width="7.5" height="7.5" rx="1.6"/><rect x="13.5" y="13.5" width="7.5" height="7.5" rx="1.6"/><rect x="3" y="13.5" width="7.5" height="7.5" rx="1.6"/>',
|
|
330
|
+
wallet: '<path d="M19 7V6a2 2 0 0 0-2-2H6a3 3 0 0 0-3 3v10a3 3 0 0 0 3 3h12a2 2 0 0 0 2-2v-1"/><path d="M3 7a3 3 0 0 0 3 3h13a2 2 0 0 1 2 2v0a2 2 0 0 1-2 2h-3"/><circle cx="16.5" cy="14" r="1.15" fill="currentColor" stroke="none"/>',
|
|
331
|
+
userRound: '<circle cx="12" cy="8" r="4.5"/><path d="M20 21a8 8 0 0 0-16 0"/>',
|
|
332
|
+
// ---- actions / chrome ----
|
|
333
|
+
search: '<circle cx="11" cy="11" r="7.5"/><path d="m21 21-4.3-4.3"/>',
|
|
334
|
+
plus: '<path d="M5 12h14M12 5v14"/>',
|
|
335
|
+
chevronRight: '<path d="m9 18 6-6-6-6"/>',
|
|
336
|
+
chevronLeft: '<path d="m15 18-6-6 6-6"/>',
|
|
337
|
+
info: '<circle cx="12" cy="12" r="9.5"/><path d="M12 16.5v-5M12 7.6h.01"/>',
|
|
338
|
+
more: '<circle cx="5" cy="12" r="1.4" fill="currentColor" stroke="none"/><circle cx="12" cy="12" r="1.4" fill="currentColor" stroke="none"/><circle cx="19" cy="12" r="1.4" fill="currentColor" stroke="none"/>',
|
|
339
|
+
x: '<path d="M18 6 6 18M6 6l12 12"/>',
|
|
340
|
+
check: '<path d="M20 6 9 17l-5-5"/>',
|
|
341
|
+
checkCheck: '<path d="M18 6 7 17l-5-5"/><path d="m22 10-7.6 7.6L13 16"/>',
|
|
342
|
+
copy: '<rect x="9" y="9" width="12" height="12" rx="2.4"/><path d="M6 15H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v1"/>',
|
|
343
|
+
// Three linked nodes — an address is for passing ON to someone else, so it
|
|
344
|
+
// must not wear the same glyph as the userid's plain copy.
|
|
345
|
+
share: '<circle cx="18" cy="5" r="2.6"/><circle cx="6" cy="12" r="2.6"/><circle cx="18" cy="19" r="2.6"/><path d="M8.3 10.8l7.4-4.3M8.3 13.2l7.4 4.3"/>',
|
|
346
|
+
refresh: '<path d="M21 12a9 9 0 1 1-2.6-6.3"/><path d="M21 4v4.5h-4.5"/>',
|
|
347
|
+
clock: '<circle cx="12" cy="12" r="9.5"/><path d="M12 7.5V12l3 2"/>',
|
|
348
|
+
edit: '<path d="M11 4H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-5"/><path d="M18.5 2.5a2.12 2.12 0 0 1 3 3L12 15l-4 1 1-4Z"/>',
|
|
349
|
+
qr: '<rect x="3" y="3" width="7" height="7" rx="1.5"/><rect x="14" y="3" width="7" height="7" rx="1.5"/><rect x="3" y="14" width="7" height="7" rx="1.5"/><path d="M14 14h3v3M21 14v.01M14 21h.01M17 21h.01M21 17v4"/>',
|
|
350
|
+
// ---- app tiles ----
|
|
351
|
+
video: '<path d="m22 8.5-5.4 3.5 5.4 3.5V8.5Z"/><rect x="2" y="6" width="14.5" height="12" rx="3"/>',
|
|
352
|
+
monitor: '<rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8M12 17v4"/>',
|
|
353
|
+
sparkles: '<path d="M12 3.5 13.6 9 19 10.5 13.6 12 12 17.5 10.4 12 5 10.5 10.4 9 12 3.5Z"/><path d="M19 3.5v3.2M20.6 5.1h-3.2"/><path d="M5 16v2.4M6.2 17.2H3.8"/>',
|
|
354
|
+
mic: '<rect x="9" y="2.5" width="6" height="11.5" rx="3"/><path d="M5.5 11a6.5 6.5 0 0 0 13 0"/><path d="M12 17.5v3.5"/>',
|
|
355
|
+
flask: '<path d="M9.5 3v6.2L4.8 17.4A2 2 0 0 0 6.5 20.5h11a2 2 0 0 0 1.7-3.1L14.5 9.2V3"/><path d="M8.5 3h7"/><path d="M7.3 15h9.4"/>',
|
|
356
|
+
headphones: '<path d="M3.5 14v-1.5a8.5 8.5 0 0 1 17 0V14"/><path d="M3.5 14.5a2.5 2.5 0 0 1 2.5-2.5h0a1.5 1.5 0 0 1 1.5 1.5v3.5a1.5 1.5 0 0 1-1.5 1.5h0a2.5 2.5 0 0 1-2.5-2.5Z"/><path d="M20.5 14.5a2.5 2.5 0 0 0-2.5-2.5h0a1.5 1.5 0 0 0-1.5 1.5v3.5a1.5 1.5 0 0 0 1.5 1.5h0a2.5 2.5 0 0 0 2.5-2.5Z"/>',
|
|
357
|
+
globe: '<circle cx="12" cy="12" r="9.5"/><path d="M2.5 12h19"/><path d="M12 2.5a14 14 0 0 1 0 19 14 14 0 0 1 0-19Z"/>',
|
|
358
|
+
store: '<path d="M4 9.5V19a1.5 1.5 0 0 0 1.5 1.5h13A1.5 1.5 0 0 0 20 19V9.5"/><path d="M3 6.5 4.5 3.5h15L21 6.5a2.5 2.5 0 0 1-4.5 1.5 2.5 2.5 0 0 1-4.5 0 2.5 2.5 0 0 1-4.5 0A2.5 2.5 0 0 1 3 6.5Z"/>',
|
|
359
|
+
// ---- chat composer ----
|
|
360
|
+
camera: '<path d="M14.5 4.5h-5L7.2 7.2H4.5A2.5 2.5 0 0 0 2 9.7V18a2.5 2.5 0 0 0 2.5 2.5h15A2.5 2.5 0 0 0 22 18V9.7a2.5 2.5 0 0 0-2.5-2.5h-2.7L14.5 4.5Z"/><circle cx="12" cy="13.5" r="3.2"/>',
|
|
361
|
+
phone: '<path d="M16.5 21a2 2 0 0 0 2-2.2 1.9 1.9 0 0 0-.6-1.2l-2-1.7a2 2 0 0 0-2.4-.1l-.9.6a14 14 0 0 1-5-5l.6-.9a2 2 0 0 0-.1-2.4l-1.7-2a1.9 1.9 0 0 0-1.2-.6A2 2 0 0 0 3 5.5 16 16 0 0 0 16.5 21Z"/>',
|
|
362
|
+
bolt: '<path d="M13 2 4 13h7l-1 9 9-11h-7l1-9Z"/>',
|
|
363
|
+
arrowUp: '<path d="M12 20V5M6 11l6-6 6 6"/>',
|
|
364
|
+
send: '<path d="M21.5 4.5 10.5 13.5"/><path d="M21.5 4.5 14.8 21.5 11 13l-8.5-3.8 19-4.7Z"/>',
|
|
365
|
+
// ---- account ----
|
|
366
|
+
shield: '<path d="M12 21.5s7.5-3.8 7.5-9.5V5.5L12 2.8 4.5 5.5V12c0 5.7 7.5 9.5 7.5 9.5Z"/>',
|
|
367
|
+
download: '<path d="M12 3.5v11M7.5 10l4.5 4.5 4.5-4.5"/><path d="M5 20.5h14"/>',
|
|
368
|
+
// Folder with a magnifier corner — "reveal / show in file manager".
|
|
369
|
+
folderOpen: '<path d="M3 7.5a2 2 0 0 1 2-2h4l2 2.5h8a2 2 0 0 1 2 2V17a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Z"/><circle cx="12" cy="13" r="2.4"/><path d="M13.9 14.9 15.5 16.5"/>',
|
|
370
|
+
migrate: '<path d="M8 4 4 8l4 4"/><path d="M4 8h13a3 3 0 0 1 3 3v1"/><path d="m16 20 4-4-4-4"/><path d="M20 16H7a3 3 0 0 1-3-3v-1"/>',
|
|
371
|
+
starCoin: '<circle cx="12" cy="12" r="9"/><path d="m12 7.2 1.4 2.9 3.2.4-2.3 2.2.6 3.1-2.9-1.5-2.9 1.5.6-3.1L8.4 10.5l3.2-.4L12 7.2Z" fill="currentColor" stroke="none"/>',
|
|
372
|
+
link: '<path d="M10.5 13.5a4 4 0 0 0 5.7 0l2.3-2.3a4 4 0 0 0-5.7-5.7l-1 1"/><path d="M13.5 10.5a4 4 0 0 0-5.7 0l-2.3 2.3a4 4 0 0 0 5.7 5.7l1-1"/>',
|
|
373
|
+
trendingUp: '<path d="M22 7.5 13.5 16l-4.5-4.5L2 18.5"/><path d="M16.5 7.5H22v5.5"/>',
|
|
374
|
+
bell: '<path d="M18 8.5a6 6 0 0 0-12 0c0 6.5-2.5 8-2.5 8h17S18 15 18 8.5Z"/><path d="M13.7 20.5a2 2 0 0 1-3.4 0"/>',
|
|
375
|
+
bot: '<rect x="3.5" y="9" width="17" height="11" rx="3"/><path d="M12 4.5v4.5"/><circle cx="12" cy="3" r="1.4"/><path d="M8.5 14.5h.01M15.5 14.5h.01"/><path d="M2 13.5v3M22 13.5v3"/>',
|
|
376
|
+
scan: '<path d="M3 8V6a3 3 0 0 1 3-3h2"/><path d="M16 3h2a3 3 0 0 1 3 3v2"/><path d="M21 16v2a3 3 0 0 1-3 3h-2"/><path d="M8 21H6a3 3 0 0 1-3-3v-2"/><path d="M7 12h10"/>',
|
|
377
|
+
userPlus: '<path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M19 8v6M22 11h-6"/>',
|
|
378
|
+
at: '<circle cx="12" cy="12" r="4"/><path d="M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-3.9 7.9"/>',
|
|
379
|
+
keyRound: '<circle cx="7.5" cy="15.5" r="5.5"/><path d="m21 2-9.6 9.6"/><path d="m15.5 7.5 3 3L22 7l-3-3"/>',
|
|
380
|
+
alert: '<path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0Z"/><path d="M12 9v4M12 17h.01"/>',
|
|
381
|
+
chevronDown: '<path d="m6 9 6 6 6-6"/>',
|
|
382
|
+
eye: '<path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7Z"/><circle cx="12" cy="12" r="3"/>',
|
|
383
|
+
book: '<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2Z"/>',
|
|
384
|
+
trash: '<path d="M3 6h18"/><path d="M8 6V4.5A1.5 1.5 0 0 1 9.5 3h5A1.5 1.5 0 0 1 16 4.5V6"/><path d="M18.5 6l-1 13.5a2 2 0 0 1-2 1.5h-7a2 2 0 0 1-2-1.5L5.5 6"/><path d="M10 10.5v6M14 10.5v6"/>',
|
|
385
|
+
arrowDown: '<path d="M12 4v15M6 13l6 6 6-6"/>',
|
|
386
|
+
shrink: '<path d="M4 14h6v6"/><path d="M20 10h-6V4"/><path d="m14 10 7-7"/><path d="m3 21 7-7"/>',
|
|
387
|
+
maximize: '<path d="M8 3H5a2 2 0 0 0-2 2v3"/><path d="M21 8V5a2 2 0 0 0-2-2h-3"/><path d="M3 16v3a2 2 0 0 0 2 2h3"/><path d="M16 21h3a2 2 0 0 0 2-2v-3"/>',
|
|
388
|
+
theater: '<rect x="2.5" y="6.5" width="19" height="11" rx="2"/>',
|
|
389
|
+
speaker: '<path d="M11 5 6 9H3v6h3l5 4V5Z"/><path d="M16 9a3 3 0 0 1 0 6"/><path d="M19 7a6 6 0 0 1 0 10"/>',
|
|
390
|
+
micFill: '<rect x="9" y="2.5" width="6" height="11.5" rx="3"/><path d="M5.5 11a6.5 6.5 0 0 0 13 0"/><path d="M12 17.5v3.5"/>'
|
|
391
|
+
};
|
|
392
|
+
function Icon({ name, size = 24, stroke = 1.75, color = "currentColor", fill = "none", style }) {
|
|
393
|
+
const d = ICON_PATHS[name];
|
|
394
|
+
if (!d)
|
|
395
|
+
return null;
|
|
396
|
+
return /* @__PURE__ */ React.createElement(
|
|
397
|
+
"svg",
|
|
398
|
+
{
|
|
399
|
+
width: size,
|
|
400
|
+
height: size,
|
|
401
|
+
viewBox: "0 0 24 24",
|
|
402
|
+
fill,
|
|
403
|
+
stroke: color,
|
|
404
|
+
strokeWidth: stroke,
|
|
405
|
+
strokeLinecap: "round",
|
|
406
|
+
strokeLinejoin: "round",
|
|
407
|
+
style: { display: "block", flexShrink: 0, ...style },
|
|
408
|
+
dangerouslySetInnerHTML: { __html: d }
|
|
409
|
+
}
|
|
410
|
+
);
|
|
634
411
|
}
|
|
635
|
-
Object.assign(window, {
|
|
636
|
-
dkHash,
|
|
637
|
-
dkIdenticon,
|
|
638
|
-
dkClock,
|
|
639
|
-
dkDayLabel,
|
|
640
|
-
dkApi,
|
|
641
|
-
useDaemonData,
|
|
642
|
-
DK_ME_FALLBACK,
|
|
643
|
-
dkCopy
|
|
644
|
-
});
|
|
412
|
+
Object.assign(window, { Icon, ICON_PATHS });
|
|
645
413
|
|
|
646
414
|
// src/chat.jsx
|
|
647
415
|
function RequestsBlock({ T, requests, onAct }) {
|
|
@@ -685,7 +453,7 @@ function RequestsBlock({ T, requests, onAct }) {
|
|
|
685
453
|
display: "flex",
|
|
686
454
|
flexDirection: "column",
|
|
687
455
|
gap: 8
|
|
688
|
-
} }, /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8 } },
|
|
456
|
+
} }, /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8 } }, /* @__PURE__ */ React.createElement(DkEnsAvatar, { userid: r.userid || r.id, name: r.name, fallbackSeed: r.carrier, size: 30, radius: 7 }), /* @__PURE__ */ React.createElement("div", { style: { minWidth: 0, flex: 1 } }, r.name ? /* @__PURE__ */ React.createElement("div", { style: {
|
|
689
457
|
fontFamily: "var(--ui)",
|
|
690
458
|
fontSize: 13,
|
|
691
459
|
fontWeight: 600,
|
|
@@ -3047,95 +2815,413 @@ function shortKey(s, head = 6, tail = 5) {
|
|
|
3047
2815
|
return s;
|
|
3048
2816
|
return s.slice(0, head) + "\u2026" + s.slice(-tail);
|
|
3049
2817
|
}
|
|
3050
|
-
function RouteTag({ peer }) {
|
|
3051
|
-
if (!peer.online)
|
|
3052
|
-
return /* @__PURE__ */ React.createElement(Tag, { tone: "off" }, "offline");
|
|
3053
|
-
const relay = peer.via === "relay";
|
|
3054
|
-
const via = peer.via || "online";
|
|
3055
|
-
return /* @__PURE__ */ React.createElement(Tag, { tone: relay ? "warn" : "ok" }, peer.ping != null ? `${via} \xB7 ${peer.ping}ms` : via);
|
|
2818
|
+
function RouteTag({ peer }) {
|
|
2819
|
+
if (!peer.online)
|
|
2820
|
+
return /* @__PURE__ */ React.createElement(Tag, { tone: "off" }, "offline");
|
|
2821
|
+
const relay = peer.via === "relay";
|
|
2822
|
+
const via = peer.via || "online";
|
|
2823
|
+
return /* @__PURE__ */ React.createElement(Tag, { tone: relay ? "warn" : "ok" }, peer.ping != null ? `${via} \xB7 ${peer.ping}ms` : via);
|
|
2824
|
+
}
|
|
2825
|
+
function Tag({ children, tone = "neutral", style, title }) {
|
|
2826
|
+
const tones = {
|
|
2827
|
+
neutral: { bg: "var(--chip)", fg: "var(--dim)", bd: "transparent" },
|
|
2828
|
+
ok: { bg: "color-mix(in oklab, var(--online), transparent 86%)", fg: "var(--online)", bd: "transparent" },
|
|
2829
|
+
warn: { bg: "color-mix(in oklab, var(--warn), transparent 86%)", fg: "var(--warn)", bd: "transparent" },
|
|
2830
|
+
off: { bg: "var(--chip)", fg: "var(--faint)", bd: "transparent" },
|
|
2831
|
+
accent: { bg: "color-mix(in oklab, var(--accent), transparent 86%)", fg: "var(--accent)", bd: "transparent" },
|
|
2832
|
+
danger: { bg: "color-mix(in oklab, var(--danger), transparent 88%)", fg: "var(--danger)", bd: "transparent" }
|
|
2833
|
+
};
|
|
2834
|
+
const t = tones[tone] || tones.neutral;
|
|
2835
|
+
return /* @__PURE__ */ React.createElement("span", { title, style: {
|
|
2836
|
+
display: "inline-flex",
|
|
2837
|
+
alignItems: "center",
|
|
2838
|
+
gap: 4,
|
|
2839
|
+
height: 18,
|
|
2840
|
+
padding: "0 6px",
|
|
2841
|
+
borderRadius: 4,
|
|
2842
|
+
background: t.bg,
|
|
2843
|
+
color: t.fg,
|
|
2844
|
+
border: `1px solid ${t.bd}`,
|
|
2845
|
+
fontFamily: "var(--mono)",
|
|
2846
|
+
fontSize: 11,
|
|
2847
|
+
fontWeight: 600,
|
|
2848
|
+
letterSpacing: -0.1,
|
|
2849
|
+
lineHeight: 1,
|
|
2850
|
+
whiteSpace: "nowrap",
|
|
2851
|
+
...style
|
|
2852
|
+
} }, children);
|
|
2853
|
+
}
|
|
2854
|
+
function Unread({ n }) {
|
|
2855
|
+
if (!n)
|
|
2856
|
+
return null;
|
|
2857
|
+
return /* @__PURE__ */ React.createElement("span", { style: {
|
|
2858
|
+
minWidth: 18,
|
|
2859
|
+
height: 18,
|
|
2860
|
+
padding: "0 5px",
|
|
2861
|
+
borderRadius: 999,
|
|
2862
|
+
flexShrink: 0,
|
|
2863
|
+
background: "var(--accent)",
|
|
2864
|
+
color: "#fff",
|
|
2865
|
+
fontFamily: "var(--mono)",
|
|
2866
|
+
fontSize: 11,
|
|
2867
|
+
fontWeight: 700,
|
|
2868
|
+
lineHeight: "18px",
|
|
2869
|
+
textAlign: "center"
|
|
2870
|
+
} }, n);
|
|
2871
|
+
}
|
|
2872
|
+
function Btn({ children, icon, tone = "ghost", onClick, size = "md", title, style }) {
|
|
2873
|
+
const tones = {
|
|
2874
|
+
ghost: { bg: "transparent", fg: "var(--text)", bd: "var(--line)" },
|
|
2875
|
+
solid: { bg: "var(--accent)", fg: "#fff", bd: "transparent" },
|
|
2876
|
+
soft: { bg: "var(--chip)", fg: "var(--text)", bd: "transparent" },
|
|
2877
|
+
ok: { bg: "color-mix(in oklab, var(--online), transparent 84%)", fg: "var(--online)", bd: "transparent" },
|
|
2878
|
+
danger: { bg: "transparent", fg: "var(--danger)", bd: "color-mix(in oklab, var(--danger), transparent 70%)" }
|
|
2879
|
+
};
|
|
2880
|
+
const t = tones[tone] || tones.ghost;
|
|
2881
|
+
const h = size === "sm" ? 26 : size === "lg" ? 36 : 30;
|
|
2882
|
+
return /* @__PURE__ */ React.createElement("button", { onClick, title, style: {
|
|
2883
|
+
height: h,
|
|
2884
|
+
padding: icon && !children ? 0 : "0 11px",
|
|
2885
|
+
minWidth: icon && !children ? h : "auto",
|
|
2886
|
+
borderRadius: 6,
|
|
2887
|
+
cursor: "pointer",
|
|
2888
|
+
fontFamily: "var(--mono)",
|
|
2889
|
+
fontWeight: 600,
|
|
2890
|
+
fontSize: size === "sm" ? 12 : 12.5,
|
|
2891
|
+
letterSpacing: -0.1,
|
|
2892
|
+
background: t.bg,
|
|
2893
|
+
color: t.fg,
|
|
2894
|
+
border: `1px solid ${t.bd}`,
|
|
2895
|
+
display: "inline-flex",
|
|
2896
|
+
alignItems: "center",
|
|
2897
|
+
justifyContent: "center",
|
|
2898
|
+
gap: 6,
|
|
2899
|
+
whiteSpace: "nowrap",
|
|
2900
|
+
...style
|
|
2901
|
+
} }, icon && /* @__PURE__ */ React.createElement(Icon, { name: icon, size: 15, stroke: 2 }), children);
|
|
2902
|
+
}
|
|
2903
|
+
function Section({ label, count, trailing, style }) {
|
|
2904
|
+
return /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8, padding: "0 2px", ...style } }, /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 11, fontWeight: 700, letterSpacing: 1, textTransform: "uppercase", color: "var(--faint)" } }, label), count != null && /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 11, fontWeight: 700, color: "var(--faint)" } }, count), /* @__PURE__ */ React.createElement("div", { style: { flex: 1, height: 1, background: "var(--line)" } }), trailing);
|
|
2905
|
+
}
|
|
2906
|
+
Object.assign(window, { DkIdenticon, DkBot, DkAvatar, DkImgAvatar, StatusDot, Mono, shortKey, RouteTag, Tag, Unread, Btn, Section });
|
|
2907
|
+
|
|
2908
|
+
// src/apps.jsx
|
|
2909
|
+
var APPS = [
|
|
2910
|
+
{
|
|
2911
|
+
id: "meet",
|
|
2912
|
+
name: "Beagle Meet",
|
|
2913
|
+
origin: "https://snoopy.fi.chat",
|
|
2914
|
+
url: "https://snoopy.fi.chat",
|
|
2915
|
+
blurb: { en: "Video calls and rooms \u2014 your Beagle identity is the login.", zh: "\u89C6\u9891\u4F1A\u8BAE\u548C\u623F\u95F4 \u2014\u2014 \u7528 Beagle \u8EAB\u4EFD\u76F4\u63A5\u767B\u5F55\u3002" },
|
|
2916
|
+
icon: "video"
|
|
2917
|
+
},
|
|
2918
|
+
{
|
|
2919
|
+
id: "interview",
|
|
2920
|
+
name: "interview.network",
|
|
2921
|
+
origin: "https://interview.network",
|
|
2922
|
+
url: "https://interview.network",
|
|
2923
|
+
blurb: { en: "Interviews, scheduled and held against a verified identity.", zh: "\u9762\u8BD5\u5B89\u6392\u4E0E\u8FDB\u884C\uFF0C\u8EAB\u4EFD\u53EF\u9A8C\u8BC1\u3002" },
|
|
2924
|
+
icon: "users"
|
|
2925
|
+
},
|
|
2926
|
+
{
|
|
2927
|
+
id: "readyplayer",
|
|
2928
|
+
name: "readyplayer.network",
|
|
2929
|
+
origin: "https://readyplayer.network",
|
|
2930
|
+
url: "https://readyplayer.network",
|
|
2931
|
+
blurb: { en: "Membership and the services that come with it.", zh: "\u4F1A\u5458\u4E0E\u914D\u5957\u670D\u52A1\u3002" },
|
|
2932
|
+
icon: "starCoin"
|
|
2933
|
+
},
|
|
2934
|
+
{
|
|
2935
|
+
id: "btc",
|
|
2936
|
+
name: "btc.fi.chat",
|
|
2937
|
+
origin: "https://btc.fi.chat",
|
|
2938
|
+
url: "https://btc.fi.chat",
|
|
2939
|
+
blurb: { en: "Trading desk and signals.", zh: "\u4EA4\u6613\u53F0\u4E0E\u4FE1\u53F7\u3002" },
|
|
2940
|
+
icon: "trendingUp"
|
|
2941
|
+
}
|
|
2942
|
+
];
|
|
2943
|
+
function dkB64Url(obj) {
|
|
2944
|
+
const json = JSON.stringify(obj);
|
|
2945
|
+
const b64 = btoa(unescape(encodeURIComponent(json)));
|
|
2946
|
+
return b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
2947
|
+
}
|
|
2948
|
+
function AppsTab({ T, t }) {
|
|
2949
|
+
const zh = t && t.lang === "zh";
|
|
2950
|
+
const [busy, setBusy] = React.useState(null);
|
|
2951
|
+
const [err, setErr] = React.useState(null);
|
|
2952
|
+
const open = async (app) => {
|
|
2953
|
+
setBusy(app.id);
|
|
2954
|
+
setErr(null);
|
|
2955
|
+
const win = window.open("", "_blank");
|
|
2956
|
+
try {
|
|
2957
|
+
const r = await dkPost("/api/launch-token", { origin: app.origin });
|
|
2958
|
+
if (!r || r.ok === false)
|
|
2959
|
+
throw new Error(r && r.error || "could not sign");
|
|
2960
|
+
const { ok, ...assertion } = r;
|
|
2961
|
+
const url = app.url + "#beagle=" + dkB64Url(assertion);
|
|
2962
|
+
if (win)
|
|
2963
|
+
win.location = url;
|
|
2964
|
+
else
|
|
2965
|
+
window.open(url, "_blank");
|
|
2966
|
+
} catch (e) {
|
|
2967
|
+
if (win)
|
|
2968
|
+
win.close();
|
|
2969
|
+
setErr(String(e && e.message || e));
|
|
2970
|
+
} finally {
|
|
2971
|
+
setBusy(null);
|
|
2972
|
+
}
|
|
2973
|
+
};
|
|
2974
|
+
return /* @__PURE__ */ React.createElement("div", { style: { flex: 1, overflow: "auto", background: "var(--bg)" } }, /* @__PURE__ */ React.createElement("div", { style: { maxWidth: 760, margin: "0 auto", padding: "24px 28px 60px", display: "flex", flexDirection: "column", gap: 16 } }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--mono)", fontSize: 11, fontWeight: 700, letterSpacing: 0.6, textTransform: "uppercase", color: "var(--faint)" } }, zh ? "\u5E94\u7528" : "Apps"), /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12.5, color: "var(--faint)", marginTop: 6, lineHeight: 1.6 } }, zh ? "\u8FD9\u4E9B\u5E94\u7528\u63A5\u53D7 Beagle \u8EAB\u4EFD\u3002\u4ECE\u8FD9\u91CC\u6253\u5F00\u4E0D\u9700\u8981\u518D\u767B\u5F55\u4E00\u6B21 \u2014\u2014 \u4F1A\u5E26\u4E0A\u4E00\u4E2A\u4E24\u5206\u949F\u5185\u6709\u6548\u7684\u7B7E\u540D\u3002" : "These accept a Beagle identity. Opening one from here does not ask you to sign in again \u2014 it carries a signature that is good for two minutes.")), err && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--mono)", fontSize: 11.5, color: "#f85149" } }, err), APPS.map((app) => /* @__PURE__ */ React.createElement("div", { key: app.id, style: {
|
|
2975
|
+
display: "flex",
|
|
2976
|
+
alignItems: "center",
|
|
2977
|
+
gap: 14,
|
|
2978
|
+
padding: "14px 16px",
|
|
2979
|
+
borderRadius: 12,
|
|
2980
|
+
background: "var(--panel)",
|
|
2981
|
+
border: "1px solid var(--line)"
|
|
2982
|
+
} }, /* @__PURE__ */ React.createElement("div", { style: {
|
|
2983
|
+
width: 38,
|
|
2984
|
+
height: 38,
|
|
2985
|
+
borderRadius: 10,
|
|
2986
|
+
flexShrink: 0,
|
|
2987
|
+
background: "var(--panel-2)",
|
|
2988
|
+
display: "flex",
|
|
2989
|
+
alignItems: "center",
|
|
2990
|
+
justifyContent: "center"
|
|
2991
|
+
} }, /* @__PURE__ */ React.createElement(Icon, { name: app.icon, size: 19, color: "var(--accent)", stroke: 1.8 })), /* @__PURE__ */ React.createElement("div", { style: { flex: 1, minWidth: 0 } }, /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 14, fontWeight: 600, color: "var(--text)" } }, app.name), /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12.5, color: "var(--faint)", marginTop: 2 } }, zh ? app.blurb.zh : app.blurb.en), /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--mono)", fontSize: 11, color: "var(--dim)", marginTop: 3 } }, app.origin.replace(/^https?:\/\//, ""))), /* @__PURE__ */ React.createElement(Btn, { tone: "accent", size: "sm", onClick: busy ? void 0 : () => open(app) }, busy === app.id ? zh ? "\u6253\u5F00\u4E2D\u2026" : "opening\u2026" : zh ? "\u6253\u5F00" : "Open")))));
|
|
2992
|
+
}
|
|
2993
|
+
|
|
2994
|
+
// src/rtc-signaling.jsx
|
|
2995
|
+
var DK_FALLBACK_ICE_SERVERS = [
|
|
2996
|
+
{ urls: "stun:stun.l.google.com:19302" },
|
|
2997
|
+
{ urls: "turn:tokyo.fi.chat:3478", username: "allcom", credential: "allcompass" },
|
|
2998
|
+
{ urls: "turn:tokyo.fi.chat:3478?transport=tcp", username: "allcom", credential: "allcompass" }
|
|
2999
|
+
];
|
|
3000
|
+
var DK_LIVE_ICE_SERVERS = [];
|
|
3001
|
+
var _dkIcePromise = null;
|
|
3002
|
+
var _dkIceWarmPromise = null;
|
|
3003
|
+
function dkWarmCallIce(iceServers) {
|
|
3004
|
+
if (_dkIceWarmPromise)
|
|
3005
|
+
return _dkIceWarmPromise;
|
|
3006
|
+
if (!window.RTCPeerConnection || !iceServers || !iceServers.length) {
|
|
3007
|
+
_dkIceWarmPromise = Promise.resolve();
|
|
3008
|
+
return _dkIceWarmPromise;
|
|
3009
|
+
}
|
|
3010
|
+
_dkIceWarmPromise = new Promise((resolve) => {
|
|
3011
|
+
let pc;
|
|
3012
|
+
let finished = false;
|
|
3013
|
+
const done = (why) => {
|
|
3014
|
+
if (finished)
|
|
3015
|
+
return;
|
|
3016
|
+
finished = true;
|
|
3017
|
+
try {
|
|
3018
|
+
if (pc)
|
|
3019
|
+
pc.close();
|
|
3020
|
+
} catch (e) {
|
|
3021
|
+
}
|
|
3022
|
+
console.log("[rtc] ICE warmup done (" + why + ")");
|
|
3023
|
+
resolve();
|
|
3024
|
+
};
|
|
3025
|
+
try {
|
|
3026
|
+
pc = new RTCPeerConnection({ iceServers, iceTransportPolicy: "all" });
|
|
3027
|
+
const timer = setTimeout(() => done("timeout"), 5e3);
|
|
3028
|
+
pc.onicecandidate = (ev) => {
|
|
3029
|
+
const c = ev.candidate && ev.candidate.candidate;
|
|
3030
|
+
if (c && /typ relay/.test(c)) {
|
|
3031
|
+
clearTimeout(timer);
|
|
3032
|
+
done("relay");
|
|
3033
|
+
}
|
|
3034
|
+
};
|
|
3035
|
+
pc.onicegatheringstatechange = () => {
|
|
3036
|
+
if (pc.iceGatheringState === "complete") {
|
|
3037
|
+
clearTimeout(timer);
|
|
3038
|
+
done("gather-complete");
|
|
3039
|
+
}
|
|
3040
|
+
};
|
|
3041
|
+
pc.createDataChannel("ice-warm");
|
|
3042
|
+
pc.createOffer().then((o) => pc.setLocalDescription(o)).catch(() => done("offer-fail"));
|
|
3043
|
+
} catch (e) {
|
|
3044
|
+
done("error");
|
|
3045
|
+
}
|
|
3046
|
+
});
|
|
3047
|
+
return _dkIceWarmPromise;
|
|
3048
|
+
}
|
|
3049
|
+
function dkLoadCallIceServers() {
|
|
3050
|
+
if (_dkIcePromise)
|
|
3051
|
+
return _dkIcePromise;
|
|
3052
|
+
_dkIcePromise = (async () => {
|
|
3053
|
+
try {
|
|
3054
|
+
const r = await fetch("/api/call-ice-servers", { headers: { "cache-control": "no-cache" } });
|
|
3055
|
+
const d = await r.json();
|
|
3056
|
+
if (d && d.ok && Array.isArray(d.iceServers) && d.iceServers.length) {
|
|
3057
|
+
DK_LIVE_ICE_SERVERS.splice(0, DK_LIVE_ICE_SERVERS.length, ...d.iceServers);
|
|
3058
|
+
console.log("[rtc] Carrier bootstrap ICE servers:", DK_LIVE_ICE_SERVERS.map((s) => s.urls));
|
|
3059
|
+
await dkWarmCallIce(DK_LIVE_ICE_SERVERS);
|
|
3060
|
+
return DK_LIVE_ICE_SERVERS;
|
|
3061
|
+
}
|
|
3062
|
+
console.warn("[rtc] call-ice-servers unavailable:", d && d.error);
|
|
3063
|
+
} catch (e) {
|
|
3064
|
+
console.warn("[rtc] call-ice-servers fetch failed", e);
|
|
3065
|
+
}
|
|
3066
|
+
console.warn("[rtc] falling back to tokyo TURN \u2014 web\u2194Android online ICE may fail");
|
|
3067
|
+
DK_LIVE_ICE_SERVERS.splice(0, DK_LIVE_ICE_SERVERS.length, ...DK_FALLBACK_ICE_SERVERS.map((s) => ({ ...s })));
|
|
3068
|
+
await dkWarmCallIce(DK_LIVE_ICE_SERVERS);
|
|
3069
|
+
return DK_LIVE_ICE_SERVERS;
|
|
3070
|
+
})();
|
|
3071
|
+
return _dkIcePromise;
|
|
3056
3072
|
}
|
|
3057
|
-
function
|
|
3058
|
-
const
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
alignItems: "center",
|
|
3070
|
-
gap: 4,
|
|
3071
|
-
height: 18,
|
|
3072
|
-
padding: "0 6px",
|
|
3073
|
-
borderRadius: 4,
|
|
3074
|
-
background: t.bg,
|
|
3075
|
-
color: t.fg,
|
|
3076
|
-
border: `1px solid ${t.bd}`,
|
|
3077
|
-
fontFamily: "var(--mono)",
|
|
3078
|
-
fontSize: 11,
|
|
3079
|
-
fontWeight: 600,
|
|
3080
|
-
letterSpacing: -0.1,
|
|
3081
|
-
lineHeight: 1,
|
|
3082
|
-
whiteSpace: "nowrap",
|
|
3083
|
-
...style
|
|
3084
|
-
} }, children);
|
|
3073
|
+
function dkAwaitCallIceServers(ms) {
|
|
3074
|
+
const budget = typeof ms === "number" ? ms : 1e4;
|
|
3075
|
+
return Promise.race([
|
|
3076
|
+
dkLoadCallIceServers(),
|
|
3077
|
+
new Promise((resolve) => setTimeout(() => {
|
|
3078
|
+
if (!DK_LIVE_ICE_SERVERS.length) {
|
|
3079
|
+
DK_LIVE_ICE_SERVERS.splice(0, DK_LIVE_ICE_SERVERS.length, ...DK_FALLBACK_ICE_SERVERS.map((s) => ({ ...s })));
|
|
3080
|
+
console.warn("[rtc] ICE wait timed out \u2014 using fallback");
|
|
3081
|
+
}
|
|
3082
|
+
resolve(DK_LIVE_ICE_SERVERS);
|
|
3083
|
+
}, budget))
|
|
3084
|
+
]).then(() => DK_LIVE_ICE_SERVERS);
|
|
3085
3085
|
}
|
|
3086
|
-
|
|
3087
|
-
|
|
3086
|
+
dkLoadCallIceServers();
|
|
3087
|
+
function dkRtcParseEnvelope(data) {
|
|
3088
|
+
const text = String(data || "").replace(/\0+$/u, "").trim();
|
|
3089
|
+
if (!text)
|
|
3088
3090
|
return null;
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
color: "#fff",
|
|
3097
|
-
fontFamily: "var(--mono)",
|
|
3098
|
-
fontSize: 11,
|
|
3099
|
-
fontWeight: 700,
|
|
3100
|
-
lineHeight: "18px",
|
|
3101
|
-
textAlign: "center"
|
|
3102
|
-
} }, n);
|
|
3091
|
+
try {
|
|
3092
|
+
const obj = JSON.parse(text);
|
|
3093
|
+
if (obj && obj.dkRtc === 1 && typeof obj.kind === "string")
|
|
3094
|
+
return obj;
|
|
3095
|
+
} catch (e) {
|
|
3096
|
+
}
|
|
3097
|
+
return null;
|
|
3103
3098
|
}
|
|
3104
|
-
function
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3099
|
+
function dkRtcSignalBus() {
|
|
3100
|
+
if (window.__dkRtcSignalBus)
|
|
3101
|
+
return window.__dkRtcSignalBus;
|
|
3102
|
+
const PW = window.PeerWebRTC;
|
|
3103
|
+
const handlers = /* @__PURE__ */ new Map();
|
|
3104
|
+
const pendingCalls = [];
|
|
3105
|
+
const PENDING_CALL_CAP = 16;
|
|
3106
|
+
let started = false;
|
|
3107
|
+
let stopped = false;
|
|
3108
|
+
function emit(kind, userid, payload) {
|
|
3109
|
+
const set = handlers.get(kind);
|
|
3110
|
+
if (!set || !set.size) {
|
|
3111
|
+
if (kind === "call") {
|
|
3112
|
+
pendingCalls.push({ userid, payload });
|
|
3113
|
+
if (pendingCalls.length > PENDING_CALL_CAP)
|
|
3114
|
+
pendingCalls.shift();
|
|
3115
|
+
}
|
|
3116
|
+
return;
|
|
3117
|
+
}
|
|
3118
|
+
for (const h of Array.from(set)) {
|
|
3119
|
+
try {
|
|
3120
|
+
h(userid, payload);
|
|
3121
|
+
} catch (e) {
|
|
3122
|
+
console.warn("[rtc] signal handler failed", e);
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
}
|
|
3126
|
+
async function pollLoop() {
|
|
3127
|
+
let cursor = null;
|
|
3128
|
+
while (!stopped) {
|
|
3129
|
+
let signals = [];
|
|
3130
|
+
try {
|
|
3131
|
+
const u = cursor == null ? "/api/call-poll" : "/api/call-poll?since=" + cursor;
|
|
3132
|
+
const r = await fetch(u, { headers: { "cache-control": "no-cache" } });
|
|
3133
|
+
const d = await r.json();
|
|
3134
|
+
signals = d && d.signals || [];
|
|
3135
|
+
if (d && typeof d.cursor === "number")
|
|
3136
|
+
cursor = d.cursor;
|
|
3137
|
+
} catch (e) {
|
|
3138
|
+
await new Promise((res) => setTimeout(res, 1e3));
|
|
3139
|
+
continue;
|
|
3140
|
+
}
|
|
3141
|
+
for (const s of signals) {
|
|
3142
|
+
const env = dkRtcParseEnvelope(s.data);
|
|
3143
|
+
if (env) {
|
|
3144
|
+
emit(env.kind, s.userid, env);
|
|
3145
|
+
continue;
|
|
3146
|
+
}
|
|
3147
|
+
if (PW) {
|
|
3148
|
+
try {
|
|
3149
|
+
emit("call", s.userid, PW.decodeSignal(s.data));
|
|
3150
|
+
} catch (e) {
|
|
3151
|
+
}
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3154
|
+
}
|
|
3155
|
+
}
|
|
3156
|
+
const bus = {
|
|
3157
|
+
start() {
|
|
3158
|
+
if (started)
|
|
3159
|
+
return;
|
|
3160
|
+
started = true;
|
|
3161
|
+
stopped = false;
|
|
3162
|
+
pollLoop();
|
|
3163
|
+
},
|
|
3164
|
+
on(kind, cb) {
|
|
3165
|
+
if (!handlers.has(kind))
|
|
3166
|
+
handlers.set(kind, /* @__PURE__ */ new Set());
|
|
3167
|
+
handlers.get(kind).add(cb);
|
|
3168
|
+
this.start();
|
|
3169
|
+
if (kind === "call" && pendingCalls.length) {
|
|
3170
|
+
const queued = pendingCalls.splice(0);
|
|
3171
|
+
console.log("[rtc] flushing " + queued.length + " buffered call signal(s)");
|
|
3172
|
+
for (const q of queued) {
|
|
3173
|
+
try {
|
|
3174
|
+
cb(q.userid, q.payload);
|
|
3175
|
+
} catch (e) {
|
|
3176
|
+
console.warn("[rtc] buffered call handler failed", e);
|
|
3177
|
+
}
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
3180
|
+
return () => {
|
|
3181
|
+
var _a;
|
|
3182
|
+
return (_a = handlers.get(kind)) == null ? void 0 : _a.delete(cb);
|
|
3183
|
+
};
|
|
3184
|
+
},
|
|
3185
|
+
async send(userid, data) {
|
|
3186
|
+
const body = JSON.stringify({ userid, data: typeof data === "string" ? data : JSON.stringify(data) });
|
|
3187
|
+
const r = await fetch("/api/call-signal", {
|
|
3188
|
+
method: "POST",
|
|
3189
|
+
headers: { "content-type": "application/json" },
|
|
3190
|
+
body
|
|
3191
|
+
});
|
|
3192
|
+
const d = await r.json().catch(() => ({ ok: r.ok }));
|
|
3193
|
+
if (!d.ok)
|
|
3194
|
+
throw new Error(d.error || "call-signal send failed");
|
|
3195
|
+
},
|
|
3196
|
+
stop() {
|
|
3197
|
+
stopped = true;
|
|
3198
|
+
}
|
|
3111
3199
|
};
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
return /* @__PURE__ */ React.createElement("button", { onClick, title, style: {
|
|
3115
|
-
height: h,
|
|
3116
|
-
padding: icon && !children ? 0 : "0 11px",
|
|
3117
|
-
minWidth: icon && !children ? h : "auto",
|
|
3118
|
-
borderRadius: 6,
|
|
3119
|
-
cursor: "pointer",
|
|
3120
|
-
fontFamily: "var(--mono)",
|
|
3121
|
-
fontWeight: 600,
|
|
3122
|
-
fontSize: size === "sm" ? 12 : 12.5,
|
|
3123
|
-
letterSpacing: -0.1,
|
|
3124
|
-
background: t.bg,
|
|
3125
|
-
color: t.fg,
|
|
3126
|
-
border: `1px solid ${t.bd}`,
|
|
3127
|
-
display: "inline-flex",
|
|
3128
|
-
alignItems: "center",
|
|
3129
|
-
justifyContent: "center",
|
|
3130
|
-
gap: 6,
|
|
3131
|
-
whiteSpace: "nowrap",
|
|
3132
|
-
...style
|
|
3133
|
-
} }, icon && /* @__PURE__ */ React.createElement(Icon, { name: icon, size: 15, stroke: 2 }), children);
|
|
3200
|
+
window.__dkRtcSignalBus = bus;
|
|
3201
|
+
return bus;
|
|
3134
3202
|
}
|
|
3135
|
-
function
|
|
3136
|
-
|
|
3203
|
+
function makeDaemonSignaling() {
|
|
3204
|
+
const PW = window.PeerWebRTC;
|
|
3205
|
+
const bus = dkRtcSignalBus();
|
|
3206
|
+
let off = null;
|
|
3207
|
+
return {
|
|
3208
|
+
async send(peerId, signal) {
|
|
3209
|
+
await bus.send(peerId, PW.encodeSignal(signal));
|
|
3210
|
+
},
|
|
3211
|
+
onSignal(cb) {
|
|
3212
|
+
if (off)
|
|
3213
|
+
off();
|
|
3214
|
+
off = bus.on("call", cb);
|
|
3215
|
+
},
|
|
3216
|
+
stop() {
|
|
3217
|
+
if (off) {
|
|
3218
|
+
off();
|
|
3219
|
+
off = null;
|
|
3220
|
+
}
|
|
3221
|
+
}
|
|
3222
|
+
};
|
|
3137
3223
|
}
|
|
3138
|
-
Object.assign(window, {
|
|
3224
|
+
Object.assign(window, { dkRtcSignalBus, makeDaemonSignaling });
|
|
3139
3225
|
|
|
3140
3226
|
// src/call.jsx
|
|
3141
3227
|
function useCallController(selfId, onCallLog) {
|
|
@@ -4316,6 +4402,7 @@ var STR = {
|
|
|
4316
4402
|
en: {
|
|
4317
4403
|
chat: "Chat",
|
|
4318
4404
|
network: "Network",
|
|
4405
|
+
apps: "Apps",
|
|
4319
4406
|
profile: "Profile",
|
|
4320
4407
|
recommended: "Discover",
|
|
4321
4408
|
registered: "Names",
|
|
@@ -4447,6 +4534,8 @@ var STR = {
|
|
|
4447
4534
|
updRestarting: "Restarting\u2026 this page reloads when it\u2019s back. (If beagle was started by hand in a terminal, run it again.)",
|
|
4448
4535
|
updNpx: "Running via npx \u2014 restarting picks up the latest version automatically.",
|
|
4449
4536
|
updDev: "Running from a source checkout \u2014 update with:",
|
|
4537
|
+
updPeerDaemon: "The peer version belongs to the running agentnet daemon, not to this app. Update it with:",
|
|
4538
|
+
updUnknown: "Update now runs the global install. If that is not how this was installed, run:",
|
|
4450
4539
|
updLanNote: "agentnet (lan): one click reinstalls it and asks the running daemon to restart itself. Manual equivalent:",
|
|
4451
4540
|
updCheck: "check for updates",
|
|
4452
4541
|
updCheckLabel: "updates",
|
|
@@ -4493,6 +4582,7 @@ var STR = {
|
|
|
4493
4582
|
zh: {
|
|
4494
4583
|
chat: "\u804A\u5929",
|
|
4495
4584
|
network: "\u7F51\u7EDC",
|
|
4585
|
+
apps: "\u5E94\u7528",
|
|
4496
4586
|
profile: "\u6211\u7684",
|
|
4497
4587
|
recommended: "\u63A8\u8350",
|
|
4498
4588
|
registered: "\u540D\u5F55",
|
|
@@ -4624,6 +4714,8 @@ var STR = {
|
|
|
4624
4714
|
updRestarting: "\u6B63\u5728\u91CD\u542F\u2026\u5B8C\u6210\u540E\u672C\u9875\u4F1A\u81EA\u52A8\u5237\u65B0\u3002(\u5982\u679C beagle \u662F\u5728\u7EC8\u7AEF\u91CC\u624B\u52A8\u542F\u52A8\u7684,\u8BF7\u91CD\u65B0\u8FD0\u884C\u4E00\u6B21\u3002)",
|
|
4625
4715
|
updNpx: "\u4F60\u662F\u7528 npx \u8FD0\u884C\u7684\u2014\u2014\u91CD\u542F\u5373\u81EA\u52A8\u83B7\u53D6\u6700\u65B0\u7248\u3002",
|
|
4626
4716
|
updDev: "\u5F53\u524D\u4ECE\u6E90\u7801\u76EE\u5F55\u8FD0\u884C,\u8BF7\u624B\u52A8\u66F4\u65B0:",
|
|
4717
|
+
updPeerDaemon: "peer \u7684\u7248\u672C\u5C5E\u4E8E\u6B63\u5728\u8FD0\u884C\u7684 agentnet daemon,\u4E0D\u5C5E\u4E8E\u672C\u5E94\u7528\u3002\u8BF7\u7528\u8FD9\u6761\u547D\u4EE4\u66F4\u65B0:",
|
|
4718
|
+
updUnknown: "\u300C\u7ACB\u5373\u66F4\u65B0\u300D\u4F1A\u6267\u884C\u5168\u5C40\u5B89\u88C5\u3002\u5982\u679C\u4E0D\u662F\u8FD9\u6837\u88C5\u7684,\u8BF7\u8FD0\u884C:",
|
|
4627
4719
|
updLanNote: "agentnet(lan):\u4E00\u952E\u91CD\u88C5\u5E76\u8BA9\u8FD0\u884C\u4E2D\u7684 daemon \u81EA\u6211\u91CD\u542F\u3002\u7B49\u4EF7\u624B\u52A8\u547D\u4EE4:",
|
|
4628
4720
|
updCheck: "\u68C0\u67E5\u66F4\u65B0",
|
|
4629
4721
|
updCheckLabel: "\u66F4\u65B0",
|
|
@@ -4689,8 +4781,10 @@ function DkUpdateModal({ T, info, onClose }) {
|
|
|
4689
4781
|
const [phase, setPhase] = React.useState("idle");
|
|
4690
4782
|
const [err, setErr] = React.useState(null);
|
|
4691
4783
|
const behind = (info.updates || []).filter((u) => u.behind);
|
|
4692
|
-
const
|
|
4784
|
+
const peerIsDaemons = info.peerOwner === "daemon";
|
|
4785
|
+
const appBehind = behind.some((u) => u.pkg !== "@decentnetwork/lan" && !(peerIsDaemons && u.pkg === "@decentnetwork/peer"));
|
|
4693
4786
|
const lanBehind = behind.find((u) => u.pkg === "@decentnetwork/lan");
|
|
4787
|
+
const daemonPeerBehind = peerIsDaemons && behind.some((u) => u.pkg === "@decentnetwork/peer");
|
|
4694
4788
|
const short = (pkg) => pkg.replace("@decentnetwork/", "");
|
|
4695
4789
|
const doUpdate = () => {
|
|
4696
4790
|
setPhase("running");
|
|
@@ -4746,10 +4840,10 @@ function DkUpdateModal({ T, info, onClose }) {
|
|
|
4746
4840
|
background: tone ? "var(--accent)" : "transparent",
|
|
4747
4841
|
color: tone ? "#fff" : "var(--text)"
|
|
4748
4842
|
} }, label);
|
|
4749
|
-
return /* @__PURE__ */ React.createElement("div", { style: { position: "fixed", inset: 0, zIndex: 95, background: "color-mix(in oklab, #000, transparent 38%)", display: "flex", alignItems: "center", justifyContent: "center", padding: 24 } }, /* @__PURE__ */ React.createElement("div", { style: { width: 430, maxWidth: "94vw", background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 16, padding: "20px 22px", display: "flex", flexDirection: "column", gap: 14 } }, /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 13.5, fontWeight: 700, color: "var(--text)" } }, T.updTitle || "Update available"), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 6 } }, behind.map((u) => /* @__PURE__ */ React.createElement("div", { key: u.pkg, style: { display: "flex", alignItems: "center", gap: 10, fontFamily: "var(--mono)", fontSize: 12.5 } }, /* @__PURE__ */ React.createElement("span", { style: { width: 70, color: "var(--faint)" } }, short(u.pkg)), /* @__PURE__ */ React.createElement("span", { style: { color: "var(--dim)" } }, u.current), /* @__PURE__ */ React.createElement("span", { style: { color: "var(--faint)" } }, "\u2192"), /* @__PURE__ */ React.createElement("span", { style: { color: "var(--accent)", fontWeight: 700 } }, u.latest)))), phase === "idle" && appBehind && info.mode === "dev" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12, color: "var(--dim)", lineHeight: 1.5 } }, T.updDev || "Running from a source checkout \u2014 update with:", /* @__PURE__ */ React.createElement("br", null), /* @__PURE__ */ React.createElement("code", { style: { fontFamily: "var(--mono)", fontSize: 11.5, color: "var(--text)" } }, "git pull && npm run build")), phase === "idle" && appBehind && info.mode === "npx" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12, color: "var(--dim)", lineHeight: 1.5 } }, T.updNpx || "Running via npx \u2014 restarting picks up the latest version automatically."), lanBehind && phase === "idle" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12, color: "var(--dim)", lineHeight: 1.5 } }, T.updLanNote || "agentnet (lan): one click reinstalls it and asks the running daemon to restart itself. Manual equivalent:", /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: 6 } }, /* @__PURE__ */ React.createElement("code", { style: { flex: 1, minWidth: 0, fontFamily: "var(--mono)", fontSize: 11.5, color: "var(--text)", background: "var(--panel-2)", border: "1px solid var(--line)", borderRadius: 8, padding: "8px 10px", userSelect: "all", wordBreak: "break-all" } }, "npm i -g @decentnetwork/lan@latest && agentnet restart"), /* @__PURE__ */ React.createElement(Btn, { size: "sm", icon: "copy", title: T.copy || "Copy", onClick: () => dkCopy("npm i -g @decentnetwork/lan@latest && agentnet restart") }))), phase === "lan-done" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12.5, color: "var(--online)" } }, T.updLanDone || "lan updated \u2014 daemon restarted with the new version \u2713"), phase === "lan-norestart" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12.5, color: "var(--warn, #f59e0b)" } }, T.updLanNoRestart || "lan updated, but the daemon was not running (or refused) \u2014 the new version applies on its next start."), phase === "running" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12.5, color: "var(--dim)" } }, T.updBusy || "Updating\u2026 (about a minute)"), phase === "done" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12.5, color: "var(--online)" } }, T.updDone || "Updated \u2014 restart to apply."), phase === "restarting" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12.5, color: "var(--dim)" } }, T.updRestarting || "Restarting\u2026 this page reloads when it\u2019s back. (If beagle was started by hand in a terminal, run it again.)"), phase === "error" && (() => {
|
|
4843
|
+
return /* @__PURE__ */ React.createElement("div", { style: { position: "fixed", inset: 0, zIndex: 95, background: "color-mix(in oklab, #000, transparent 38%)", display: "flex", alignItems: "center", justifyContent: "center", padding: 24 } }, /* @__PURE__ */ React.createElement("div", { style: { width: 430, maxWidth: "94vw", background: "var(--panel)", border: "1px solid var(--line)", borderRadius: 16, padding: "20px 22px", display: "flex", flexDirection: "column", gap: 14 } }, /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 13.5, fontWeight: 700, color: "var(--text)" } }, T.updTitle || "Update available"), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 6 } }, behind.map((u) => /* @__PURE__ */ React.createElement("div", { key: u.pkg, style: { display: "flex", alignItems: "center", gap: 10, fontFamily: "var(--mono)", fontSize: 12.5 } }, /* @__PURE__ */ React.createElement("span", { style: { width: 70, color: "var(--faint)" } }, short(u.pkg)), /* @__PURE__ */ React.createElement("span", { style: { color: "var(--dim)" } }, u.current), /* @__PURE__ */ React.createElement("span", { style: { color: "var(--faint)" } }, "\u2192"), /* @__PURE__ */ React.createElement("span", { style: { color: "var(--accent)", fontWeight: 700 } }, u.latest)))), phase === "idle" && appBehind && info.mode === "dev" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12, color: "var(--dim)", lineHeight: 1.5 } }, T.updDev || "Running from a source checkout \u2014 update with:", /* @__PURE__ */ React.createElement("br", null), /* @__PURE__ */ React.createElement("code", { style: { fontFamily: "var(--mono)", fontSize: 11.5, color: "var(--text)" } }, "git pull && npm run build")), phase === "idle" && appBehind && info.mode === "unknown" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12, color: "var(--dim)", lineHeight: 1.5 } }, T.updUnknown || "Update now runs the global install. If that is not how this was installed, run:", /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: 6 } }, /* @__PURE__ */ React.createElement("code", { style: { flex: 1, minWidth: 0, fontFamily: "var(--mono)", fontSize: 11.5, color: "var(--text)", background: "var(--panel-2)", border: "1px solid var(--line)", borderRadius: 8, padding: "8px 10px", userSelect: "all", wordBreak: "break-all" } }, "npm i -g @decentnetwork/beagle@latest"), /* @__PURE__ */ React.createElement(Btn, { size: "sm", icon: "copy", title: T.copy || "Copy", onClick: () => dkCopy("npm i -g @decentnetwork/beagle@latest") }))), phase === "idle" && appBehind && info.mode === "npx" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12, color: "var(--dim)", lineHeight: 1.5 } }, T.updNpx || "Running via npx \u2014 restarting picks up the latest version automatically."), daemonPeerBehind && phase === "idle" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12, color: "var(--dim)", lineHeight: 1.5 } }, T.updPeerDaemon || "The peer version belongs to the running agentnet daemon, not to this app. Update it with:", /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: 6 } }, /* @__PURE__ */ React.createElement("code", { style: { flex: 1, minWidth: 0, fontFamily: "var(--mono)", fontSize: 11.5, color: "var(--text)", background: "var(--panel-2)", border: "1px solid var(--line)", borderRadius: 8, padding: "8px 10px", userSelect: "all", wordBreak: "break-all" } }, "npm i -g @decentnetwork/lan@latest && agentnet restart"), /* @__PURE__ */ React.createElement(Btn, { size: "sm", icon: "copy", title: T.copy || "Copy", onClick: () => dkCopy("npm i -g @decentnetwork/lan@latest && agentnet restart") }))), lanBehind && phase === "idle" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12, color: "var(--dim)", lineHeight: 1.5 } }, T.updLanNote || "agentnet (lan): one click reinstalls it and asks the running daemon to restart itself. Manual equivalent:", /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8, marginTop: 6 } }, /* @__PURE__ */ React.createElement("code", { style: { flex: 1, minWidth: 0, fontFamily: "var(--mono)", fontSize: 11.5, color: "var(--text)", background: "var(--panel-2)", border: "1px solid var(--line)", borderRadius: 8, padding: "8px 10px", userSelect: "all", wordBreak: "break-all" } }, "npm i -g @decentnetwork/lan@latest && agentnet restart"), /* @__PURE__ */ React.createElement(Btn, { size: "sm", icon: "copy", title: T.copy || "Copy", onClick: () => dkCopy("npm i -g @decentnetwork/lan@latest && agentnet restart") }))), phase === "lan-done" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12.5, color: "var(--online)" } }, T.updLanDone || "lan updated \u2014 daemon restarted with the new version \u2713"), phase === "lan-norestart" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12.5, color: "var(--warn, #f59e0b)" } }, T.updLanNoRestart || "lan updated, but the daemon was not running (or refused) \u2014 the new version applies on its next start."), phase === "running" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12.5, color: "var(--dim)" } }, T.updBusy || "Updating\u2026 (about a minute)"), phase === "done" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12.5, color: "var(--online)" } }, T.updDone || "Updated \u2014 restart to apply."), phase === "restarting" && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12.5, color: "var(--dim)" } }, T.updRestarting || "Restarting\u2026 this page reloads when it\u2019s back. (If beagle was started by hand in a terminal, run it again.)"), phase === "error" && (() => {
|
|
4750
4844
|
const m = /`([^`]+)`/.exec(err || "");
|
|
4751
4845
|
return /* @__PURE__ */ React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 8 } }, /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 12, color: "var(--danger)", wordBreak: "break-word" } }, m ? err.replace("`" + m[1] + "`", "") : err), m && /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8 } }, /* @__PURE__ */ React.createElement("code", { style: { flex: 1, minWidth: 0, fontFamily: "var(--mono)", fontSize: 11.5, color: "var(--text)", background: "var(--panel-2)", border: "1px solid var(--line)", borderRadius: 8, padding: "8px 10px", userSelect: "all", wordBreak: "break-all" } }, m[1]), /* @__PURE__ */ React.createElement(Btn, { size: "sm", icon: "copy", title: T.copy || "Copy", onClick: () => dkCopy(m[1]) })), m && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 11.5, color: "var(--dim)" } }, T.updManualHint || "Run it in a terminal, then click Restart to apply."));
|
|
4752
|
-
})(), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8 } }, (phase === "idle" || phase === "error" || phase === "lan-done" || phase === "lan-norestart") && btn(phase === "idle" ? T.updLater || "Later" : T.receivedClose || "Close", onClose), phase === "idle" && lanBehind && btn(T.updLanNow || "Update lan", doLanUpdate, !appBehind), phase === "idle" && appBehind && info.mode === "global" && btn(T.updNow || "Update now", doUpdate, true), phase === "idle" && appBehind && info.mode === "npx" && btn(T.updRestart || "Restart", doRestart, true), phase === "error" && btn(T.updRestart || "Restart", doRestart, true), phase === "done" && btn(T.updRestart || "Restart", doRestart, true))));
|
|
4846
|
+
})(), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", justifyContent: "flex-end", gap: 8 } }, (phase === "idle" || phase === "error" || phase === "lan-done" || phase === "lan-norestart") && btn(phase === "idle" ? T.updLater || "Later" : T.receivedClose || "Close", onClose), phase === "idle" && lanBehind && btn(T.updLanNow || "Update lan", doLanUpdate, !appBehind), phase === "idle" && appBehind && (info.mode === "global" || info.mode === "unknown") && btn(T.updNow || "Update now", doUpdate, true), phase === "idle" && appBehind && info.mode === "npx" && btn(T.updRestart || "Restart", doRestart, true), phase === "error" && btn(T.updRestart || "Restart", doRestart, true), phase === "done" && btn(T.updRestart || "Restart", doRestart, true))));
|
|
4753
4847
|
}
|
|
4754
4848
|
function DkApp() {
|
|
4755
4849
|
const [t, setTweak] = useTweaks({ ...DK_DEFAULTS, lang: dkDetectLang() });
|
|
@@ -4999,9 +5093,10 @@ function DkApp() {
|
|
|
4999
5093
|
{ id: "recommended", icon: "sparkles", label: T.recommended },
|
|
5000
5094
|
{ id: "registered", icon: "at", label: T.registered },
|
|
5001
5095
|
{ id: "network", icon: "network", label: T.network },
|
|
5096
|
+
{ id: "apps", icon: "grid", label: T.apps },
|
|
5002
5097
|
{ id: "profile", icon: "userRound", label: T.profile }
|
|
5003
5098
|
];
|
|
5004
|
-
return /* @__PURE__ */ React.createElement("div", { style: { ...vars, "--row-pad": rowPad, position: "fixed", inset: 0, display: "flex", background: "var(--bg)", color: "var(--text)", fontFamily: "var(--ui)" } }, /* @__PURE__ */ React.createElement("div", { style: { width: 68, flexShrink: 0, borderRight: "1px solid var(--line)", background: "var(--rail)", display: "flex", flexDirection: "column", alignItems: "center", padding: "14px 0", gap: 8 } }, /* @__PURE__ */ React.createElement("div", { style: { width: 38, height: 38, borderRadius: 10, background: "var(--accent)", display: "flex", alignItems: "center", justifyContent: "center", marginBottom: 8 } }, /* @__PURE__ */ React.createElement(Icon, { name: "terminal", size: 20, color: "#fff", stroke: 2.2 })), nav.map((n) => /* @__PURE__ */ React.createElement(RailBtn, { key: n.id, icon: n.icon, label: n.label, active: tab === n.id, soon: n.soon, onClick: () => setTab(n.id) })), /* @__PURE__ */ React.createElement("div", { style: { flex: 1 } }), /* @__PURE__ */ React.createElement("div", { style: { position: "relative" } }, /* @__PURE__ */ React.createElement(DkAvatar, { peer: { ...me, id: me.userId, agent: false }, size: 36, radius: 9 }))), /* @__PURE__ */ React.createElement("div", { style: { flex: 1, minWidth: 0, minHeight: 0, display: "flex", flexDirection: "column" } }, /* @__PURE__ */ React.createElement(DkBrowserNotice, { lang: t.lang }), /* @__PURE__ */ React.createElement("div", { style: { height: 46, flexShrink: 0, borderBottom: "1px solid var(--line)", background: "var(--panel)", display: "flex", alignItems: "center", gap: 12, padding: "0 16px" } }, /* @__PURE__ */ React.createElement("svg", { width: 20, height: 20, viewBox: "0 0 24 24", fill: "none", stroke: "var(--accent)", strokeWidth: 2.2, strokeLinecap: "round", strokeLinejoin: "round", style: { display: "block", flexShrink: 0 } }, /* @__PURE__ */ React.createElement("path", { d: "m4.5 17 6-6-6-6" }), /* @__PURE__ */ React.createElement("path", { d: "M12 18.5h7.5" })), /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 14, fontWeight: 700, letterSpacing: -0.3, color: "var(--text)" } }, "beagle"), /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 12, color: "var(--faint)" } }, "\xB7 ", nav.find((n) => n.id === tab).label.toLowerCase()), /* @__PURE__ */ React.createElement("div", { style: { flex: 1 } }), /* @__PURE__ */ React.createElement(Tag, { tone: "accent" }, me.channel, " \xB7 lan ", me.lanVer), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 7, padding: "0 4px" } }, /* @__PURE__ */ React.createElement(StatusDot, { online: me.online }), /* @__PURE__ */ React.createElement(Mono, { size: 12.5, copy: me.ip }, me.ip)), /* @__PURE__ */ React.createElement("span", { style: { width: 1, height: 22, background: "var(--line)" } }), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8 } }, /* @__PURE__ */ React.createElement(DkAvatar, { peer: { ...me, id: me.userId, agent: false }, size: 26, radius: 7 }), /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 12.5, fontWeight: 600, color: "var(--text)" } }, me.name))), tab === "chat" && /* @__PURE__ */ React.createElement(ChatTab, { T, lang: t.lang, peers, requests, activeId, thread: data.threads[activeId], onSelect, onAct, onAdd, onSend, onSendFile, onSendRtcFile, onAlias, onRemove, onOpenNet, onCall, onReloadThread: () => activeId && data.loadThread(activeId), prefillAddr: pendingAddr, onPrefillConsumed: () => setPendingAddr("") }), tab === "here" && /* @__PURE__ */ React.createElement(DiscoverTab, { T, kind: "bridge", peers, meId: me.userId, onAdd, onOpenChat }), tab === "recommended" && /* @__PURE__ */ React.createElement(DiscoverTab, { T, kind: "recommended", peers, meId: me.userId, onAdd, onOpenChat }), tab === "registered" && /* @__PURE__ */ React.createElement(DiscoverTab, { T, kind: "registered", peers, meId: me.userId, onAdd, onOpenChat }), tab === "network" && /* @__PURE__ */ React.createElement(NetworkTab, { T, me, peers, exits, activeExit, reqCount: requests.length, onSetExit, onOpenChat, backend, onArmLan: armLan, onCancelLan: cancelLan }), tab === "profile" && /* @__PURE__ */ React.createElement(ProfileTab, { T, me, onEdit, t, setTweak })), data.locked && /* @__PURE__ */ React.createElement(
|
|
5099
|
+
return /* @__PURE__ */ React.createElement("div", { style: { ...vars, "--row-pad": rowPad, position: "fixed", inset: 0, display: "flex", background: "var(--bg)", color: "var(--text)", fontFamily: "var(--ui)" } }, /* @__PURE__ */ React.createElement("div", { style: { width: 68, flexShrink: 0, borderRight: "1px solid var(--line)", background: "var(--rail)", display: "flex", flexDirection: "column", alignItems: "center", padding: "14px 0", gap: 8 } }, /* @__PURE__ */ React.createElement("div", { style: { width: 38, height: 38, borderRadius: 10, background: "var(--accent)", display: "flex", alignItems: "center", justifyContent: "center", marginBottom: 8 } }, /* @__PURE__ */ React.createElement(Icon, { name: "terminal", size: 20, color: "#fff", stroke: 2.2 })), nav.map((n) => /* @__PURE__ */ React.createElement(RailBtn, { key: n.id, icon: n.icon, label: n.label, active: tab === n.id, soon: n.soon, onClick: () => setTab(n.id) })), /* @__PURE__ */ React.createElement("div", { style: { flex: 1 } }), /* @__PURE__ */ React.createElement("div", { style: { position: "relative" } }, /* @__PURE__ */ React.createElement(DkAvatar, { peer: { ...me, id: me.userId, agent: false }, size: 36, radius: 9 }))), /* @__PURE__ */ React.createElement("div", { style: { flex: 1, minWidth: 0, minHeight: 0, display: "flex", flexDirection: "column" } }, /* @__PURE__ */ React.createElement(DkBrowserNotice, { lang: t.lang }), /* @__PURE__ */ React.createElement("div", { style: { height: 46, flexShrink: 0, borderBottom: "1px solid var(--line)", background: "var(--panel)", display: "flex", alignItems: "center", gap: 12, padding: "0 16px" } }, /* @__PURE__ */ React.createElement("svg", { width: 20, height: 20, viewBox: "0 0 24 24", fill: "none", stroke: "var(--accent)", strokeWidth: 2.2, strokeLinecap: "round", strokeLinejoin: "round", style: { display: "block", flexShrink: 0 } }, /* @__PURE__ */ React.createElement("path", { d: "m4.5 17 6-6-6-6" }), /* @__PURE__ */ React.createElement("path", { d: "M12 18.5h7.5" })), /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 14, fontWeight: 700, letterSpacing: -0.3, color: "var(--text)" } }, "beagle"), /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 12, color: "var(--faint)" } }, "\xB7 ", nav.find((n) => n.id === tab).label.toLowerCase()), /* @__PURE__ */ React.createElement("div", { style: { flex: 1 } }), /* @__PURE__ */ React.createElement(Tag, { tone: "accent" }, me.channel, " \xB7 lan ", me.lanVer), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 7, padding: "0 4px" } }, /* @__PURE__ */ React.createElement(StatusDot, { online: me.online }), /* @__PURE__ */ React.createElement(Mono, { size: 12.5, copy: me.ip }, me.ip)), /* @__PURE__ */ React.createElement("span", { style: { width: 1, height: 22, background: "var(--line)" } }), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", alignItems: "center", gap: 8 } }, /* @__PURE__ */ React.createElement(DkAvatar, { peer: { ...me, id: me.userId, agent: false }, size: 26, radius: 7 }), /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 12.5, fontWeight: 600, color: "var(--text)" } }, me.name))), tab === "chat" && /* @__PURE__ */ React.createElement(ChatTab, { T, lang: t.lang, peers, requests, activeId, thread: data.threads[activeId], onSelect, onAct, onAdd, onSend, onSendFile, onSendRtcFile, onAlias, onRemove, onOpenNet, onCall, onReloadThread: () => activeId && data.loadThread(activeId), prefillAddr: pendingAddr, onPrefillConsumed: () => setPendingAddr("") }), tab === "here" && /* @__PURE__ */ React.createElement(DiscoverTab, { T, kind: "bridge", peers, meId: me.userId, onAdd, onOpenChat }), tab === "recommended" && /* @__PURE__ */ React.createElement(DiscoverTab, { T, kind: "recommended", peers, meId: me.userId, onAdd, onOpenChat }), tab === "registered" && /* @__PURE__ */ React.createElement(DiscoverTab, { T, kind: "registered", peers, meId: me.userId, onAdd, onOpenChat }), tab === "network" && /* @__PURE__ */ React.createElement(NetworkTab, { T, me, peers, exits, activeExit, reqCount: requests.length, onSetExit, onOpenChat, backend, onArmLan: armLan, onCancelLan: cancelLan }), tab === "apps" && /* @__PURE__ */ React.createElement(AppsTab, { T, t }), tab === "profile" && /* @__PURE__ */ React.createElement(ProfileTab, { T, me, onEdit, t, setTweak })), data.locked && /* @__PURE__ */ React.createElement(
|
|
5005
5100
|
DkLockedOut,
|
|
5006
5101
|
{
|
|
5007
5102
|
compact: true,
|
package/package.json
CHANGED